source: qesdi/wms_ddc_vis/trunk/lib/wms_ddc_vis/controllers/coastwms.py @ 5752

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/qesdi/wms_ddc_vis/trunk/lib/wms_ddc_vis/controllers/coastwms.py@5752
Revision 5752, 11.5 KB checked in by pnorton, 11 years ago (diff)

Fixed the PIL import in coastwms so it tries to import Image from PIL and directly.

Line 
1import logging
2
3import thread
4import re
5import simplejson as json
6
7from StringIO import StringIO
8from sets import Set
9from matplotlib.cm import get_cmap
10from pylons import request, response, c
11from routes import url_for
12from routes.util import GenerationException
13from genshi.template import NewTextTemplate
14from cows.pylons.wms_controller import WMSController
15from cows.model.wms import WmsDatasetSummary, Dimension, DataURL
16from cows.model import PossibleValues, WGS84BoundingBox, BoundingBox, Contents
17from cows.pylons import ows_controller
18from cows.exceptions import *
19from cows import bbox_util
20from cows.service.imps.data_reader_geoplot_backend.rendering_option import RenderingOption
21from cows.service.imps.data_reader_geoplot_backend.slab_options_parser import SlabOptionsParser
22from cows.service.imps.data_reader_geoplot_backend.slab_options_json_generator import SlabJSONGenerator
23
24from wms_ddc_vis.lib.image_import import Image
25from wms_ddc_vis.lib.wms_request_log_utils import buildLogString, wms_request_logger
26
27import time
28
29from geoplot.layer_drawer_coastline import LayerDrawerCoastlines
30
31from cows.model.wms import Style, LegendURL, FormattedURL, MetadataURL
32from cows.xml.iso19115_subset import OnlineResource
33
34log = logging.getLogger(__name__)
35
36class CoastwmsController(ows_controller.OWSController):
37
38    renderingOptions = [
39        RenderingOption('show_rivers', "Show Rivers" ,bool , False ),
40        RenderingOption('coastline_colour', "Coastline Colour" ,str , "black" ),
41        RenderingOption('resolution', "Coastline Resolution" ,str , "auto", ["coarse","low", "intermediate", "high", "auto"]  ),           
42    ]
43       
44
45    #layers = {}   
46    _pilImageFormats = {
47        'image/png': 'PNG',
48        'image/jpg': 'JPEG',
49        'image/gif': 'GIF',
50        'image/tiff': 'TIFF'
51        }
52   
53    _layerSlabCache = {}
54
55    #-------------------------------------------------------------------------
56    # Attributes required by OWSController
57
58    service = 'WMS'
59    owsOperations = (ows_controller.OWSController.owsOperations +
60        ['GetMap', 'GetContext', 'GetLegend', 'GetFeatureInfo', 'GetInfo', 'GetDisplayOptions'])
61   
62    validVersions = ['1.1.1', '1.3.0']
63
64
65    def __before__(self, **kwargs):
66        wms_request_logger.info( buildLogString(request) )
67
68    def _renderCapabilities(self, version, format):
69        if format == 'application/json':
70            t = ows_controller.templateLoader.load('wms_capabilities_json.txt',
71                                                   cls=NewTextTemplate)
72        elif version == '1.1.1':
73            t = ows_controller.templateLoader.load('wms_capabilities_1_1_1.xml')
74        elif version == '1.3.0':
75            t = ows_controller.templateLoader.load('wms_capabilities_1_3_0.xml')
76        else:
77            # We should never get here!  The framework should raise an exception before now.
78            raise RuntimeError("Version %s not supported" % version)
79       
80        return t.generate(c=c).render()
81
82    def _loadCapabilities(self):
83        """
84        @note: Assumes self.layers has already been created by __before__().
85
86        """
87        #!TODO: Add json format to GetCapabilities operation
88
89        ows_controller.addOperation('GetMap', formats=self._pilImageFormats.keys())
90        ows_controller.addOperation('GetContext', formats=['text/xml', 'application/json'])
91
92       
93        featureInfoFormats = Set()
94
95        log.debug('Loading capabilities contents')
96        c.capabilities.contents = Contents()
97       
98       
99 
100       
101        layers = ( ('coastline', 'coastline', 'Coast Outline'), )
102       
103       
104        for layerName, title,  abstract in layers:
105            log.debug('LayerName: %s' % layerName)
106            log.debug('Loading layer %s' % layerName)
107
108            wgs84BBox = WGS84BoundingBox((-180,-90), (180,90))
109
110            # Get CRS/BBOX pairs
111            bboxObjs = []
112            for crs in ('EPSG:4326', 'CRS:84', 'WGS84'):
113                bbox = [-180,-90,180,90]
114                bboxObjs.append(BoundingBox(bbox[:2], bbox[2:], crs=crs))
115               
116
117               
118            #URL to WCS - uses named route 'wcsroute'
119            #TODO: Allow for a WCS blacklist to opt out of providing dataurls for certain datasets?
120            #TODO: How to make this more configurable - what if WCS is not coupled with WMS?
121#            try:
122#                version='1.0.0' #wcs version
123#                wcsbaseurl=url_for('wcsroute', fileoruri=c.fileoruri,qualified=True)+'?'
124#                dataURLs=[DataURL(format='WCS:CoverageDescription', onlineResource='%sService=WCS&Request=DescribeCoverage&Coverage=%s&Version=%s'%(wcsbaseurl, layerName, version))]
125#            except GenerationException:
126#                log.info("dataURLs not populated: could not generate WCS url with url_for('wcsroute', filedoruri=%s,qualified=True)"%c.fileoruri)
127#                dataURLs=[]
128           
129            onlineRes = OnlineResource(url_for(qualified=True, action='index') +\
130                                    "?request=GetDisplayOptions&layers=%s" % layerName)
131            metadataURL = MetadataURL(metadataType='display_options', format='application/json', onlineResource=onlineRes)
132       
133            # Create the cows object
134            ds = WmsDatasetSummary(identifier=layerName,
135                                   titles=[title],
136                                   CRSs=('EPSG:4326', 'CRS:84', 'WGS84'),
137                                   wgs84BoundingBoxes=[wgs84BBox],
138                                   boundingBoxes=bboxObjs,
139                                   abstracts=[abstract],
140                                   dimensions={},
141                                   queryable=False,
142                                   dataURLs=[],
143                                   styles=[],
144                                   metadataURLs=[metadataURL])
145
146            # Stuff that should go in the capabilities tree eventually
147            ds.legendSize = (630,80)
148            ds.legendFormats = ['image/png']
149
150            c.capabilities.contents.datasetSummaries.append(ds)
151
152        # Add this operation here after we have found all formats
153        ows_controller.addOperation('GetFeatureInfo',
154                                    formats = list(featureInfoFormats))
155
156
157    _escapedDimNames = ['width', 'height', 'version', 'request',
158                        'layers', 'styles', 'crs', 'srs', 'bbox',
159                        'format', 'transparent', 'bgcolor',
160                        'exceptions']
161
162
163    def _mapDimToParam(self, dimName):
164        """
165        Dimension names might clash with WMS parameter names, making
166        them inaccessible in WMS requests.  This method maps a
167        dimension name to a parameter name that appears in the
168        capabilities document and WMS requests.
169
170        """
171        if dimName.lower() in self._escapedDimNames:
172            return dimName+'_dim'
173        else:
174            return dimName
175       
176   
177    def GetMap(self):       
178        st = time.time()
179
180
181        parser = SlabOptionsParser(CoastwmsController.renderingOptions, request.params)
182       
183
184       
185        # Housekeeping
186        version = self.getOwsParam('version', default=self.validVersions[0])
187        if version not in self.validVersions:
188            raise InvalidParameterValue('Version %s not supported' % version,
189                                        'version')
190        styles = self.getOwsParam('styles', default='')
191        transparent = self.getOwsParam('transparent', default='FALSE')
192        bgcolor = self.getOwsParam('bgcolor', default='0xFFFFFF')
193
194        # Layer handling
195        layerName = self.getOwsParam('layers')
196       
197        transparent = self.getOwsParam('transparent').lower() == 'true'
198       
199       
200        # Coordinate parameters
201        bbox = tuple(float(x) for x in self.getOwsParam('bbox').split(','))
202        width = int(self.getOwsParam('width'))
203        height = int(self.getOwsParam('height'))
204
205        if version == '1.1.1':
206            srs = self.getOwsParam('srs')
207        else:
208            srs = self.getOwsParam('crs')
209
210        # Get format
211        format = self.getOwsParam('format')
212        if format not in self._pilImageFormats:
213            raise InvalidParameterValue(
214                'Format %s not supported' % format, 'format')
215
216 
217        longResolution = parser.getOption('resolution')
218        log.debug("longResolution = %s" % (longResolution,))
219        resMap = {'coarse':'c',
220                  'low':'l',
221                  'intermediate':'i',
222                  'high':'h',
223                  'full':'f',
224                  'auto':None
225                  }
226        resolution = resMap[longResolution]
227         
228        log.debug("resolution = %s" % (resolution,))
229        ldg = LayerDrawerCoastlines(transparent=transparent,
230                                    resolution=resolution)
231
232
233        ldg.drawRivers = parser.getOption('show_rivers')
234        ldg.coastlineColour = parser.getOption('coastline_colour')
235
236        xLimits = (bbox[0], bbox[2])
237        yLimits = (bbox[1], bbox[3])       
238        finalImg = ldg.makeImage(xLimits, yLimits, width, height)     
239
240       
241        # IE < 7 doesn't display the alpha layer right.  Here we sniff the
242        # user agent and remove the alpha layer if necessary.
243        try:
244            ua = request.headers['User-Agent']
245            log.debug("ua = %s" % (ua,))
246        except:
247            pass
248        else:
249            if 'MSIE 6.0' in ua:
250                finalImg = finalImg.convert('RGB')
251
252        buf = StringIO()
253        finalImg.save(buf, self._pilImageFormats[format])
254
255        response.headers['Content-Type'] = format
256        response.write(buf.getvalue())
257
258       
259        log.debug("got coastline in %s" % (time.time() - st,))
260
261    def GetContext(self):
262        """
263        Return a WebMap Context document for a given set of layers.
264
265        """
266        # Parameters
267        layers = self.getOwsParam('layers', default=None)
268        format = self.getOwsParam('format', default='text/xml')
269
270        # Filter self.layers for selected layers
271        if layers is not None:
272            newLayerMap = {}
273            for layerName in layers.split(','):
274                try:
275                    newLayerMap[layerName] = self.layers[layerName]
276                except KeyError:
277                    raise InvalidParameterValue('Layer %s not found' % layerName,
278                                                'layers')
279                   
280            self.layers = newLayerMap
281
282        # Automatically select the first bbox/crs for the first layer
283        aLayer = self.layers.values()[0]
284        crs = aLayer.crss[0]
285        bb = aLayer.getBBox(crs)
286        c.bbox = BoundingBox(bb[:2], bb[2:], crs)
287
288        # Initialise as if doing GetCapabilities
289        ows_controller.initCapabilities()
290        self._loadCapabilities()
291
292        if format == 'text/xml':
293           
294            response.headers['Content-Type'] = format
295            t = ows_controller.templateLoader.load('wms_context_1_1_1.xml')
296            return t.generate(c=c).render()
297       
298        elif format == 'application/json':
299           
300            response.headers['Content-Type'] = format
301            t = ows_controller.templateLoader.load('wms_context_json.txt',
302                                                   cls=NewTextTemplate)
303            return t.generate(c=c).render()
304       
305        else:
306            raise InvalidParameterValue('Format %s not supported' % format)
307
308
309    def GetDisplayOptions(self):
310       
311       
312        generator = SlabJSONGenerator({'':CoastwmsController.renderingOptions})
313        request.headers['Content-Type'] = 'application/json'
314        response.write( generator.generateJSON() )
315
Note: See TracBrowser for help on using the repository browser.