def test_profile_typesafety(self): """ Profile init type safety prepatch, these would segfault, postpatch they should emit a typeerror """ with self.assertRaises(TypeError): ImageCms.ImageCmsProfile(0).tobytes() with self.assertRaises(TypeError): ImageCms.ImageCmsProfile(1).tobytes()
def make_prw(self, prw_name, image=None, LayoutQC_DEBAG=False): if not image: image = self.image if not self.image.info.get('icc_profile', ''): profile_assighned = ImageCms.ImageCmsProfile(io.BytesIO(euroscale_profile.tobytes())) if LayoutQC_DEBAG: print("Untagged layout, assighned profile Euroscale Coated for converting to RGB preview") else: profile_assighned = ImageCms.ImageCmsProfile(io.BytesIO(self.image.info.get('icc_profile', ''))) screen = ImageCms.profileToProfile(image, profile_assighned, screen_profile, 0, 'RGB') screen.save(prw_name, quality=100, dpi=(self.resolution, self.resolution), )
def _decode_icc(data): try: from PIL import ImageCms except ImportError: return data return ImageCms.ImageCmsProfile(io.BytesIO(data))
def read_and_make(item): print('reading %s...' %item) item_path = os.path.join(target_path,item) srcs = [] if not os.path.isdir(item_path): os.makedirs(item_path) for file in os.listdir(item_path): if file.split('.')[-1].upper() in ['JPG', 'JPEG', 'PNG']: img = Image.open(os.path.join(item_path,file)) icc_profile = img.info.get('icc_profile') f = io.BytesIO(icc_profile) try: icc=ImageCms.ImageCmsProfile(f) img = ImageCms.profileToProfile(img,icc,srgb) except: pass srcs.append(np.asarray(img)) if srcs!=[]: try: if not os.path.isdir(gif_path): os.makedirs(gif_path) print('saving %s.gif' %item) imageio.mimwrite(os.path.join(gif_path,item+'.gif'), srcs, duration=1) except: print('ERROR: An error occured! Target images might have different sizes or this is an IO error.')
def _apply_icc(psd, image): """Apply ICC Color profile.""" from io import BytesIO try: from PIL import ImageCms except ImportError: logger.debug( 'ICC profile found but not supported. Install little-cms.' ) return image if image.mode not in ('RGB',): logger.debug('%s ICC profile is not supported.' % image.mode) return image try: in_profile = ImageCms.ImageCmsProfile( BytesIO(psd.image_resources.get_data('ICC_PROFILE')) ) out_profile = ImageCms.createProfile('sRGB') return ImageCms.profileToProfile(image, in_profile, out_profile) except ImageCms.PyCMSError as e: logger.warning('PyCMSError: %s' % (e)) return image
def imageRGB(self, prof_out=False): image = self.image() alpha_band = False if image.mode in ('LA', 'PA', 'RGBA'): bands = image.split() alpha_band = bands[-1] image = Image.merge(image.mode[:-1], bands[:-1]) sRGB = ImageCms.createProfile("sRGB") if 'icc_profile' in image.info: inputProfile = ImageCms.ImageCmsProfile( StringIO(image.info['icc_profile'])) else: if image.mode == "CMYK": inputProfile = (dirpath(__file__) or ".") + "/Fogra27L.icm" elif image.mode == "LAB": inputProfile = ImageCms.createProfile("LAB") else: image = image.convert('RGB') inputProfile = sRGB if prof_out: outputProfile = prof_out else: outputProfile = sRGB new_image = ImageCms.profileToProfile(image, inputProfile, outputProfile, outputMode="RGB") if not alpha_band: alpha_band = Image.new('L', image.size, 255) new_image.putalpha(alpha_band) return new_image
def convert_to_srgb(img): icc = img.info.get('icc_profile', '') if icc: fd = io.BytesIO(icc) sPrf = ImageCms.ImageCmsProfile(fd) dPrf = ImageCms.createProfile('sRGB') img = ImageCms.profileToProfile(img, sPrf, dPrf) return img
def get_image_np(image_name): image_path = 'images/' + image_name image = Image.open(image_path) iccProfile = image.info.get('icc_profile') iccBytes = io.BytesIO(iccProfile) originalColorProfile = ImageCms.ImageCmsProfile(iccBytes) return (np.array(image.convert('RGB')), originalColorProfile)
def convert_to_srgb(img): '''Convert PIL image to sRGB color space (if possible)''' icc = img.info.get('icc_profile', '') if icc: io_handle = io.BytesIO(icc) # virtual file src_profile = ImageCms.ImageCmsProfile(io_handle) dst_profile = ImageCms.createProfile('sRGB') img = ImageCms.profileToProfile(img, src_profile, dst_profile) return img
def _decode_icc(data): try: from PIL import ImageCms return ImageCms.ImageCmsProfile(io.BytesIO(data)) except ImportError: warnings.warn( "ICC profile is not handled; colors could be incorrect. " "Please build PIL or Pillow with littlecms/littlecms2 support.") return data
def convert_to_srgb(self, img): """Convert PIL image to sRGB color space (if possible)""" icc = img.info.get("icc_profile", "") if icc: io_handle = io.BytesIO(icc) # virtual file src_profile = ImageCms.ImageCmsProfile(io_handle) dst_profile = ImageCms.createProfile("sRGB") img = ImageCms.profileToProfile(img, src_profile, dst_profile) return img
def test_icc_conversion(self): with temporary_folder() as output_folder: output_file = os.path.join(output_folder, 'output.tif') conversion.Converter().convert_icc_profile( filepaths.STANDARD_TIF, output_file, filepaths.SRGB_ICC_PROFILE) assert os.path.isfile(output_file) with Image.open(filepaths.STANDARD_TIF) as input_pil: old_icc = input_pil.info.get('icc_profile') f = io.BytesIO(old_icc) prf = ImageCms.ImageCmsProfile(f) assert prf.profile.profile_description == "Adobe RGB (1998)" with Image.open(output_file) as output_pil: new_icc = output_pil.info.get('icc_profile') f = io.BytesIO(new_icc) prf = ImageCms.ImageCmsProfile(f) assert prf.profile.profile_description == "sRGB v4 ICC preference perceptual intent beta"
def NormaliseICCProfilePILImageToSRGB( pil_image: PILImage.Image) -> PILImage.Image: try: icc_profile_bytes = GetICCProfileBytes(pil_image) except HydrusExceptions.DataMissing: return pil_image try: f = io.BytesIO(icc_profile_bytes) src_profile = PILImageCms.ImageCmsProfile(f) if pil_image.mode in ('L', 'LA'): # had a bunch of LA pngs that turned pure white on RGBA ICC conversion # but seem to work fine if keep colourspace the same for now # it is a mystery, I guess a PIL bug, but presumably L and LA are technically sRGB so it is still ok to this outputMode = pil_image.mode else: if PILImageHasAlpha(pil_image): outputMode = 'RGBA' else: outputMode = 'RGB' pil_image = PILImageCms.profileToProfile(pil_image, src_profile, PIL_SRGB_PROFILE, outputMode=outputMode) except (PILImageCms.PyCMSError, OSError): # 'cannot build transform' and presumably some other fun errors # way more advanced than we can deal with, so we'll just no-op # OSError is due to a "OSError: cannot open profile from string" a user got # no idea, but that seems to be an ImageCms issue doing byte handling and ending up with an odd OSError? # or maybe somehow my PIL reader or bytesIO sending string for some reason? # in any case, nuke it for now pass pil_image = NormalisePILImageToRGB(pil_image) return pil_image
def thumbnailer(fileSkel, existingFiles, params): blob = bucket.get_blob("%s/source/%s" % (fileSkel["dlkey"], fileSkel["name"])) if not blob: logging.warning("Blob %s is missing from Cloudstore!" % fileSkel["dlkey"]) return fileData = BytesIO() blob.download_to_file(fileData) resList = [] for sizeDict in params: fileData.seek(0) outData = BytesIO() try: img = Image.open(fileData) except Image.UnidentifiedImageError: # We can't load this image; so there's no need to try other resolutions return [] iccProfile = img.info.get('icc_profile') if iccProfile: # JPEGs might be encoded with a non-standard color-profile; we need to compensate for this if we convert # to WEBp as we'll loose this color-profile information f = BytesIO(iccProfile) src_profile = ImageCms.ImageCmsProfile(f) dst_profile = ImageCms.createProfile('sRGB') img = ImageCms.profileToProfile(img, inputProfile=src_profile, outputProfile=dst_profile, outputMode="RGB") fileExtension = sizeDict.get("fileExtension", "webp") if "width" in sizeDict and "height" in sizeDict: width = sizeDict["width"] height = sizeDict["height"] targetName = "thumbnail-%s-%s.%s" % (width, height, fileExtension) elif "width" in sizeDict: width = sizeDict["width"] height = int( (float(img.size[1]) * float(width / float(img.size[0])))) targetName = "thumbnail-w%s.%s" % (width, fileExtension) else: # No default fallback - ignore continue mimeType = sizeDict.get("mimeType", "image/webp") img = img.resize((width, height), Image.ANTIALIAS) img.save(outData, fileExtension) outSize = outData.tell() outData.seek(0) targetBlob = bucket.blob("%s/derived/%s" % (fileSkel["dlkey"], targetName)) targetBlob.upload_from_file(outData, content_type=mimeType) resList.append((targetName, outSize, mimeType, { "mimetype": mimeType, "width": width, "height": height })) return resList
def convert_to_srgb(img): """ convert to sRGB if image contain 'icc_profile' :param img: :return: """ # get icc profile from img info icc = img.info.get('icc_profile', '') if icc: # convert to sRGB io_handle = io.BytesIO(icc) src_profile = ImageCms.ImageCmsProfile(io_handle) dst_profile = ImageCms.createProfile('sRGB') img = ImageCms.profileToProfile(img, src_profile, dst_profile) return img
def screencap(self): from PIL import Image as PILImage, ImageCms s = self.device_session_factory().exec_stream(self.command) data = recvall(s, 4194304, True) img = PILImage.open(BytesIO(data)) if self.screenshot_rotate != 0: img = img.rotate(self.screenshot_rotate) if icc := img.info.get('icc_profile', ''): iccio = BytesIO(icc) src_profile = ImageCms.ImageCmsProfile(iccio) from imgreco.cms import srgb_profile ImageCms.profileToProfile(img, src_profile, srgb_profile, ImageCms.INTENT_RELATIVE_COLORIMETRIC, inPlace=True)
def icc(self): """If an ICC profile is attached, return a Pillow object that describe it. Most of the information may be found in ``icc.profile``. Returns: PIL.ImageCms.ImageCmsProfile """ if self.colorspace not in ('/ICCBased', '/Indexed'): return None if not self._icc: iccstream = self._iccstream iccbuffer = iccstream.get_stream_buffer() iccbytesio = BytesIO(iccbuffer) self._icc = ImageCms.ImageCmsProfile(iccbytesio) return self._icc
def test_icc_palette(resources): xobj, _pdf = first_image_in(resources / 'pink-palette-icc.pdf') pim = PdfImage(xobj) assert pim.icc.profile.xcolor_space == 'RGB ' # with trailing space b = BytesIO() pim.extract_to(stream=b) b.seek(0) im = Image.open(b) assert im.size == (xobj.Width, xobj.Height) assert im.mode == 'P' pil_icc = im.info.get('icc_profile') pil_icc_stream = BytesIO(pil_icc) pil_prf = ImageCms.ImageCmsProfile(pil_icc_stream) assert pil_prf.tobytes() == pim.icc.tobytes()
def convert_to_srgb(file_path): '''Convert PIL image to sRGB color space (if possible)''' img = Image.open(file_path) icc = img.info.get('icc_profile', '') if icc: io_handle = io.BytesIO(icc) # virtual file src_profile = ImageCms.ImageCmsProfile(io_handle) dst_profile = ImageCms.createProfile('sRGB') img_conv = ImageCms.profileToProfile(img, src_profile, dst_profile) icc_conv = img_conv.info.get('icc_profile', '') if icc != icc_conv: # ICC profile was changed -> save converted file img_conv.save(file_path, format='JPEG', quality=50, icc_profile=icc_conv)
def convert_to_srgb(img): '''Convert PIL image to sRGB color space (if possible)''' # ok there might be a problem using this function # to solve it, completely remove PIL and Pillow package # then reinstall it using pip or conda or whatever # this is a pretty shitty problem # and there is no other solution other than this icc = img.info.get('icc_profile', '') if_changed = False if icc: try: io_handle = io.BytesIO(icc) # virtual file src_profile = ImageCms.ImageCmsProfile(io_handle) dst_profile = ImageCms.createProfile('sRGB') img = ImageCms.profileToProfile(img, src_profile, dst_profile) if_changed = True except: ## this happens when we cannot handle the color profile, f**k this pass return img, if_changed
def icc(self) -> Optional[ImageCms.ImageCmsProfile]: """If an ICC profile is attached, return a Pillow object that describe it. Most of the information may be found in ``icc.profile``. """ if self.colorspace not in ('/ICCBased', '/Indexed'): return None if not self._icc: iccstream = self._iccstream iccbuffer = iccstream.get_stream_buffer() iccbytesio = BytesIO(iccbuffer) try: self._icc = ImageCms.ImageCmsProfile(iccbytesio) except OSError as e: if str(e) == 'cannot open profile from string': # ICC profile is corrupt raise UnsupportedImageTypeError( "ICC profile corrupt or not readable" ) from e return self._icc
from . import resources from PIL import ImageCms p3_profile = ImageCms.ImageCmsProfile(resources.open_file('DisplayP3.icm')) srgb_profile = ImageCms.createProfile('sRGB') # numpy is slower than ImageCms (LittleCMS) # import numpy as np # denorm8 = np.arange(256, dtype=np.float32) / 255 # denorm_degamma8 = np.piecewise(denorm8, [denorm8 <= 0.04045, denorm8 > 0.04045], [lambda x: x / 12.92, lambda x: ((x + 0.055) / 1.055) ** 2.4]) # norm10 = np.arange(1024, dtype=np.float32) / 1023 # regamma10 = np.piecewise(norm10, [norm10 <= 0.0031308, norm10 > 0.0031308], [lambda x: x * 12.92, lambda x: 1.055 * (x ** (1.0 / 2.4)) - 0.055]) # regamma10_norm8 = np.round(regamma10 * 255).astype(np.uint8) # def matrix_for_primaries(red, green, blue, white): # Yxy = np.array([(1, *red), (1, *green), (1, *blue), (1, *white)], dtype=np.float32) # x = Yxy[:, 1] # y = Yxy[:, 2] # X = x / y # Z = (1 - x - y) / y # XYZ = np.array([X, Yxy[:, 0], Z]) # S = np.linalg.inv(XYZ[..., :3]) @ XYZ[..., 3] # M = S * XYZ[..., :3] # return M # M_srgb_to_xyz = matrix_for_primaries((0.64, 0.33), (0.3, 0.6), (0.15, 0.06), (0.3127, 0.3290)) # M_xyz_to_srgb = np.linalg.inv(M_srgb_to_xyz) # M_p3_to_xyz = matrix_for_primaries((0.680, 0.320), (0.265, 0.690), (0.150, 0.060), (0.3127, 0.3290)) # M_p3_to_srgb = M_xyz_to_srgb @ M_p3_to_xyz
def profile_conversion(image): maybe_icc = image.info.get("icc_profile") if not prefer_embedded or maybe_icc is None: return ImageCms.applyTransform(image, transform) em_profile = ImageCms.ImageCmsProfile(io.BytesIO(maybe_icc)) return ImageCms.profileToProfile(image, em_profile, profiles[1], renderingIntent=intent, outputMode=modes[1])
def ConvertMode_and_Icc(self, prof=euroscale_profile): conv_mode_profile = ImageCms.ImageCmsProfile(io.BytesIO(prof.tobytes())) im_mode_profile = ImageCms.ImageCmsProfile(io.BytesIO(self.image.info.get('icc_profile', ''))) self.image = ImageCms.profileToProfile(self.image, im_mode_profile, conv_mode_profile, 0, 'CMYK') self.prw_name = 'temp/convert_ICC_temp.png' self.make_prw(self.prw_name)
def resize_img(path, size): files_exten = [ 'jpg', 'JPG', 'JPEG', 'png', 'tiff', 'tif', 'TIFF', 'PNG', ] print(f'Path to search: {path}') files = [] for file in os.listdir(path): x = file.split('.') if len(x) > 1: if x[1] in files_exten: files.append(file) extentions = [] for ext in files: if '.' in ext: extention = ext.split('.') extentions.append(extention[1]) print(f'{len(extentions)} find!') if os.path.isdir(path + '/resized_to_' + str(size) + 'px'): pass else: os.mkdir(path + '/resized_to_' + str(size) + 'px') count = 0 for x in files: if extentions[count] in files_exten: dir_img = path + '/' + files[count] img = Image.open(dir_img) if img.mode == 'RGBA': img = img.convert('RGB') icc = img.info.get('icc_profile', '') if icc: handler = io.BytesIO(icc) src_profile = ImageCms.ImageCmsProfile(handler) dst_profile = ImageCms.createProfile('sRGB') img = ImageCms.profileToProfile(img, src_profile, dst_profile) new_size_y = int(size) / (int(img.size[0]) / int(img.size[1])) rezized = img.resize((size, int(new_size_y)), Image.LANCZOS) new_name = files[count].split('.') save_file = path + '/resized_to_' + str(size) + 'px/' + str( new_name[0]) + '.jpeg' rezized.save(save_file, 'JPEG', quality=90) print(f'image {files[count]} resized!') count += 1 else: print(f'{x} not rezized') count += 1 return count
GAUSSIAN_BLUR_RADIUS = int(sys.argv[2]) elif len(sys.argv) == 2: IMAGE_FILE = sys.argv[1] GAUSSIAN_BLUR_RADIUS = 10 else: print("Not enough arguments provided. Exiting.") sys.exit() # Open two versions of the image - one for the actual image to show and one to use as background image = Image.open(IMAGE_FILE) imageBackground = Image.open(IMAGE_FILE) # Get original color profile so it can be preserved iccProfile = image.info.get('icc_profile') iccBytes = io.BytesIO(iccProfile) originalColorProfile = ImageCms.ImageCmsProfile(iccBytes) # some math width, height = image.size if width > height: ratio = width / height else: ratio = height / width incRatioSize = int(round(INSTAGRAM_PHOTO_SIZE * ratio)) decRatioSize = int(round(INSTAGRAM_PHOTO_SIZE / ratio)) x = int(round((incRatioSize - INSTAGRAM_PHOTO_SIZE) / 2)) y = int(round((INSTAGRAM_PHOTO_SIZE - decRatioSize) / 2)) # Prepare image and background sizes - background fills 2048 square, image is centered on it if width > height: # Image background goes to height of instagram square
def createImage(path, fileformat): import tempfile import cairo try: #DPD - get unquote regardless of Python version from urllib.parse import unquote #Python3 except ImportError: from urlparse import unquote #Python2 import overpass #For real-time data query import time import psycopg2 p = parse_query(path) EPSG900913 = "+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" C_SCALE_FACTOR = 1.4 SCALE_FACTOR = p['dpi'] / 72.0 S2P = SCALE_FACTOR * 360 / 0.127 # Feature widths/diameters and stroke thicknesses, in m. From the ISOM/ISSOM specs. SC_W = 0.007 * C_SCALE_FACTOR SC_T = 0.00035 * C_SCALE_FACTOR C_R = 0.003 * C_SCALE_FACTOR CDOT_R = 0.00035 * C_SCALE_FACTOR C_T = 0.00035 * C_SCALE_FACTOR CL_H = 0.005 * C_SCALE_FACTOR CTEXT_S = 0.005 * C_SCALE_FACTOR CONTENT_NM = 0.0045 MAP_NM = 0.014 MAP_EM = 0.008 MAP_SM = 0.013 MAP_WM = 0.008 ADORN_TITLE_SM = 0.002 ADORN_SCALE_SM = 0.005 ADORN_SCALEBAR_SM = 0.002 ADORN_SCALEBAR_LARGETICK = 0.002 ADORN_SCALEBAR_SMALLTICK = 0.001 ADORN_SCALEBAR_PADDING = 0.002 ADORN_ATTRIB_NM = 0.0035 ADORN_URL_NM = 0.001 ADORN_LOGO_SCALE = 0.175 * SCALE_FACTOR #0.038 ADORN_LOGO_SCALE_IOA = 0.175 * SCALE_FACTOR #= 0.25 ADORN_ARROW_W = 0.012 ADORN_LOGO_W = 0.018 style = p['style'] if style != "crew" and style != 'blueprint' and style != "urban_skeleton" and style != "streeto" and style != "oterrain" and style != "adhoc": return "Unknown style." PAPER_W = float(p['paper'].split(",")[0]) PAPER_H = float(p['paper'].split(",")[1]) scale = int(p['scale']) clat = int(p['centre'].split(",")[0]) clon = int(p['centre'].split(",")[1]) try: rotation = float(p['rotation']) except: rotation = 0 try: title = p['title'] except: title = "OpenOrienteeringMap" mapid = p.get('mapid', 'new') slon = slat = flon = flat = 0 if 'start' in p: slat = flat = int(p['start'].split(",")[0]) slon = flon = int(p['start'].split(",")[1]) if 'finish' in p: flat = int(p['finish'].split(",")[0]) flon = int(p['finish'].split(",")[1]) controlsArr = [] if 'controls' in p: controlsArr = p['controls'].split(",") crossesArr = [] if 'crosses' in p: crossesArr = p['crosses'].split(",") cpsArr = [] if 'cps' in p: cpsArr = p['cps'].split(",") projection = mapnik.Projection(EPSG900913) wgs84lat = mapnik.Coord(clon, clat).inverse(projection).y wgs84lon = mapnik.Coord(clon, clat).inverse(projection).x scaleCorrectionFactor = math.cos(wgs84lat * math.pi / 180) scaleCorrected = scale / scaleCorrectionFactor #get declination from local Python web service (declination.py; mod_wsgi alias for /wmm) wmmParams = {'lat': str(wgs84lat), 'lon': str(wgs84lon)} wmmResponse = requests.get(web_root + "wmm", params=wmmParams) magdec = float(wmmResponse.text) if style == "adhoc": MAP_EM = MAP_WM MAP_NM = MAP_WM MAP_SM = MAP_WM MAP_W = PAPER_W - MAP_WM - MAP_EM MAP_H = PAPER_H - MAP_NM - MAP_SM EXTENT_W = MAP_W * math.cos(rotation) + MAP_H * abs(math.sin(rotation)) EXTENT_H = MAP_H * math.cos(rotation) + MAP_W * abs(math.sin(rotation)) mapSLat = clat - (EXTENT_H / 2) * scaleCorrected mapNLat = clat + (EXTENT_H / 2) * scaleCorrected mapWLon = clon - (EXTENT_W / 2) * scaleCorrected mapELon = clon + (EXTENT_W / 2) * scaleCorrected pagePolyUnrotated = ((clon - (MAP_W / 2 + MAP_WM) * scaleCorrected, clat - (MAP_H / 2 + MAP_SM) * scaleCorrected), (clon - (MAP_W / 2 + MAP_WM) * scaleCorrected, clat + (MAP_H / 2 + MAP_NM) * scaleCorrected), (clon + (MAP_W / 2 + MAP_EM) * scaleCorrected, clat + (MAP_H / 2 + MAP_NM) * scaleCorrected), (clon + (MAP_W / 2 + MAP_EM) * scaleCorrected, clat - (MAP_H / 2 + MAP_SM) * scaleCorrected)) pagePoly = (rotate((clon, clat), pagePolyUnrotated[0], rotation), rotate((clon, clat), pagePolyUnrotated[1], rotation), rotate((clon, clat), pagePolyUnrotated[2], rotation), rotate((clon, clat), pagePolyUnrotated[3], rotation)) styleFile = home + "/styles/" + style + ".xml" with open(styleFile, mode="r") as f: styleString = f.read() bbox2 = mapnik.Box2d(mapWLon, mapSLat, mapELon, mapNLat).inverse(projection) if len(mapid ) == 13: #If existing id, use that, otherwise generate new one. tmpid = "h" + mapid #Add "h" prefix - postgres tables can't start with a number else: tmpid = "h" + hex(int(time.time()))[2:10] + hex( int(time.time() * 1000000) % 0x100000)[2:7] styleFile = home + "/styles/" + tmpid + ".xml" # Get contour attribution from custom Postgres DB table # based on centre location and type (e.g. "LIDAR") of contour selected. conn = psycopg2.connect(database="gis", user="******", host="127.0.0.1", port="5432") cur = conn.cursor() cur.execute( """ select attrib, tablename from attrib WHERE ST_Within(ST_SetSRID(ST_Point(%s, %s),900913),way) and type = %s; """, (clon, clat, p['contour'])) # If at least 1 hit choose the first one, otherwise no contours available. if cur.rowcount > 0: db_result = cur.fetchone() contour_text = "Contours: " + db_result[0] contour_table = db_result[1] else: contour_text = "" contour_table = "lidar_null" # If stylefile exists, data has been recently fetched - can use existing DB tables. # Recreate stylefile regardless - might need a new style on existing data. if not os.path.isfile(styleFile): # api = overpass.API() api = overpass.API( endpoint="https://overpass.kumi.systems/api/interpreter", timeout=120) MapQuery = overpass.MapQuery(bbox2.miny, bbox2.minx, bbox2.maxy, bbox2.maxx) try: response = api.get(MapQuery, responseformat="xml") except Exception as e: return "Overpass API error: " + type(e).__name__ + ", " + str(e) + "\n" + \ "Use the following ID to recover your map: " + tmpid[1:] tmpname = "/tmp/" + tmpid + ".osm" with open(tmpname, mode="wb") as f: f.write(response.encode("utf-8")) # Populate Postgres db with data, using tables with temporary id prefix os.system("osm2pgsql -d otf1 --hstore --multi-geometry --number-processes 1" + \ " -p " + tmpid + \ " --tag-transform-script /home/osm/openstreetmap-carto/openstreetmap-carto.lua" + \ " --style /home/osm/openstreetmap-carto/openstreetmap-carto.style -C 200 -U osm "+ tmpname) os.unlink(tmpname) #Finished with temporary osm data file - delete. if p['contour'] == "SRTM" or p['contour'] == "COPE": #Now get contours using phyghtmap: #Use Phyghtmap just to get DEM data - process separately if p['contour'] == "SRTM": sourceText = " --source=srtm1 --srtm-version=3 " else: sourceText = " --source=cope1" phyString="phyghtmap --area="+str(bbox2.minx-0.0002)+":"+str(bbox2.miny-0.0002)+":"+ \ str(bbox2.maxx+0.0002)+":"+str(bbox2.maxy+0.0002)+ sourceText + \ " --earthexplorer-user="******" --earthexplorer-password="******" --hgtdir=" + home_base + "/hgt -p " + home_base + "/"+tmpid + " >> " + home_base + "/phy.log" os.system(phyString) #Merge file(s) into single virtual dataset (prevents contour boundaries at degree grid lines) os.system("gdalbuildvrt " + home_base + "/" + tmpid + "_a.vrt " + home_base + "/" + tmpid + "_lon*") #Resample at 10m intervals to get smoother contours. Reproject at the same time os.system("gdalwarp -r cubic -tr 10 10 -s_srs EPSG:4326 -t_srs EPSG:3857 -te_srs EPSG:4326 -te " + \ str(bbox2.minx-0.0001)+" "+str(bbox2.miny-0.0001)+" "+ \ str(bbox2.maxx+0.0001)+" "+str(bbox2.maxy+0.0001)+ \ " -of SAGA -ot Float32 " + home_base + "/"+tmpid + "_a.vrt " + home_base + "/"+tmpid + ".sdat") #Apply Guassian blur to further smooth contours os.system( "saga_cmd grid_filter \"Gaussian Filter\" -SIGMA 2.0 -RADIUS 12 -INPUT " + home_base + "/" + tmpid + ".sdat -RESULT " + home_base + "/" + tmpid + "_s") #Generate contours os.system("gdal_contour -b 1 -a height -i " + p['interval'] + " " + home_base + "/" + tmpid + "_s.sdat " + home_base + "/" + tmpid + ".shp") # If contour generation failed, use a dummy dataset so that the DB table # gets created and the SQL query returns without errors. try: os.stat(home_base + "/" + tmpid + ".shp") except: os.system("cp " + home_base + "/null.shp " + home_base + "/" + tmpid + ".shp") os.system("cp " + home_base + "/null.shx " + home_base + "/" + tmpid + ".shx") os.system("cp " + home_base + "/null.dbf " + home_base + "/" + tmpid + ".dbf") #then load contours to database os.system("shp2pgsql -g way -s 3857 " + home_base + "/" + tmpid + ".shp " + tmpid + "_srtm_line | psql -h localhost -p 5432 -U osm -d otf1") contour_table = tmpid + "_srtm_line" import glob for i in glob.glob(home_base + '/' + tmpid + '*'): os.unlink(i) #Finished with temporary files - delete. else: # If SRTM or COPE contours, still need to point to correct contour table for reused data so: if p['contour'] == "SRTM" or p['contour'] == "COPE": contour_table = tmpid + "_srtm_line" # Need a custom Mapnik style file to find tables with temo id prefix. # Therefore inject "prefix" entity into appropriate base style definition and save using temp id as name. if p.get( 'drives', "no" ) != "no": #Render driveways as near-transparent if not selected. Allows recovery later if needed. driveway_colour = "#010101FF" else: driveway_colour = "#01010101" import re insertstring="%settings;\n<!ENTITY prefix \"" + tmpid + "\">" + \ "\n<!ENTITY driveway \"" + driveway_colour + "\">" + \ "\n<!ENTITY rail \"" + ("yes" if p.get('rail',"yes") != "no" else "no") + "\">" + \ "\n<!ENTITY walls \"" + ("yes" if p.get('walls',"yes") != "no" else "no") + "\">" + \ "\n<!ENTITY trees \"" + ("yes" if p.get('trees',"yes") != "no" else "no") + "\">" + \ "\n<!ENTITY hedges \"" + ("yes" if p.get('hedges',"yes") != "no" else "no") + "\">" + \ "\n<!ENTITY fences \"" + ("yes" if p.get('fences',"yes") != "no" else "no") + "\">" + \ "\n<!ENTITY lidartable \"" + contour_table + "\">" + \ "\n<!ENTITY contourSeparation \"" + p['interval'] + "\">" + \ "\n<!ENTITY layers-contours SYSTEM \"inc/layers_contours_" + p['contour'] + ".xml.inc\">" searchstring = "\%settings;" styleString = re.sub(searchstring, insertstring, styleString) with open(styleFile, mode="w") as f: f.write(styleString) cbbox = mapnik.Box2d(mapWLon, mapSLat, mapELon, mapNLat) # Limit the size of map we are prepared to produce to roughly A2 size. if PAPER_W * PAPER_H > 0.25 and style != "adhoc": return "Map too large. Try increasing the scale value or using a smaller paper size." if scale > 50000 and style != "adhoc": return "Scale too small. Try using a lower scale value." # Calculate scale, for scale bar and grid lines scaleBarMetres = 500 if scale < 10000: scaleBarMetres = 200 scaleBarW = scaleBarMetres / float(scale) # Create map map = mapnik.Map(int(EXTENT_W * S2P), int(EXTENT_H * S2P)) # Load map configuration mapnik.load_map(map, styleFile) # Zoom the map to the Gbounding box map.zoom_to_box(cbbox) file = tempfile.NamedTemporaryFile() surface = None if fileformat == 'jpg' or fileformat == 'pre': surface = cairo.ImageSurface(cairo.FORMAT_ARGB32, int(PAPER_W * S2P), int(PAPER_H * S2P)) elif fileformat == 'svg': surface = cairo.SVGSurface(file.name, PAPER_W * S2P / SCALE_FACTOR, PAPER_H * S2P / SCALE_FACTOR) surface.set_device_scale(1.0 / SCALE_FACTOR, 1.0 / SCALE_FACTOR) versions = surface.get_versions() version = versions[1] surface.restrict_to_version(version) else: surface = cairo.PDFSurface(file.name, PAPER_W * S2P / SCALE_FACTOR, PAPER_H * S2P / SCALE_FACTOR) surface.set_device_scale(1.0 / SCALE_FACTOR, 1.0 / SCALE_FACTOR) # Adornments - Title swoosh back ctx = cairo.Context(surface) ctx.translate(0, 0) ctx.set_line_width(1 * SCALE_FACTOR) ctx.move_to(0, 0) ctx.rel_line_to(0, 0.25 * PAPER_H * S2P) ctx.rel_line_to(0.2 * PAPER_W * S2P, 0) ctx.rel_line_to(0.4 * PAPER_W * S2P, -0.25 * PAPER_H * S2P) ctx.close_path() ctx.set_source_rgb(0.91, 0.15, 0.28) if style != 'blueprint': ctx.fill() #Adornments - Attrib swoosh back ctx = cairo.Context(surface) ctx.translate(0, 0) ctx.set_line_width(1 * SCALE_FACTOR) ctx.move_to(PAPER_W * S2P, PAPER_H * S2P) ctx.rel_line_to(0, -0.25 * PAPER_H * S2P) ctx.rel_line_to(-0.2 * PAPER_W * S2P, 0) ctx.rel_line_to(-0.4 * PAPER_W * S2P, 0.25 * PAPER_H * S2P) ctx.close_path() ctx.set_source_rgb(0.12, 0.5, 0.65) if style != "blueprint": ctx.fill() # Background map ctx = cairo.Context(surface) ctx.set_operator(cairo.Operator.OVER) ctx.translate(MAP_WM * S2P, MAP_NM * S2P) ctx.rectangle(0, 0, MAP_W * S2P, MAP_H * S2P) ctx.clip() #Clip to map area ctx.save() ctx.translate(MAP_W * S2P / 2, MAP_H * S2P / 2) # translate origin to the center ctx.rotate(rotation) ctx.translate(-EXTENT_W * S2P / 2, -EXTENT_H * S2P / 2) mapnik.render(map, ctx, SCALE_FACTOR, 0, 0) ctx.restore() if style == "adhoc": ctx = cairo.Context(surface) ctx.set_source_rgb(1, 1, 1) ctx.select_font_face("Arial", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) ctx.set_font_size(0.5 * SCALE_FACTOR) text = path ctx.translate(MAP_WM * S2P, (MAP_NM + MAP_H + 0.001) * S2P) ctx.show_text(text) if fileformat == 'jpg' or fileformat == 'pre': surface.write_to_png(file.name) else: surface.finish() return file # Add grid lines in same layer - allows darken comp-op if style != "blueprint" and p.get('grid', "yes") != "no": ctx.set_source_rgb(0.5, 0.5, 1) ctx.set_operator(cairo.Operator.MULTIPLY) ctx.set_line_width(0.5 * SCALE_FACTOR) northSpacing = scaleBarW / math.cos(magdec * math.pi / 180 + rotation) shift = MAP_H * S2P * math.tan(magdec * math.pi / 180 + rotation) * 0.5 lines = range(int(-northSpacing * S2P / 2), int((MAP_W + northSpacing) * S2P), int(northSpacing * S2P)) for line in lines: ctx.move_to(line + shift, 0) ctx.line_to(line - shift, MAP_H * S2P) ctx.stroke() # Start control if slon != 0 and slat != 0: ctx = cairo.Context(surface) ctx.set_operator(cairo.Operator.MULTIPLY) ctx.set_source_rgb(0.651, 0.149, 1) ctx.translate(MAP_WM * S2P + MAP_W * S2P / 2, MAP_NM * S2P + MAP_H * S2P / 2) # translate origin to the center ctx.rotate(rotation) # rotate map to correct angle ctx.translate(-EXTENT_W * S2P / 2, -EXTENT_H * S2P / 2) # set origin to NW corner ctx.set_line_width(SC_T * S2P) ctx.set_line_join(cairo.LINE_JOIN_ROUND) ctx.translate((slon - mapWLon) * EXTENT_W * S2P / (mapELon - mapWLon), (mapNLat - slat) * EXTENT_H * S2P / (mapNLat - mapSLat)) startRot = 0 #rotation of start triangle - if linear course and at least 1 control if len(controlsArr) > 0 and p.get('linear', "no") != "no": startRot = math.atan2( slat - float(controlsArr[2]), float(controlsArr[3]) - slon) - math.pi / 6 + rotation ctx.rotate(startRot - rotation) ctx.move_to(0, -0.577 * SC_W * S2P) ctx.rel_line_to(-0.5 * SC_W * S2P, 0.866 * SC_W * S2P) ctx.rel_line_to(SC_W * S2P, 0) ctx.close_path() ctx.stroke() ctx.rotate(-startRot) #Finish control (same place as start, unless separate finish coords) if flon != 0 and flat != 0: ctx.rotate(rotation) ctx.translate((flon - slon) * EXTENT_W * S2P / (mapELon - mapWLon), (slat - flat) * EXTENT_H * S2P / (mapNLat - mapSLat)) ctx.set_line_width(C_T * S2P) ctx.arc(0, 0, C_R * S2P * 1.2, 0, 2 * math.pi) #Outer circle ctx.stroke() ctx.arc(0, 0, C_R * S2P * 0.8, 0, 2 * math.pi) #inner circle ctx.stroke() # Controls and labels if len(controlsArr) > 0: ctx = cairo.Context(surface) ctx.translate(MAP_WM * S2P + MAP_W * S2P / 2, MAP_NM * S2P + MAP_H * S2P / 2) # translate origin to the center ctx.rotate(rotation) ctx.translate(-EXTENT_W * S2P / 2, -EXTENT_H * S2P / 2) ctx.select_font_face("Arial", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) ctx.set_font_size(CTEXT_S * S2P) numControls = len(controlsArr) // 4 #Draw white halo around control numbers for legibility on complex maps ctx.set_operator(cairo.Operator.SOURCE) ctx.set_source_rgb(1, 0.997, 1) for i in range(numControls): text = controlsArr[4 * i] labelAngle = float(controlsArr[4 * i + 1]) controllat = float(controlsArr[4 * i + 2]) controllon = float(controlsArr[4 * i + 3]) controllatP = (mapNLat - controllat) * EXTENT_H / (mapNLat - mapSLat) controllonP = (controllon - mapWLon) * EXTENT_W / (mapELon - mapWLon) x_bearing, y_bearing, width, height = ctx.text_extents(text)[:4] labelX = C_R * 2.5 * math.sin(math.pi * labelAngle / 180) labelY = C_R * 2.5 * math.cos(math.pi * labelAngle / 180) ctx.save() ctx.translate(controllonP * S2P, controllatP * S2P) ctx.rotate(-rotation) ctx.move_to(labelX * S2P - width / 2, -labelY * S2P + height / 2) ctx.text_path(text) ctx.set_line_width(C_T * S2P) ctx.stroke_preserve() ctx.fill() ctx.restore() ctx.set_source_rgb(0.651, 0.149, 1) ctx.set_operator(cairo.Operator.MULTIPLY) lastlonP = (slon - mapWLon) * EXTENT_W / (mapELon - mapWLon) lastlatP = (mapNLat - slat) * EXTENT_H / (mapNLat - mapSLat) for i in range(numControls): text = controlsArr[4 * i] labelAngle = float(controlsArr[4 * i + 1]) controllat = float(controlsArr[4 * i + 2]) controllon = float(controlsArr[4 * i + 3]) controllatP = (mapNLat - controllat) * EXTENT_H / (mapNLat - mapSLat) controllonP = (controllon - mapWLon) * EXTENT_W / (mapELon - mapWLon) ctx.move_to((controllonP + C_R) * S2P, controllatP * S2P) ctx.set_line_width(C_T * S2P) ctx.arc(controllonP * S2P, controllatP * S2P, C_R * S2P, 0, 2 * math.pi) ctx.stroke() ctx.move_to((controllonP + CDOT_R) * S2P, controllatP * S2P) ctx.arc(controllonP * S2P, controllatP * S2P, CDOT_R * S2P, 0, 2 * math.pi) ctx.fill() if p.get('linear', "no") != "no": angle = math.atan2((controllatP - lastlatP), (controllonP - lastlonP)) start2lonP = lastlonP + math.cos(angle) * C_R * (1.3 if i == 0 else 1.0) start2latP = lastlatP + math.sin(angle) * C_R * (1.3 if i == 0 else 1.0) end2lonP = controllonP - math.cos(angle) * C_R end2latP = controllatP - math.sin(angle) * C_R ctx.move_to(start2lonP * S2P, start2latP * S2P) ctx.line_to(end2lonP * S2P, end2latP * S2P) #draw line between controls lastlonP = controllonP lastlatP = controllatP x_bearing, y_bearing, width, height = ctx.text_extents(text)[:4] labelX = C_R * 2.5 * math.sin(math.pi * labelAngle / 180) labelY = C_R * 2.5 * math.cos(math.pi * labelAngle / 180) ctx.save() ctx.translate(controllonP * S2P, controllatP * S2P) ctx.rotate(-rotation) ctx.move_to(labelX * S2P - width / 2, -labelY * S2P + height / 2) ctx.show_text(text) ctx.restore() # draw line from last control to finish if p.get('linear', "no") != "no": controllatP = (mapNLat - flat) * EXTENT_H / (mapNLat - mapSLat) controllonP = (flon - mapWLon) * EXTENT_W / (mapELon - mapWLon) angle = math.atan2((controllatP - lastlatP), (controllonP - lastlonP)) start2lonP = lastlonP + math.cos(angle) * C_R start2latP = lastlatP + math.sin(angle) * C_R end2lonP = controllonP - math.cos(angle) * C_R * 1.2 end2latP = controllatP - math.sin(angle) * C_R * 1.2 ctx.move_to(start2lonP * S2P, start2latP * S2P) ctx.line_to(end2lonP * S2P, end2latP * S2P) ctx.stroke() # Crosses and labels if len(crossesArr) > 0: #ctx = cairo.Context(surface) ctx.set_source_rgb(0.651, 0.149, 1) ctx.set_operator(cairo.Operator.MULTIPLY) ctx.select_font_face("Arial", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_BOLD) ctx.set_font_size(CTEXT_S * S2P / 1.5) #ctx.set_source_rgb(1, 0, 0) numCrosses = len(crossesArr) // 2 for i in range(numCrosses): text = "X" controllat = float(crossesArr[2 * i]) controllon = float(crossesArr[2 * i + 1]) controllatP = (mapNLat - controllat) * EXTENT_H / (mapNLat - mapSLat) controllonP = (controllon - mapWLon) * EXTENT_W / (mapELon - mapWLon) x_bearing, y_bearing, width, height = ctx.text_extents(text)[:4] ctx.move_to((controllonP) * S2P - width / 2, (controllatP) * S2P + height / 2) ctx.show_text(text) #Crossing points and labels if len(cpsArr) > 0: #ctx = cairo.Context(surface) ctx.set_source_rgb(0.651, 0.149, 1) ctx.set_operator(cairo.Operator.DARKEN) ctx.select_font_face("Arial", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) ctx.set_font_size(CTEXT_S * S2P / 1.1) #ctx.set_source_rgb(1, 0, 0) numCps = len(cpsArr) // 3 for i in range(numCps): text = "][" controlAngle = float(cpsArr[3 * i]) controllat = float(cpsArr[3 * i + 1]) controllon = float(cpsArr[3 * i + 2]) controlAngleRads = math.pi * controlAngle / 180 controllatP = (mapNLat - controllat) * EXTENT_H / (mapNLat - mapSLat) controllonP = (controllon - mapWLon) * EXTENT_W / (mapELon - mapWLon) x_bearing, y_bearing, width, height, x_advance, y_advance = ctx.text_extents( text)[:6] ctx.move_to((controllonP) * S2P, (controllatP) * S2P) ctx.rotate(controlAngleRads) ctx.rel_move_to(-width / 2, height / 3.5) ctx.show_text(text) ctx.rotate(-1.0 * controlAngleRads) #ctx.save() # Adornments - Title ctx = cairo.Context(surface) ctx.select_font_face("Arial", cairo.FONT_SLANT_ITALIC, cairo.FONT_WEIGHT_NORMAL) if style == 'blueprint': ctx.select_font_face("Impact", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) text = unquote(title) if len(text) > 26: ctx.set_font_size(15 * SCALE_FACTOR) elif len(text) > 18: ctx.set_font_size(18 * SCALE_FACTOR) else: ctx.set_font_size(21 * SCALE_FACTOR) ctx.translate((MAP_WM + 0.014) * S2P, (MAP_NM - ADORN_TITLE_SM) * S2P) #add space to left for logo if style == 'blueprint': ctx.set_source_rgb(0, 0.5, 0.8) else: ctx.set_source_rgb(1, 1, 1) ctx.show_text(text.upper()) # Adornments - Scale Text ctx = cairo.Context(surface) ctx.select_font_face("Arial", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) text = "scale 1:" + str(scale) if style == "oterrain" or style == "streeto": text = "scale 1:" + str(scale) + ", contours " + p['interval'] + "m" ctx.set_source_rgb(0, 0, 0) if style == 'blueprint': ctx.set_source_rgb(0, 0.5, 0.8) ctx.set_font_size(11 * SCALE_FACTOR) width = ctx.text_extents(text)[4] ctx.translate( (MAP_WM + MAP_W) * S2P - width - (ADORN_ARROW_W + ADORN_LOGO_W) * S2P, (MAP_NM - ADORN_SCALE_SM) * S2P) ctx.show_text(text) # Adornments - Scale Bar and Caption ctx = cairo.Context(surface) ctx.select_font_face("Arial", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) text = str(scaleBarMetres) + "m" ctx.set_source_rgb(0, 0, 0) if style == 'blueprint': ctx.set_source_rgb(0, 0.5, 0.8) ctx.set_font_size(7 * SCALE_FACTOR) width = ctx.text_extents(text)[4] barCaptionX = (MAP_WM + MAP_W - (ADORN_ARROW_W + ADORN_LOGO_W)) * S2P - width ctx.translate(barCaptionX, (MAP_NM - ADORN_SCALEBAR_SM) * S2P) ctx.show_text(text) ctx.set_line_width(0.5 * SCALE_FACTOR) ctx.move_to((-scaleBarW - ADORN_SCALEBAR_PADDING) * S2P, 0) ctx.rel_line_to(0, -ADORN_SCALEBAR_LARGETICK * S2P) ctx.rel_line_to(0, ADORN_SCALEBAR_LARGETICK * S2P) ctx.rel_line_to(scaleBarW * S2P / 2, 0) ctx.rel_line_to(0, -ADORN_SCALEBAR_SMALLTICK * S2P) ctx.rel_line_to(0, ADORN_SCALEBAR_SMALLTICK * S2P) ctx.rel_line_to(scaleBarW * S2P / 2, 0) ctx.rel_line_to(0, -ADORN_SCALEBAR_LARGETICK * S2P) ctx.stroke() # Adornments - North Arrow ctx = cairo.Context(surface) ctx.translate((MAP_WM + MAP_W - ADORN_LOGO_W) * S2P - width, (CONTENT_NM + 0.004) * S2P) #set to centre of symbol... ctx.rotate( magdec * math.pi / 180 + rotation) #so that rotation doesn't add translation. Point to mag. N ctx.set_line_width(1 * SCALE_FACTOR) ctx.set_source_rgb(0, 0, 0) if style == 'blueprint': ctx.set_source_rgb(0, 0.5, 0.8) ctx.move_to(0, -0.004 * S2P) ctx.line_to(0.001 * S2P, -0.002 * S2P) ctx.line_to(-0.001 * S2P, -0.002 * S2P) ctx.close_path() ctx.fill() ctx.move_to(0, -0.003 * S2P) ctx.line_to(0, 0.004 * S2P) ctx.stroke() ctx.set_line_join(cairo.LINE_JOIN_ROUND) ctx.set_line_cap(cairo.LINE_CAP_ROUND) ctx.move_to(-0.001 * S2P, 0.001 * S2P) ctx.rel_line_to(0, -0.002 * S2P) ctx.rel_line_to(0.002 * S2P, 0.002 * S2P) ctx.rel_line_to(0, -0.002 * S2P) ctx.stroke() # Adornments - Logo if style != "blueprint": logoSurface = cairo.ImageSurface.create_from_png(home + "/images/oflogo.png") ctx = cairo.Context(surface) width = logoSurface.get_width() * ADORN_LOGO_SCALE ctx.translate((MAP_WM + MAP_W) * S2P - width, CONTENT_NM * S2P) ctx.scale(ADORN_LOGO_SCALE, ADORN_LOGO_SCALE) ctx.set_source_surface(logoSurface, 0, 0) ctx.paint() # Adornments - Attribution left line 1 ctx = cairo.Context(surface) ctx.select_font_face("Arial", cairo.FONT_SLANT_ITALIC, cairo.FONT_WEIGHT_NORMAL) ctx.set_source_rgb(0.12, 0.5, 0.65) if style == 'blueprint': ctx.set_source_rgb(0, 0.5, 0.8) ctx.set_font_size(7 * SCALE_FACTOR) text = "Map data: © OpenStreetMap contributors; Open Database Licence." ctx.translate((MAP_WM) * S2P, (MAP_NM + MAP_H + ADORN_ATTRIB_NM) * S2P) ctx.show_text(text) # Adornments - Attribution left line 2 - contours ctx = cairo.Context(surface) ctx.select_font_face("Arial", cairo.FONT_SLANT_ITALIC, cairo.FONT_WEIGHT_NORMAL) ctx.set_source_rgb(0.12, 0.5, 0.65) ctx.set_font_size(7 * SCALE_FACTOR) ctx.translate((MAP_WM) * S2P, (MAP_NM + MAP_H + ADORN_ATTRIB_NM + 0.002) * S2P) ctx.show_text(contour_text) cur.close() conn.close() #Adornments - Attribution left line 3 ctx = cairo.Context(surface) ctx.select_font_face("Arial", cairo.FONT_SLANT_ITALIC, cairo.FONT_WEIGHT_NORMAL) ctx.set_source_rgb(0.12, 0.5, 0.65) if style == "blueprint": ctx.set_source_rgb(0, 0.5, 0.8) ctx.set_font_size(7 * SCALE_FACTOR) text = "OOM created by Oliver O'Brien. Make your own: " + web_root ctx.translate((MAP_WM) * S2P, (MAP_NM + MAP_H + ADORN_ATTRIB_NM + 0.004) * S2P) ctx.show_text(text) #Adornments - Attribution right line 1 if style == "oterrain" or style == "streeto" or style == "blueprint": ctx = cairo.Context(surface) ctx.select_font_face("Arial", cairo.FONT_SLANT_ITALIC, cairo.FONT_WEIGHT_BOLD) ctx.set_source_rgb(1, 1, 1) if style == "blueprint": ctx.set_source_rgb(0, 0.5, 0.8) ctx.set_font_size(9 * SCALE_FACTOR) text = "OOM v3 developed with a grant from the Orienteering Foundation" width = ctx.text_extents(text)[4] ctx.translate((MAP_WM + MAP_W) * S2P - width, (MAP_NM + MAP_H + ADORN_ATTRIB_NM) * S2P) ctx.show_text(text) #Attribution right line 2 ctx = cairo.Context(surface) ctx.select_font_face("Arial", cairo.FONT_SLANT_ITALIC, cairo.FONT_WEIGHT_NORMAL) ctx.set_source_rgb(1, 1, 1) if style == "blueprint": ctx.set_source_rgb(0, 0.5, 0.8) ctx.set_font_size(9 * SCALE_FACTOR) text = "Map ID: " + mapid width = ctx.text_extents(text)[4] ctx.translate((MAP_WM + MAP_W) * S2P - width, (MAP_NM + MAP_H + ADORN_ATTRIB_NM + ADORN_ATTRIB_NM) * S2P) ctx.show_text(text) # Adornments - URL ctx = cairo.Context(surface) ctx.select_font_face("Arial", cairo.FONT_SLANT_NORMAL, cairo.FONT_WEIGHT_NORMAL) ctx.set_font_size(0.5 * SCALE_FACTOR) text = web_root + "render/" + fileformat + '/?' + path ctx.translate(MAP_WM * S2P, (MAP_NM + MAP_H + ADORN_URL_NM) * S2P) ctx.show_text(text) if fileformat == 'jpg' or fileformat == 'pre': from PIL import Image, ImageCms surface.write_to_png(file.name + '.png') im = Image.open(file.name + '.png') bg = Image.new("RGB", im.size, (255, 255, 255)) profile = ImageCms.createProfile("sRGB") profile2 = ImageCms.ImageCmsProfile(profile) bg.paste(im, im) bg.save(file.name, 'JPEG', quality=95, icc_profile=profile2.tobytes()) else: surface.finish() surface.flush() if fileformat == 'pdf': # Add Geospatial PDF metadata map_bounds = (MAP_WM / PAPER_W, (PAPER_H - MAP_SM) / PAPER_H, MAP_WM / PAPER_W, MAP_NM / PAPER_H, (PAPER_W - MAP_EM) / PAPER_W, MAP_NM / PAPER_H, (PAPER_W - MAP_EM) / PAPER_W, (PAPER_H - MAP_SM) / PAPER_H) file2 = tempfile.NamedTemporaryFile() file = add_geospatial_pdf_header(map, file, file2, map_bounds, pagePoly, epsg=3857) #Delete temporary style file and postgres tables (everything beginning with "h"): #BUT - don't delete here as may be needed for related query. Periodically clean out with cron job instead #os.unlink(styleFile) #dropTables = 'psql -U osm otf1 -t -c "select \'drop table \\"\' || tablename || \'\\" cascade;\' from pg_tables where schemaname = \'public\' and tablename like \'h%\'" | psql -U osm otf1' #os.system(dropTables) return file
def get_image_profile(self, image): try: return ImageCms.ImageCmsProfile( io.BytesIO(image.info.get('icc_profile'))) except: return None
def generate(cut_type, choice, fabric_type): ''' Based on the size choice, select a template. ''' template = Image.open(path1 + str(choice)+'-'+ randomTemplateString +template_type).convert(convert_mode) ''' Saving metadata from template to result file ''' ''' Exif Loaded to readable format ''' exif_dict = piexif.load(template.info.get('exif')) ''' ICC Profile ''' if (fabric_mode != "CMYK"): icc_profile = template.info.get('icc_profile') else: icc_profile = ImageCms.ImageCmsProfile(io.BytesIO(template.info.get('icc_profile'))) ''' Changes "Program name" attribute ''' exif_dict["0th"][305] = GENERATOR_NAME ''' Resets thumbnail to later get automatically generated ''' exif_dict.pop('thumbnail', None) ''' Dumpted to bytes ''' exif_bytes = piexif.dump(exif_dict) ''' Draw variable. ''' draw = ImageDraw.Draw(template) ''' Upper stamp ''' ''' Stamp seperator. ''' draw.text((SEP1, 23), "|", font=font, fill=TEXT_COLOR) draw.text((SEP2, 23), "|", font=font, fill=TEXT_COLOR) draw.text((SEP1, 35), "|", font=font, fill=TEXT_COLOR) draw.text((SEP2, 35), "|", font=font, fill=TEXT_COLOR) ''' Safety spray ''' draw.text((5453, -10), "|", font=font, fill=TEXT_COLOR) ''' Left section ''' ''' Pasting icons. ''' template.paste(cmyk, (CMYK_X, CMYK_Y), cmyk) template.paste(logo, (LOGO_X, LOGO_Y), logo) template.paste(handIcon, (HAND_X,HAND_Y), handIcon) ''' Website stamp. ''' draw.text((HAND_X-len(WEBSITE_LINK)*CHAR_WIDTH-25, LINE1_Y), WEBSITE_LINK , font=font, fill=TEXT_COLOR) ''' Fabric ID stamp ''' draw.text((HAND_X-len(FABRIC_ID)*CHAR_WIDTH-25, LINE2_Y), FABRIC_ID , font=font, fill=TEXT_COLOR) ''' Fabric name ''' if len(fabric_name) > 22: draw.text((NAME_X, LINE1_Y), fabric_name_1, font=font, fill=TEXT_COLOR) draw.text((NAME_X, LINE2_Y), fabric_name_2, font=font, fill=TEXT_COLOR) else: draw.text((NAME_X, LINE_Y), fabric_name, font=font, fill=TEXT_COLOR) ''' Client link if provided ''' ''' Fabric type ''' fabric_type_name = returnFabricTypeName(fabric_type).replace('-', ' ') if len(CLIENT_LINK) != 0: draw.text((HALF_WIDH-(len(fabric_type_name)*CHAR_WIDTH)-75, LINE1_Y), fabric_type_name, font=font, fill=TEXT_COLOR) draw.text((HALF_WIDH-(len(CLIENT_LINK)*CHAR_WIDTH)-62, LINE2_Y), CLIENT_LINK, font=font, fill=TEXT_COLOR) else: draw.text((HALF_WIDH-(len(fabric_type_name)*CHAR_WIDTH)-35, LINE_Y), fabric_type_name, font=font, fill=TEXT_COLOR) ''' Right section ''' fabric_type_name = returnFabricTypeName(fabric_type).replace('-', ' ') if len(CLIENT_LINK) != 0: draw.text((HALF_WIDH+80, LINE1_Y), fabric_type_name, font=font, fill=TEXT_COLOR) draw.text((HALF_WIDH+80, LINE2_Y), CLIENT_LINK, font=font, fill=TEXT_COLOR) else: draw.text((HALF_WIDH+80, LINE_Y), fabric_type_name, font=font, fill=TEXT_COLOR) template.paste(logo, (WIDTH-LOGO_X-100, LOGO_Y), logo) template.paste(handIcon, (WIDTH-HAND_X-85,HAND_Y), handIcon) draw.text((WIDTH-HAND_X+60, LINE1_Y), WEBSITE_LINK, font=font, fill=TEXT_COLOR) draw.text((WIDTH-HAND_X+60, LINE2_Y), FABRIC_ID , font=font, fill=TEXT_COLOR) if len(fabric_name) > 22: draw.text((WIDTH-LOGO_X-125-(len(fabric_name_1)*CHAR_WIDTH), LINE1_Y), fabric_name_1, font=font, fill=TEXT_COLOR) draw.text((WIDTH-LOGO_X-125-(len(fabric_name_2)*CHAR_WIDTH), LINE2_Y), fabric_name_2, font=font, fill=TEXT_COLOR) else: draw.text((WIDTH-LOGO_X-125-(len(fabric_name)*CHAR_WIDTH), LINE_Y), fabric_name, font=font, fill=TEXT_COLOR) ''' Lower stamp ''' uppper_stamp = template.crop((0,0,WIDTH,150)).convert(convert_mode).rotate(180) template.paste(uppper_stamp, (0, 8250), uppper_stamp) if choice == 56 else template.paste(uppper_stamp, (0, 6150), uppper_stamp) ''' Resizing and pasting fabric ''' for fabPart in returnFabricParts(cut_type, choice, SEAMLESS, INCHES, HEADER): if (keep_ratio): '''specialFabric = fillColor.resize(fabPart.size) template.paste(specialFabric, fabPart.location, specialFabric)''' ''' Resize image with keeping ratio and pasting it on the space filler ''' ''' Get new sizes and locations ''' x = fabPart.location[0] y = fabPart.location[1] nx = x ny = y w = fabPart.size[0] h = fabPart.size[1] nw = w nh = h m = min(w,h) if m == w: nh = nw * (fabric.size[1] / fabric.size[0]) ny = y + ((h - nh)//2) else: nw = nh * (fabric.size[0] / fabric.size[1]) nx = x + ((w - nw)//2) newLocation = (int(nx),int(ny)) specialSize = (int(nw),int(nh)) fabricSize = fabric.resize(specialSize) template.paste(fabricSize, newLocation, fabricSize) else: fabricSize = fabric.resize(fabPart.size) template.paste(fabricSize, fabPart.location, fabricSize) ''' Create image final structured name ''' file_name = fabric_name.replace(' ', '_')+"-"+cut_type+"-"+returnFabricTypeName(fabric_type)+"-36x"+str(choice)+".jpg" ''' Finally save the image as JPEG ''' if (fabric_mode != "CMYK"): template.convert(fabric_mode).save(path2 + fabric_name.replace(' ', '_')+'/'+file_name, "JPEG", dpi=(150,150), exif=exif_bytes, quality=100, icc_profile=icc_profile, optimize=False) else: template = ImageCms.profileToProfile(template, icc_profile, 'sRGB Color Space Profile.icm', renderingIntent=0, outputMode='RGB') template.save(path2 + fabric_name.replace(' ', '_')+'/'+file_name, "JPEG", dpi=(150,150), exif=exif_bytes, quality=100, optimize=False)
# -*- coding: utf-8 -*- from __future__ import absolute_import import os from PyBundle import bundle_dir GRAY_PATH = os.path.join(bundle_dir(), 'Gray-CIE_L.icc') try: from PIL import ImageCms gray = ImageCms.ImageCmsProfile(GRAY_PATH) sRGB = ImageCms.createProfile('sRGB') except ImportError: gray = None sRGB = None