class CoverageDescriptionMapServerRenderer(BaseRenderer): """ A coverage description renderer implementation using mapserver. """ versions = (Version(1, 1), Version(1, 0)) def supports(self, params): return ( params.version in self.versions and all( not coverage.grid.is_referenceable for coverage in params.coverages ) ) def render(self, params): map_ = self.create_map() use_name = (params.version == Version(1, 0)) for coverage in params.coverages: # ReferenceableDatasets are not supported in WCS < 2.0 if coverage.grid.is_referenceable: raise NoSuchCoverageException((coverage.identifier,)) data_locations = self.arraydata_locations_for_coverage(coverage) native_format = self.get_native_format(coverage, data_locations) layer = self.layer_for_coverage( coverage, native_format, params.version ) map_.insertLayer(layer) for outputformat in self.get_all_outputformats(not use_name): map_.appendOutputFormat(outputformat) request = ms.create_request(params) raw_result = ms.dispatch(map_, request) result = result_set_from_raw_data(raw_result) # load XML using lxml # find and exclude <metadataLink> nodes if present # re-encode xml_result = etree.fromstring(result[0].data) for elem in xml_result.xpath('//*[local-name() = "metadataLink"]'): elem.getparent().remove(elem) xml_result_data = etree.tostring(xml_result, pretty_print=True, encoding='UTF-8', xml_declaration=True) result[0] = ResultBuffer(xml_result_data, result[0].content_type) return result
class NativeWCS20CapabilitiesRenderer(Component): implements(WCSCapabilitiesRendererInterface) versions = (Version(2, 0), ) def supports(self, params): if params.version not in self.versions: return False if params.accept_formats and "text/xml" not in params.accept_formats: return False # TODO: accept_languages? return True def render(self, params): encoder = WCS20CapabilitiesXMLEncoder() return [ ResultBuffer( encoder.serialize(encoder.encode_capabilities( params.sections or ("all"), None, params.coverages, params.dataset_series, params.http_request), pretty_print=settings.DEBUG), encoder.content_type) ]
class CoverageDescriptionMapServerRenderer(BaseRenderer): """ A coverage description renderer implementation using mapserver. """ implements(WCSCoverageDescriptionRendererInterface) versions = (Version(1, 1), Version(1, 0)) handles = (models.RectifiedDataset, models.RectifiedStitchedMosaic, models.ReferenceableDataset) def supports(self, params): return (params.version in self.versions and all( map(lambda c: issubclass(c.real_type, self.handles), params.coverages))) def render(self, params): map_ = self.create_map() use_name = (params.version == Version(1, 0)) for coverage in params.coverages: # ReferenceableDatasets are not supported in WCS < 2.0 if issubclass(coverage.real_type, models.ReferenceableDataset): raise NoSuchCoverageException((coverage.identifier, )) data_items = self.data_items_for_coverage(coverage) native_format = self.get_native_format(coverage, data_items) layer = self.layer_for_coverage(coverage, native_format, params.version) map_.insertLayer(layer) for outputformat in self.get_all_outputformats(not use_name): map_.appendOutputFormat(outputformat) request = ms.create_request(params) raw_result = ms.dispatch(map_, request) result = result_set_from_raw_data(raw_result) return result
class NativeWCS20CoverageDescriptionRenderer(Component): """ Coverage description renderer for WCS 2.0 using the EO application profile. """ implements(WCSCoverageDescriptionRendererInterface) versions = (Version(2, 0), ) def supports(self, params): return params.version in self.versions def render(self, params): encoder = WCS20EOXMLEncoder() return [ ResultBuffer( encoder.serialize( encoder.encode_coverage_descriptions(params.coverages), pretty_print=settings.DEBUG), encoder.content_type) ]
def render(self, params): map_ = self.create_map() use_name = (params.version == Version(1, 0)) for coverage in params.coverages: # ReferenceableDatasets are not supported in WCS < 2.0 if issubclass(coverage.real_type, models.ReferenceableDataset): raise NoSuchCoverageException((coverage.identifier, )) data_items = self.data_items_for_coverage(coverage) native_format = self.get_native_format(coverage, data_items) layer = self.layer_for_coverage(coverage, native_format, params.version) map_.insertLayer(layer) for outputformat in self.get_all_outputformats(not use_name): map_.appendOutputFormat(outputformat) request = ms.create_request(params) raw_result = ms.dispatch(map_, request) result = result_set_from_raw_data(raw_result) return result
def render(self, params): # get coverage related stuff coverage = params.coverage # ReferenceableDataset are not supported in WCS < 2.0 if issubclass(coverage.real_type, models.ReferenceableDataset): raise NoSuchCoverageException((coverage.identifier, )) data_items = self.data_items_for_coverage(coverage) range_type = coverage.range_type bands = list(range_type) subsets = params.subsets if subsets: subsets.srid # this automatically checks the validity # create and configure map object map_ = self.create_map() # configure outputformat native_format = self.get_native_format(coverage, data_items) if get_format_by_mime(native_format) is None: native_format = "image/tiff" frmt = params.format or native_format if frmt is None: raise RenderException("Format could not be determined", "format") mime_type, frmt = split_format(frmt) imagemode = ms.gdalconst_to_imagemode(bands[0].data_type) time_stamp = datetime.now().strftime("%Y%m%d%H%M%S") basename = "%s_%s" % (coverage.identifier, time_stamp) of = create_outputformat(mime_type, frmt, imagemode, basename, getattr(params, "encoding_params", {})) map_.appendOutputFormat(of) map_.setOutputFormat(of) # TODO: use layer factory here layer = self.layer_for_coverage(coverage, native_format, params.version) map_.insertLayer(layer) for connector in self.connectors: if connector.supports(data_items): break else: raise OperationNotSupportedException( "Could not find applicable layer connector.", "coverage") try: connector.connect(coverage, data_items, layer, {}) # create request object and dispatch it against the map request = ms.create_request( self.translate_params(params, range_type)) request.setParameter("format", mime_type) raw_result = ms.dispatch(map_, request) finally: # perform any required layer related cleanup connector.disconnect(coverage, data_items, layer, {}) result_set = result_set_from_raw_data(raw_result) if params.version == Version(2, 0): if getattr(params, "mediatype", None) in ("multipart/mixed", "multipart/related"): encoder = WCS20EOXMLEncoder() is_mosaic = issubclass(coverage.real_type, models.RectifiedStitchedMosaic) if not is_mosaic: tree = encoder.alter_rectified_dataset( coverage, getattr(params, "http_request", None), etree.parse(result_set[0].data_file).getroot(), subsets.bounding_polygon(coverage) if subsets else None) else: tree = encoder.alter_rectified_stitched_mosaic( coverage.cast(), getattr(params, "http_request", None), etree.parse(result_set[0].data_file).getroot(), subsets.bounding_polygon(coverage) if subsets else None) result_set[0] = ResultBuffer(encoder.serialize(tree), encoder.content_type) # "default" response return result_set
class RectifiedCoverageMapServerRenderer(BaseRenderer): """ A coverage renderer for rectified coverages. Uses mapserver to process the request. """ implements(WCSCoverageRendererInterface) # ReferenceableDatasets are not handled in WCS >= 2.0 versions_full = (Version(1, 1), Version(1, 0)) versions_partly = (Version(2, 0), ) versions = versions_full + versions_partly handles_full = (models.RectifiedDataset, models.RectifiedStitchedMosaic, models.ReferenceableDataset) handles_partly = (models.RectifiedDataset, models.RectifiedStitchedMosaic) handles = handles_full + handles_partly connectors = ExtensionPoint(ConnectorInterface) layer_factories = ExtensionPoint(LayerFactoryInterface) def supports(self, params): return ((params.version in self.versions_full and issubclass(params.coverage.real_type, self.handles_full)) or (params.version in self.versions_partly and issubclass( params.coverage.real_type, self.handles_partly))) def render(self, params): # get coverage related stuff coverage = params.coverage # ReferenceableDataset are not supported in WCS < 2.0 if issubclass(coverage.real_type, models.ReferenceableDataset): raise NoSuchCoverageException((coverage.identifier, )) data_items = self.data_items_for_coverage(coverage) range_type = coverage.range_type bands = list(range_type) subsets = params.subsets if subsets: subsets.srid # this automatically checks the validity # create and configure map object map_ = self.create_map() # configure outputformat native_format = self.get_native_format(coverage, data_items) if get_format_by_mime(native_format) is None: native_format = "image/tiff" frmt = params.format or native_format if frmt is None: raise RenderException("Format could not be determined", "format") mime_type, frmt = split_format(frmt) imagemode = ms.gdalconst_to_imagemode(bands[0].data_type) time_stamp = datetime.now().strftime("%Y%m%d%H%M%S") basename = "%s_%s" % (coverage.identifier, time_stamp) of = create_outputformat(mime_type, frmt, imagemode, basename, getattr(params, "encoding_params", {})) map_.appendOutputFormat(of) map_.setOutputFormat(of) # TODO: use layer factory here layer = self.layer_for_coverage(coverage, native_format, params.version) map_.insertLayer(layer) for connector in self.connectors: if connector.supports(data_items): break else: raise OperationNotSupportedException( "Could not find applicable layer connector.", "coverage") try: connector.connect(coverage, data_items, layer, {}) # create request object and dispatch it against the map request = ms.create_request( self.translate_params(params, range_type)) request.setParameter("format", mime_type) raw_result = ms.dispatch(map_, request) finally: # perform any required layer related cleanup connector.disconnect(coverage, data_items, layer, {}) result_set = result_set_from_raw_data(raw_result) if params.version == Version(2, 0): if getattr(params, "mediatype", None) in ("multipart/mixed", "multipart/related"): encoder = WCS20EOXMLEncoder() is_mosaic = issubclass(coverage.real_type, models.RectifiedStitchedMosaic) if not is_mosaic: tree = encoder.alter_rectified_dataset( coverage, getattr(params, "http_request", None), etree.parse(result_set[0].data_file).getroot(), subsets.bounding_polygon(coverage) if subsets else None) else: tree = encoder.alter_rectified_stitched_mosaic( coverage.cast(), getattr(params, "http_request", None), etree.parse(result_set[0].data_file).getroot(), subsets.bounding_polygon(coverage) if subsets else None) result_set[0] = ResultBuffer(encoder.serialize(tree), encoder.content_type) # "default" response return result_set def translate_params(self, params, range_type): """ "Translate" parameters to be understandable by mapserver. """ if params.version.startswith("2.0"): for key, value in params: if key == "interpolation": interpolation = INTERPOLATION_TRANS.get(value) if not interpolation: raise InterpolationMethodNotSupportedException( "Interpolation method '%s' is not supported." % value) yield key, value else: yield key, value rangesubset = params.rangesubset if rangesubset: yield "rangesubset", ",".join( map(str, rangesubset.get_band_indices(range_type, 1))) # TODO: this only works in newer MapServer implementations # (since 6.4?). SCALE_AVAILABLE = ms.msGetVersionInt() > 60401 scalefactor = params.scalefactor if scalefactor is not None: if SCALE_AVAILABLE: yield "scalefactor", str(scalefactor) else: raise RenderException( "'ScaleFactor' is not supported by MapServer in the " "current version.", "scalefactor") for scale in params.scales: scaleaxes = [] if isinstance(scale, ScaleSize): yield "size", "%s(%d)" % (scale.axis, scale.size) elif isinstance(scale, ScaleExtent): yield "size", "%s(%d)" % (scale.axis, scale.high - scale.low) elif isinstance(scale, ScaleAxis): if SCALE_AVAILABLE: scaleaxes.append(scale) else: raise RenderException( "'ScaleAxes' is not supported by MapServer in the " "current version.", "scaleaxes") if scaleaxes: yield "scaleaxes", ",".join("%s(%f)" % (scale.axis, scale.scale) for scale in scaleaxes) if params.outputcrs is not None: srid = crss.parseEPSGCode( params.outputcrs, (crss.fromURL, crss.fromURN, crss.fromShortCode)) if srid is None: raise InvalidOutputCrsException( "Failed to extract an EPSG code from the OutputCRS URI " "'%s'." % params.outputcrs) yield "outputcrs", params.outputcrs else: for key, value in params: yield key, value
class MapServerWCSCapabilitiesRenderer(BaseRenderer): """ WCS Capabilities renderer implementation using MapServer. """ implements(WCSCapabilitiesRendererInterface) versions = (Version(1, 0), Version(1, 1)) def supports(self, params): return params.version in self.versions def render(self, params): conf = CapabilitiesConfigReader(get_eoxserver_config()) http_service_url = get_http_service_url(params.http_request) map_ = Map() map_.setMetaData( { "enable_request": "*", "onlineresource": http_service_url, "service_onlineresource": conf.onlineresource, "updateSequence": conf.update_sequence, "name": conf.name, "title": conf.title, "label": conf.title, "abstract": conf.abstract, "accessconstraints": conf.access_constraints, "addresstype": "", "address": conf.delivery_point, "stateorprovince": conf.administrative_area, "city": conf.city, "postcode": conf.postal_code, "country": conf.country, "contactelectronicmailaddress": conf.electronic_mail_address, "contactfacsimiletelephone": conf.phone_facsimile, "contactvoicetelephone": conf.phone_voice, "contactperson": conf.individual_name, "contactorganization": conf.provider_name, "contactposition": conf.position_name, "role": conf.role, "hoursofservice": conf.hours_of_service, "contactinstructions": conf.contact_instructions, "fees": conf.fees, "keywordlist": ",".join(conf.keywords), "formats": " ".join([f.wcs10name for f in self.get_wcs_formats()]), "srs": " ".join( crss.getSupportedCRS_WCS( format_function=crss.asShortCode)), }, namespace="ows") map_.setProjection("EPSG:4326") for outputformat in self.get_all_outputformats(False): map_.appendOutputFormat(outputformat) for coverage in params.coverages: layer = Layer(coverage.identifier) render_coverage = Coverage.from_model(coverage) layer.setProjection(render_coverage.grid.spatial_reference.proj) extent = render_coverage.extent size = render_coverage.size resolution = ((extent[2] - extent[0]) / float(size[0]), (extent[1] - extent[3]) / float(size[1])) layer.setExtent(*extent) layer.setMetaData( { "title": coverage.identifier, "label": coverage.identifier, "extent": "%.10g %.10g %.10g %.10g" % extent, "resolution": "%.10g %.10g" % resolution, "size": "%d %d" % size, "formats": " ".join([f.wcs10name for f in self.get_wcs_formats()]), "srs": " ".join( crss.getSupportedCRS_WCS( format_function=crss.asShortCode)), }, namespace="wcs") map_.insertLayer(layer) request = create_request(params) request.setParameter("version", params.version) raw_result = map_.dispatch(request) result = result_set_from_raw_data(raw_result) xml_result = etree.fromstring(result[0].data) for elem in xml_result.xpath('//*[local-name() = "metadataLink"]'): elem.getparent().remove(elem) # Add CQL parameter to GetCapabilities operation for elem in xml_result.xpath( '//*[local-name() = "Operation"][@name = "GetCapabilities"]'): ows = elem.nsmap['ows'] param = etree.SubElement(elem, '{%s}Parameter' % ows) param.attrib['name'] = 'cql' etree.SubElement(param, '{%s}AnyValue' % ows) xml_result_data = etree.tostring(xml_result, pretty_print=True, encoding='UTF-8', xml_declaration=True) result[0] = ResultBuffer(xml_result_data, result[0].content_type) return result
def render(self, params): # get coverage related stuff coverage = params.coverage # ReferenceableDataset are not supported in WCS < 2.0 if params.coverage.grid.is_referenceable and params.version: raise NoSuchCoverageException((coverage.identifier, )) data_locations = self.arraydata_locations_for_coverage(coverage) range_type = coverage.range_type bands = list(range_type) subsets = params.subsets if subsets: subsets.srid # this automatically checks the validity # create and configure map object map_ = self.create_map() env = {} for data_location in data_locations: env.update(data_location.env) gdal.set_env(env, False) # configure outputformat native_format = self.get_native_format(coverage, data_locations) if native_format and get_format_by_mime(native_format) is None: native_format = "image/tiff" frmt = params.format or native_format if frmt is None: raise RenderException("Format could not be determined", "format") mime_type, frmt = split_format(frmt) imagemode = ms.gdalconst_to_imagemode(bands[0].data_type) time_stamp = datetime.now().strftime("%Y%m%d%H%M%S") basename = "%s_%s" % (coverage.identifier, time_stamp) of = create_outputformat(mime_type, frmt, imagemode, basename, getattr(params, "encoding_params", {})) map_.appendOutputFormat(of) map_.setOutputFormat(of) # TODO: use layer factory here layer = self.layer_for_coverage(coverage, native_format, params.version) map_.insertLayer(layer) connector = get_connector_by_test(coverage, data_locations) if not connector: raise OperationNotSupportedException( "Could not find applicable layer connector.", "coverage") try: connector.connect(coverage, data_locations, layer, {}) # create request object and dispatch it against the map request = ms.create_request( self.translate_params(params, range_type)) request.setParameter("format", mime_type) raw_result = ms.dispatch(map_, request) finally: # perform any required layer related cleanup connector.disconnect(coverage, data_locations, layer, {}) result_set = result_set_from_raw_data(raw_result) if params.version == Version(2, 0): mediatype = getattr(params, "mediatype", None) if mediatype in ("multipart/mixed", "multipart/related"): with vsi.TemporaryVSIFile.from_buffer(result_set[1].data) as f: ds = gdal.Open(f.name) grid = objects.Grid.from_gdal_dataset(ds) # get the output CRS definition crs = params.outputcrs or subsets.crs or 'imageCRS' if crs == 'imageCRS': crs = coverage.grid.coordinate_reference_system grid._coordinate_reference_system = crs origin = objects.Origin.from_gdal_dataset(ds) size = [ds.RasterXSize, ds.RasterYSize] range_type = coverage.range_type if params.rangesubset: range_type = range_type.subset(params.rangesubset) coverage._grid = grid coverage._origin = origin coverage._size = size coverage._range_type = range_type if isinstance(result_set[1].filename, binary_type): file_name = result_set[1].filename.decode() else: file_name = result_set[1].filename reference = 'cid:coverage/%s' % file_name encoder = WCS20EOXMLEncoder() if not isinstance(coverage, objects.Mosaic): tree = encoder.encode_rectified_dataset( coverage, getattr(params, "http_request", None), reference, mime_type, subsets.bounding_polygon(coverage) if subsets else None) else: tree = encoder.encode_rectified_stitched_mosaic( coverage, getattr(params, "http_request", None), reference, mime_type, subsets.bounding_polygon(coverage) if subsets else None) result_set[0] = ResultBuffer(encoder.serialize(tree), encoder.content_type) # "default" response return result_set
class RectifiedCoverageMapServerRenderer(BaseRenderer): """ A coverage renderer for rectified coverages. Uses mapserver to process the request. """ # ReferenceableDatasets are not handled in WCS >= 2.0 versions_full = (Version(1, 1), Version(1, 0)) versions_partly = (Version(2, 0), ) versions = versions_full + versions_partly # handles_full = ( # models.RectifiedDataset, # models.RectifiedStitchedMosaic, # models.ReferenceableDataset # ) # handles_partly = (models.RectifiedDataset, models.RectifiedStitchedMosaic) # handles = handles_full + handles_partly # connectors = ExtensionPoint(ConnectorInterface) # layer_factories = ExtensionPoint(LayerFactoryInterface) def supports(self, params): # return ( # ( # params.version in self.versions_full and # and issubclass(params.coverage.real_type, self.handles_full)) # or # (params.version in self.versions_partly # and issubclass(params.coverage.real_type, self.handles_partly)) # ) return params.version in self.versions and not params.coverage.grid.is_referenceable def render(self, params): # get coverage related stuff coverage = params.coverage # ReferenceableDataset are not supported in WCS < 2.0 if params.coverage.grid.is_referenceable and params.version: raise NoSuchCoverageException((coverage.identifier, )) data_locations = self.arraydata_locations_for_coverage(coverage) range_type = coverage.range_type bands = list(range_type) subsets = params.subsets if subsets: subsets.srid # this automatically checks the validity # create and configure map object map_ = self.create_map() env = {} for data_location in data_locations: env.update(data_location.env) gdal.set_env(env, False) # configure outputformat native_format = self.get_native_format(coverage, data_locations) if native_format and get_format_by_mime(native_format) is None: native_format = "image/tiff" frmt = params.format or native_format if frmt is None: raise RenderException("Format could not be determined", "format") mime_type, frmt = split_format(frmt) imagemode = ms.gdalconst_to_imagemode(bands[0].data_type) time_stamp = datetime.now().strftime("%Y%m%d%H%M%S") basename = "%s_%s" % (coverage.identifier, time_stamp) of = create_outputformat(mime_type, frmt, imagemode, basename, getattr(params, "encoding_params", {})) map_.appendOutputFormat(of) map_.setOutputFormat(of) # TODO: use layer factory here layer = self.layer_for_coverage(coverage, native_format, params.version) map_.insertLayer(layer) connector = get_connector_by_test(coverage, data_locations) if not connector: raise OperationNotSupportedException( "Could not find applicable layer connector.", "coverage") try: connector.connect(coverage, data_locations, layer, {}) # create request object and dispatch it against the map request = ms.create_request( self.translate_params(params, range_type)) request.setParameter("format", mime_type) raw_result = ms.dispatch(map_, request) finally: # perform any required layer related cleanup connector.disconnect(coverage, data_locations, layer, {}) result_set = result_set_from_raw_data(raw_result) if params.version == Version(2, 0): mediatype = getattr(params, "mediatype", None) if mediatype in ("multipart/mixed", "multipart/related"): with vsi.TemporaryVSIFile.from_buffer(result_set[1].data) as f: ds = gdal.Open(f.name) grid = objects.Grid.from_gdal_dataset(ds) # get the output CRS definition crs = params.outputcrs or subsets.crs or 'imageCRS' if crs == 'imageCRS': crs = coverage.grid.coordinate_reference_system grid._coordinate_reference_system = crs origin = objects.Origin.from_gdal_dataset(ds) size = [ds.RasterXSize, ds.RasterYSize] range_type = coverage.range_type if params.rangesubset: range_type = range_type.subset(params.rangesubset) coverage._grid = grid coverage._origin = origin coverage._size = size coverage._range_type = range_type if isinstance(result_set[1].filename, binary_type): file_name = result_set[1].filename.decode() else: file_name = result_set[1].filename reference = 'cid:coverage/%s' % file_name encoder = WCS20EOXMLEncoder() if not isinstance(coverage, objects.Mosaic): tree = encoder.encode_rectified_dataset( coverage, getattr(params, "http_request", None), reference, mime_type, subsets.bounding_polygon(coverage) if subsets else None) else: tree = encoder.encode_rectified_stitched_mosaic( coverage, getattr(params, "http_request", None), reference, mime_type, subsets.bounding_polygon(coverage) if subsets else None) result_set[0] = ResultBuffer(encoder.serialize(tree), encoder.content_type) # "default" response return result_set def translate_params(self, params, range_type): """ "Translate" parameters to be understandable by mapserver. """ if params.version.startswith("2.0"): for key, value in params: if key == 'coverageid': try: models.identifier_validators[0](value) except: value = 'not-ncname' yield key, value elif key == "interpolation": interpolation = INTERPOLATION_TRANS.get(value) if not interpolation: raise InterpolationMethodNotSupportedException( "Interpolation method '%s' is not supported." % value) yield key, value else: yield key, value rangesubset = params.rangesubset if rangesubset: yield "rangesubset", ",".join( map(str, rangesubset.get_band_indices(range_type, 1))) # TODO: this only works in newer MapServer implementations # (since 6.4?). SCALE_AVAILABLE = ms.msGetVersionInt() > 60401 scalefactor = params.scalefactor if scalefactor is not None: if SCALE_AVAILABLE: yield "scalefactor", str(scalefactor) else: raise RenderException( "'ScaleFactor' is not supported by MapServer in the " "current version.", "scalefactor") for scale in params.scales: scaleaxes = [] if isinstance(scale, ScaleSize): yield "size", "%s(%d)" % (scale.axis, scale.size) elif isinstance(scale, ScaleExtent): yield "size", "%s(%d)" % (scale.axis, scale.high - scale.low) elif isinstance(scale, ScaleAxis): if SCALE_AVAILABLE: scaleaxes.append(scale) else: raise RenderException( "'ScaleAxes' is not supported by MapServer in the " "current version.", "scaleaxes") if scaleaxes: yield "scaleaxes", ",".join("%s(%f)" % (scale.axis, scale.scale) for scale in scaleaxes) if params.outputcrs is not None: srid = crss.parseEPSGCode( params.outputcrs, (crss.fromURL, crss.fromURN, crss.fromShortCode)) if srid is None: raise InvalidOutputCrsException( "Failed to extract an EPSG code from the OutputCRS URI " "'%s'." % params.outputcrs) yield "outputcrs", params.outputcrs else: for key, value in params: yield key, value
class MapServerWCSCapabilitiesRenderer(BaseRenderer): """ WCS Capabilities renderer implementation using MapServer. """ implements(WCSCapabilitiesRendererInterface) versions = (Version(1, 0), Version(1, 1)) def supports(self, params): return params.version in self.versions def render(self, params): conf = CapabilitiesConfigReader(get_eoxserver_config()) http_service_url = get_http_service_url(params.http_request) map_ = Map() map_.setMetaData({ "enable_request": "*", "onlineresource": http_service_url, "service_onlineresource": conf.onlineresource, "updateSequence": conf.update_sequence, "name": conf.name, "title": conf.title, "label": conf.title, "abstract": conf.abstract, "accessconstraints": conf.access_constraints, "addresstype": "", "address": conf.delivery_point, "stateorprovince": conf.administrative_area, "city": conf.city, "postcode": conf.postal_code, "country": conf.country, "contactelectronicmailaddress": conf.electronic_mail_address, "contactfacsimiletelephone": conf.phone_facsimile, "contactvoicetelephone": conf.phone_voice, "contactperson": conf.individual_name, "contactorganization": conf.provider_name, "contactposition": conf.position_name, "role": conf.role, "hoursofservice": conf.hours_of_service, "contactinstructions": conf.contact_instructions, "fees": conf.fees, "keywordlist": ",".join(conf.keywords), "formats": " ".join([f.wcs10name for f in self.get_wcs_formats()]), "srs": " ".join(crss.getSupportedCRS_WCS(format_function=crss.asShortCode)), }, namespace="ows") map_.setProjection("EPSG:4326") for outputformat in self.get_all_outputformats(False): map_.appendOutputFormat(outputformat) for coverage in params.coverages: layer = Layer(coverage.identifier) layer.setProjection(coverage.spatial_reference.proj) extent = coverage.extent size = coverage.size resolution = ((extent[2] - extent[0]) / float(size[0]), (extent[1] - extent[3]) / float(size[1])) layer.setExtent(*extent) layer.setMetaData({ "title": coverage.identifier, "label": coverage.identifier, "extent": "%.10g %.10g %.10g %.10g" % extent, "resolution": "%.10g %.10g" % resolution, "size": "%d %d" % size, "formats": " ".join([f.wcs10name for f in self.get_wcs_formats()]), "srs": " ".join(crss.getSupportedCRS_WCS(format_function=crss.asShortCode)), }, namespace="wcs") map_.insertLayer(layer) request = create_request(params) request.setParameter("version", params.version) raw_result = map_.dispatch(request) result = result_set_from_raw_data(raw_result) return result
class SiteRenderer(Component): """ A coverage renderer for VirES Products and Product Collections. """ implements(WCSCoverageRendererInterface) versions = (Version(2, 0), ) handles = (models.SiteDataset, ) def supports(self, params): return issubclass(params.coverage.real_type, self.handles) def render(self, params): coverage = params.coverage.cast() frmt = params.format # get subset subset = self._apply_subsets(coverage, params.subsets) output_data = self._read_data(coverage, subset, params.rangesubset) result = self._encode_data(coverage, output_data, frmt) # TODO: coverage description if "multipart" return [result] def _apply_subsets(self, coverage, subsets): if len(subsets) > 1: raise InvalidSubsettingException("Too many subsets supplied") elif len(subsets): subset = subsets[0] if not isinstance(subset, Trim): raise InvalidSubsettingException( "Invalid subsetting method: only trims are allowed") if subset.is_temporal: begin_time, end_time = coverage.time_extent if subset.low < begin_time or subset.high > end_time: raise InvalidSubsettingException( "Temporal subset does not match coverage temporal " "extent.") resolution = get_total_seconds(coverage.resolution_time) low = get_total_seconds(subset.low - begin_time) / resolution high = get_total_seconds(subset.high - begin_time) / resolution subset = Trim("x", low, high) else: if subset.low < 0 or subset.high > coverage.size_x: raise InvalidSubsettingException( "Subset size does not match coverage size.") else: subset = Trim("x", 0, coverage.size_x) return subset def _read_data(self, coverage, subset, rangesubset): range_type = coverage.range_type # Open file filename = connect(coverage.data_items.all()[0]) root = etree.parse(filename).getroot() output_data = OrderedDict() # Read data band = range_type[0] if not rangesubset or band in rangesubset: data = map(float, root.xpath("data/value/text()")) print data, root data = data[int(subset.low):int(subset.high)] output_data[band.identifier] = data return output_data def _encode_data(self, coverage, output_data, frmt): # Encode data if frmt == "text/csv": output_filename = "/tmp/%s.csv" % uuid4().hex with open(output_filename, "w+") as f: writer = csv.writer(f) writer.writerow(output_data.keys()) for row in izip(*output_data.values()): writer.writerow(row) return ResultFile(output_filename, "text/csv", "%s.csv" % coverage.identifier, coverage.identifier) else: raise RenderException("Invalid format '%s'" % frmt, "format")
class GDALReferenceableDatasetRenderer(Component): implements(WCSCoverageRendererInterface) versions = (Version(2, 0), ) def supports(self, params): return (issubclass(params.coverage.real_type, models.ReferenceableDataset) and params.version in self.versions) def render(self, params): # get the requested coverage, data items and range type. coverage = params.coverage data_items = coverage.data_items.filter(semantic__startswith="bands") range_type = coverage.range_type subsets = params.subsets # GDAL source dataset. Either a single file dataset or a composed VRT # dataset. src_ds = self.get_source_dataset(coverage, data_items, range_type) # retrieve area of interest of the source image according to given # subsets src_rect, dst_rect = self.get_source_and_dest_rect(src_ds, subsets) # deduct "native" format of the source image native_format = data_items[0].format if len(data_items) == 1 else None # get the requested image format, which defaults to the native format # if available frmt = params.format or native_format if not frmt: raise RenderException("No format specified.", "format") if params.scalefactor is not None or params.scales: raise RenderException( "ReferenceableDataset cannot be scaled.", "scalefactor" if params.scalefactor is not None else "scale") maxsize = WCSConfigReader(get_eoxserver_config()).maxsize if maxsize is not None: if maxsize < dst_rect.size_x or maxsize < dst_rect.size_y: raise RenderException( "Requested image size %dpx x %dpx exceeds the allowed " "limit maxsize=%dpx." % (dst_rect.size_x, dst_rect.size_y, maxsize), "size") # perform subsetting either with or without rangesubsetting subsetted_ds = self.perform_subset(src_ds, range_type, src_rect, dst_rect, params.rangesubset) # encode the processed dataset and save it to the filesystem out_ds, out_driver = self.encode( subsetted_ds, frmt, getattr(params, "encoding_params", {})) driver_metadata = out_driver.GetMetadata_Dict() mime_type = driver_metadata.get("DMD_MIMETYPE") extension = driver_metadata.get("DMD_EXTENSION") time_stamp = datetime.now().strftime("%Y%m%d%H%M%S") filename_base = "%s_%s" % (coverage.identifier, time_stamp) result_set = [ ResultFile(path, mime_type, "%s.%s" % (filename_base, extension), ("cid:coverage/%s" % coverage.identifier) if i == 0 else None) for i, path in enumerate(out_ds.GetFileList()) ] if params.mediatype and params.mediatype.startswith("multipart"): reference = "cid:coverage/%s" % result_set[0].filename if subsets.has_x and subsets.has_y: footprint = GEOSGeometry(reftools.get_footprint_wkt(out_ds)) if not subsets.srid: extent = footprint.extent else: extent = subsets.xy_bbox encoder_subset = (subsets.srid, src_rect.size, extent, footprint) else: encoder_subset = None encoder = WCS20EOXMLEncoder() content = encoder.serialize( encoder.encode_referenceable_dataset(coverage, range_type, reference, mime_type, encoder_subset)) result_set.insert(0, ResultBuffer(content, encoder.content_type)) return result_set def get_source_dataset(self, coverage, data_items, range_type): if len(data_items) == 1: return gdal.OpenShared(abspath(connect(data_items[0]))) else: vrt = VRTBuilder(coverage.size_x, coverage.size_y, vrt_filename=temp_vsimem_filename()) # sort in ascending order according to semantic data_items = sorted(data_items, key=(lambda d: d.semantic)) gcps = [] compound_index = 0 for data_item in data_items: path = abspath(connect(data_item)) # iterate over all bands of the data item for set_index, item_index in self._data_item_band_indices( data_item): if set_index != compound_index + 1: raise ValueError compound_index = set_index band = range_type[set_index] vrt.add_band(band.data_type) vrt.add_simple_source(set_index, path, item_index) return vrt.dataset def get_source_and_dest_rect(self, dataset, subsets): size_x, size_y = dataset.RasterXSize, dataset.RasterYSize image_rect = Rect(0, 0, size_x, size_y) if not subsets: subset_rect = image_rect # pixel subset elif subsets.srid is None: # means "imageCRS" minx, miny, maxx, maxy = subsets.xy_bbox minx = int(minx) if minx is not None else image_rect.offset_x miny = int(miny) if miny is not None else image_rect.offset_y maxx = int(maxx) if maxx is not None else image_rect.upper_x maxy = int(maxy) if maxy is not None else image_rect.upper_y subset_rect = Rect(minx, miny, maxx - minx + 1, maxy - miny + 1) # subset in geographical coordinates else: vrt = VRTBuilder(*image_rect.size) vrt.copy_gcps(dataset) options = reftools.suggest_transformer(dataset) subset_rect = reftools.rect_from_subset(vrt.dataset, subsets.srid, *subsets.xy_bbox, **options) # check whether or not the subsets intersect with the image if not image_rect.intersects(subset_rect): raise RenderException("Subset outside coverage extent.", "subset") src_rect = subset_rect #& image_rect # TODO: why no intersection?? dst_rect = src_rect - subset_rect.offset return src_rect, dst_rect def perform_subset(self, src_ds, range_type, subset_rect, dst_rect, rangesubset=None): vrt = VRTBuilder(*subset_rect.size) input_bands = list(range_type) # list of band indices/names. defaults to all bands if rangesubset: subset_bands = rangesubset.get_band_indices(range_type, 1) else: subset_bands = xrange(1, len(range_type) + 1) for dst_index, src_index in enumerate(subset_bands, start=1): input_band = input_bands[src_index - 1] vrt.add_band(input_band.data_type) vrt.add_simple_source(dst_index, src_ds, src_index, subset_rect, dst_rect) vrt.copy_metadata(src_ds) vrt.copy_gcps(src_ds, subset_rect) return vrt.dataset def encode(self, dataset, frmt, encoding_params): options = () if frmt == "image/tiff": options = _get_gtiff_options(**encoding_params) args = [("%s=%s" % key, value) for key, value in options] path = "/tmp/%s" % uuid4().hex out_driver = gdal.GetDriverByName("GTiff") return out_driver.CreateCopy(path, dataset, True, args), out_driver