def tile_wms(layer, extent, docsize, dpi, workdir, wmsauth): ''' takes a layer and generates a tiled wms of that layer in the current dir for the specified extent and template size ''' logger = logger_setup('tile_wms') logger.info('Called with: {0}'.format( (layer, extent, docsize, dpi, workdir))) if layer.transparent: layerimage, outputformat = layer.layer_id + ".png", "PNG" else: layerimage, outputformat = layer.layer_id + ".jpg", "JPEG" sizex = docsize[0] / 25.4 * dpi sizey = sizex * (extent[3] - extent[1]) / (extent[2] - extent[0]) layerurl = "http:" + layer.url.replace("gwc/service/wms", "ows") logger.info('layerurl: {0}'.format(layerurl)) gdaltile = render_to_response('spatial/gdalwms.xml', locals()) logger.info('gdaltile:') logger.info(gdaltile.content) with open(layer.layer_id + ".xml", "w") as gdalfile: gdalfile.write(gdaltile.content) subprocess.check_call( "gdal_translate -q -of {0} {1}.xml {2} && convert {2} -transparent white {2}" .format(outputformat, layer.layer_id, layerimage), shell=True) logger.info("layerimage creation successful: {0}".format(layerimage)) return layerimage
def tile_wms(layer, extent, docsize, dpi, workdir, wmsauth): ''' takes a layer and generates a tiled wms of that layer in the current dir for the specified extent and template size ''' logger = logger_setup('tile_wms') logger.info('Called with: {0}'.format((layer, extent, docsize, dpi, workdir))) if layer.transparent: layerimage, outputformat = layer.layer_id + ".png", "PNG" else: layerimage, outputformat = layer.layer_id + ".jpg", "JPEG" sizex = docsize[0] / 25.4 * dpi sizey = sizex * (extent[3] - extent[1]) / (extent[2] - extent[0]) layerurl = "http:" + layer.url.replace("gwc/service/wms", "ows") logger.info('layerurl: {0}'.format(layerurl)) gdaltile = render_to_response('spatial/gdalwms.xml', locals()) logger.info('gdaltile:') logger.info(gdaltile.content) with open(layer.layer_id + ".xml", "w") as gdalfile: gdalfile.write(gdaltile.content) subprocess.check_call("gdal_translate -q -of {0} {1}.xml {2} && convert {2} -transparent white {2}".format(outputformat, layer.layer_id, layerimage), shell=True) logger.info("layerimage creation successful: {0}".format(layerimage)) return layerimage
def print(request, dpi=200, fmt="pdf"): ''' If post create/end a map in database If get print latest map for workdir specified ''' cachekey = "print.{}?{}".format(fmt, request.META["QUERY_STRING"]) cacheddata = cache.get(cachekey) if cacheddata: content, mimetype, filename = cacheddata response = http.HttpResponse(content, content_type=mimetype) response["Content-Disposition"] = 'inline; filename="{}"'.format(filename) return response logger = logger_setup('print') try: spatial_state = json.loads(request.GET["ss"]) except: return http.HttpResponse(subprocess.check_output([GDAL_TRANSLATE, "--version"])) cwd = os.getcwd() spatialmap = Map(name=request.GET["name"], created_by=request.user, modified_by=request.user) spatialmap.layers = spatial_state["layers"] spatialmap.center = "POINT ({0} {1})".format(*spatial_state["center"]["coordinates"]) spatialmap.scale = int(spatial_state["scale"]) spatialmap.workdir = spatialmap.created_by.email + "-sssprint-" + spatialmap.date_created.strftime("%Y%m%d_%H%M") spatialmap.template = "inkscape_a3_landscape" workdir = os.path.join("/run/shm", spatialmap.workdir) logger.info("Workdir: {0}".format(workdir)) # take lock for current folder/map try: os.makedirs(workdir) os.chdir(workdir) logger.info('Taking a lock in the workdir') except: return http.HttpResponse("Busy, please try later") docsize = document_sizes[spatialmap.template] spatialmap.bounds = centerscale_topoly(spatialmap.center, spatialmap.scale, docsize) # find out projection for printing eastings/northings srid = False if spatialmap.center.x > 108 and spatialmap.center.x <= 114: srid = 28349 elif spatialmap.center.x > 114 and spatialmap.center.x <= 120: srid = 28350 elif spatialmap.center.x > 120 and spatialmap.center.x <= 126: srid = 28351 elif spatialmap.center.x > 126 and spatialmap.center.x <= 132: srid = 28352 elif spatialmap.center.x > 132 and spatialmap.center.x <= 138: srid = 28353 elif spatialmap.center.x > 138 and spatialmap.center.x <= 144: srid = 28354 elif spatialmap.center.x > 144 and spatialmap.center.x <= 150: srid = 28355 elif spatialmap.center.x > 150 and spatialmap.center.x <= 156: srid = 28356 class bnds: pass bnds.xmin, bnds.ymin = round(spatialmap.bounds.extent[0], 5), round(spatialmap.bounds.extent[1], 5) bnds.xmid, bnds.ymid = round(spatialmap.center.x, 5), round(spatialmap.center.y, 5) bnds.xmax, bnds.ymax = round(spatialmap.bounds.extent[2], 5), round(spatialmap.bounds.extent[3], 5) # pbnds is projected bounds if srid: class pbnds: pass from django.contrib.gis.geos.point import Point pbnds.xmin, pbnds.ymin = Point(bnds.xmin, bnds.ymin, srid=4283).transform(srid, clone=True) pbnds.xmid, pbnds.ymid = Point(bnds.xmid, bnds.ymid, srid=4283).transform(srid, clone=True) pbnds.xmax, pbnds.ymax = Point(bnds.xmax, bnds.ymax, srid=4283).transform(srid, clone=True) pbnds.xmin, pbnds.ymin = int(round(pbnds.xmin, 0)), int(round(pbnds.ymin, 0)) pbnds.xmid, pbnds.ymid = int(round(pbnds.xmid, 0)), int(round(pbnds.ymid, 0)) pbnds.xmax, pbnds.ymax = int(round(pbnds.xmax, 0)), int(round(pbnds.ymax, 0)) # calculate this from scalebars/km given scalebar is 0.2m scalebar_kms = round(spatialmap.scale / 5000, 2) # this should asjust for users local time not servers local time. Users offset should be set automatically on map load by browsers offset. spatialmap_datetime = datetime.fromtimestamp(time.mktime(time.localtime(calendar.timegm(spatialmap.date_created.timetuple())))).strftime("%a, %d %b %Y %H:%M") # Well this is needlessly complex: #compositepng, compositejpg, compositepdf, zipped = [(n+".png",n+".jpg",n+".pdf",n+".zip") for n in [spatialmap.map_id + spatialmap.date_created.strftime("_%Y%m%d_%H%M")]][0] composite = spatialmap.map_id + spatialmap.date_created.strftime("_%Y%m%d_%H%M") compositepng = "{0}.png".format(composite) compositejpg = "{0}.jpg".format(composite) compositepdf = "{0}.pdf".format(composite) # grab user shared_id for login wmsauth = "{}:{}".format(request.META["HTTP_REMOTE_USER"], request.META["HTTP_X_SHARED_ID"]) logger.info("Starting to iterate through layers: {0}".format(spatialmap.layers)) for index, lyr in enumerate(spatialmap.layers): logger.info("Layer: {0}".format(lyr)) if not RasterLayer.objects.filter(url__startswith="//kmi.dpaw.wa.gov.au/", layer_id=lyr["layer_id"]).order_by("-effective_from").exists(): if lyr["layer_id"].startswith("resource_tracking_week_base"): lyr["layer_id"] = "resource_tracking_printable" else: continue layer = RasterLayer.objects.filter(layer_id=lyr["layer_id"]).order_by("-effective_from")[0] logger.info("Layer {0} is a raster layer, call tile_wms".format(layer)) try: lyr["location"] = tile_wms(layer=layer, extent=spatialmap.bounds.extent, docsize=docsize, dpi=dpi, workdir=workdir, wmsauth=wmsauth) except Exception as e: os.chdir(cwd) return http.HttpResponse("<h2>Layer <u>{0}</u> failed to render, try zooming in or disabling this layer and printing again.</h2>workdir: <pre>{1}</pre><br>error: <pre>{2}</pre>".format(layer.name, workdir, e)) finalpng = "inkscape_" + compositepng finaljpg = "inkscape_" + compositejpg finalsvg = finaljpg.replace(".jpg", ".svg") finalpdf = "inkscape_" + compositepdf with open(finalsvg, "w") as inkscapesvg: inkscapesvg.write(render_to_response('spatial/{0}.svg'.format(spatialmap.template), locals()).content) if fmt == "pdf": subprocess.check_call("inkscape {0} --export-dpi={2} --export-pdf={1}".format(finalsvg, finalpdf, dpi), shell=True) content = open(finalpdf).read() mimetype = "application/pdf" filename = spatialmap.name + ".pdf" elif fmt == "jpg": subprocess.check_call("inkscape {0} --export-dpi={2} --export-png={1} && convert {1} -quality 100% {3}".format(finalsvg, finalpng, dpi, finaljpg), shell=True) content = open(finaljpg).read() mimetype = "image/jpg" filename = spatialmap.name + ".jpg" cache.set(cachekey, (content, mimetype, filename), 600) response = http.HttpResponse(content, content_type=mimetype) response["Content-Disposition"] = 'inline; filename="{}"'.format(filename) logger.info('Freeing the workdir lock') os.chdir(cwd) shutil.rmtree(workdir) return response
def print(request, dpi=200, fmt="pdf"): ''' If post create/end a map in database If get print latest map for workdir specified ''' cachekey = "print.{}?{}".format(fmt, request.META["QUERY_STRING"]) cacheddata = cache.get(cachekey) if cacheddata: content, mimetype, filename = cacheddata response = http.HttpResponse(content, content_type=mimetype) response["Content-Disposition"] = 'inline; filename="{}"'.format( filename) return response logger = logger_setup('print') try: spatial_state = json.loads(request.GET["ss"]) except: return http.HttpResponse( subprocess.check_output([GDAL_TRANSLATE, "--version"])) cwd = os.getcwd() spatialmap = Map(name=request.GET["name"], created_by=request.user, modified_by=request.user) spatialmap.layers = spatial_state["layers"] spatialmap.center = "POINT ({0} {1})".format( *spatial_state["center"]["coordinates"]) spatialmap.scale = int(spatial_state["scale"]) spatialmap.workdir = spatialmap.created_by.email + "-sssprint-" + spatialmap.date_created.strftime( "%Y%m%d_%H%M") spatialmap.template = "inkscape_a3_landscape" workdir = os.path.join("/run/shm", spatialmap.workdir) logger.info("Workdir: {0}".format(workdir)) # take lock for current folder/map try: os.makedirs(workdir) os.chdir(workdir) logger.info('Taking a lock in the workdir') except: return http.HttpResponse("Busy, please try later") docsize = document_sizes[spatialmap.template] spatialmap.bounds = centerscale_topoly(spatialmap.center, spatialmap.scale, docsize) # find out projection for printing eastings/northings srid = False if spatialmap.center.x > 108 and spatialmap.center.x <= 114: srid = 28349 elif spatialmap.center.x > 114 and spatialmap.center.x <= 120: srid = 28350 elif spatialmap.center.x > 120 and spatialmap.center.x <= 126: srid = 28351 elif spatialmap.center.x > 126 and spatialmap.center.x <= 132: srid = 28352 elif spatialmap.center.x > 132 and spatialmap.center.x <= 138: srid = 28353 elif spatialmap.center.x > 138 and spatialmap.center.x <= 144: srid = 28354 elif spatialmap.center.x > 144 and spatialmap.center.x <= 150: srid = 28355 elif spatialmap.center.x > 150 and spatialmap.center.x <= 156: srid = 28356 class bnds: pass bnds.xmin, bnds.ymin = round(spatialmap.bounds.extent[0], 5), round(spatialmap.bounds.extent[1], 5) bnds.xmid, bnds.ymid = round(spatialmap.center.x, 5), round(spatialmap.center.y, 5) bnds.xmax, bnds.ymax = round(spatialmap.bounds.extent[2], 5), round(spatialmap.bounds.extent[3], 5) # pbnds is projected bounds if srid: class pbnds: pass from django.contrib.gis.geos.point import Point pbnds.xmin, pbnds.ymin = Point(bnds.xmin, bnds.ymin, srid=4283).transform(srid, clone=True) pbnds.xmid, pbnds.ymid = Point(bnds.xmid, bnds.ymid, srid=4283).transform(srid, clone=True) pbnds.xmax, pbnds.ymax = Point(bnds.xmax, bnds.ymax, srid=4283).transform(srid, clone=True) pbnds.xmin, pbnds.ymin = int(round(pbnds.xmin, 0)), int(round(pbnds.ymin, 0)) pbnds.xmid, pbnds.ymid = int(round(pbnds.xmid, 0)), int(round(pbnds.ymid, 0)) pbnds.xmax, pbnds.ymax = int(round(pbnds.xmax, 0)), int(round(pbnds.ymax, 0)) # calculate this from scalebars/km given scalebar is 0.2m scalebar_kms = round(spatialmap.scale / 5000, 2) # this should asjust for users local time not servers local time. Users offset should be set automatically on map load by browsers offset. spatialmap_datetime = datetime.fromtimestamp( time.mktime( time.localtime(calendar.timegm( spatialmap.date_created.timetuple())))).strftime( "%a, %d %b %Y %H:%M") # Well this is needlessly complex: #compositepng, compositejpg, compositepdf, zipped = [(n+".png",n+".jpg",n+".pdf",n+".zip") for n in [spatialmap.map_id + spatialmap.date_created.strftime("_%Y%m%d_%H%M")]][0] composite = spatialmap.map_id + spatialmap.date_created.strftime( "_%Y%m%d_%H%M") compositepng = "{0}.png".format(composite) compositejpg = "{0}.jpg".format(composite) compositepdf = "{0}.pdf".format(composite) # grab user shared_id for login wmsauth = "{}:{}".format(request.META["HTTP_REMOTE_USER"], request.META["HTTP_X_SHARED_ID"]) logger.info("Starting to iterate through layers: {0}".format( spatialmap.layers)) for index, lyr in enumerate(spatialmap.layers): logger.info("Layer: {0}".format(lyr)) if not RasterLayer.objects.filter( url__startswith="//kmi.dpaw.wa.gov.au/", layer_id=lyr["layer_id"]).order_by("-effective_from").exists(): if lyr["layer_id"].startswith("resource_tracking_week_base"): lyr["layer_id"] = "resource_tracking_printable" else: continue layer = RasterLayer.objects.filter( layer_id=lyr["layer_id"]).order_by("-effective_from")[0] logger.info("Layer {0} is a raster layer, call tile_wms".format(layer)) try: lyr["location"] = tile_wms(layer=layer, extent=spatialmap.bounds.extent, docsize=docsize, dpi=dpi, workdir=workdir, wmsauth=wmsauth) except Exception as e: os.chdir(cwd) return http.HttpResponse( "<h2>Layer <u>{0}</u> failed to render, try zooming in or disabling this layer and printing again.</h2>workdir: <pre>{1}</pre><br>error: <pre>{2}</pre>" .format(layer.name, workdir, e)) finalpng = "inkscape_" + compositepng finaljpg = "inkscape_" + compositejpg finalsvg = finaljpg.replace(".jpg", ".svg") finalpdf = "inkscape_" + compositepdf with open(finalsvg, "w") as inkscapesvg: inkscapesvg.write( render_to_response('spatial/{0}.svg'.format(spatialmap.template), locals()).content) if fmt == "pdf": subprocess.check_call( "inkscape {0} --export-dpi={2} --export-pdf={1}".format( finalsvg, finalpdf, dpi), shell=True) content = open(finalpdf).read() mimetype = "application/pdf" filename = spatialmap.name + ".pdf" elif fmt == "jpg": subprocess.check_call( "inkscape {0} --export-dpi={2} --export-png={1} && convert {1} -quality 100% {3}" .format(finalsvg, finalpng, dpi, finaljpg), shell=True) content = open(finaljpg).read() mimetype = "image/jpg" filename = spatialmap.name + ".jpg" cache.set(cachekey, (content, mimetype, filename), 600) response = http.HttpResponse(content, content_type=mimetype) response["Content-Disposition"] = 'inline; filename="{}"'.format(filename) logger.info('Freeing the workdir lock') os.chdir(cwd) shutil.rmtree(workdir) return response