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
Exemple #2
0
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)
Exemple #3
0
    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)
Exemple #4
0
 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)
Exemple #5
0
    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))
Exemple #6
0
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"
Exemple #7
0
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"
Exemple #8
0
def test_pil_kwargs_png():
    Image = pytest.importorskip("PIL.Image")
    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"
Exemple #9
0
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()
Exemple #10
0
    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()
Exemple #11
0
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)
Exemple #12
0
 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)
Exemple #13
0
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()
Exemple #14
0
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())
Exemple #15
0
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 {}
Exemple #16
0
 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)
Exemple #17
0
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)
Exemple #18
0
    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)
Exemple #19
0
    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
Exemple #20
0
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)
Exemple #21
0
    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 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)
Exemple #23
0
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 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)
Exemple #25
0
    def to_file(self, filename, *, palette=False):
        # assemble comment
        comment = self._assemble_comment()

        # assemble spritesheet
        W, H = self.width, self.height
        num_frames = sum(len(state.frames) for state in self.states)
        sqrt = math.ceil(math.sqrt(num_frames))
        output = Image.new('RGBA', (sqrt * W, math.ceil(num_frames / sqrt) * H))

        i = 0
        for state in self.states:
            for frame in state.frames:
                output.paste(frame, ((i % sqrt) * W, (i // sqrt) * H))
                i += 1

        # save
        pnginfo = PngInfo()
        pnginfo.add_text('Description', comment, zip=True)
        if palette:
            output = output.convert('P')
        output.save(filename, 'png', optimize=True, pnginfo=pnginfo)
Exemple #26
0
    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)
Exemple #27
0
    def save_image(cls, img, outfile, info=None):
        '''
        Given an image and an optional metadata
        dictionary, write the image as .png, include
        the metadata. 
        
        :param img: image to save
        :type img: np_array
        :param outfile: destination path
        :type outfile: str
        :param info: metadata to add
        :type info: {str : str}
        '''

        # Create metadata to include in the
        # spectrogram .png file:
        if info is not None:
            metadata = PngInfo()
            for key, val in info.items():
                metadata.add_text(key, str(val))

        skimage.io.imsave(outfile, img, pnginfo=metadata)
Exemple #28
0
    def find_plate(filename, image, plate_width):
        from ..image.circle import detect_circles
        mask = image > .6  ## constant
        cluster = _clean_label(_nd.label(mask)[0], min_dim=100)  ## cosntant

        # find plate mask and hull
        pmask, phull = mask_fillhull(cluster > 0)
        pwidth = pmask.sum()**.5  # estimated plate width in pixels
        border = pwidth * .03  ## constant 3% of plate width
        pmask = pmask + 2 * _nd.binary_erosion(pmask > 0,
                                               iterations=int(border))
        px_scale = plate_width / pwidth

        # detect codebar box as the biggest connex cluster
        cbmask = _nd.label(
            _nd.binary_closing((cluster > 0) & (pmask == 3), iterations=5))[0]
        obj = _nd.find_objects(cbmask)
        cbbox = _np.argmax([max([o.stop - o.start for o in ob])
                            for ob in obj]) + 1

        # find codebar mask and hull
        cbmask, cbhull = mask_fillhull(cbmask == cbbox)

        # stack masks such that
        #   pixels to process = 3,
        #   codebar pixels = 2
        #   plate border = 1
        ##mask = pmask + 1*cbmask + 1*_nd.binary_erosion(pmask, iterations=int(border))
        pmask[cbmask > 0] = 2

        # save plate mask
        from PIL.PngImagePlugin import PngInfo
        meta = PngInfo()
        meta.add_text('px_scale', repr(px_scale))
        _Image(pmask).save(filename, dtype='uint8', scale=85,
                           pnginfo=meta)  # 85 = 255/pmask.max()

        return pmask, px_scale
Exemple #29
0
    def to_file(self, filename, *, palette=False):
        # assemble comment
        comment = self._assemble_comment()

        # assemble spritesheet
        W, H = self.width, self.height
        num_frames = sum(len(state.frames) for state in self.states)
        sqrt = math.ceil(math.sqrt(num_frames))
        output = Image.new('RGBA',
                           (sqrt * W, math.ceil(num_frames / sqrt) * H))

        i = 0
        for state in self.states:
            for frame in state.frames:
                output.paste(frame, ((i % sqrt) * W, (i // sqrt) * H))
                i += 1

        # save
        pnginfo = PngInfo()
        pnginfo.add_text('Description', comment, zip=True)
        if palette:
            output = output.convert('P')
        output.save(filename, 'png', optimize=True, pnginfo=pnginfo)
Exemple #30
0
 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)
Exemple #31
0
 def _get_EXIF_DateTimeOriginal(self, file_path):
     """ try to get the recording date from the EXIF in PNG file """
     try:
         image = PngImageFile(file_path)
         metadata = PngInfo()
         exif_array = []
         for i in image.text:
             compile = i, str(image.text[i])
             exif_array.append(compile)
         if len(exif_array) > 0:
             header = exif_array[0][0]
             if header.startswith("XML"):
                 xml = exif_array[0][1]
                 for line in xml.splitlines():
                     if 'DateCreated' in line:
                         idx1 = line.find('>')
                         idx2 = line.rfind('<')
                         if (idx1 != -1) and (idx2 != -1):
                             dt = line[idx1 + 1:idx2]
                             return dt
     except Exception as err:
         pass  # returns None
     return None
    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)
Exemple #33
0
    def print_png(self, filename_or_obj, *args,
                  metadata=None, pil_kwargs=None,
                  **kwargs):
        """
        Write the figure to a PNG file.

        Parameters
        ----------
        filename_or_obj : str or PathLike or file-like object
            The file to write to.

        metadata : dict, optional
            Metadata in the PNG file as key-value pairs of bytes or latin-1
            encodable strings.
            According to the PNG specification, keys must be shorter than 79
            chars.

            The `PNG specification`_ defines some common keywords that may be
            used as appropriate:

            - Title: Short (one line) title or caption for image.
            - Author: Name of image's creator.
            - Description: Description of image (possibly long).
            - Copyright: Copyright notice.
            - Creation Time: Time of original image creation
              (usually RFC 1123 format).
            - Software: Software used to create the image.
            - Disclaimer: Legal disclaimer.
            - Warning: Warning of nature of content.
            - Source: Device used to create the image.
            - Comment: Miscellaneous comment;
              conversion from other image format.

            Other keywords may be invented for other purposes.

            If 'Software' is not given, an autogenerated value for matplotlib
            will be used.

            For more details see the `PNG specification`_.

            .. _PNG specification: \
                https://www.w3.org/TR/2003/REC-PNG-20031110/#11keywords

        pil_kwargs : dict, optional
            If set to a non-None value, use Pillow to save the figure instead
            of Matplotlib's builtin PNG support, and pass these keyword
            arguments to `PIL.Image.save`.

            If the 'pnginfo' key is present, it completely overrides
            *metadata*, including the default 'Software' key.
        """
        from matplotlib import _png

        if metadata is None:
            metadata = {}
        metadata = {
            "Software":
                f"matplotlib version{__version__}, http://matplotlib.org/",
            **metadata,
        }

        if pil_kwargs is not None:
            from PIL import Image
            from PIL.PngImagePlugin import PngInfo
            buf, size = self.print_to_buffer()
            # 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.frombuffer("RGBA", size, buf, "raw", "RGBA", 0, 1)
             .save(filename_or_obj, format="png", **pil_kwargs))

        else:
            FigureCanvasAgg.draw(self)
            renderer = self.get_renderer()
            with cbook._setattr_cm(renderer, dpi=self.figure.dpi), \
                    cbook.open_file_cm(filename_or_obj, "wb") as fh:
                _png.write_png(renderer._renderer, fh,
                               self.figure.dpi, metadata=metadata)
	def generateComics( self, instance ):
		image = Image.new( mode="1", size=(0, 0) )
		for self.generatedComicNumber in range( self.numberOfComics ):
			try:
				if self.commandLineComicID is None:
					wordBubbleFileName = random.choice( os.listdir( self.wordBubblesDir ) )
				else:
					wordBubbleFileName = os.path.join( self.wordBubblesDir, self.commandLineComicID + ".tsv" )
			except IndexError as error:
				six.print_( error, file=sys.stderr )
				exit( EX_NOINPUT )
			
			if not self.silence:
				six.print_( "wordBubbleFileName:", wordBubbleFileName )
			
			if self.commandLineComicID is None:
				comicID = os.path.splitext( wordBubbleFileName )[ 0 ]
			else:
				comicID = self.commandLineComicID
			wordBubbleFileName = os.path.join( self.wordBubblesDir, wordBubbleFileName )
			if not self.silence:
				six.print_( "Loading word bubbles from", wordBubbleFileName )

			try:
				wordBubbleFile = open( wordBubbleFileName, mode="rt" )
			except OSError as error:
				six.print_( error, file=sys.stderr )
				exit( EX_NOINPUT )
			
			if not idChecker.checkFile( wordBubbleFile, wordBubbleFileName, self.commentMark ):
				six.print_( "Error: Word bubble file", wordBubbleFileName, "is not in the correct format." )
				exit( EX_DATAERR )
			
			lookForSpeakers = True
			speakers = []
			while lookForSpeakers:
				line = wordBubbleFile.readline()
				if len( line ) > 0:
					line = line.partition( self.commentMark )[0].strip()
					if len( line ) > 0:
						speakers = line.upper().split( "\t" )
						if len( speakers ) > 0:
							lookForSpeakers = False
				else:
					lookForSpeakers = False; #End of file reached, no speakers found
			
			if len( speakers ) == 0:
				six.print_( "Error: Word bubble file", wordBubbleFileName, "contains no speakers." )
				exit( EX_DATAERR )
			
			if not self.silence:
				six.print_( "These characters speak:", speakers )
			
			for speaker in speakers:
				if speaker not in self.generators:
					if not self.silence:
						six.print_( "Now building a Markov graph for character", speaker, "..." )
					newGenerator = Generator( charLabel = speaker, cm = self.commentMark, randomizeCapitals = self.randomizeCapitals )
					newGenerator.buildGraph( self.inDir )
					
					if not self.silence:
						newGenerator.showStats()
					
					self.generators[ speaker ] = newGenerator
			
			if not self.silence:
				six.print_( comicID )
			
			inImageFileName = os.path.join( self.imageDir, comicID + ".png" )
			
			try:
				image = Image.open( inImageFileName ).convert() #Text rendering looks better if we ensure the image's mode is not palette-based. Calling convert() with no mode argument does this.
			except IOError as error:
				six.print_( error, file=sys.stderr )
				exit( EX_NOINPUT )
			
			transcript = str( comicID ) + "\n"
			
			previousBox = ( int( -1 ), int( -1 ), int( -1 ), int( -1 ) ) #For detecting when two characters share a speech bubble; don't generate text twice.
			
			for line in wordBubbleFile:
				line = line.partition( self.commentMark )[ 0 ].strip()
				
				if len( line ) > 0:
					line = line.split( "\t" )
					character = line[ 0 ].rstrip( ":" ).strip().upper()
					
					try:
						generator = self.generators[ character ]
					except:
						six.print_( "Error: Word bubble file", wordBubbleFileName, "does not list", character, "in its list of speakers.", file=sys.stderr )
						exit( EX_DATAERR )
					
					topLeftX = int( line[ 1 ] )
					topLeftY = int( line[ 2 ] )
					bottomRightX = int( line[ 3 ] )
					bottomRightY = int( line[ 4 ] )
					
					box = ( topLeftX, topLeftY, bottomRightX, bottomRightY )
					
					if box != previousBox:
						previousBox = box
						
						text = ""
						nodeList = generator.generateSentences( 1 )[ 0 ]
						for node in nodeList:
							text += node.word + " "
						text.rstrip()
						
						oneCharacterTranscript = character + ": "
						oneCharacterTranscript += self.stringFromNodes( nodeList )
						if not self.silence:
							six.print_( oneCharacterTranscript )
						oneCharacterTranscript += "\n"
						transcript += oneCharacterTranscript
						
						wordBubble = image.crop( box )
						draw = ImageDraw.Draw( wordBubble )
						
						width = bottomRightX - topLeftX
						if width <= 0: #Width must be positive
							width = 1
						height = bottomRightY - topLeftY
						if height <= 0:
							height = 1
						
						size = int( height * 1.2 ) #Contrary to the claim by PIL's documentation, font sizes are apparently in pixels, not points. The size being requested is the height of a generic character; the actual height of any particular character will be approximately (not exactly) the requested size. We will try smaller and smaller sizes in the while loop below. The 1.2, used to account for the fact that real character sizes aren't exactly the same as the requested size, I just guessed an appropriate value.
						
						normalFont = ImageFont.truetype( self.normalFontFile, size = size )
						boldFont = ImageFont.truetype( self.boldFontFile, size = size )
						
						listoflists = self.rewrap_nodelistlist( nodeList, normalFont, boldFont, width, fontSize = size )
						
						margin = 0
						offset = originalOffset = 0
						goodSizeFound = False
						
						while not goodSizeFound:
							goodSizeFound = True
							totalHeight = 0
							for line in listoflists:
								
								lineWidth = 0
								lineHeight = 0
								for node in line:
									wordSize = normalFont.getsize( node.word + " " )
									lineWidth += wordSize[ 0 ]
									lineHeight = max( lineHeight, wordSize[ 1 ] )
								lineWidth -= normalFont.getsize( " " )[ 0 ]
								totalHeight += lineHeight
								if lineWidth > width:
									goodSizeFound = False
							
							if totalHeight > height:
								goodSizeFound = False
							
							if not goodSizeFound:
								size -= 1
								try:
									normalFont = ImageFont.truetype( self.normalFontFile, size = size )
									boldFont = ImageFont.truetype( self.boldFontFile, size = size )
								except IOError as error:
									six.print_( error, "\nUsing default font instead.", file=sys.stderr )
									normalFont = ImageFont.load_default()
									boldFont = ImageFont.load_default()
								listoflists = self.rewrap_nodelistlist( nodeList, normalFont, boldFont, width, fontSize = size )
						
						midX = int( wordBubble.size[ 0 ] / 2 )
						midY = int( wordBubble.size[ 1 ] / 2 )
						
						try: #Choose a text color that will be visible against the background
							backgroundColor = ImageStat.Stat( wordBubble ).mean #wordBubble.getpixel( ( midX, midY ) )
							textColorList = []
							
							useIntegers = False
							useFloats = False
							if wordBubble.mode.startswith( "1" ):
								bandMax = 1
								useIntegers = True
							elif wordBubble.mode.startswith( "L" ) or wordBubble.mode.startswith( "P" ) or wordBubble.mode.startswith( "RGB" ) or wordBubble.mode.startswith( "CMYK" ) or wordBubble.mode.startswith( "YCbCr" ) or wordBubble.mode.startswith( "LAB" ) or wordBubble.mode.startswith( "HSV" ):
								bandMax = 255
								useIntegers = True
							elif wordBubble.mode.startswith( "I" ):
								bandMax = 2147483647 #max for a 32-bit signed integer
								useIntegers = True
							elif wordBubble.mode.startswith( "F" ):
								bandMax = float( "infinity" )
								useFloats = True
							else: #I've added all modes currently supported according to Pillow documentation; this is for future compatibility
								bandMax = max( ImageStat.Stat( image ).extrema )
							
							for c in backgroundColor:
								d = bandMax - ( c * 1.5 )
								
								if d < 0:
									d = 0
								
								if useIntegers:
									d = int( d )
								elif useFloats:
									d = float( d )
								
								textColorList.append( d )
							
							if wordBubble.mode.endswith( "A" ): #Pillow supports two modes with alpha channels
								textColorList[ -1 ] = bandMax
							
							textColor = tuple( textColorList )
							
						except ValueError:
							textColor = "black"
						
						offset = originalOffset
						for line in listoflists:
							xOffset = 0
							yOffsetAdditional = 0
							for node in line:
								usedFont = node.font
								draw.text( ( margin + xOffset, offset ), node.word + " ", font = usedFont, fill = textColor )
								tempSize = usedFont.getsize( node.word + " " )
								xOffset += tempSize[ 0 ]
								yOffsetAdditional = max( yOffsetAdditional, tempSize[ 1 ] )
								node.unselectStyle()
							offset += yOffsetAdditional
						
						image.paste( wordBubble, box )
						
			wordBubbleFile.close()
			
			if self.numberOfComics > 1:
				oldOutTextFileName = self.outTextFileName
				temp = os.path.splitext(self.outTextFileName )
				self.outTextFileName = temp[ 0 ] + str( self.generatedComicNumber ) + temp[ 1 ]
			
			#---------------------------Split into separate function
			try:
				#os.makedirs( os.path.dirname( outTextFileName ), exist_ok = True )
				outFile = open( self.outTextFileName, mode="wt" )
			except OSError as error:
				six.print_( error, "\nUsing standard output instead", file=sys.stderr )
				outFile = sys.stdout
			
			if self.numberOfComics > 1:
				self.outTextFileName = oldOutTextFileName
			
			six.print_( transcript, file=outFile )
			
			outFile.close()
			
			if self.numberOfComics > 1:
				oldOutImageFileName = self.outImageFileName
				temp = os.path.splitext( self.outImageFileName )
				outImageFileName = temp[ 0 ] + str( self.generatedComicNumber ) + temp[ 1 ]
			
			if self.topImageFileName != None:
				try:
					topImage = Image.open( self.topImageFileName ).convert( mode=image.mode )
				except IOError as error:
					six.print_( error, file=sys.stderr )
					exit( EX_NOINPUT )
				oldSize = topImage.size
				size = ( max( topImage.size[ 0 ], image.size[ 0 ] ), topImage.size[ 1 ] + image.size[ 1 ] )
				
				newImage = Image.new( mode=image.mode, size=size )
				newImage.paste( im=topImage, box=( 0, 0 ) )
				newImage.paste( im=image, box=( 0, oldSize[ 1 ] ) )
				image = newImage
			
			
			
			originalURL = None
			URLFile = open( os.path.join( self.inDir, "sources.tsv" ), "rt" )
			for line in URLFile:
				line = line.partition( self.commentMark )[ 0 ].strip()
				
				if len( line ) > 0:
					line = line.split( "\t" )
					
					if comicID == line[ 0 ]:
						originalURL = line[ 1 ]
						break;
			URLFile.close()
			
			transcriptWithURL = transcript + "\n" + originalURL #The transcript that gets embedded into the image file should include the URL. The transcript that gets uploaded to blogs doesn't need it, as the URL gets sent anyway.
			
			infoToSave = PngInfo()
			
			encodingErrors = "backslashreplace" #If we encounter errors during text encoding, I feel it best to replace unencodable text with escape sequences; that way it may be possible for reader programs to recover the original unencodable text.
			
			#According to the Pillow documentation, key names should be "latin-1 encodable". I take this to mean that we ourselves don't need to encode it in latin-1.
			key = "transcript"
			keyUTF8 = key.encode( "utf-8", errors=encodingErrors )
			
			#uncomment the following if using Python 3
			#transcriptISO = transcriptWithURL.encode( "iso-8859-1", errors=encodingErrors )
			#transcriptUTF8 = transcriptWithURL.encode( "utf-8", errors=encodingErrors )
			
			#python 2:
			tempencode = transcriptWithURL.decode( 'ascii', errors='replace' ) # I really don't like using this ascii-encoded intermediary called tempencode, but i couldn't get the program to work when encoding directly to latin-1
			transcriptISO = tempencode.encode( "iso-8859-1", errors='replace' )
			transcriptUTF8 = tempencode.encode( "utf-8", errors='replace' )
			
			
			infoToSave.add_itxt( key=key, value=transcriptUTF8, tkey=keyUTF8 )
			infoToSave.add_text( key=key, value=transcriptISO )
			
			#GIMP only recognizes comments
			key = "Comment"
			keyUTF8 = key.encode( "utf-8", errors=encodingErrors )
			
			infoToSave.add_text( key=key, value=transcriptISO )
			infoToSave.add_itxt( key=key, value=transcriptUTF8, tkey=keyUTF8 )
			
			try:
				#os.makedirs( os.path.dirname( outImageFileName ), exist_ok = True )
				if self.saveForWeb:
					image = image.convert( mode = "P", palette="ADAPTIVE", dither=False ) #Try turning dithering on or off.
					image.save( self.outImageFileName, format="PNG", optimize=True, pnginfo=infoToSave )
				else:
					image.save( self.outImageFileName, format="PNG", pnginfo=infoToSave )
			except IOError as error:
				six.print_( error, file = sys.stderr )
				exit( EX_CANTCREAT )
			except OSError as error:
				six.print_( error, file = sys.stderr )
				exit( EX_CANTCREAT )
			
			if not self.silence:
				six.print_( "Original comic URL:", originalURL )
			
			for blog in self.blogUploaders:
				blog.upload( postStatus = "publish", inputFileName = outImageFileName, shortComicTitle = self.shortName, longComicTitle = self.longName, transcript = transcript, originalURL = originalURL, silence = self.silence )
			
			if self.numberOfComics > 1:
				outImageFileName = oldOutImageFileName
		#end of loop: for generatedComicNumber in range( numberOfComics ):
		
		#---------------------------It's display time!
		if image.mode != "RGB":
			image = image.convert( mode = "RGB" )
		self.gui.comicArea.texture = Texture.create( size = image.size, colorfmt = 'rgb' )
		self.gui.comicArea.texture.blit_buffer( pbuffer = image.transpose( Image.FLIP_TOP_BOTTOM ).tobytes(), colorfmt = 'rgb' )
Exemple #35
0
import sys
from PIL import Image
from PIL.PngImagePlugin import PngInfo

png = Image.open('original.png')
pixels = png.load()

new_pixels = []
with open(sys.argv[1], "r") as kg:
    new_pixels = kg.read()

print "setting %d new pixels" % len(new_pixels)

k = 0

for i in range(png.size[0]):    # for every pixel:
    if k >= len(new_pixels):
        break
    for j in range(png.size[1]):
        r, g, b = list(pixels[i, j])
        b = new_pixels[k]  # change the blue pixel ;)
        pixels[i, j] = r, g, ord(b)
        k += 1
        if k >= len(new_pixels):
            break

info = PngInfo()
info.add_text("flag", "not here ...but john loves that song ;)")
png.save('Ub7XL8T.png', 'PNG', compress_level=9, pnginfo=info)