Example #1
0
def _save(im, fp, tile, bufsize=0):
    """Helper to save image based on tile list

    :param im: Image object.
    :param fp: File object.
    :param tile: Tile list.
    :param bufsize: Optional buffer size
    """

    im.load()
    if not hasattr(im, "encoderconfig"):
        im.encoderconfig = ()
    tile.sort(key=_tilesort)
    # FIXME: make MAXBLOCK a configuration parameter
    # It would be great if we could have the encoder specify what it needs
    # But, it would need at least the image size in most cases. RawEncode is
    # a tricky case.
    bufsize = max(MAXBLOCK, bufsize, im.size[0] * 4)  # see RawEncode.c
    if fp == sys.stdout:
        fp.flush()
        return
    try:
        fh = fp.fileno()
        fp.flush()
    except (AttributeError, io.UnsupportedOperation):
        # compress to Python file-compatible object
        for e, b, o, a in tile:
            e = Image._getencoder(im.mode, e, a, im.encoderconfig)
            if o > 0:
                fp.seek(o, 0)
            e.setimage(im.im, b)
            if e.pushes_fd:
                e.setfd(fp)
                l, s = e.encode_to_pyfd()
            else:
                while True:
                    l, s, d = e.encode(bufsize)
                    fp.write(d)
                    if s:
                        break
            if s < 0:
                raise IOError("encoder error %d when writing image file" % s)
            e.cleanup()
    else:
        # slight speedup: compress to real file object
        for e, b, o, a in tile:
            e = Image._getencoder(im.mode, e, a, im.encoderconfig)
            if o > 0:
                fp.seek(o, 0)
            e.setimage(im.im, b)
            if e.pushes_fd:
                e.setfd(fp)
                l, s = e.encode_to_pyfd()
            else:
                s = e.encode_to_file(fh, bufsize)
            if s < 0:
                raise IOError("encoder error %d when writing image file" % s)
            e.cleanup()
    if hasattr(fp, "flush"):
        fp.flush()
Example #2
0
def _save(im, fp, tile, bufsize=0):
    """Helper to save image based on tile list

    :param im: Image object.
    :param fp: File object.
    :param tile: Tile list.
    :param bufsize: Optional buffer size
    """

    im.load()
    if not hasattr(im, "encoderconfig"):
        im.encoderconfig = ()
    tile.sort(key=_tilesort)
    # FIXME: make MAXBLOCK a configuration parameter
    # It would be great if we could have the encoder specify what it needs
    # But, it would need at least the image size in most cases. RawEncode is
    # a tricky case.
    bufsize = max(MAXBLOCK, bufsize, im.size[0] * 4)  # see RawEncode.c
    if fp == sys.stdout:
        fp.flush()
        return
    try:
        fh = fp.fileno()
        fp.flush()
    except (AttributeError, io.UnsupportedOperation):
        # compress to Python file-compatible object
        for e, b, o, a in tile:
            e = Image._getencoder(im.mode, e, a, im.encoderconfig)
            if o > 0:
                fp.seek(o, 0)
            e.setimage(im.im, b)
            if e.pushes_fd:
                e.setfd(fp)
                l, s = e.encode_to_pyfd()
            else:
                while True:
                    l, s, d = e.encode(bufsize)
                    fp.write(d)
                    if s:
                        break
            if s < 0:
                raise IOError("encoder error %d when writing image file" % s)
            e.cleanup()
    else:
        # slight speedup: compress to real file object
        for e, b, o, a in tile:
            e = Image._getencoder(im.mode, e, a, im.encoderconfig)
            if o > 0:
                fp.seek(o, 0)
            e.setimage(im.im, b)
            if e.pushes_fd:
                e.setfd(fp)
                l, s = e.encode_to_pyfd()
            else:
                s = e.encode_to_file(fh, bufsize)
            if s < 0:
                raise IOError("encoder error %d when writing image file" % s)
            e.cleanup()
    if hasattr(fp, "flush"):
        fp.flush()
Example #3
0
def _to_bytes_generator(pil_image, min_buffer_size=65536):
    """
    An iterator version of the :func:`PIL.Image.tobytes` method
    .. note:: The PIL implementation stores the data in a separate array, doubling the memory usage.
    This is implemented as a generator to be a more efficient way of processing the data.

    :param pil_image: :class:`PIL.Image` instance
    :param min_buffer_size:
    """
    pil_image.load()
    e = Image._getencoder(pil_image.mode, 'raw', pil_image.mode)
    e.setimage(pil_image.im)

    # This encoder fails if the buffer is not large enough to hold one full line of data - see RawEncode.c
    buffer_size = max(min_buffer_size, pil_image.size[0] * 4)

    # signal is negative for errors, 1 for finished, and 0 otherwise
    length, signal, data = e.encode(buffer_size)
    while signal == 0:
        yield data
        length, signal, data = e.encode(buffer_size)
    if signal > 0:
        yield data
    else:
        raise RuntimeError("encoder error {0} in tobytes when reading image pixel data".format(signal))
Example #4
0
    def test_encode_registry(self):

        Image.register_encoder("MOCK", mock_encode)
        self.assertIn("MOCK", Image.ENCODERS)

        enc = Image._getencoder("RGB", "MOCK", ("args",), extra=("extra",))

        self.assertIsInstance(enc, MockEncoder)
        self.assertEqual(enc.args, ("RGB", "args", "extra"))
Example #5
0
    def test_encode_registry(self):

        Image.register_encoder('MOCK', mock_encode)
        self.assertIn('MOCK', Image.ENCODERS)

        enc = Image._getencoder('RGB', 'MOCK', ('args', ), extra=('extra', ))

        self.assertIsInstance(enc, MockEncoder)
        self.assertEqual(enc.args, ('RGB', 'args', 'extra'))
    def test_encode_registry(self):

        Image.register_encoder("MOCK", mock_encode)
        assert "MOCK" in Image.ENCODERS

        enc = Image._getencoder("RGB", "MOCK", ("args", ), extra=("extra", ))

        assert isinstance(enc, MockEncoder)
        assert enc.args == ("RGB", "args", "extra")
Example #7
0
    def test_encode_registry(self):

        Image.register_encoder('MOCK', mock_encode)
        self.assertIn('MOCK', Image.ENCODERS)

        enc = Image._getencoder('RGB', 'MOCK', ('args',), extra=('extra',))

        self.assertIsInstance(enc, MockEncoder)
        self.assertEqual(enc.args, ('RGB', 'args', 'extra'))
Example #8
0
def _save(im, fp, tile):
    "Helper to save image based on tile list"

    im.load()
    if not hasattr(im, "encoderconfig"):
        im.encoderconfig = ()
    tile.sort(key=_tilesort)
    # FIXME: make MAXBLOCK a configuration parameter
    bufsize = max(MAXBLOCK, im.size[0] * 4) # see RawEncode.c
    try:
        fh = fp.fileno()
        fp.flush()
    except (AttributeError, io.UnsupportedOperation):
        # compress to Python file-compatible object
        for e, b, o, a in tile:
            e = Image._getencoder(im.mode, e, a, im.encoderconfig)
            if o > 0:
                fp.seek(o, 0)
            e.setimage(im.im, b)
            while True:
                l, s, d = e.encode(bufsize)
                fp.write(d)
                if s:
                    break
            if s < 0:
                raise IOError("encoder error %d when writing image file" % s)
    else:
        # slight speedup: compress to real file object
        for e, b, o, a in tile:
            e = Image._getencoder(im.mode, e, a, im.encoderconfig)
            if o > 0:
                fp.seek(o, 0)
            e.setimage(im.im, b)
            s = e.encode_to_file(fh, bufsize)
            if s < 0:
                raise IOError("encoder error %d when writing image file" % s)
    try:
        fp.flush()
    except: pass
Example #9
0
def PilImageToNp(im: Image.Image):
    im.load()

    encoder = Image._getencoder(im.mode, 'raw', im.mode)
    encoder.setimage(im.im)

    shape, typestr = Image._conv_type_shape(im)
    data = np.empty(shape, dtype=np.dtype(typestr))
    mem = data.data.cast('B', (data.data.nbytes,))

    bufsize, s, offset = 65536, 0, 0
    while not s:
        _, s, d = encoder.encode(bufsize)
        mem[offset:offset + len(d)] = d
        offset += len(d)
    if s < 0:
        raise GraphicsException(f"Encoder error: {s}")
		
    return data
Example #10
0
def _save(im, fp, filename):

    try:
        rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as TIFF" % im.mode)

    ifd = ImageFileDirectory(prefix)

    compression = im.info.get('compression','raw')
    libtiff = compression in ["tiff_ccitt", "group3",
                              "group4", "tiff_raw_16"]

    # -- multi-page -- skip TIFF header on subsequent pages
    if not libtiff and fp.tell() == 0:
        # tiff header (write via IFD to get everything right)
        # PIL always starts the first IFD at offset 8
        fp.write(ifd.prefix + ifd.o16(42) + ifd.o32(8))

    ifd[IMAGEWIDTH] = im.size[0]
    ifd[IMAGELENGTH] = im.size[1]

    # additions written by Greg Couch, [email protected]
    # inspired by image-sig posting from Kevin Cazabon, [email protected]
    if hasattr(im, 'tag'):
        # preserve tags from original TIFF image file
        for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION):
            if key in im.tag.tagdata:
                ifd[key] = im.tag.tagdata.get(key)
        # preserve some more tags from original TIFF image file
        # -- 2008-06-06 Florian Hoech
        ifd.tagtype = im.tag.tagtype
        for key in (IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, XMP):
            if key in im.tag:
                ifd[key] = im.tag[key]
        # preserve ICC profile (should also work when saving other formats
        # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
        if "icc_profile" in im.info:
            ifd[ICCPROFILE] = im.info["icc_profile"]
    if "description" in im.encoderinfo:
        ifd[IMAGEDESCRIPTION] = im.encoderinfo["description"]
    if "resolution" in im.encoderinfo:
        ifd[X_RESOLUTION] = ifd[Y_RESOLUTION] \
                                = _cvt_res(im.encoderinfo["resolution"])
    if "x resolution" in im.encoderinfo:
        ifd[X_RESOLUTION] = _cvt_res(im.encoderinfo["x resolution"])
    if "y resolution" in im.encoderinfo:
        ifd[Y_RESOLUTION] = _cvt_res(im.encoderinfo["y resolution"])
    if "resolution unit" in im.encoderinfo:
        unit = im.encoderinfo["resolution unit"]
        if unit == "inch":
            ifd[RESOLUTION_UNIT] = 2
        elif unit == "cm" or unit == "centimeter":
            ifd[RESOLUTION_UNIT] = 3
        else:
            ifd[RESOLUTION_UNIT] = 1
    if "software" in im.encoderinfo:
        ifd[SOFTWARE] = im.encoderinfo["software"]
    if "date time" in im.encoderinfo:
        ifd[DATE_TIME] = im.encoderinfo["date time"]
    if "artist" in im.encoderinfo:
        ifd[ARTIST] = im.encoderinfo["artist"]
    if "copyright" in im.encoderinfo:
        ifd[COPYRIGHT] = im.encoderinfo["copyright"]

    dpi = im.encoderinfo.get("dpi")
    if dpi:
        ifd[RESOLUTION_UNIT] = 2
        ifd[X_RESOLUTION] = _cvt_res(dpi[0])
        ifd[Y_RESOLUTION] = _cvt_res(dpi[1])

    if bits != (1,):
        ifd[BITSPERSAMPLE] = bits
        if len(bits) != 1:
            ifd[SAMPLESPERPIXEL] = len(bits)
    if extra is not None:
        ifd[EXTRASAMPLES] = extra
    if format != 1:
        ifd[SAMPLEFORMAT] = format

    ifd[PHOTOMETRIC_INTERPRETATION] = photo

    if im.mode == "P":
        lut = im.im.getpalette("RGB", "RGB;L")
        ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)

    # data orientation
    stride = len(bits) * ((im.size[0]*bits[0]+7)//8)
    ifd[ROWSPERSTRIP] = im.size[1]
    ifd[STRIPBYTECOUNTS] = stride * im.size[1]
    ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
    ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression,1) # no compression by default

    if libtiff:
        if Image.DEBUG:
            print ("Saving using libtiff encoder")
            print (ifd.items())
        _fp = 0
        if hasattr(fp, "fileno"):
            fp.seek(0)
            _fp = os.dup(fp.fileno())

        blocklist =  [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP, ICCPROFILE] # ICC Profile crashes.
        atts = dict([(k,v) for (k,(v,)) in ifd.items() if k not in blocklist])
        try:
            # pull in more bits from the original file, e.g x,y resolution
            # so that we can save(load('')) == original file.
            for k,v in im.ifd.items():
                if k not in atts and k not in blocklist:
                    if type(v[0]) == tuple and len(v) > 1:
                       # A tuple of more than one rational tuples
                        # flatten to floats, following tiffcp.c->cpTag->TIFF_RATIONAL
                        atts[k] = [float(elt[0])/float(elt[1]) for elt in v]
                        continue
                    if type(v[0]) == tuple and len(v) == 1:
                       # A tuple of one rational tuples
                        # flatten to floats, following tiffcp.c->cpTag->TIFF_RATIONAL
                        atts[k] = float(v[0][0])/float(v[0][1])
                        continue
                    if type(v) == tuple and len(v) == 1:
                        # int or similar
                        atts[k] = v[0]
                        continue
                    if type(v) == str:
                        atts[k] = v
                        continue

        except:
            # if we don't have an ifd here, just punt.
            pass
        if Image.DEBUG:
            print (atts)
        a = (rawmode, compression, _fp, filename, atts)
        e = Image._getencoder(im.mode, compression, a, im.encoderconfig)
        e.setimage(im.im, (0,0)+im.size)
        while 1:
            l, s, d = e.encode(16*1024) # undone, change to self.decodermaxblock
            if not _fp:
                fp.write(d)
            if s:
                break
        if s < 0:
            raise IOError("encoder error %d when writing image file" % s)

    else:
        offset = ifd.save(fp)

        ImageFile._save(im, fp, [
            ("raw", (0,0)+im.size, offset, (rawmode, stride, 1))
            ])


    # -- helper for multi-page save --
    if "_debug_multipage" in im.encoderinfo:
        #just to access o32 and o16 (using correct byte order)
        im._debug_multipage = ifd
Example #11
0
def _save(im, fp, filename):

    try:
        rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as TIFF" % im.mode)

    ifd = ImageFileDirectory(prefix)

    compression = im.encoderinfo.get('compression', im.info.get('compression',
                                     'raw'))

    libtiff = WRITE_LIBTIFF or compression != 'raw'

    # required for color libtiff images
    ifd[PLANAR_CONFIGURATION] = getattr(im, '_planar_configuration', 1)

    # -- multi-page -- skip TIFF header on subsequent pages
    if not libtiff and fp.tell() == 0:
        # tiff header (write via IFD to get everything right)
        # PIL always starts the first IFD at offset 8
        fp.write(ifd.prefix + ifd.o16(42) + ifd.o32(8))

    ifd[IMAGEWIDTH] = im.size[0]
    ifd[IMAGELENGTH] = im.size[1]

    # write any arbitrary tags passed in as an ImageFileDirectory
    info = im.encoderinfo.get("tiffinfo", {})
    if Image.DEBUG:
        print("Tiffinfo Keys: %s" % info.keys)
    keys = list(info.keys())
    for key in keys:
        ifd[key] = info.get(key)
        try:
            ifd.tagtype[key] = info.tagtype[key]
        except:
            pass  # might not be an IFD, Might not have populated type

    # additions written by Greg Couch, [email protected]
    # inspired by image-sig posting from Kevin Cazabon, [email protected]
    if hasattr(im, 'tag'):
        # preserve tags from original TIFF image file
        for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION,
                    IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, XMP):
            if key in im.tag:
                ifd[key] = im.tag[key]
            ifd.tagtype[key] = im.tag.tagtype.get(key, None)

        # preserve ICC profile (should also work when saving other formats
        # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
        if "icc_profile" in im.info:
            ifd[ICCPROFILE] = im.info["icc_profile"]

    for key, name, cvt in [
            (IMAGEDESCRIPTION, "description", lambda x: x),
            (X_RESOLUTION, "resolution", _cvt_res),
            (Y_RESOLUTION, "resolution", _cvt_res),
            (X_RESOLUTION, "x_resolution", _cvt_res),
            (Y_RESOLUTION, "y_resolution", _cvt_res),
            (RESOLUTION_UNIT, "resolution_unit",
             lambda x: {"inch": 2, "cm": 3, "centimeter": 3}.get(x, 1)),
            (SOFTWARE, "software", lambda x: x),
            (DATE_TIME, "date_time", lambda x: x),
            (ARTIST, "artist", lambda x: x),
            (COPYRIGHT, "copyright", lambda x: x)]:
        name_with_spaces = name.replace("_", " ")
        if "_" in name and name_with_spaces in im.encoderinfo:
            warnings.warn("%r is deprecated; use %r instead" %
                          (name_with_spaces, name), DeprecationWarning)
            ifd[key] = cvt(im.encoderinfo[name.replace("_", " ")])
        if name in im.encoderinfo:
            ifd[key] = cvt(im.encoderinfo[name])

    dpi = im.encoderinfo.get("dpi")
    if dpi:
        ifd[RESOLUTION_UNIT] = 2
        ifd[X_RESOLUTION] = _cvt_res(dpi[0])
        ifd[Y_RESOLUTION] = _cvt_res(dpi[1])

    if bits != (1,):
        ifd[BITSPERSAMPLE] = bits
        if len(bits) != 1:
            ifd[SAMPLESPERPIXEL] = len(bits)
    if extra is not None:
        ifd[EXTRASAMPLES] = extra
    if format != 1:
        ifd[SAMPLEFORMAT] = format

    ifd[PHOTOMETRIC_INTERPRETATION] = photo

    if im.mode == "P":
        lut = im.im.getpalette("RGB", "RGB;L")
        ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)

    # data orientation
    stride = len(bits) * ((im.size[0]*bits[0]+7)//8)
    ifd[ROWSPERSTRIP] = im.size[1]
    ifd[STRIPBYTECOUNTS] = stride * im.size[1]
    ifd[STRIPOFFSETS] = 0  # this is adjusted by IFD writer
    # no compression by default:
    ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)

    if libtiff:
        if Image.DEBUG:
            print("Saving using libtiff encoder")
            print(ifd.items())
        _fp = 0
        if hasattr(fp, "fileno"):
            try:
                fp.seek(0)
                _fp = os.dup(fp.fileno())
            except io.UnsupportedOperation:
                pass

        # ICC Profile crashes.
        blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP, ICCPROFILE]
        atts = {}
        # bits per sample is a single short in the tiff directory, not a list.
        atts[BITSPERSAMPLE] = bits[0]
        # Merge the ones that we have with (optional) more bits from
        # the original file, e.g x,y resolution so that we can
        # save(load('')) == original file.
        for k, v in itertools.chain(ifd.items(),
                                    getattr(im, 'ifd', {}).items()):
            if k not in atts and k not in blocklist:
                if type(v[0]) == tuple and len(v) > 1:
                    # A tuple of more than one rational tuples
                    # flatten to floats,
                    # following tiffcp.c->cpTag->TIFF_RATIONAL
                    atts[k] = [float(elt[0])/float(elt[1]) for elt in v]
                    continue
                if type(v[0]) == tuple and len(v) == 1:
                    # A tuple of one rational tuples
                    # flatten to floats,
                    # following tiffcp.c->cpTag->TIFF_RATIONAL
                    atts[k] = float(v[0][0])/float(v[0][1])
                    continue
                if (type(v) == tuple and
                        (len(v) > 2 or
                            (len(v) == 2 and v[1] == 0))):
                    # List of ints?
                    # Avoid divide by zero in next if-clause
                    if type(v[0]) in (int, float):
                        atts[k] = list(v)
                    continue
                if type(v) == tuple and len(v) == 2:
                    # one rational tuple
                    # flatten to float,
                    # following tiffcp.c->cpTag->TIFF_RATIONAL
                    atts[k] = float(v[0])/float(v[1])
                    continue
                if type(v) == tuple and len(v) == 1:
                    v = v[0]
                    # drop through
                if isStringType(v):
                    atts[k] = bytes(v.encode('ascii', 'replace')) + b"\0"
                    continue
                else:
                    # int or similar
                    atts[k] = v

        if Image.DEBUG:
            print(atts)

        # libtiff always expects the bytes in native order.
        # we're storing image byte order. So, if the rawmode
        # contains I;16, we need to convert from native to image
        # byte order.
        if im.mode in ('I;16B', 'I;16'):
            rawmode = 'I;16N'

        a = (rawmode, compression, _fp, filename, atts)
        # print (im.mode, compression, a, im.encoderconfig)
        e = Image._getencoder(im.mode, 'libtiff', a, im.encoderconfig)
        e.setimage(im.im, (0, 0)+im.size)
        while True:
            # undone, change to self.decodermaxblock:
            l, s, d = e.encode(16*1024)
            if not _fp:
                fp.write(d)
            if s:
                break
        if s < 0:
            raise IOError("encoder error %d when writing image file" % s)

    else:
        offset = ifd.save(fp)

        ImageFile._save(im, fp, [
            ("raw", (0, 0)+im.size, offset, (rawmode, stride, 1))
            ])

    # -- helper for multi-page save --
    if "_debug_multipage" in im.encoderinfo:
        # just to access o32 and o16 (using correct byte order)
        im._debug_multipage = ifd
Example #12
0
 def test_encode_registry_fail(self):
     with pytest.raises(OSError):
         Image._getencoder("RGB",
                           "DoesNotExist", ("args", ),
                           extra=("extra", ))
Example #13
0
def _save(im, fp, filename):

    try:
        rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as TIFF" % im.mode)

    ifd = ImageFileDirectory_v2(prefix=prefix)

    compression = im.encoderinfo.get('compression',
                                     im.info.get('compression', 'raw'))

    libtiff = WRITE_LIBTIFF or compression != 'raw'

    # required for color libtiff images
    ifd[PLANAR_CONFIGURATION] = getattr(im, '_planar_configuration', 1)

    ifd[IMAGEWIDTH] = im.size[0]
    ifd[IMAGELENGTH] = im.size[1]

    # write any arbitrary tags passed in as an ImageFileDirectory
    info = im.encoderinfo.get("tiffinfo", {})
    if DEBUG:
        print("Tiffinfo Keys: %s" % list(info))
    if isinstance(info, ImageFileDirectory_v1):
        info = info.to_v2()
    for key in info:
        ifd[key] = info.get(key)
        try:
            ifd.tagtype[key] = info.tagtype[key]
        except:
            pass  # might not be an IFD, Might not have populated type

    # additions written by Greg Couch, [email protected]
    # inspired by image-sig posting from Kevin Cazabon, [email protected]
    if hasattr(im, 'tag_v2'):
        # preserve tags from original TIFF image file
        for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION,
                    IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, XMP):
            if key in im.tag_v2:
                ifd[key] = im.tag_v2[key]
            ifd.tagtype[key] = im.tag_v2.tagtype.get(key, None)

        # preserve ICC profile (should also work when saving other formats
        # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
        if "icc_profile" in im.info:
            ifd[ICCPROFILE] = im.info["icc_profile"]

    for key, name in [(IMAGEDESCRIPTION, "description"),
                      (X_RESOLUTION, "resolution"),
                      (Y_RESOLUTION, "resolution"),
                      (X_RESOLUTION, "x_resolution"),
                      (Y_RESOLUTION, "y_resolution"),
                      (RESOLUTION_UNIT, "resolution_unit"),
                      (SOFTWARE, "software"),
                      (DATE_TIME, "date_time"),
                      (ARTIST, "artist"),
                      (COPYRIGHT, "copyright")]:
        name_with_spaces = name.replace("_", " ")
        if "_" in name and name_with_spaces in im.encoderinfo:
            warnings.warn("%r is deprecated; use %r instead" %
                          (name_with_spaces, name), DeprecationWarning)
            ifd[key] = im.encoderinfo[name.replace("_", " ")]
        if name in im.encoderinfo:
            ifd[key] = im.encoderinfo[name]

    dpi = im.encoderinfo.get("dpi")
    if dpi:
        ifd[RESOLUTION_UNIT] = 2
        ifd[X_RESOLUTION] = dpi[0]
        ifd[Y_RESOLUTION] = dpi[1]

    if bits != (1,):
        ifd[BITSPERSAMPLE] = bits
        if len(bits) != 1:
            ifd[SAMPLESPERPIXEL] = len(bits)
    if extra is not None:
        ifd[EXTRASAMPLES] = extra
    if format != 1:
        ifd[SAMPLEFORMAT] = format

    ifd[PHOTOMETRIC_INTERPRETATION] = photo

    if im.mode == "P":
        lut = im.im.getpalette("RGB", "RGB;L")
        ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)

    # data orientation
    stride = len(bits) * ((im.size[0]*bits[0]+7)//8)
    ifd[ROWSPERSTRIP] = im.size[1]
    ifd[STRIPBYTECOUNTS] = stride * im.size[1]
    ifd[STRIPOFFSETS] = 0  # this is adjusted by IFD writer
    # no compression by default:
    ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)

    if libtiff:
        if DEBUG:
            print("Saving using libtiff encoder")
            print("Items: %s" % sorted(ifd.items()))
        _fp = 0
        if hasattr(fp, "fileno"):
            try:
                fp.seek(0)
                _fp = os.dup(fp.fileno())
            except io.UnsupportedOperation:
                pass

        # STRIPOFFSETS and STRIPBYTECOUNTS are added by the library
        # based on the data in the strip.
        # ICCPROFILE crashes.
        blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ICCPROFILE]
        atts = {}
        # bits per sample is a single short in the tiff directory, not a list.
        atts[BITSPERSAMPLE] = bits[0]
        # Merge the ones that we have with (optional) more bits from
        # the original file, e.g x,y resolution so that we can
        # save(load('')) == original file.
        legacy_ifd = {}
        if hasattr(im, 'tag'):
            legacy_ifd = im.tag.to_v2()
        for k, v in itertools.chain(ifd.items(),
                                    getattr(im, 'tag_v2', {}).items(),
                                    legacy_ifd.items()):
            if k not in atts and k not in blocklist:
                if isinstance(v, unicode if bytes is str else str):
                    atts[k] = v.encode('ascii', 'replace') + b"\0"
                else:
                    atts[k] = v

        if DEBUG:
            print("Converted items: %s" % sorted(atts.items()))

        # libtiff always expects the bytes in native order.
        # we're storing image byte order. So, if the rawmode
        # contains I;16, we need to convert from native to image
        # byte order.
        if im.mode in ('I;16B', 'I;16'):
            rawmode = 'I;16N'

        a = (rawmode, compression, _fp, filename, atts)
        # print(im.mode, compression, a, im.encoderconfig)
        e = Image._getencoder(im.mode, 'libtiff', a, im.encoderconfig)
        e.setimage(im.im, (0, 0)+im.size)
        while True:
            # undone, change to self.decodermaxblock:
            l, s, d = e.encode(16*1024)
            if not _fp:
                fp.write(d)
            if s:
                break
        if s < 0:
            raise IOError("encoder error %d when writing image file" % s)

    else:
        offset = ifd.save(fp)

        ImageFile._save(im, fp, [
            ("raw", (0, 0)+im.size, offset, (rawmode, stride, 1))
            ])

    # -- helper for multi-page save --
    if "_debug_multipage" in im.encoderinfo:
        # just to access o32 and o16 (using correct byte order)
        im._debug_multipage = ifd
Example #14
0
if hasattr(img, '_getexif'):
    exifinfo = img._getexif()
    if None != exifinfo:
        for tag, value in exifinfo.items():
            decoded = TAGS.get(tag, tag)
            print decoded

filein = open("org.jpg","rb")
da = exifread.process_file(filein, debug=True)
f2 = open("org2.jpg","rb")
da2 = exifread.process_file(f2)
filein.close()
f2.close()
exif_dict2 = piexif.load("org.jpg")
im = Image.open("org.jpg")
exif_dict = piexif.load(im.info["exif"])
w,h = im.size
print exif_dict["0th"]
exif_dict["0th"][piexif.ImageIFD.XResolution] = (w,1)
exif_dict["0th"][piexif.ImageIFD.YResolution] = (h,1)
exif_dict["Exif"][piexif.ExifIFD.UserComment] = "wyscsddgdfg"
#exif_dict.update({"Image":{305:"wyscsddgdfg"}})
exif_dict["0th"][piexif.ImageIFD.Software] = "1212122wyscsddgdfg"
exif_bytes = piexif.dump(exif_dict)
im.app.update({"COM":"ABCDEFEG"})
im.applist.append(('COM','ADBCDEFG'))
encd = Image._getencoder()
im.save("oorg.jpg","jpeg",exif=exif_bytes,app=im.app, applist=im.applist,encoderinfo=im.encoderinfo)
im2 = Image.open("oorg.jpg")
exif_dict21 = piexif.load("oorg.jpg")
print da
Example #15
0
 def test_encode_registry_fail(self):
     self.assertRaises(
         IOError, lambda: Image._getencoder(
             'RGB', 'DoesNotExist', ('args', ), extra=('extra', )))
Example #16
0
def _save(im, fp, filename):

    try:
        rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as TIFF" % im.mode)

    ifd = ImageFileDirectory(prefix)

    compression = im.info.get('compression', 'raw')
    libtiff = compression in [
        "tiff_ccitt", "group3", "group4", "tiff_jpeg", "tiff_adobe_deflate",
        "tiff_thunderscan", "tiff_deflate", "tiff_sgilog", "tiff_sgilog24",
        "tiff_raw_16"
    ]

    # -- multi-page -- skip TIFF header on subsequent pages
    if not libtiff and fp.tell() == 0:
        # tiff header (write via IFD to get everything right)
        # PIL always starts the first IFD at offset 8
        fp.write(ifd.prefix + ifd.o16(42) + ifd.o32(8))

    ifd[IMAGEWIDTH] = im.size[0]
    ifd[IMAGELENGTH] = im.size[1]

    # additions written by Greg Couch, [email protected]
    # inspired by image-sig posting from Kevin Cazabon, [email protected]
    if hasattr(im, 'tag'):
        # preserve tags from original TIFF image file
        for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION):
            if key in im.tag.tagdata:
                ifd[key] = im.tag.tagdata.get(key)
        # preserve some more tags from original TIFF image file
        # -- 2008-06-06 Florian Hoech
        ifd.tagtype = im.tag.tagtype
        for key in (IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, XMP):
            if key in im.tag:
                ifd[key] = im.tag[key]
        # preserve ICC profile (should also work when saving other formats
        # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
        if "icc_profile" in im.info:
            ifd[ICCPROFILE] = im.info["icc_profile"]
    if "description" in im.encoderinfo:
        ifd[IMAGEDESCRIPTION] = im.encoderinfo["description"]
    if "resolution" in im.encoderinfo:
        ifd[X_RESOLUTION] = ifd[Y_RESOLUTION] \
                                = _cvt_res(im.encoderinfo["resolution"])
    if "x resolution" in im.encoderinfo:
        ifd[X_RESOLUTION] = _cvt_res(im.encoderinfo["x resolution"])
    if "y resolution" in im.encoderinfo:
        ifd[Y_RESOLUTION] = _cvt_res(im.encoderinfo["y resolution"])
    if "resolution unit" in im.encoderinfo:
        unit = im.encoderinfo["resolution unit"]
        if unit == "inch":
            ifd[RESOLUTION_UNIT] = 2
        elif unit == "cm" or unit == "centimeter":
            ifd[RESOLUTION_UNIT] = 3
        else:
            ifd[RESOLUTION_UNIT] = 1
    if "software" in im.encoderinfo:
        ifd[SOFTWARE] = im.encoderinfo["software"]
    if "date time" in im.encoderinfo:
        ifd[DATE_TIME] = im.encoderinfo["date time"]
    if "artist" in im.encoderinfo:
        ifd[ARTIST] = im.encoderinfo["artist"]
    if "copyright" in im.encoderinfo:
        ifd[COPYRIGHT] = im.encoderinfo["copyright"]

    dpi = im.encoderinfo.get("dpi")
    if dpi:
        ifd[RESOLUTION_UNIT] = 2
        ifd[X_RESOLUTION] = _cvt_res(dpi[0])
        ifd[Y_RESOLUTION] = _cvt_res(dpi[1])

    if bits != (1, ):
        ifd[BITSPERSAMPLE] = bits
        if len(bits) != 1:
            ifd[SAMPLESPERPIXEL] = len(bits)
    if extra is not None:
        ifd[EXTRASAMPLES] = extra
    if format != 1:
        ifd[SAMPLEFORMAT] = format

    ifd[PHOTOMETRIC_INTERPRETATION] = photo

    if im.mode == "P":
        lut = im.im.getpalette("RGB", "RGB;L")
        ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)

    # data orientation
    stride = len(bits) * ((im.size[0] * bits[0] + 7) // 8)
    ifd[ROWSPERSTRIP] = im.size[1]
    ifd[STRIPBYTECOUNTS] = stride * im.size[1]
    ifd[STRIPOFFSETS] = 0  # this is adjusted by IFD writer
    ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression,
                                                1)  # no compression by default

    if libtiff:
        if Image.DEBUG:
            print("Saving using libtiff encoder")
            print(ifd.items())
        _fp = 0
        if hasattr(fp, "fileno"):
            fp.seek(0)
            _fp = os.dup(fp.fileno())

        blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP,
                     ICCPROFILE]  # ICC Profile crashes.
        atts = dict([(k, v) for (k, (v, )) in ifd.items()
                     if k not in blocklist])
        try:
            # pull in more bits from the original file, e.g x,y resolution
            # so that we can save(load('')) == original file.
            for k, v in im.ifd.items():
                if k not in atts and k not in blocklist:
                    if type(v[0]) == tuple and len(v) > 1:
                        # A tuple of more than one rational tuples
                        # flatten to floats, following tiffcp.c->cpTag->TIFF_RATIONAL
                        atts[k] = [float(elt[0]) / float(elt[1]) for elt in v]
                        continue
                    if type(v[0]) == tuple and len(v) == 1:
                        # A tuple of one rational tuples
                        # flatten to floats, following tiffcp.c->cpTag->TIFF_RATIONAL
                        atts[k] = float(v[0][0]) / float(v[0][1])
                        continue
                    if type(v) == tuple and len(v) == 1:
                        # int or similar
                        atts[k] = v[0]
                        continue
                    if type(v) == str:
                        atts[k] = v
                        continue

        except:
            # if we don't have an ifd here, just punt.
            pass
        if Image.DEBUG:
            print(atts)
        a = (rawmode, compression, _fp, filename, atts)
        e = Image._getencoder(im.mode, compression, a, im.encoderconfig)
        e.setimage(im.im, (0, 0) + im.size)
        while 1:
            l, s, d = e.encode(16 *
                               1024)  # undone, change to self.decodermaxblock
            if not _fp:
                fp.write(d)
            if s:
                break
        if s < 0:
            raise IOError("encoder error %d when writing image file" % s)

    else:
        offset = ifd.save(fp)

        ImageFile._save(im, fp, [("raw", (0, 0) + im.size, offset,
                                  (rawmode, stride, 1))])

    # -- helper for multi-page save --
    if "_debug_multipage" in im.encoderinfo:
        #just to access o32 and o16 (using correct byte order)
        im._debug_multipage = ifd
Example #17
0
def merge_gif(fp, images, durations, loops=0):
    _im = images[0]
    _durations = [durations for im in images] if isinstance(durations, int) else durations

    _bits = 8
    _size = _im.size
    try:
        assert len(_durations) == len(images)
        for im in images:
            im.load()
            assert _size == im.size
    except AssertionError:
        raise

    # Header
    _h = [
        'GIF89a',
        o16(_size[0]),              # width
        o16(_size[1]),              # height
        chr(128 + (_bits - 1)),     # flags: palette + bits
        chr(0),                     # background
        chr(0),                     # reserved/aspect
    ]
    fp.write(''.join(_h))

    # Palette
    _mode = 'P'     # palette/grayscale (P/L)
    _colors = 256
    _palette = _im.im.getpalette('RGB')[:_colors * 3]
    fp.write(_palette)

    # Ext: application extension
    _loop = loops
    _ext = [
        '\x21\xFF\x0B',
        'NETSCAPE2.0',
        '\x03\x01',
        o16(_loop),
        '\x00',
    ]
    fp.write(''.join(_ext))

    # Images
    for idx, im in enumerate(images):
        # Ext: graphics control extension
        _cext = [
            '\x21\xF9\x04',
            '\x08',                 # flag: transparency: \x08 | \x09
            o16(_durations[idx]),   # druation
            '\x00',                 # transparency
            '\x00',
        ]
        fp.write(''.join(_cext))

        # Image
        _h = [
            '\x2C',                             # ',' sperator
            o16(0), o16(0),                     # offset
            o16(im.size[0]), o16(im.size[1]),   # size
            chr(0),                             # flag: no local palette
            chr(_bits),                         # color bits
        ]
        fp.write(''.join(_h))

        _encoder = Image._getencoder(im.mode, "gif", im.mode)
        _encoder.setimage(im.im, (0, 0) + im.size)
        _bufsize = 4096
        while True:
            l, s, d = _encoder.encode(_bufsize)
            fp.write(d)
            if s: break
        if s < 0:
            raise IOError("encoder error %d when writing image file" % s)
        fp.write('\x00')

    # End
    fp.write('\x3b')    # ';' trailer
    fp.flush()
Example #18
0
def _save(im, fp, filename):

    try:
        rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as TIFF" % im.mode)

    ifd = ImageFileDirectory_v2(prefix=prefix)

    compression = im.encoderinfo.get('compression',
                                     im.info.get('compression', 'raw'))

    libtiff = WRITE_LIBTIFF or compression != 'raw'

    # required for color libtiff images
    ifd[PLANAR_CONFIGURATION] = getattr(im, '_planar_configuration', 1)

    ifd[IMAGEWIDTH] = im.size[0]
    ifd[IMAGELENGTH] = im.size[1]

    # write any arbitrary tags passed in as an ImageFileDirectory
    info = im.encoderinfo.get("tiffinfo", {})
    if DEBUG:
        print("Tiffinfo Keys: %s" % list(info))
    if isinstance(info, ImageFileDirectory_v1):
        info = info.to_v2()
    for key in info:
        ifd[key] = info.get(key)
        try:
            ifd.tagtype[key] = info.tagtype[key]
        except:
            pass  # might not be an IFD, Might not have populated type

    # additions written by Greg Couch, [email protected]
    # inspired by image-sig posting from Kevin Cazabon, [email protected]
    if hasattr(im, 'tag_v2'):
        # preserve tags from original TIFF image file
        for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION,
                    IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, XMP):
            if key in im.tag_v2:
                ifd[key] = im.tag_v2[key]
            ifd.tagtype[key] = im.tag_v2.tagtype.get(key, None)

        # preserve ICC profile (should also work when saving other formats
        # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
        if "icc_profile" in im.info:
            ifd[ICCPROFILE] = im.info["icc_profile"]

    for key, name in [(IMAGEDESCRIPTION, "description"),
                      (X_RESOLUTION, "resolution"),
                      (Y_RESOLUTION, "resolution"),
                      (X_RESOLUTION, "x_resolution"),
                      (Y_RESOLUTION, "y_resolution"),
                      (RESOLUTION_UNIT, "resolution_unit"),
                      (SOFTWARE, "software"), (DATE_TIME, "date_time"),
                      (ARTIST, "artist"), (COPYRIGHT, "copyright")]:
        name_with_spaces = name.replace("_", " ")
        if "_" in name and name_with_spaces in im.encoderinfo:
            warnings.warn(
                "%r is deprecated; use %r instead" % (name_with_spaces, name),
                DeprecationWarning)
            ifd[key] = im.encoderinfo[name.replace("_", " ")]
        if name in im.encoderinfo:
            ifd[key] = im.encoderinfo[name]

    dpi = im.encoderinfo.get("dpi")
    if dpi:
        ifd[RESOLUTION_UNIT] = 2
        ifd[X_RESOLUTION] = dpi[0]
        ifd[Y_RESOLUTION] = dpi[1]

    if bits != (1, ):
        ifd[BITSPERSAMPLE] = bits
        if len(bits) != 1:
            ifd[SAMPLESPERPIXEL] = len(bits)
    if extra is not None:
        ifd[EXTRASAMPLES] = extra
    if format != 1:
        ifd[SAMPLEFORMAT] = format

    ifd[PHOTOMETRIC_INTERPRETATION] = photo

    if im.mode == "P":
        lut = im.im.getpalette("RGB", "RGB;L")
        ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)

    # data orientation
    stride = len(bits) * ((im.size[0] * bits[0] + 7) // 8)
    ifd[ROWSPERSTRIP] = im.size[1]
    ifd[STRIPBYTECOUNTS] = stride * im.size[1]
    ifd[STRIPOFFSETS] = 0  # this is adjusted by IFD writer
    # no compression by default:
    ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)

    if libtiff:
        if DEBUG:
            print("Saving using libtiff encoder")
            print("Items: %s" % sorted(ifd.items()))
        _fp = 0
        if hasattr(fp, "fileno"):
            try:
                fp.seek(0)
                _fp = os.dup(fp.fileno())
            except io.UnsupportedOperation:
                pass

        # ICC Profile crashes.
        blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP, ICCPROFILE]
        atts = {}
        # bits per sample is a single short in the tiff directory, not a list.
        atts[BITSPERSAMPLE] = bits[0]
        # Merge the ones that we have with (optional) more bits from
        # the original file, e.g x,y resolution so that we can
        # save(load('')) == original file.
        legacy_ifd = {}
        if hasattr(im, 'tag'):
            legacy_ifd = im.tag.to_v2()
        for k, v in itertools.chain(ifd.items(),
                                    getattr(im, 'tag_v2', {}).items(),
                                    legacy_ifd.items()):
            if k not in atts and k not in blocklist:
                if isinstance(v, unicode if bytes is str else str):
                    atts[k] = v.encode('ascii', 'replace') + b"\0"
                else:
                    atts[k] = v

        if DEBUG:
            print("Converted items: %s" % sorted(atts.items()))

        # libtiff always expects the bytes in native order.
        # we're storing image byte order. So, if the rawmode
        # contains I;16, we need to convert from native to image
        # byte order.
        if im.mode in ('I;16B', 'I;16'):
            rawmode = 'I;16N'

        a = (rawmode, compression, _fp, filename, atts)
        # print(im.mode, compression, a, im.encoderconfig)
        e = Image._getencoder(im.mode, 'libtiff', a, im.encoderconfig)
        e.setimage(im.im, (0, 0) + im.size)
        while True:
            # undone, change to self.decodermaxblock:
            l, s, d = e.encode(16 * 1024)
            if not _fp:
                fp.write(d)
            if s:
                break
        if s < 0:
            raise IOError("encoder error %d when writing image file" % s)

    else:
        offset = ifd.save(fp)

        ImageFile._save(im, fp, [("raw", (0, 0) + im.size, offset,
                                  (rawmode, stride, 1))])

    # -- helper for multi-page save --
    if "_debug_multipage" in im.encoderinfo:
        # just to access o32 and o16 (using correct byte order)
        im._debug_multipage = ifd
Example #19
0
def _save(im, fp, filename):

    try:
        rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as TIFF" % im.mode)

    ifd = ImageFileDirectory(prefix)

    compression = im.encoderinfo.get('compression',
                                     im.info.get('compression', 'raw'))

    libtiff = WRITE_LIBTIFF or compression != 'raw'

    # required for color libtiff images
    ifd[PLANAR_CONFIGURATION] = getattr(im, '_planar_configuration', 1)

    # -- multi-page -- skip TIFF header on subsequent pages
    if not libtiff and fp.tell() == 0:
        # tiff header (write via IFD to get everything right)
        # PIL always starts the first IFD at offset 8
        fp.write(ifd.prefix + ifd.o16(42) + ifd.o32(8))

    ifd[IMAGEWIDTH] = im.size[0]
    ifd[IMAGELENGTH] = im.size[1]

    # write any arbitrary tags passed in as an ImageFileDirectory
    info = im.encoderinfo.get("tiffinfo", {})
    if Image.DEBUG:
        print("Tiffinfo Keys: %s" % info.keys)
    keys = list(info.keys())
    for key in keys:
        ifd[key] = info.get(key)
        try:
            ifd.tagtype[key] = info.tagtype[key]
        except:
            pass  # might not be an IFD, Might not have populated type

    # additions written by Greg Couch, [email protected]
    # inspired by image-sig posting from Kevin Cazabon, [email protected]
    if hasattr(im, 'tag'):
        # preserve tags from original TIFF image file
        for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION,
                    IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, XMP):
            if key in im.tag:
                ifd[key] = im.tag[key]
            ifd.tagtype[key] = im.tag.tagtype.get(key, None)

        # preserve ICC profile (should also work when saving other formats
        # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
        if "icc_profile" in im.info:
            ifd[ICCPROFILE] = im.info["icc_profile"]

    if "description" in im.encoderinfo:
        ifd[IMAGEDESCRIPTION] = im.encoderinfo["description"]
    if "resolution" in im.encoderinfo:
        ifd[X_RESOLUTION] = ifd[Y_RESOLUTION] \
            = _cvt_res(im.encoderinfo["resolution"])
    if "x resolution" in im.encoderinfo:
        ifd[X_RESOLUTION] = _cvt_res(im.encoderinfo["x resolution"])
    if "y resolution" in im.encoderinfo:
        ifd[Y_RESOLUTION] = _cvt_res(im.encoderinfo["y resolution"])
    if "resolution unit" in im.encoderinfo:
        unit = im.encoderinfo["resolution unit"]
        if unit == "inch":
            ifd[RESOLUTION_UNIT] = 2
        elif unit == "cm" or unit == "centimeter":
            ifd[RESOLUTION_UNIT] = 3
        else:
            ifd[RESOLUTION_UNIT] = 1
    if "software" in im.encoderinfo:
        ifd[SOFTWARE] = im.encoderinfo["software"]
    if "date time" in im.encoderinfo:
        ifd[DATE_TIME] = im.encoderinfo["date time"]
    if "artist" in im.encoderinfo:
        ifd[ARTIST] = im.encoderinfo["artist"]
    if "copyright" in im.encoderinfo:
        ifd[COPYRIGHT] = im.encoderinfo["copyright"]

    dpi = im.encoderinfo.get("dpi")
    if dpi:
        ifd[RESOLUTION_UNIT] = 2
        ifd[X_RESOLUTION] = _cvt_res(dpi[0])
        ifd[Y_RESOLUTION] = _cvt_res(dpi[1])

    if bits != (1, ):
        ifd[BITSPERSAMPLE] = bits
        if len(bits) != 1:
            ifd[SAMPLESPERPIXEL] = len(bits)
    if extra is not None:
        ifd[EXTRASAMPLES] = extra
    if format != 1:
        ifd[SAMPLEFORMAT] = format

    ifd[PHOTOMETRIC_INTERPRETATION] = photo

    if im.mode == "P":
        lut = im.im.getpalette("RGB", "RGB;L")
        ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)

    # data orientation
    stride = len(bits) * ((im.size[0] * bits[0] + 7) // 8)
    ifd[ROWSPERSTRIP] = im.size[1]
    ifd[STRIPBYTECOUNTS] = stride * im.size[1]
    ifd[STRIPOFFSETS] = 0  # this is adjusted by IFD writer
    # no compression by default:
    ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression, 1)

    if libtiff:
        if Image.DEBUG:
            print("Saving using libtiff encoder")
            print(ifd.items())
        _fp = 0
        if hasattr(fp, "fileno"):
            fp.seek(0)
            _fp = os.dup(fp.fileno())

        # ICC Profile crashes.
        blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP, ICCPROFILE]
        atts = {}
        # bits per sample is a single short in the tiff directory, not a list.
        atts[BITSPERSAMPLE] = bits[0]
        # Merge the ones that we have with (optional) more bits from
        # the original file, e.g x,y resolution so that we can
        # save(load('')) == original file.
        for k, v in itertools.chain(ifd.items(),
                                    getattr(im, 'ifd', {}).items()):
            if k not in atts and k not in blocklist:
                if type(v[0]) == tuple and len(v) > 1:
                    # A tuple of more than one rational tuples
                    # flatten to floats,
                    # following tiffcp.c->cpTag->TIFF_RATIONAL
                    atts[k] = [float(elt[0]) / float(elt[1]) for elt in v]
                    continue
                if type(v[0]) == tuple and len(v) == 1:
                    # A tuple of one rational tuples
                    # flatten to floats,
                    # following tiffcp.c->cpTag->TIFF_RATIONAL
                    atts[k] = float(v[0][0]) / float(v[0][1])
                    continue
                if type(v) == tuple and len(v) > 2:
                    # List of ints?
                    if type(v[0]) in (int, float):
                        atts[k] = list(v)
                    continue
                if type(v) == tuple and len(v) == 2:
                    # one rational tuple
                    # flatten to float,
                    # following tiffcp.c->cpTag->TIFF_RATIONAL
                    atts[k] = float(v[0]) / float(v[1])
                    continue
                if type(v) == tuple and len(v) == 1:
                    v = v[0]
                    # drop through
                if isStringType(v):
                    atts[k] = bytes(v.encode('ascii', 'replace')) + b"\0"
                    continue
                else:
                    # int or similar
                    atts[k] = v

        if Image.DEBUG:
            print(atts)

        # libtiff always expects the bytes in native order.
        # we're storing image byte order. So, if the rawmode
        # contains I;16, we need to convert from native to image
        # byte order.
        if im.mode in ('I;16B', 'I;16'):
            rawmode = 'I;16N'

        a = (rawmode, compression, _fp, filename, atts)
        # print (im.mode, compression, a, im.encoderconfig)
        e = Image._getencoder(im.mode, 'libtiff', a, im.encoderconfig)
        e.setimage(im.im, (0, 0) + im.size)
        while True:
            # undone, change to self.decodermaxblock:
            l, s, d = e.encode(16 * 1024)
            if not _fp:
                fp.write(d)
            if s:
                break
        if s < 0:
            raise IOError("encoder error %d when writing image file" % s)

    else:
        offset = ifd.save(fp)

        ImageFile._save(im, fp, [("raw", (0, 0) + im.size, offset,
                                  (rawmode, stride, 1))])

    # -- helper for multi-page save --
    if "_debug_multipage" in im.encoderinfo:
        # just to access o32 and o16 (using correct byte order)
        im._debug_multipage = ifd
Example #20
0
def _save(im, fp, filename):

    try:
        rawmode, prefix, photo, format, bits, extra = SAVE_INFO[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as TIFF" % im.mode)

    ifd = ImageFileDirectory(prefix)

    compression = im.encoderinfo.get('compression',im.info.get('compression','raw'))
    libtiff = compression in ["tiff_ccitt", "group3", "group4",
                              "tiff_jpeg", "tiff_adobe_deflate",
                              "tiff_thunderscan", "tiff_deflate",
                              "tiff_sgilog", "tiff_sgilog24",
                              "tiff_raw_16"]

    # -- multi-page -- skip TIFF header on subsequent pages
    if not libtiff and fp.tell() == 0:
        # tiff header (write via IFD to get everything right)
        # PIL always starts the first IFD at offset 8
        fp.write(ifd.prefix + ifd.o16(42) + ifd.o32(8))

    ifd[IMAGEWIDTH] = im.size[0]
    ifd[IMAGELENGTH] = im.size[1]

    # write any arbitrary tags passed in as an ImageFileDirectory
    info = im.encoderinfo.get("tiffinfo",{})
    if Image.DEBUG:
        print ("Tiffinfo Keys: %s"% info.keys)
    keys = list(info.keys())
    for key in keys:
        ifd[key] = info.get(key)
        try:
            ifd.tagtype[key] = info.tagtype[key]
        except:
            pass # might not be an IFD, Might not have populated type


    # additions written by Greg Couch, [email protected]
    # inspired by image-sig posting from Kevin Cazabon, [email protected]
    if hasattr(im, 'tag'):
        # preserve tags from original TIFF image file
        for key in (RESOLUTION_UNIT, X_RESOLUTION, Y_RESOLUTION,
                    IPTC_NAA_CHUNK, PHOTOSHOP_CHUNK, XMP):
            if key in im.tag:
                ifd[key] = im.tag[key]
            ifd.tagtype[key] = im.tag.tagtype.get(key, None)

        # preserve ICC profile (should also work when saving other formats
        # which support profiles as TIFF) -- 2008-06-06 Florian Hoech
        if "icc_profile" in im.info:
            ifd[ICCPROFILE] = im.info["icc_profile"]
            
    if "description" in im.encoderinfo:
        ifd[IMAGEDESCRIPTION] = im.encoderinfo["description"]
    if "resolution" in im.encoderinfo:
        ifd[X_RESOLUTION] = ifd[Y_RESOLUTION] \
                                = _cvt_res(im.encoderinfo["resolution"])
    if "x resolution" in im.encoderinfo:
        ifd[X_RESOLUTION] = _cvt_res(im.encoderinfo["x resolution"])
    if "y resolution" in im.encoderinfo:
        ifd[Y_RESOLUTION] = _cvt_res(im.encoderinfo["y resolution"])
    if "resolution unit" in im.encoderinfo:
        unit = im.encoderinfo["resolution unit"]
        if unit == "inch":
            ifd[RESOLUTION_UNIT] = 2
        elif unit == "cm" or unit == "centimeter":
            ifd[RESOLUTION_UNIT] = 3
        else:
            ifd[RESOLUTION_UNIT] = 1
    if "software" in im.encoderinfo:
        ifd[SOFTWARE] = im.encoderinfo["software"]
    if "date time" in im.encoderinfo:
        ifd[DATE_TIME] = im.encoderinfo["date time"]
    if "artist" in im.encoderinfo:
        ifd[ARTIST] = im.encoderinfo["artist"]
    if "copyright" in im.encoderinfo:
        ifd[COPYRIGHT] = im.encoderinfo["copyright"]

    dpi = im.encoderinfo.get("dpi")
    if dpi:
        ifd[RESOLUTION_UNIT] = 2
        ifd[X_RESOLUTION] = _cvt_res(dpi[0])
        ifd[Y_RESOLUTION] = _cvt_res(dpi[1])

    if bits != (1,):
        ifd[BITSPERSAMPLE] = bits
        if len(bits) != 1:
            ifd[SAMPLESPERPIXEL] = len(bits)
    if extra is not None:
        ifd[EXTRASAMPLES] = extra
    if format != 1:
        ifd[SAMPLEFORMAT] = format

    ifd[PHOTOMETRIC_INTERPRETATION] = photo

    if im.mode == "P":
        lut = im.im.getpalette("RGB", "RGB;L")
        ifd[COLORMAP] = tuple(i8(v) * 256 for v in lut)

    # data orientation
    stride = len(bits) * ((im.size[0]*bits[0]+7)//8)
    ifd[ROWSPERSTRIP] = im.size[1]
    ifd[STRIPBYTECOUNTS] = stride * im.size[1]
    ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
    ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression,1) # no compression by default

    if libtiff:
        if Image.DEBUG:
            print ("Saving using libtiff encoder")
            print (ifd.items())
        _fp = 0
        if hasattr(fp, "fileno"):
            fp.seek(0)
            _fp = os.dup(fp.fileno())

        blocklist =  [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP, ICCPROFILE] # ICC Profile crashes.
        atts={}
        # Merge the ones that we have with (optional) more bits from
        # the original file, e.g x,y resolution so that we can
        # save(load('')) == original file.
        for k,v in itertools.chain(ifd.items(), getattr(im, 'ifd', {}).items()):
            if k not in atts and k not in blocklist:
                if type(v[0]) == tuple and len(v) > 1:
                    # A tuple of more than one rational tuples
                    # flatten to floats, following tiffcp.c->cpTag->TIFF_RATIONAL
                    atts[k] = [float(elt[0])/float(elt[1]) for elt in v]
                    continue
                if type(v[0]) == tuple and len(v) == 1:
                    # A tuple of one rational tuples
                    # flatten to floats, following tiffcp.c->cpTag->TIFF_RATIONAL
                    atts[k] = float(v[0][0])/float(v[0][1])
                    continue
                if type(v) == tuple and len(v) > 2:
                    # List of ints?
                    # BitsPerSample is one example, I get (8,8,8)
                    # UNDONE
                    continue
                if type(v) == tuple and len(v) == 2:
                    # one rational tuple
                    # flatten to float, following tiffcp.c->cpTag->TIFF_RATIONAL
                    atts[k] = float(v[0])/float(v[1])
                    continue
                if type(v) == tuple and len(v) == 1:
                    v = v[0]
                    # drop through
                if isStringType(v):
                    atts[k] = bytes(v.encode('ascii', 'replace')) + b"\0"
                    continue
                else:
                    # int or similar
                    atts[k] = v

        if Image.DEBUG:
            print (atts)

        # libtiff always returns the bytes in native order.
        # we're expecting image byte order. So, if the rawmode
        # contains I;16, we need to convert from native to image
        # byte order.
        if im.mode in ('I;16B', 'I;16'):
            rawmode = 'I;16N'

        a = (rawmode, compression, _fp, filename, atts)
        # print (im.mode, compression, a, im.encoderconfig)
        e = Image._getencoder(im.mode, compression, a, im.encoderconfig)
        e.setimage(im.im, (0,0)+im.size)
        while 1:
            l, s, d = e.encode(16*1024) # undone, change to self.decodermaxblock
            if not _fp:
                fp.write(d)
            if s:
                break
        if s < 0:
            raise IOError("encoder error %d when writing image file" % s)

    else:
        offset = ifd.save(fp)

        ImageFile._save(im, fp, [
            ("raw", (0,0)+im.size, offset, (rawmode, stride, 1))
            ])


    # -- helper for multi-page save --
    if "_debug_multipage" in im.encoderinfo:
        #just to access o32 and o16 (using correct byte order)
        im._debug_multipage = ifd