Example #1
0
def read_png_or_jpeg2000(fobj, start_length, size):
    (start, length) = start_length
    fobj.seek(start)
    sig = fobj.read(12)
    if sig[:8] == b"\x89PNG\x0d\x0a\x1a\x0a":
        fobj.seek(start)
        im = PngImagePlugin.PngImageFile(fobj)
        Image._decompression_bomb_check(im.size)
        return {"RGBA": im}
    elif (
        sig[:4] == b"\xff\x4f\xff\x51"
        or sig[:4] == b"\x0d\x0a\x87\x0a"
        or sig == b"\x00\x00\x00\x0cjP  \x0d\x0a\x87\x0a"
    ):
        if not enable_jpeg2k:
            raise ValueError(
                "Unsupported icon subimage format (rebuild PIL "
                "with JPEG 2000 support to fix this)"
            )
        # j2k, jpc or j2c
        fobj.seek(start)
        jp2kstream = fobj.read(length)
        f = io.BytesIO(jp2kstream)
        im = Jpeg2KImagePlugin.Jpeg2KImageFile(f)
        Image._decompression_bomb_check(im.size)
        if im.mode != "RGBA":
            im = im.convert("RGBA")
        return {"RGBA": im}
    else:
        raise ValueError("Unsupported icon subimage format")
Example #2
0
 def _open(self, pilmode=None, as_gray=False):
     Image = self.format._init_pillow()
     try:
         factory, accept = Image.OPEN[self.format.plugin_id]
     except KeyError:
         raise RuntimeError("Format %s cannot read images." %
                            self.format.name)
     self._fp = self._get_file()
     self._im = factory(self._fp, "")
     if hasattr(Image, "_decompression_bomb_check"):
         Image._decompression_bomb_check(self._im.size)
     # Save the raw mode used by the palette for a BMP because it may not be the number of channels
     # When the data is read, imageio hands the palette to PIL to handle and clears the rawmode argument
     # However, there is a bug in PIL with handling animated GIFs with a different color palette on each frame.
     # This issue is resolved by using the raw palette data but the rawmode information is now lost. So we
     # store the raw mode for later use
     if self._im.palette and self._im.palette.dirty:
         self._im.palette.rawmode_saved = self._im.palette.rawmode
     pil_try_read(self._im)
     # Store args
     self._kwargs = dict(as_gray=as_gray,
                         is_gray=_palette_is_grayscale(self._im))
     # setting mode=None is not the same as just not providing it
     if pilmode is not None:
         self._kwargs["mode"] = pilmode
     # Set length
     self._length = 1
     if hasattr(self._im, "n_frames"):
         self._length = self._im.n_frames
Example #3
0
 def _open(self, pilmode=None, as_gray=False):
     Image = self.format._init_pillow()
     try:
         factory, accept = Image.OPEN[self.format.plugin_id]
     except KeyError:
         raise RuntimeError("Format %s cannot read images." % self.format.name)
     self._fp = self._get_file()
     self._im = factory(self._fp, "")
     if hasattr(Image, "_decompression_bomb_check"):
         Image._decompression_bomb_check(self._im.size)
     # Save the raw mode used by the palette for a BMP because it may not be the number of channels
     # When the data is read, imageio hands the palette to PIL to handle and clears the rawmode argument
     # However, there is a bug in PIL with handling animated GIFs with a different color palette on each frame.
     # This issue is resolved by using the raw palette data but the rawmode information is now lost. So we
     # store the raw mode for later use
     if self._im.palette and self._im.palette.dirty:
         self._im.palette.rawmode_saved = self._im.palette.rawmode
     pil_try_read(self._im)
     # Store args
     self._kwargs = dict(
         as_gray=as_gray, is_gray=_palette_is_grayscale(self._im)
     )
     # setting mode=None is not the same as just not providing it
     if pilmode is not None:
         self._kwargs["mode"] = pilmode
     # Set length
     self._length = 1
     if hasattr(self._im, "n_frames"):
         self._length = self._im.n_frames
Example #4
0
 def seek(self, frame):
     "Select a given frame as current image"
     self._seek(max(frame, 0))  # Questionable backwards compatibility.
     # Create a new core image object on second and
     # subsequent frames in the image. Image may be
     # different size/mode.
     Image._decompression_bomb_check(self.size)
     self.im = Image.core.new(self.mode, self.size)
Example #5
0
 def seek(self, frame):
     "Select a given frame as current image"
     self._seek(max(frame, 0))  # Questionable backwards compatibility.
     # Create a new core image object on second and
     # subsequent frames in the image. Image may be
     # different size/mode.
     Image._decompression_bomb_check(self.size)
     self.im = Image.core.new(self.mode, self.size)
Example #6
0
 def seek(self, frame):
     "Select a given frame as current image"
     if frame < 0:
         frame = 0
     self._seek(frame)
     # Create a new core image object on second and
     # subsequent frames in the image. Image may be
     # different size/mode.
     Image._decompression_bomb_check(self.size)
     self.im = Image.core.new(self.mode, self.size)
Example #7
0
 def seek(self, frame):
     "Select a given frame as current image"
     if frame < 0:
         frame = 0
     self._seek(frame)
     # Create a new core image object on second and
     # subsequent frames in the image. Image may be
     # different size/mode.
     Image._decompression_bomb_check(self.size)
     self.im = Image.core.new(self.mode, self.size)
Example #8
0
 def _open(self, **kwargs):
     Image = self.format._init_pillow()
     try:
         factory, accept = Image.OPEN[self.format.plugin_id]
     except KeyError:
         raise RuntimeError('Format %s cannot read images.' %
                            self.format.name)
     self._fp = self.request.get_file()
     self._im = factory(self._fp, '')
     if hasattr(Image, '_decompression_bomb_check'):
         Image._decompression_bomb_check(self._im.size)
     pil_try_read(self._im)
     self._grayscale = _palette_is_grayscale(self._im)
     # Set length
     self._length = 1
     if hasattr(self._im, 'n_frames'):
         self._length = self._im.n_frames
Example #9
0
 def _open(self, **kwargs):
     Image = self.format._init_pillow()
     try:
         factory, accept = Image.OPEN[self.format.plugin_id]
     except KeyError:
         raise RuntimeError('Format %s cannot read images.' %
                            self.format.name)
     self._fp = self.request.get_file()
     self._im = factory(self._fp, '')
     if hasattr(Image, '_decompression_bomb_check'):
         Image._decompression_bomb_check(self._im.size)
     pil_try_read(self._im)
     self._grayscale = _palette_is_grayscale(self._im)
     # Set length
     self._length = 1
     if hasattr(self._im, 'n_frames'):
         self._length = self._im.n_frames
Example #10
0
    def _open(self):
        s = self.fp.read(4)
        t = self.fp.read(4)
        if len(s) < 4 or len(t) < 4:
            raise InvalidFileType("not a GIMP brush")
        header_size = i32(s)
        version = i32(t)
        if header_size < 20:
            raise InvalidFileType("not a GIMP brush")
        if version not in (1, 2):
            raise NotImplementedError("Unsupported GIMP brush version: %s" % version)

        width = i32(self.fp.read(4))
        height = i32(self.fp.read(4))
        color_depth = i32(self.fp.read(4))
        if width <= 0 or height <= 0:
            raise InvalidFileType("not a GIMP brush")
        if color_depth not in (1, 4):
            raise NotImplementedError("Unsupported GIMP brush color depth: %s" % color_depth)

        if version == 1:
            comment_length = header_size-20
        else:
            comment_length = header_size-28
            magic_number = self.fp.read(4)
            if magic_number != b'GIMP':
                raise InvalidFileType("not a GIMP brush, bad magic number")
            self.info['spacing'] = i32(self.fp.read(4))

        comment = self.fp.read(comment_length)[:-1]

        if color_depth == 1:
            self.mode = "L"
        else:
            self.mode = 'RGBA'

        self.size = width, height

        self.info["comment"] = comment

        # Image might not be small
        Image._decompression_bomb_check(self.size)

        # Data is an uncompressed block of w * h * bytes/pixel
        self._data_size = width * height * color_depth
Example #11
0
 def _open(self, pilmode=None, as_gray=False):
     Image = self.format._init_pillow()
     try:
         factory, accept = Image.OPEN[self.format.plugin_id]
     except KeyError:
         raise RuntimeError("Format %s cannot read images." % self.format.name)
     self._fp = self._get_file()
     self._im = factory(self._fp, "")
     if hasattr(Image, "_decompression_bomb_check"):
         Image._decompression_bomb_check(self._im.size)
     pil_try_read(self._im)
     # Store args
     self._kwargs = dict(
         mode=pilmode, as_gray=as_gray, is_gray=_palette_is_grayscale(self._im)
     )
     # Set length
     self._length = 1
     if hasattr(self._im, "n_frames"):
         self._length = self._im.n_frames
Example #12
0
    def _open(self):
        header_size = i32(self.fp.read(4))
        version = i32(self.fp.read(4))
        if header_size < 20:
            raise SyntaxError("not a GIMP brush")
        if version not in (1, 2):
            raise SyntaxError("Unsupported GIMP brush version: %s" % version)

        width = i32(self.fp.read(4))
        height = i32(self.fp.read(4))
        color_depth = i32(self.fp.read(4))
        if width <= 0 or height <= 0:
            raise SyntaxError("not a GIMP brush")
        if color_depth not in (1, 4):
            raise SyntaxError("Unsupported GMP brush color depth: %s" % color_depth)

        if version == 1:
            comment_length = header_size-20
        else:
            comment_length = header_size-28
            magic_number = self.fp.read(4)
            if magic_number != b'GIMP':
                raise SyntaxError("not a GIMP brush, bad magic number")
            self.info['spacing'] = i32(self.fp.read(4))

        comment = self.fp.read(comment_length)[:-1]

        if color_depth == 1:
            self.mode = "L"
        else:
            self.mode = 'RGBA'

        self.size = width, height

        self.info["comment"] = comment

        # Image might not be small
        Image._decompression_bomb_check(self.size)

        # Data is an uncompressed block of w * h * bytes/pixel
        self._data_size = width * height * color_depth
Example #13
0
    def imopen(fp):
        # read header fields
        header = fp.read(32 + 24 + 32 + 12)
        size = i32(header, 32), i32(header, 36)
        offset = i32(header, 40)

        # load pixel data
        fp.seek(offset)

        Image._decompression_bomb_check(size)
        im = Image.frombytes("P", size, fp.read(size[0] * size[1]))
        im.putpalette(quake2palette)

        im.format = "WAL"
        im.format_description = "Quake2 Texture"

        # strings are null-terminated
        im.info["name"] = header[:32].split(b"\0", 1)[0]
        next_name = header[56:56 + 32].split(b"\0", 1)[0]
        if next_name:
            im.info["next_name"] = next_name

        return im
Example #14
0
    def imopen(fp):
        # read header fields
        header = fp.read(32+24+32+12)
        size = i32(header, 32), i32(header, 36)
        offset = i32(header, 40)

        # load pixel data
        fp.seek(offset)

        Image._decompression_bomb_check(size)
        im = Image.frombytes("P", size, fp.read(size[0] * size[1]))
        im.putpalette(quake2palette)

        im.format = "WAL"
        im.format_description = "Quake2 Texture"

        # strings are null-terminated
        im.info["name"] = header[:32].split(b"\0", 1)[0]
        next_name = header[56:56+32].split(b"\0", 1)[0]
        if next_name:
            im.info["next_name"] = next_name

        return im
    def frame(self, idx):
        """
        Get an image from frame idx
        """

        header = self.entry[idx]

        self.buf.seek(header['offset'])
        data = self.buf.read(8)
        self.buf.seek(header['offset'])

        if data[:8] == PngImagePlugin._MAGIC:
            # png frame
            im = PngImagePlugin.PngImageFile(self.buf)
        else:
            # XOR + AND mask bmp frame
            im = BmpImagePlugin.DibImageFile(self.buf)
            Image._decompression_bomb_check(im.size)

            # change tile dimension to only encompass XOR image
            im.size = (im.size[0], int(im.size[1] / 2))
            d, e, o, a = im.tile[0]
            im.tile[0] = d, (0, 0) + im.size, o, a

            # figure out where AND mask image starts
            mode = a[0]
            bpp = 8
            for k in BmpImagePlugin.BIT2MODE.keys():
                if mode == BmpImagePlugin.BIT2MODE[k][1]:
                    bpp = k
                    break

            if 32 == bpp:
                # 32-bit color depth icon image allows semitransparent areas
                # PIL's DIB format ignores transparency bits, recover them.
                # The DIB is packed in BGRX byte order where X is the alpha
                # channel.

                # Back up to start of bmp data
                self.buf.seek(o)
                # extract every 4th byte (eg. 3,7,11,15,...)
                alpha_bytes = self.buf.read(im.size[0] * im.size[1] * 4)[3::4]

                # convert to an 8bpp grayscale image
                mask = Image.frombuffer(
                    'L',  # 8bpp
                    im.size,  # (w, h)
                    alpha_bytes,  # source chars
                    'raw',  # raw decoder
                    ('L', 0, -1)  # 8bpp inverted, unpadded, reversed
                )
            else:
                # get AND image from end of bitmap
                w = im.size[0]
                if (w % 32) > 0:
                    # bitmap row data is aligned to word boundaries
                    w += 32 - (im.size[0] % 32)

                # the total mask data is
                # padded row size * height / bits per char

                and_mask_offset = o + int(im.size[0] * im.size[1] *
                                          (bpp / 8.0))
                total_bytes = int((w * im.size[1]) / 8)

                self.buf.seek(and_mask_offset)
                maskData = self.buf.read(total_bytes)

                # convert raw data to image
                mask = Image.frombuffer(
                    '1',  # 1 bpp
                    im.size,  # (w, h)
                    maskData,  # source chars
                    'raw',  # raw decoder
                    ('1;I', int(w / 8), -1)  # 1bpp inverted, padded, reversed
                )

                # now we have two images, im is XOR image and mask is AND image

            # apply mask image as alpha channel
            im = im.convert('RGBA')
            im.putalpha(mask)

        return im
Example #16
0
    def _seek(self, frame):

        if frame == 0:
            # rewind
            self.__offset = 0
            self.dispose = None
            self.dispose_extent = [0, 0, 0, 0]  # x0, y0, x1, y1
            self.__frame = -1
            self.__fp.seek(self.__rewind)
            self._prev_im = None
            self.disposal_method = 0
        else:
            # ensure that the previous frame was loaded
            if not self.im:
                self.load()

        if frame != self.__frame + 1:
            raise ValueError("cannot seek to frame %d" % frame)
        self.__frame = frame

        self.tile = []

        self.fp = self.__fp
        if self.__offset:
            # backup to last frame
            self.fp.seek(self.__offset)
            while self.data():
                pass
            self.__offset = 0

        if self.dispose:
            self.im.paste(self.dispose, self.dispose_extent)

        from copy import copy
        self.palette = copy(self.global_palette)

        while True:

            s = self.fp.read(1)
            if not s or s == b";":
                break

            elif s == b"!":
                #
                # extensions
                #
                s = self.fp.read(1)
                block = self.data()
                if i8(s) == 249:
                    #
                    # graphic control extension
                    #
                    flags = i8(block[0])
                    if flags & 1:
                        self.info["transparency"] = i8(block[3])
                    self.info["duration"] = i16(block[1:3]) * 10

                    # disposal method - find the value of bits 4 - 6
                    dispose_bits = 0b00011100 & flags
                    dispose_bits = dispose_bits >> 2
                    if dispose_bits:
                        # only set the dispose if it is not
                        # unspecified. I'm not sure if this is
                        # correct, but it seems to prevent the last
                        # frame from looking odd for some animations
                        self.disposal_method = dispose_bits
                elif i8(s) == 255:
                    #
                    # application extension
                    #
                    self.info["extension"] = block, self.fp.tell()
                    if block[:11] == b"NETSCAPE2.0":
                        block = self.data()
                        if len(block) >= 3 and i8(block[0]) == 1:
                            self.info["loop"] = i16(block[1:3])
                while self.data():
                    pass

            elif s == b",":
                #
                # local image
                #
                s = self.fp.read(9)

                # extent
                x0, y0 = i16(s[0:]), i16(s[2:])
                x1, y1 = x0 + i16(s[4:]), y0 + i16(s[6:])
                self.dispose_extent = x0, y0, x1, y1
                flags = i8(s[8])

                interlace = (flags & 64) != 0

                if flags & 128:
                    bits = (flags & 7) + 1
                    self.palette =\
                        ImagePalette.raw("RGB", self.fp.read(3 << bits))

                # image data
                bits = i8(self.fp.read(1))
                self.__offset = self.fp.tell()
                self.tile = [("gif", (x0, y0, x1, y1), self.__offset,
                              (bits, interlace))]
                break

            else:
                pass
                # raise IOError, "illegal GIF tag `%x`" % i8(s)

        try:
            if self.disposal_method < 2:
                # do not dispose or none specified
                self.dispose = None
            elif self.disposal_method == 2:
                # replace with background colour
                Image._decompression_bomb_check(self.size)
                self.dispose = Image.core.fill("P", self.size,
                                               self.info["background"])
            else:
                # replace with previous contents
                if self.im:
                    self.dispose = self.im.copy()

            # only dispose the extent in this frame
            if self.dispose:
                self.dispose = self.dispose.crop(self.dispose_extent)
        except (AttributeError, KeyError):
            pass

        if not self.tile:
            # self.__fp = None
            raise EOFError

        self.mode = "L"
        if self.palette:
            self.mode = "P"