source: TI05-delivery/ows_framework/branches/ows_framework-refactor/ows_common/ows_common/pylons/wms_controller.py @ 3548

Subversion URL: http://proj.badc.rl.ac.uk/svn/ndg/TI05-delivery/ows_framework/branches/ows_framework-refactor/ows_common/ows_common/pylons/wms_controller.py@3548
Revision 3548, 5.6 KB checked in by spascoe, 12 years ago (diff)

Added a simple data interface for WMS. This may not live in ows_common
in the long term but is the most convenient place to put it for now.

Line 
1"""
2WMS controller for OGC Web Services (OWS).
3
4@author: Stephen Pascoe
5"""
6
7from cStringIO import StringIO
8
9from matplotlib.cm import get_cmap
10from pylons import request, response
11
12import logging
13log = logging.getLogger(__name__)
14
15from ows_common.wms import WmsDatasetSummary, Dimension, PossibleValues
16from ows_common.pylons import ows_controller, model
17from ows_common.exceptions import *
18
19class WMSController(ows_controller.OWSController):
20
21    service = 'WMS'
22    owsOperations = ows_controller.OWSController.owsOperations + ['GetMap', 'GetInfo']
23    validVersions = ['1.1.1']
24
25    _pilImageFormats = {
26        'image/png': 'PNG',
27        'image/jpg': 'JPEG',
28        'image/gif': 'GIF',
29        'image/tiff': 'TIFF'
30        }
31
32    def __before__(self, **kwargs):
33        """
34        This default implementation of __before__() will pass all routes
35        arguments to the layer mapper to retrieve a list of layers for
36        this WMS.
37
38        It will be called automatically by pylons before each action method.
39
40        @todo: The layer mapper needs to come from somewhere.
41
42        """
43        self.layers = model.getLayerMapper().map(**kwargs)
44
45    #-------------------------------------------------------------------------
46    # Methods implementing stubs in OWSController
47
48    def _renderCapabilities(self, version, format):
49        t = ows_controller.templateLoader.load('wms_capabilities_1_1_1.xml')
50        return t.generate(c=c).render()
51
52    def _loadCapabilities(self):
53        """
54        @note: Assumes self.layers has already been created by __before__().
55
56        """
57        ows_controller.addOperation('GetMap', formats=self._pilImageFormats.keys())
58        ows_controller.addOperation('GetInfo')
59        log.debug('Loading capabilities contents')
60        for layerName, layer in self.layers.items():
61            log.debug('Loading layer %s' % layerName)
62
63            # Get CRS/BBOX pairs
64            bboxObjs = []
65            for crs in layer.crss:
66                bbox = layer.getBbox(crs)
67                bboxObjs.append(BoundingBox(bbox[:2], bbox[2:], crs=crs))
68            # Get dimensions
69            dims = {}
70            for dimName, dim in layer.dimensions.items():
71                dims[dimName] = Dimension(valuesUnit=dim.units,
72                                          unitSymbol=dim.units,
73                                          possibleValues=
74                                            PossibleValues.fromAllowedValues(dim.extent))
75            # Create the ows_common object
76            ds = WmsDatasetSummary(identifier=layerName,
77                                   titles=[layer.title],
78                                   boundingBoxes=bboxObjs,
79                                   abstracts=[layer.abstract])
80
81            c.capabilities.contents.datasetSummaries.append(ds)
82
83    #-------------------------------------------------------------------------
84    # OWS Operation methods
85   
86    def GetMap(self):
87
88        # Housekeeping
89        version = self.getOwsParam('version', default=self.validVersions[0])
90        if version not in self.validVersions:
91            raise InvalidParameterValue('Version %s not supported' % version,
92                                        'version')
93        styles = self.getOwsParam('styles', default='')
94        transparent = self.getOwsParam('transparent', default='FALSE')
95        bgcolor = self.getOwsParam('bgcolor', default='0xFFFFFF')
96
97        # Layer handling
98        layerName = self.getOwsParam('layers')
99        if ',' in layer:
100            raise InvalidParameterValue(
101                'Multi-layer GetMap requests are not supported', 'layers')
102        try:
103            layerObj = self.layers[layerName]
104        except KeyError:
105            raise InvalidParameterValue('Layer %s not found' % layerName, 'layers')
106
107               
108        # Coordinate parameters
109        bbox = tuple(float(x) for x in self.getOwsParam('bbox').split(','))
110        width = int(self.getOwsParam('width'))
111        height = int(self.getOwsParam('height'))
112        srs = self.getOwsParam('srs')
113        if srs not in layerObj.crss:
114            raise InvalidParameterValue('Layer %s does not support SRS %s' % (layerName, srs))
115
116        # Get format
117        format = self.getOwsParam('format')
118        if format not in self._pilImageFormats:
119            raise InvalidParameterValue(
120                'Format %s not supported' % format, 'format')
121
122        # Dimension handling
123        dimValues = {}
124        for dimName, dim in self.layer.dimensions.items():
125            defaultValue = dim.extent[0]
126            dimValues[dimName] = self.getOwsParam('time', default=defaultValue)
127
128        # The real work
129        #!TODO: Minimum and maximum values
130        slab = layerObj.getSlab(srs, dims, dict(minValue=0, maxValue=100))
131        img = view.getImage(bbox, width, height)
132
133        # IE < 7 doesn't display the alpha layer right.  Here we sniff the
134        # user agent and remove the alpha layer if necessary.
135        try:
136            ua = request.headers['User-Agent']
137        except:
138            pass
139        else:
140            if 'MSIE' in ua and 'MSIE 7' not in ua:
141                img = img.convert('RGB')
142
143        buf = StringIO()
144        img.save(buf, self._pilImageFormats[format])
145
146        response.headers['Content-Type'] = format
147        response.write(buf.getvalue())
148
149        return request
150
151    def GetInfo(self):
152        from pprint import pformat
153        request.headers['Content-Type'] = 'text/ascii'
154        response.write('Some info about this service\n')
155        for layer in model.ukcip02.layers:
156            response.write('Layer %s: %s\n' % (layer, pformat(g.ukcip02_layers[layer].__dict__)))
157
158           
Note: See TracBrowser for help on using the repository browser.