def GetMap(self, params): if params["bbox"][0] >= params["bbox"][2]: raise OGCException("BBOX values don't make sense. minx is greater than maxx.") if params["bbox"][1] >= params["bbox"][3]: raise OGCException("BBOX values don't make sense. miny is greater than maxy.") if params.has_key("styles") and len(params["styles"]) != len(params["layers"]): raise OGCException("STYLES length does not match LAYERS length.") m = Map(params["width"], params["height"]) if params.has_key("transparent") and params["transparent"] == "FALSE": m.background = params["bgcolor"] else: m.background = Color(0, 0, 0, 0) maplayers = self.mapfactory.layers mapstyles = self.mapfactory.styles for layername in params["layers"]: try: layer = maplayers[layername] except KeyError: raise OGCException('Layer "%s" not defined.' % layername, "LayerNotDefined") for stylename in layer.styles: if stylename in mapstyles.keys(): m.append_style(stylename, mapstyles[stylename]) else: raise ServerConfigurationError( 'Layer "%s" refers to non-existent style "%s".' % (layername, stylename) ) m.layers.append(layer) m.zoom_to_box(Envelope(params["bbox"][0], params["bbox"][1], params["bbox"][2], params["bbox"][3])) im = Image(params["width"], params["height"]) render(m, im) im = fromstring("RGBA", (params["width"], params["height"]), rawdata(im)) fh = StringIO() im.save(fh, PIL_TYPE_MAPPING[params["format"]], quality=100) fh.seek(0) return Response(params["format"], fh.read())
def render_map(map, bbox, width, height): """Render a map within a given bounding box and size""" map.resize(width, height) map.zoom_to_box(bbox) image = Image(width, height) render(map, image) return image.tostring('png')
def GetMap(self, params): m = self._buildMap(params) im = Image(params['width'], params['height']) render(m, im) im = fromstring('RGBA', (params['width'], params['height']), rawdata(im)) fh = StringIO() im.save(fh, PIL_TYPE_MAPPING[params['format']], quality=100) fh.seek(0) return Response(params['format'], fh.read())
def GetMap(self, params): m = self._buildMap(params) im = Image(params['width'], params['height']) render(m, im) format = PIL_TYPE_MAPPING[params['format']] if mapnik_version() >= 200300: # Mapnik 2.3 uses png8 as default, use png32 for backwards compatibility if format == 'png': format = 'png32' return Response(params['format'].replace('8', ''), im.tostring(format))
def GetMap(self, params): m = self._buildMap(params) im = Image(params['width'], params['height']) render(m, im) format = PIL_TYPE_MAPPING[params['format']] if mapnik_version() >= 200300: # Mapnik 2.3 uses png8 as default, use png32 for backwards compatibility if format == 'png': format = 'png32' return Response(params['format'].replace('8',''), im.tostring(format))
def newGetMap(self, params): # HACK: check if the image should be strechted bbox_ratio = float(params['bbox'][2] - params['bbox'][0]) / float(params['bbox'][3] - params['bbox'][1]) image_ratio = float(params['width']) / float(params['height']) img_height = params['height'] resize = False if int(bbox_ratio * 100) != int(image_ratio * 100): params['height'] = int(params['height'] / bbox_ratio) resize = True m = self._buildMap(params) im = Image(params['width'], params['height']) render(m, im) format = PIL_TYPE_MAPPING[params['format']] if resize: import Image as PILImage size = params['width'], params['height'] im = PILImage.open(StringIO(im.tostring(format))) size = params['width'], img_height im = im.resize(size) output = StringIO() im.save(output, format=format) return Response(params['format'].replace('8',''), output.getvalue()) return Response(params['format'].replace('8',''), im.tostring(format))
def GetMap(self, params): if params['bbox'][0] >= params['bbox'][2]: raise OGCException( "BBOX values don't make sense. minx is greater than maxx.") if params['bbox'][1] >= params['bbox'][3]: raise OGCException( "BBOX values don't make sense. miny is greater than maxy.") if params.has_key('styles') and len(params['styles']) != len( params['layers']): raise OGCException('STYLES length does not match LAYERS length.') m = Map(params['width'], params['height']) if params.has_key('transparent') and params['transparent'] == 'FALSE': m.background = params['bgcolor'] else: m.background = Color(0, 0, 0, 0) maplayers = self.mapfactory.layers mapstyles = self.mapfactory.styles for layername in params['layers']: try: layer = maplayers[layername] except KeyError: raise OGCException('Layer "%s" not defined.' % layername, 'LayerNotDefined') for stylename in layer.styles: if stylename in mapstyles.keys(): m.append_style(stylename, mapstyles[stylename]) else: raise ServerConfigurationError( 'Layer "%s" refers to non-existent style "%s".' % (layername, stylename)) m.layers.append(layer) m.zoom_to_box( Envelope(params['bbox'][0], params['bbox'][1], params['bbox'][2], params['bbox'][3])) im = Image(params['width'], params['height']) render(m, im) im = fromstring('RGBA', (params['width'], params['height']), rawdata(im)) fh = StringIO() im.save(fh, PIL_TYPE_MAPPING[params['format']], quality=100) fh.seek(0) return Response(params['format'], fh.read())
def cached_image(self): """ If caching is enabled, ensure that only one image object is generated, otherwise generate a fresh one. """ if self._image is not None: return self._image i = Image(self.image_width, self.image_height) if self.cache: self._image = i return i
def __call__(self, layers, system): request = system['request'] # get image width and height width = 256 height = 256 # get image bbox z = int(request.matchdict['z']) x = int(request.matchdict['x']) y = int(request.matchdict['y']) step = max/(2**(int(z) - 1)) xmin = x*step-max ymin = max-y*step xmax = (x+1)*step-max ymax = max-(y+1)*step bbox = Box2d(xmin, ymax, xmax, ymin) m = Map(width, height) load_map(m, abspath_from_asset_spec('osmtm:views/map.xml')) for l in layers: m.layers.append(l) m.zoom_to_box(bbox) format = request.matchdict['format'] if format == 'png': im = Image(width, height) render(m, im, 1, 1) request.response_content_type = 'image/png' return im.tostring('png') elif format == 'json': grid = Grid(width, height) render_layer(m, grid, layer=0, fields=['id']) utfgrid = grid.encode('utf', resolution=4) return json.dumps(utfgrid)
def __call__(self, layers, system): request = system['request'] # get image width and height width = 256 height = 256 # get image bbox z = int(request.matchdict['z']) x = int(request.matchdict['x']) y = int(request.matchdict['y']) step = max / (2**(int(z) - 1)) xmin = x * step - max ymin = max - y * step xmax = (x + 1) * step - max ymax = max - (y + 1) * step bbox = Box2d(xmin, ymax, xmax, ymin) m = Map(width, height) load_map(m, abspath_from_asset_spec('osmtm:views/map.xml')) for l in layers: m.layers.append(l) m.zoom_to_box(bbox) format = request.matchdict['format'] if format == 'png': im = Image(width, height) render(m, im, 1, 1) request.response_content_type = 'image/png' return im.tostring('png') elif format == 'json': grid = Grid(width, height) render_layer(m, grid, layer=0, fields=['id']) utfgrid = grid.encode('utf', resolution=4) return json.dumps(utfgrid)
def GetMap(self, params): m = self._buildMap(params) im = Image(params['width'], params['height']) render(m, im) format = PIL_TYPE_MAPPING[params['format']] return Response(params['format'].replace('8',''), im.tostring(format))
from mapnik import PolygonSymbolizer, LineSymbolizer, Rule, Style, Color, Layer, Shapefile, Map, Image, render rule = Rule() rule.symbols.append(PolygonSymbolizer(Color("grey"))) rule.symbols.append(LineSymbolizer(Color("black"), 0.1)) style = Style() style.rules.append(rule) layer = Layer("world") layer.datasource = Shapefile(file="coastlines/land") layer.styles.append("world") m = Map(800, 400) m.background = Color("white") m.append_style("world", style) m.layers.append(layer) m.zoom_to_box(layer.envelope()) image = Image(800, 400) render(m, image) with open("test.png", "w") as image_file: image_file.write(image.tostring("png"))
logging.info("range: bottomleft(%s, %s), topright(%s, %s)" % (west, lat - lat_half, east, lat + lat_half)) return west, south, east, north if __name__ == "__main__": mapfile = "my_styles/mapnik2normal.xml" map_uri = "map.png" lat = 49.25 lon = 7.0 if len(sys.argv) == 2: zoom = int(sys.argv[1]) else: zoom = 13 imgx = 500 imgy = 400 ll = center_to_bbox(lat, lon, zoom, imgx, imgy) m = Map(imgx, imgy) load_map(m, mapfile) prj = Projection("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m" " +nadgrids=@null +no_defs +over") c0 = prj.forward(Coord(ll[0], ll[1])) c1 = prj.forward(Coord(ll[2], ll[3])) bbox = Box2d(c0.x, c0.y, c1.x, c1.y) m.zoom_to_box(bbox) im = Image(imgx, imgy) render(m, im) view = im.view(0, 0, imgx, imgy) # x,y,width,height view.save(map_uri, 'png')
from mapnik import render, Image, Map, load_map, Projection, Coord, Envelope projection = Projection("+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 " "+lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m " "+nadgrids=@null +no_defs +over") map = Map(600, 600) load_map(map, "simple.xml") bbox = Envelope(Coord(-20037508.34, -20037508.34), Coord(20037508.34, 20037508.34)) map.zoom_to_box(bbox) image = Image(600, 600) render(map, image) with open('test.png', 'w') as image_file: image_file.write(image.tostring('png'))
def main(argv): b = "-180,-90,180,90" i = "" o = "" l = "-1" try: opts, args = getopt.getopt(argv,"hb:i:o:l:",["bbox","inputXml","output","layerGrid"]) except getopt.GetoptError: print 'tilep.py -b <bbox> -i <inputXml> -o <output> -l <layerGrid>' sys.exit(2) for opt, arg in opts: if opt == '-h': print 'tilep.py -b <bbox> -i <inputXml> -o <output> -l <layerGrid>' sys.exit() elif opt in ("-b", "--bbox"): b = arg elif opt in ("-i", "--inputXml"): i = arg elif opt in ("-o", "--output"): o = arg elif opt in ("-l", "--layerGrid"): l = arg box = [] for s in b.split(",") : box.append(float(s)) geo_extent = Box2d(box[0],box[1],box[2],box[3]) geo_proj = Projection('+init=epsg:4326') merc_proj = Projection('+init=epsg:3857') transform = ProjTransform(geo_proj,merc_proj) merc_extent = transform.forward(geo_extent) mp = mapnik.Map(256,256) #sys.exit(i) if i.find('http') >= 0: xmlurl=urllib2.urlopen(i) xmlstr=xmlurl.read() #xmlstr = '<Map srs="+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m +nadgrids=@null +wktext +no_defs"><Style name="Style1"><Rule><PolygonSymbolizer fill="#ffbf00" fill-opacity="0.5"/><LineSymbolizer stroke="#ff7b00" stroke-width="1" stroke-opacity="1" stroke-linejoin="bevel"/></Rule></Style><Layer name="Layer1" srs="+proj=longlat +ellps=WGS84 +datum=WGS84 +no_defs "><StyleName>Style1</StyleName><Datasource><Parameter name="type">postgis</Parameter><Parameter name="host">localhost</Parameter><Parameter name="dbname">webgisPEP</Parameter><Parameter name="username">iyo</Parameter><Parameter name="password">SAlamaH</Parameter><Parameter name="table">(SELECT * FROM sxz51_iyo_data_6) as layer1</Parameter><Parameter name="geometry_field">the_geom</Parameter><Parameter name="srid">EPSG:4326</Parameter><Parameter name="fields">gid,nama_kebun,sk</Parameter></Datasource></Layer></Map>' mapnik.load_map_from_string(mp,xmlstr) xmldoc = minidom.parseString(xmlstr) else: mapnik.load_map(mp, i) xmldoc = minidom.parse(i) mp.zoom_to_box(merc_extent) printed = 0 if o == 'png': im = Image(mp.width,mp.height) mapnik.render(mp,im) fd, path = tempfile.mkstemp() os.write(fd,im.tostring('png')) os.fsync(fd) print path elif o == 'json': printed = 1 else: image = o+".png" if not os.path.exists(os.path.dirname(image)): try: os.makedirs(os.path.dirname(image)) except: pass mapnik.render_to_file(mp, image) if l == '-1': print image #print ((time.time())-(t0))*1000 #sys.exit() lgrids = [] if l != '-1': for s in l.split(",") : lgrids.append(s) else: sys.exit() itemlist = xmldoc.getElementsByTagName('Layer') fields = [] resolution = 4 #Pixel resolution of output. printed = 0 for lysl in lgrids : lys = lysl.split(":") ly = int(lys[0]) lz = '' if (len(lys) == 2): lz = lys[1] dat = itemlist[ly].getElementsByTagName('Datasource')[0] par = dat.getElementsByTagName('Parameter') for s in par : dv = s.attributes['name'].value dck = False if (dv[6:] == '' or lz == ''): dck = True elif (dv[6:].isdigit() and lz.isdigit()): dck = (int(lz) >= int(dv[6:])) if dv[:6] == 'fields' and dck and fields == [] : text = s.childNodes[0].nodeValue.encode("utf-8") #print "fields "+text fields = text.split(",") #elif dv[:6] == 'fields': # ly = ly + 1 if dv == 'resolution': res = s.childNodes[0].nodeValue.encode("utf-8") #print "resolution "+res resolution = int(res) layer_index = ly #First layer on the map - index in m.layers key = "__id__" #Field used for the key in mapnik (should probably be unique) enfix = "" if ly > 0: enfix = "_"+str(ly) d = mapnik.render_grid(mp, layer_index, key, resolution, fields) #returns a dictionary d = "grid("+json.dumps(d)+")" if o == 'json' and printed == 0: print d printed = 1 elif o == 'png': printed = 1 else: print d f = open(o+enfix+".json",'wb') f.write(d) f.close()
def GetMap(self, params): m = self._buildMap(params) im = Image(params['width'], params['height']) render(m, im) return Response(params['format'], im.tostring(PIL_TYPE_MAPPING[params['format']]))
from mapnik import render, Image, Map, load_map map = Map(600, 600) load_map(map, "simple.xml") map.zoom_to_box(map.layers[0].envelope()) image = Image(600, 600) render(map, image) with open('test.png', 'w') as f: f.write(image.tostring('png'))
def _render(value, system): request = system['request'] if not isinstance(value, tuple): value = (None, value) layer_name, collection = value if not hasattr(collection, 'features'): raise ValueError('renderer is not passed a feature collection') # get image width and height try: img_width = int(request.params.get('img_width', 256)) except: request.response_status = 400 return 'incorrect img_width' try: img_height = int(request.params.get('img_height', 256)) except: request.response_status = 400 return 'incorrect img_height' # get image format try: img_format = request.params.get( 'img_format', request.matchdict.get('format', 'png')) img_format = str(img_format) except: request.response_status = 400 return 'incorrect img_format' # get image bbox img_bbox = request.params.get('img_bbox', request.params.get('bbox')) if img_bbox: try: img_bbox = map(float, img_bbox.split(',')) except ValueError: request.response_status = 400 return 'incorrect img_bbox' img_bbox = Box2d(*img_bbox) m = Map(img_width, img_height) load_map(m, mapfile) if len(m.layers) == 0: raise ValueError('no layer in the mapnik map') # if no layer_name is provided then, by convention, use # the first layer in the mapnik map if layer_name is None: layer_name = m.layers[0].name layer = self._set_layer_in_map(m, layer_name) layer.datasource = self._create_datasource(collection) m.zoom_to_box(img_bbox or layer.envelope()) im = Image(img_width, img_height) render(m, im, 1, 1) # get the image format from the request request.response.content_type = 'image/%s' % img_format return im.tostring(img_format)
if __name__ == "__main__": mapfile = "my_styles/mapnik2normal.xml" map_uri = "map.png" lat = 49.25 lon = 7.0 if len(sys.argv) == 2: zoom = int(sys.argv[1]) else: zoom = 13 imgx = 500 imgy = 400 ll = center_to_bbox(lat, lon, zoom, imgx, imgy) m = Map(imgx, imgy) load_map(m, mapfile) prj = Projection( "+proj=merc +a=6378137 +b=6378137 +lat_ts=0.0 +lon_0=0.0 +x_0=0.0 +y_0=0 +k=1.0 +units=m" " +nadgrids=@null +no_defs +over") c0 = prj.forward(Coord(ll[0], ll[1])) c1 = prj.forward(Coord(ll[2], ll[3])) bbox = Box2d(c0.x, c0.y, c1.x, c1.y) m.zoom_to_box(bbox) im = Image(imgx, imgy) render(m, im) view = im.view(0, 0, imgx, imgy) # x,y,width,height view.save(map_uri, 'png')
def GET(self, tilename, z, x, y, sffx): z = int(z) x = int(x) y = int(y) if (z < 0 or z > 19): return '' cType = { "png":"image/png", "json":"text/plain" } qs = web.input(r='',x='',q='') isCache = False if qs.r == '': isCache = True output = False tilep = Tilep() web.header("Access-Control-Allow-Origin", "*") dbfilet = tilep.getDb(tilename) if dbfilet: cont = lite.connect(dbfilet) curt = cont.cursor() if isCache and dbfilet: if (qs.q == '') : sql = "SELECT * from tiles WHERE z = ? AND x = ? AND y = ? AND sffx = ? AND (q is null or q = ?);" else : sql = "SELECT * from tiles WHERE z = ? AND x = ? AND y = ? AND sffx = ? AND q = ?;" curt.execute(sql,[z,x,y,sffx,qs.q]) rows = curt.fetchall() for row in rows: output = zlib.decompress(row[7]) if output: web.header("Content-Type", cType[sffx]) return output if not output: isforce = True if qs.x == '': isforce = False xmlstr = tilep.getXml(tilename,isforce,qs.q) if not xmlstr: return '' else: box = tilep.getBbox(z=z,x=x,y=y) geo_extent = Box2d(box[0],box[1],box[2],box[3]) geo_proj = Projection('+init=epsg:4326') merc_proj = Projection('+init=epsg:3857') transform = ProjTransform(geo_proj,merc_proj) merc_extent = transform.forward(geo_extent) mp = mapnik.Map(256,256) mapnik.load_map_from_string(mp,xmlstr) mp.zoom_to_box(merc_extent) if sffx == 'png': im = Image(mp.width,mp.height) mapnik.render(mp,im) output = im.tostring('png') if dbfilet: minx = box[0] miny = box[1] maxx = box[2] maxy = box[3] sql = "INSERT INTO tiles VALUES (?,?,?,?,?,?,?,?,?,?);" curt.execute(sql,[z,x,y,minx,miny,maxx,maxy,lite.Binary(zlib.compress(output)),sffx,qs.q]) cont.commit() curt.close() #if zoomcache >= z : # mapnik.render_to_file(mp, str(afile)) web.header("Content-Type", cType[sffx]) return output elif sffx == 'json': xmldoc = minidom.parseString(xmlstr) itemlist = xmldoc.getElementsByTagName('Layer') nlay = len(itemlist) fields = [] resolution = 4 #Pixel resolution of output. li = 0 for ly in range(0, nlay): resolution = 4 dat = itemlist[ly].getElementsByTagName('Datasource')[0] par = dat.getElementsByTagName('Parameter') for s in par : dv = s.attributes['name'].value dck = False if (dv[6:] == ''): dck = True elif (dv[6:].isdigit()): dck = (z >= int(dv[6:])) if dv[:6] == 'fields' and dck and fields == [] : text = s.childNodes[0].nodeValue.encode("utf-8") fields = text.split(",") li = ly if dv == 'resolution': res = s.childNodes[0].nodeValue.encode("utf-8") resolution = int(res) layer_index = li #First layer on the map - index in m.layers key = "__id__" #Field used for the key in mapnik (should probably be unique) enfix = "" #if ly > 0: # enfix = "_"+str(ly) #return str(len(fields)) if len(fields) > 0: d = mapnik.render_grid(mp, layer_index, key, resolution, fields) #returns a dictionary output = "grid("+json.dumps(d)+")" else: output = '' if output != '': if dbfilet: minx = box[0] miny = box[1] maxx = box[2] maxy = box[3] sql = "INSERT INTO tiles VALUES (?,?,?,?,?,?,?,?,?,?);" curt.execute(sql,[z,x,y,minx,miny,maxx,maxy,lite.Binary(zlib.compress(output)),sffx,qs.q]) cont.commit() curt.close() #if zoomcache >= z : # f = open(afile,'wb') # f.write(output) # f.close() web.header("Content-Type", cType[sffx]) return output else: return ''
def GET(self, tilename, epsg, z, x, y): global cached_maps sffx = 'png' epsg = int(epsg) z = int(z) x = int(x) y = int(y) if (z < 0 or z > 19): return '' cType = { "png":"image/png" } qs = web.input(r='',x='',q='') isCache = False if qs.r == '': isCache = True output = False tilep = Tilep() web.header("Access-Control-Allow-Origin", "*") atilename = tilename+'_'+str(epsg) dbfilet = tilep.getDb(atilename) if dbfilet: cont = lite.connect(dbfilet) curt = cont.cursor() if isCache and dbfilet: if (qs.q == '') : sql = "SELECT * from tiles WHERE z = ? AND x = ? AND y = ? AND sffx = ? AND (q is null or q = ?);" else : sql = "SELECT * from tiles WHERE z = ? AND x = ? AND y = ? AND sffx = ? AND q = ?;" curt.execute(sql,[z,x,y,sffx,qs.q]) rows = curt.fetchall() for row in rows: output = zlib.decompress(row[7]) if output: web.header("Content-Type", cType[sffx]) return output if not output: box = tilep.getBbox(z=z,x=x,y=y) geo_extent = Box2d(box[0],box[1],box[2],box[3]) geo_proj = Projection('+init=epsg:4326') merc_proj = Projection('+init=epsg:'+str(epsg)) transform = ProjTransform(geo_proj,merc_proj) merc_extent = transform.forward(geo_extent) mp = False if isCache and atilename in cached_maps : if qs.q in cached_maps[atilename]: mp = cached_maps[atilename][qs.q] if not mp: mp = mapnik.Map(256,256,'+init=epsg:'+str(epsg)) s = mapnik.Style() r = mapnik.Rule() r.symbols.append(mapnik.RasterSymbolizer()) s.rules.append(r) mp.append_style('RStyle',s) adir = os.path.dirname(os.path.realpath(__file__)) coni = lite.connect(adir+'/indeks.db') curi = coni.cursor() sql = "SELECT * FROM indeks WHERE name = ? AND epsg = ? AND ((maxx >= ? AND maxy >= ? AND minx <= ? AND miny <= ?) OR (minx <= ? AND miny <= ? AND maxx >= ? AND maxy >= ?))" if (qs.q != '') : try: qray = json.loads(qs.q) except ValueError: qray = False if isinstance(qray, list): qray[0]= 'filename' qc = str(tilep.getQuery(qray)) sql = sql+"AND "+qc curi.execute(sql,[tilename,epsg,str(merc_extent[0]),str(merc_extent[1]),str(merc_extent[2]),str(merc_extent[3]),str(merc_extent[0]),str(merc_extent[1]),str(merc_extent[2]),str(merc_extent[3])]) #ok sql = "SELECT * FROM indeks WHERE name = ? AND epsg = ?;" #ok curi.execute(sql,[tilename,epsg]) rows = curi.fetchall() n = 0 for row in rows: afilename = str(row[1]) ds = mapnik.Gdal(file=afilename) layer = mapnik.Layer('raster'+str(n),'+init=epsg:'+str(epsg)) layer.datasource = ds layer.styles.append('RStyle') mp.layers.append(layer) n = n+1 #xmlstr = mapnik.save_map_to_string(mp) #print xmlstr #mapnik.load_map_from_string(mp,xmlstr) if atilename not in cached_maps : cached_maps[atilename] = {} #cached_maps[atilename][qs.q] = mp mp.zoom_to_box(merc_extent) im = Image(mp.width,mp.height) mapnik.render(mp,im) output = im.tostring('png') if dbfilet: minx = box[0] miny = box[1] maxx = box[2] maxy = box[3] sql = "INSERT INTO tiles VALUES (?,?,?,?,?,?,?,?,?,?);" curt.execute(sql,[z,x,y,minx,miny,maxx,maxy,lite.Binary(zlib.compress(output)),sffx,qs.q]) cont.commit() curt.close() web.header("Content-Type", cType[sffx]) return output else: return ''