def add_png_metadata(self, path, glyph): ''' given the path to a png file and the glyph it contains, write appropriate metadata fields into the file ''' self.metadata['Description'] = self.metadata[ '_Description_tmpl'].format(glyph=glyph) self.metadata['Title'] = self.metadata['_Title_tmpl'].format( glyph=glyph, border=self.args['bordercolor_name'], color=self.args['bgcolor_name']) with Image.open(path) as image: info = PngInfo() for entry in ["Author", "Description", "Title", "Software"]: if not entry.startswith('_'): info.add_itxt(entry, self.metadata[entry], "en", entry) basename, filename = os.path.split(path) newname = os.path.join(basename, 'new-' + filename) image.save(newname, pnginfo=info) if self.args['verbose']: with Image.open(newname) as image: print("new image is", newname) print(image.info) os.unlink(path) os.rename(newname, path)
def print_png(self, filename_or_obj, *args, metadata=None, pil_kwargs=None, **kwargs): if metadata is None: metadata = {} if pil_kwargs is None: pil_kwargs = {} metadata = { "Software": f"matplotlib version{__version__}, http://matplotlib.org/", **metadata, } if "pnginfo" not in pil_kwargs: pnginfo = PngInfo() for k, v in metadata.items(): pnginfo.add_text(k, v) pil_kwargs["pnginfo"] = pnginfo pil_kwargs.setdefault("dpi", (self.figure.dpi, self.figure.dpi)) data = self.get_pixel_data() (Image.fromarray(data).save(filename_or_obj, format="png", **pil_kwargs))
def _prepare_slide(self, mols, properties): if mols is None: raise ValueError( 'Expected a list of rdkit molecule instances but got \'None\'') # cut-off mols + properties silently. I think this is better than raising a ValueError mols = mols[:self.max_mols] properties = properties[:self.max_mols] if self.number_of_properties > 0 and len(mols) != len(properties): raise ValueError( 'Number of molecules must match number of properties.') if len(mols) == self.max_mols: slide = Image.new('RGBA', [self.slide_width, self.slide_height], (255, 255, 255, 0)) # less mols -> smaller image elif len(mols) < self.mols_per_row: slide = Image.new('RGBA', [len(mols) * self.image_width, self.row_height], (255, 255, 255, 0)) else: num_rows = (len(mols) // self.mols_per_row) + 1 slide = Image.new('RGBA', [self.slide_width, self.row_height * num_rows], (255, 255, 255, 0)) png_info = PngInfo() png_info.add_text('numProperties', str(self.number_of_properties)) return mols, slide, png_info
def hide_information(self): """ Method to hide a key into the given image """ #first of all is to change original cover file metadata #because if we do it later, bits will be changed and key # will not be recovered _tmp_image = self.image_object.copy() max_with = _tmp_image.size[0] - 1 (coord_x, coord_y) = (0, 0) for pixel in self.encode_imdata(_tmp_image.getdata(), self.key_to_hide): _tmp_image.putpixel((coord_x, coord_y), pixel) if (coord_x == max_with): coord_x = 0 coord_y += 1 else: coord_x += 1 #save the resulting image #image_format = self.image_where_to_hide.split(".")[1] image_format = "png" f_name = self.image_where_to_hide.split( ".")[0] + "_hide." + image_format metadata = PngInfo() metadata.add_text("url", self.url_metadata) metadata.add_text("language", self.url_language) _tmp_image.save(f_name, image_format.upper(), pnginfo=metadata)
def encode(filename, mode="RGB", verbose=False): if mode == "P": print( "invalid choice: 'P' for PNG (choose from '1', 'L', 'RGB', 'RGBA')" ) sys.exit() if mode not in ["RGB", "L"]: print(mode, "coming soon") sys.exit() try: with open(filename, 'rb') as f: data = f.read() except IOError as e: print(e) sys.exit() output_filename = change_ext(filename, "png") output_size, extra_bytes_lenght = calc_size(len(data), mode) data += (b'\0' * extra_bytes_lenght) metadata = PngInfo() metadata.add_text("filename", str(os.path.basename(filename))) metadata.add_text("extra_bytes", str(extra_bytes_lenght)) if os.path.isfile(output_filename): output_filename = get_unique_filename(output_filename) im = Image.frombytes(mode, output_size, data) im.save(output_filename, pnginfo=metadata) if verbose: print(f"Extra bytes: {extra_bytes_lenght}") print(f"Image size: {output_size}") print(f"Image mode: {im.mode}") print(f"Filename: {output_filename}") sys.exit()
def encrypt_png(self, in_path: PathType, out_path: PathType) -> None: image = PngImageFile(in_path) # convert pixels to bytes in order to encrypt them im_bytes = bytearray(self.__get_pixels(image)) # get random IV and calculate MAC iv = get_random_bytes(CryptoAES.block_size) h = HMAC.new(self.__key, digestmod=SHA256) h.update(im_bytes) # create metadata object in order to save IV and MAC to image metadata = PngInfo() metadata.add_text('iv', iv.hex()) metadata.add_text('mac', h.hexdigest()) print(f'writing IV = {iv.hex()} and MAC = {h.hexdigest()} to image metadata') # encrypt image cipher = CryptoAES.new(self.__key, CryptoAES.MODE_ECB) enc_data = cipher.encrypt(im_bytes) # write image to file with metadata image.frombytes(enc_data) image.save(out_path, pnginfo=metadata)
def print_png(self, path_or_stream, *, dryrun=False, metadata=None, pil_kwargs=None, **kwargs): _check_print_extra_kwargs(**kwargs) img = self._get_fresh_straight_rgba8888() if dryrun: return metadata = { "Software": f"matplotlib version {mpl.__version__}, https://matplotlib.org", **(metadata if metadata is not None else {}), } if pil_kwargs is None: pil_kwargs = {} # Only use the metadata kwarg if pnginfo is not set, because the # semantics of duplicate keys in pnginfo is unclear. if "pnginfo" not in pil_kwargs: pnginfo = PngInfo() for k, v in metadata.items(): pnginfo.add_text(k, v) pil_kwargs["pnginfo"] = pnginfo pil_kwargs.setdefault("dpi", (self.figure.dpi, self.figure.dpi)) Image.fromarray(img).save(path_or_stream, format="png", **pil_kwargs)
def encrypt(self): """ Encode in base64 the string/file, create a PNG file with previously selected colors; encrypt in AES-256 characters + RGB values dataset, and append to image as zTXt chunk; save PNG file with uuid4 filename or return image PIL object depending on directory parameter. """ if path.isfile(self.data): with open(self.data, "rb") as file: self.data = urlsafe_b64encode(file.read()).decode('utf8') file.close() else: self.data = urlsafe_b64encode(self.data.encode()).decode('utf8') encrypted = self.encrypt_aes256(dataset=None) self.data = encrypted["CipherData"] colorslist, dataset = self.colors_list(self.data) imgsize = int(sqrt(len(colorslist))) img = Image.new(mode = "RGB", size = (imgsize, imgsize)) img.putdata(colorslist) encdataset = self.encrypt_aes256(str(dataset)) metadata = PngInfo() metadata.add_text("Dataset", encdataset["CipherData"], zip = True) metadata.add_text("DatasetNonce", encdataset["Nonce"], zip = True) metadata.add_text("DatasetSalt", encdataset["Salt"], zip = True) metadata.add_text("DatasetTag", encdataset["Tag"], zip = True) metadata.add_text("DataNonce", encrypted["Nonce"], zip = True) metadata.add_text("DataSalt", encrypted["Salt"], zip = True) metadata.add_text("DataTag", encrypted["Tag"], zip = True) if not self.directory: b = BytesIO() img.save(b, "PNG", pnginfo = metadata) b.seek(0) return b img.save(self.directory + sep + str(uuid4()) + ".png", "PNG", pnginfo = metadata)
def ExportPicture(self, index, path): pnginfo = PngInfo() pnginfo.add_text("Software", "FlashGBX") pnginfo.add_text("Source", "Pocket Camera") pnginfo.add_text("Creation Time", email.utils.formatdate()) if index == 0: pic = self.GetPicture(0) pnginfo.add_text("Title", "Game Face") else: pic = self.GetPicture(index) pnginfo.add_text("Title", "Photo {:02d}".format(index)) ext = os.path.splitext(path)[1] if ext.lower() == ".png": outpic = pic outpic.save(path, pnginfo=pnginfo) elif ext.lower() == ".gif": outpic = pic outpic.save(path) elif ext.lower() in (".jpg", ".jpeg"): outpic = pic.convert("RGB") outpic.save(path, quality=100, subsampling=0) else: outpic = pic.convert("RGB") outpic.save(path)
def resize_card(image_load_args, fmt, height, axis): try: image = load_image(*image_load_args) except IOError: return (1, None) scalefactor = height / (image.height if axis == "h" else image.width) if image.format == "PNG" and (image.mode != "RGB" or image.mode != "RGBA"): image = image.convert("RGBA") image = image.resize( (round(image.width * scalefactor), round(image.height * scalefactor)), reducing_gap=3.0) bio = io.BytesIO() try: if fmt == "jpg": image.save(bio, "jpeg", quality=90, exif=make_exif(b"SkyfarerGalleryResizeTag")) else: meta = PngInfo() meta.add_text("Skyfarer", f"GalleryResizeTag") image.save(bio, "png", optimize=True, pnginfo=meta) except IOError as e: return (3, None) return (0, bio.getvalue())
def main(): try: opts, args = getopt.getopt(sys.argv[1:], "t:o:s:h", ["text=", "output=", "script=", "help"]) except getopt.GetoptError as err: # print help information and exit: print(err) # will print something like "option -a not recognized" usage() sys.exit(2) output = None text = None script = None for o, a in opts: if o in ("-t", "--text"): text = a elif o in ("-o", "--output"): output = a elif o in ("-s", "--script"): script = a elif o in ("-h", "--help"): usage() sys.exit() else: assert False, "unhandled option" img = scriptList[script](text, method=Image.LANCZOS) metadata = PngInfo() metadata.add_itxt("Content", text) img.save(output, pnginfo=metadata)
def test_pil_kwargs_png(): from PIL.PngImagePlugin import PngInfo buf = io.BytesIO() pnginfo = PngInfo() pnginfo.add_text("Software", "test") plt.figure().savefig(buf, format="png", pil_kwargs={"pnginfo": pnginfo}) im = Image.open(buf) assert im.info["Software"] == "test"
def display_pil_image(img): """displayhook function for PIL Images, rendered as PNG""" # pull metadata from the image, if there metadata = PngInfo() for k, v in img.info.items(): metadata.add_text(k, v) bio = BytesIO() img.save(bio, format='PNG', pnginfo=metadata) return bio.getvalue()
def test_imsave_pil_kwargs_png(): from PIL.PngImagePlugin import PngInfo buf = io.BytesIO() pnginfo = PngInfo() pnginfo.add_text("Software", "test") plt.imsave(buf, [[0, 1], [2, 3]], format="png", pil_kwargs={"pnginfo": pnginfo}) im = Image.open(buf) assert im.info["Software"] == "test"
def __init__(self, image: ndarray, from_color_space: str = None, to_color_space: str = None): raiseif( not isinstance(image, ndarray), UnearthtimeException(f'Image is type [{type(image)}] and must be type `numpy.ndarray`') ) self.__image, self.__color_space = Image.__resolve_image(image, from_color_space, to_color_space) self.__hash = 0 self.__height, self.__width = image.shape[0], image.shape[1] self.__info = PngInfo()
def patch_image(): # <- image with a text inside can be loaded as a playlist with open("proto_image.png", mode="rb") as i: img = Image.open(i) info = PngInfo() with open("attacking_playlist.m3u") as pl: text = pl.read() info.add_text("attack", text) img.save("vuln_image.png", "PNG", pnginfo=info)
def add_tags_to_png_file(fpath): try: info = create_file_info(fpath) png_image = PngImageFile(open(fpath, 'rb')) png_info = PngInfo() for k, v in info.items(): png_info.add_text(k, v) png_image.save(fpath, pnginfo=png_info) except (Exception, OSError): print("WARNING: Could not add debug info to file '{}'.".format(fpath)) traceback.print_exc()
def _include_provenance_png(filename, attributes): pnginfo = PngInfo() exif_tags = { 'provenance': 'ImageHistory', 'caption': 'ImageDescription', 'software': 'Software', } for key, value in attributes.items(): pnginfo.add_text(exif_tags.get(key, key), value, zip=True) with Image.open(filename) as image: image.save(filename, pnginfo=pnginfo)
def stack_card(image_load_args, fmt, frame_num, role_num, attr_num): global G_CARD_ICON_ATLAS if not frame_num < 4: return (1, None) if not role_num < 5: return (1, None) if not attr_num < 7: return (1, None) if not G_CARD_ICON_ATLAS: try: G_CARD_ICON_ATLAS = Image.open( os.path.join(os.path.dirname(__file__), "assets", "cardicons.png")) except IOError: return (1, None) try: face = load_image(*image_load_args) except IOError: return (1, None) icon = Image.new("RGBA", (128, 128)) icon.paste(face, ((icon.size[0] - face.size[0]) // 2, (icon.size[1] - face.size[1]) // 2)) if frame_num: icon.alpha_composite(G_CARD_ICON_ATLAS, source=frame_coordinate[frame_num]) if attr_num: icon.alpha_composite(G_CARD_ICON_ATLAS, (97, 3), attribute_coordinate[attr_num]) if role_num: icon.alpha_composite(G_CARD_ICON_ATLAS, (2, 98), role_coordinate[role_num]) bio = io.BytesIO() try: if fmt == "jpg": icon.convert("RGB").save(bio, "jpeg", quality=90, exif=make_icon_exif( frame_num, attr_num, role_num)) else: meta = PngInfo() meta.add_text("Skyfarer", f"v:2,f:{frame_num},a:{attr_num},r:{role_num}") icon.save(bio, "png", optimize=True, pnginfo=meta) except IOError: return (3, None) return (0, bio.getvalue())
def capture(): if args is None: raise RuntimeError("Something horribly wrong has happened") if "pullTime" not in request.form: return {"error": "No pull time!"}, 400 pull_time = request.form["pullTime"] if not pull_time.isdigit(): return {"error": "Invalid pull time"}, 400 pull_time = int(pull_time) img = request.form["image"] resp = urlopen(img) machine = request.form["machine"] now = int(time.time()) ext = ".png" name = f"{now}-{machine}{ext}" fs, path = mkstemp(suffix=ext) os.close(fs) try: with open(path, "wb") as ofs: ofs.write(resp.file.read()) img = load_img(path) finally: os.remove(path) # Simple way of storing more information about the image metadata = PngInfo() fields_to_not_attach = {"image"} for key, value in request.form.items(): if key in fields_to_not_attach: continue metadata.add_text(key, value) # Don't do this every request if args.capture_split: split_ratios = [int(x) for x in args.split_ratio.split(",")] ratio_total = sum(split_ratios) rand = random.randint(0, ratio_total) limit = 0 for i, split in enumerate(split_ratios): limit += split if rand <= limit: output_dir = os.path.join(args.capture_dir, OUTPUTS[i]) if not os.path.isdir(output_dir): os.mkdir(output_dir) output_dir = os.path.join(output_dir, str(pull_time)) break else: output_dir = os.path.join(args.capture_dir, str(pull_time)) if not os.path.isdir(output_dir): os.mkdir(output_dir) img.save(os.path.join(output_dir, name), pnginfo=metadata) return {}
def savemeta(*args, **kwargs): path = args[1] if path.endswith(".fig"): import pickle as pkl pkl.dump(args[0], open(path, 'wb')) else: mpl_savefig(*args, **kwargs) #fig = args[0] if path.endswith(".png"): targetImage = PngImageFile(path) metadata = PngInfo() metadata.add_text("Description", str(meta)) targetImage.save(path, pnginfo=metadata)
def saveImg(self, path): """ Save information as an image """ arr = self.grid arr[self.coffset[1], self.coffset[0]] = 0.8 # Save map info meta = PngInfo() meta.add_text("iposx", str(self.ipos[0])) meta.add_text("iposy", str(self.ipos[1])) meta.add_text("tsize", str(self.tsize)) arr = np.flipud(arr) img = Image.fromarray(np.uint8(arr * 255), 'L') img.save(path, "PNG", pnginfo=meta)
def write_png_metadata(filename, settings): targetImage = PngImageFile(filename) metadata = PngInfo() for (k, v) in settings.items(): if type(v) == list: value = "" for item in v: value += str(item) + " " v = value if type(v) == bool: v = str(v) if v is None: continue else: metadata.add_text(k, str(v)) targetImage.save(filename, pnginfo=metadata)
def sample_image_path(self): """Copy the sample image to to a unique file name and return the path. Returns: tuple of (the filename, the new sample image path) """ filename = self.generate_alphanumeric() + ".png" new_file = self.tmp_file_path(filename) shutil.copy(self.original_sample_image_path, new_file) # make the image content unique image_file = PngImageFile(open(new_file, "r")) info = PngInfo() info.add_text('Comment', self.generate_alphanumeric(length=30)) image_file.save(new_file, pnginfo=info) self.temp_files.append(new_file) return (filename, new_file)
def decrypt_png(self, in_path: PathType, out_path: PathType) -> None: image = PngImageFile(in_path) iv: Optional[str] = None mac: Optional[str] = None # try to get IV from metadata try: iv = image.text['iv'] print(f'found IV = {iv}') except KeyError: print('IV was not found in file') # try to get MAC from metadata try: mac = image.text['mac'] print(f'found MAC = {mac}') except KeyError: print('MAC was not found in file') # convert pixels to bytes in order to decrypt them im_bytes = bytearray(self.__get_pixels(image)) # decrypt image cipher = CryptoAES.new(self.__key, CryptoAES.MODE_ECB) dec: bytes = cipher.decrypt(im_bytes) # try to verify MAC try: self.__hmac.update(dec) self.__hmac.verify(bytes.fromhex(mac)) print('MAC is valid') except ValueError: print('MAC is invalid') # don't forget about metadata metadata = PngInfo() metadata.add_text('iv', iv) metadata.add_text('mac', mac) # save decrypted image to file image.frombytes(dec) image.save(out_path, pnginfo=metadata)
def segment_image(filename, image, mask, root_max_radius=15, min_dimension=50, smooth=1): #mask = _nd.binary_erosion(mask==mask.max(), iterations= mask = mask == mask.max() # find the bounding box, and crop image and mask bbox = _nd.find_objects(mask)[0] mask = mask[bbox] img = image[bbox] if smooth: smooth_img = _nd.gaussian_filter(img * mask, sigma=smooth) smooth_img /= _np.maximum( _nd.gaussian_filter(mask.astype('f'), sigma=smooth), 2**-10) img[mask] = smooth_img[mask] # background removal _print_state(verbose, 'remove background') img = _remove_background(img, distance=root_max_radius, smooth=1) img *= _nd.binary_erosion(mask, iterations=root_max_radius) # image binary segmentation _print_state(verbose, 'segment binary mask') rmask = _segment_root(img) rmask[-mask] = 0 if min_dimension > 0: cluster = _nd.label(rmask)[0] cluster = _clean_label(cluster, min_dim=min_dimension) rmask = cluster > 0 # save the mask, and bbox from PIL.PngImagePlugin import PngInfo meta = PngInfo() meta.add_text( 'bbox', repr([(bbox[0].start, bbox[0].stop), (bbox[1].start, bbox[1].stop)])) _Image(rmask).save(filename, dtype='uint8', scale=255, pnginfo=meta) return rmask, bbox
def replace_meta(filename, fields): metaname = get_dumpfile(filename) with open(metaname) as json_file: meta = json.load(json_file) if fields and fields[0] != '*': print(f"overwriting metadata[{fields}] in {filename} from {metaname}") newmeta = {} for f in fields: newmeta[f] = meta[f] else: print(f"overwriting metadata in {filename} from {metaname}") newmeta = meta newmeta['Metadata Modification Time'] = f"{datetime.now()}" img = PngImageFile(filename) metadata = PngInfo() for f in newmeta: metadata.add_text(f, newmeta[f]) img.save(filename, pnginfo=metadata)
def compute_circle(filename, image, circle_number): from ..image.circle import detect_circles cmask = _nd.binary_opening(image > .45, iterations=5) cluster = _nd.label(cmask)[0] cluster = _clean_label(cluster, min_dim=30) ind, qual, c, dmap = detect_circles(n=circle_number, cluster=cluster) radius = qual**.5 / _np.pi #cind = _np.zeros(c.max()+1) #cind[ind] = _np.arange(1,len(ind)+1) #cmask = cind[c] from PIL.PngImagePlugin import PngInfo meta = PngInfo() meta.add_text('circles', repr(ind.tolist())) meta.add_text('radius', repr(radius.tolist())) _Image(cluster).save(filename, dtype='uint8', scale=1, pnginfo=meta) #_Image(cmask).save(filename, dtype='uint8', scale=1) return cluster, ind, radius
def on_save_clicked(self, button): current_path = self.entry.get_text() # write metadata metadata = PngInfo() metadata.add_text("screenshat", self.entryy.get_text()) img = PngImageFile(img_path) img.save(img_path, pnginfo=metadata) # Update config file pathlib.Path(config_path).write_text(current_path) # in doubt do mkdir -p new directory pathlib.Path(current_path).mkdir(parents=True, exist_ok=True) # move file shutil.move(img_path, current_path) self.destroy()
def encode_to_img(self, secret: str, scale: bool = True) -> PixelImage: """Encodes secret to a colorful png square Parameters ___________ secret: str Secret to be encoded consisting of any utf8 chars including whitespace ones scale: bool = True Whether or not to enlarge output image. Only enourmous secrets will produce image bigger than a couple pixels by a couple pixels which is miserable to look at. Basically a choice of aesthetics over pragmatism""" self.encode(secret) edge, *_ = self.arr.shape metadata = PngInfo() if scale and (scale_up := (self.max_scale_up // edge)) > 1: s = edge * scale_up img = Image.fromarray(self.arr).resize((s, s), Image.NEAREST) metadata.add_text("edge", str(edge)) return PixelImage(img, pnginfo=metadata)