def create_outputformat(mime_type, options, imagemode, basename, parameters): """ Returns a ``mapscript.outputFormatObj`` for the given format name and imagemode. """ reg_format = get_format_by_mime(mime_type) if not reg_format: raise RenderException("Unsupported output format '%s'." % mime_type, "format") outputformat = ms.outputFormatObj(reg_format.driver, "custom") outputformat.name = reg_format.wcs10name outputformat.mimetype = reg_format.mimeType outputformat.extension = reg_format.defaultExt outputformat.imagemode = imagemode #for key, value in options: # outputformat.setOption(str(key), str(value)) if mime_type == "image/tiff": _apply_gtiff(outputformat, **parameters) filename = basename + reg_format.defaultExt outputformat.setOption("FILENAME", str(filename)) return outputformat
def check_parameters(self, map_, request_values): for key, value in request_values: if key.lower() == "format": if not map_.getOutputFormatByName(value): raise InvalidFormat(value) break else: raise RenderException("Missing 'format' parameter")
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")
def create_dataset(self, llbbox, time, elevation, size, product, out_file): if size[0] != size[1]: raise RenderException("Size needs to be quadratic.", "width") resx = (llbbox[2] - llbbox[0]) / size[0] resy = (llbbox[3] - llbbox[1]) / size[1] wmmbbox = ( llbbox[1], # - resy, llbbox[0], # - resx, llbbox[3], # + resy, llbbox[2], # + resx ) return main( out_file, product, wmmbbox, size[0], # + 2, elevation, to_year_fraction(time))
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 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
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 render(self, layers, bbox, crs, size, frmt, time, elevation, styles): if not time: raise RenderException("Missing mandatory 'time' parameter.") try: time = time.value except AttributeError: raise RenderException( "Parameter 'time' must be a slice and not a range.") llbbox = self.get_llbbox(bbox, crs) mapfile_path = get_eoxserver_config().get("wmm", "mapfile") map_ = ms.mapObj(mapfile_path) #TODO: path to map map_.setMetaData("ows_enable_request", "*") map_.setProjection("EPSG:4326") map_.imagecolor.setRGB(0, 0, 0) # set supported CRSs decoder = crss.CRSsConfigReader(get_eoxserver_config()) crss_string = " ".join( map(lambda crs: "EPSG:%d" % crs, decoder.supported_crss_wms)) map_.setMetaData("ows_srs", crss_string) map_.setMetaData("wms_srs", crss_string) datasources = [] datasets = [] for layer_name in layers: layer = map_.getLayerByName(layer_name) if not layer: continue product = layer.metadata.get("wmm_product") filename = self.generate_filename("tif") ds = self.create_dataset(llbbox, time, elevation, size, product, filename) datasets.append(ds) if layer.type == ms.MS_LAYER_LINE: flavor = layer.metadata.get("wmm_flavor") contour_steps = self.get_contour_intervals( flavor, llbbox, size) filename = self.generate_filename("shp") self.generate_contours(ds, contour_steps, filename) layer.connectiontype = ms.MS_OGR layer.connection = filename layer.data, _ = splitext(basename(filename)) datasources.append(filename) ms_request = ms.create_request( (("service", "WMS"), ("version", "1.3.0"), ("request", "GetMap"), ("layers", ",".join(layers)), ("bbox", "%f,%f,%f,%f" % (bbox[1], bbox[0], bbox[3], bbox[2])), ("crs", crs), ("width", str(size[0])), ("height", str(size[1])), ("styles", ",".join(styles)), ("format", frmt))) raw_result = ms.dispatch(map_, ms_request) result = result_set_from_raw_data(raw_result) shp_drv = ogr.GetDriverByName("ESRI Shapefile") # cleanup datasources and datasets for filename in datasources: shp_drv.DeleteDataSource(filename) for ds in datasets: driver = ds.GetDriver() for filename in ds.GetFileList(): os.remove(filename) return result, get_content_type(result)
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