Exemple #1
0
	def saveGif(self, filename):
		with open(filename, 'wb') as f:
			#TODO: check if file is writable?
			#Write the header
			f.write(self.headerBytes())
			#Write the screen descriptor
			f.write(self.screenDescriptorBytes())
			#write global colour palette, if any
			if self.globalPalette:
				assert(len(self.globalPalette) == 768)
				f.write(self.globalPalette)
			if len(self.Frames)>1:
					f.write(self.loopControlBytes())
			for GCE, ID, img in self.Frames:
				if len(self.Frames)>1:
					f.write(GCE.toBytes())
				f.write(ID.toBytes())
				#convert to new image.
				imOut = self.convertRGBtoIndexed(img, self.globalPalette)
				imOut.encoderconfig = (8, False) #no interlace.
				f.write(b'\x08')
				ImageFile._save(imOut, f, [("gif", (0,0)+imOut.size, 0, RAWMODE[imOut.mode])])
				f.write(b"\0") #end of image data.
			#Write end of file (0x3B)
			f.write(b';')
Exemple #2
0
def _save(im, fp, filename, check=0):

    try:
        type, rawmode = SAVE[im.mode]
    except KeyError:
        raise ValueError("Cannot save %s images as IM" % im.mode)

    try:
        frames = im.encoderinfo["frames"]
    except KeyError:
        frames = 1

    if check:
        return check

    fp.write(("Image type: %s image\r\n" % type).encode('ascii'))
    if filename:
        fp.write(("Name: %s\r\n" % filename).encode('ascii'))
    fp.write(("Image size (x*y): %d*%d\r\n" % im.size).encode('ascii'))
    fp.write(("File size (no of images): %d\r\n" % frames).encode('ascii'))
    if im.mode == "P":
        fp.write(b"Lut: 1\r\n")
    fp.write(b"\000" * (511-fp.tell()) + b"\032")
    if im.mode == "P":
        fp.write(im.im.getpalette("RGB", "RGB;L")) # 768 bytes
    ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, -1))])
def _save(im, fp, filename):
    if im.mode == "1":
        rawmode, head = "1;I", b"P4"
    elif im.mode == "L":
        rawmode, head = "L", b"P5"
    elif im.mode == "I":
        if im.getextrema()[1] < 2 ** 16:
            rawmode, head = "I;16B", b"P5"
        else:
            rawmode, head = "I;32B", b"P5"
    elif im.mode == "RGB":
        rawmode, head = "RGB", b"P6"
    elif im.mode == "RGBA":
        rawmode, head = "RGB", b"P6"
    else:
        raise IOError("cannot write mode %s as PPM" % im.mode)
    fp.write(head + ("\n%d %d\n" % im.size).encode("ascii"))
    if head == b"P6":
        fp.write(b"255\n")
    if head == b"P5":
        if rawmode == "L":
            fp.write(b"255\n")
        elif rawmode == "I;16B":
            fp.write(b"65535\n")
        elif rawmode == "I;32B":
            fp.write(b"2147483648\n")
    ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, 1))])
Exemple #4
0
def _save(im, fp, filename):

    if im.mode != "1":
        raise IOError("cannot write mode %s as MSP" % im.mode)

    # create MSP header
    header = [0] * 16

    header[0], header[1] = i16(b"Da"), i16(b"nM")  # version 1
    header[2], header[3] = im.size
    header[4], header[5] = 1, 1
    header[6], header[7] = 1, 1
    header[8], header[9] = im.size

    checksum = 0
    for h in header:
        checksum = checksum ^ h
    header[12] = checksum  # FIXME: is this the right field?

    # header
    for h in header:
        fp.write(o16(h))

    # image body
    ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 32, ("1", 0, 1))])
Exemple #5
0
def getdata(im, offset = (0, 0), **params):
    """Return a list of strings representing this image.
       The first string is a local image header, the rest contains
       encoded image data."""

    class collector:
        data = []
        def write(self, data):
            self.data.append(data)

    im.load() # make sure raster data is available

    fp = collector()

    try:
        im.encoderinfo = params

        # local image header
        fp.write(b"," +
                 o16(offset[0]) +       # offset
                 o16(offset[1]) +
                 o16(im.size[0]) +      # size
                 o16(im.size[1]) +
                 o8(0) +                # flags
                 o8(8))                 # bits

        ImageFile._save(im, fp, [("gif", (0,0)+im.size, 0, RAWMODE[im.mode])])

        fp.write(b"\0") # end of image data

    finally:
        del im.encoderinfo

    return fp.data
def _save(im, fp, filename):

    try:
        rawmode = RAWMODE[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as JPEG" % im.mode)

    info = im.encoderinfo

    dpi = info.get("dpi", (0, 0))

    # get keyword arguments
    im.encoderconfig = (
        info.get("quality", 0),
        # "progressive" is the official name, but older documentation
        # says "progression"
        # FIXME: issue a warning if the wrong form is used (post-1.1.5)
        info.has_key("progressive") or info.has_key("progression"),
        info.get("smooth", 0),
        info.has_key("optimize"),
        info.get("streamtype", 0),
        dpi[0], dpi[1]
        )

    if im.mode == "CMYK":
        # invert it so it's handled correctly in Photoshop/etc. - Kevin Cazabon.
        im = ImageChops.invert(im)

    ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)])
Exemple #7
0
def getdata(im, offset=(0, 0), **params):
    """Return a list of strings representing this image.
       The first string is a local image header, the rest contains
       encoded image data."""

    class Collector(object):
        data = []

        def write(self, data):
            self.data.append(data)

    im.load()  # make sure raster data is available

    fp = Collector()

    try:
        im.encoderinfo = params

        # local image header
        _get_local_header(fp, im, offset, 0)

        ImageFile._save(im, fp, [("gif", (0, 0)+im.size, 0, RAWMODE[im.mode])])

        fp.write(b"\0")  # end of image data

    finally:
        del im.encoderinfo

    return fp.data
Exemple #8
0
def encode_image(img):
	img = img.convert('P', palette=Image.ADAPTIVE, colors=256)
	palbytes = img.palette.palette
#	assert len(img.palette) in (2, 4, 8, 0x10, 0x20, 0x40, 0x80, 0x100)
	imio = io.BytesIO()
	ImageFile._save(img, imio, [("gif", (0, 0)+img.size, 0, 'P')])
	return (
		# GCE
		  b'\x21' # extension block
		+ b'\xf9' # graphic control extension
		+ b'\x04' # block size
		+ b'\x00' # flags
		+ b'\x00\x00' # frame delay
		+ b'\x00' # transparent color index
		+ b'\x00' # block terminator
		# Image headers
		+ b'\x2c' # image block
		+ b'\x00\x00' # image x
		+ b'\x00\x00' # image y
		+ struct.pack('<H', img.width) # image width
		+ struct.pack('<H', img.height) # image height
		+ bytes((0x80 | int(math.log(len(palbytes)//3, 2.0))-1,)) # flags (local palette and palette size)
		# Palette
		+ palbytes
		# LZW code size
		+ b'\x08'
		# Image data. We're using pillow here because I was too lazy finding a suitable LZW encoder.
		+ imio.getbuffer()
		# End of image data
		+ b'\x00'
		)
Exemple #9
0
def _save(im, fp, filename, eps=1):
    """EPS Writer for the Python Imaging Library."""

    #
    # make sure image data is available
    im.load()

    #
    # determine postscript image mode
    if im.mode == "L":
        operator = (8, 1, "image")
    elif im.mode == "RGB":
        operator = (8, 3, "false 3 colorimage")
    elif im.mode == "CMYK":
        operator = (8, 4, "false 4 colorimage")
    else:
        raise ValueError("image mode is not supported")

    class NoCloseStream:
        def __init__(self, fp):
            self.fp = fp
        def __getattr__(self, name):
            return getattr(self.fp, name)
        def close(self):
            pass

    base_fp = fp
    fp = io.TextIOWrapper(NoCloseStream(fp), encoding='latin-1')

    if eps:
        #
        # write EPS header
        fp.write("%!PS-Adobe-3.0 EPSF-3.0\n")
        fp.write("%%Creator: PIL 0.1 EpsEncode\n")
        #fp.write("%%CreationDate: %s"...)
        fp.write("%%%%BoundingBox: 0 0 %d %d\n" % im.size)
        fp.write("%%Pages: 1\n")
        fp.write("%%EndComments\n")
        fp.write("%%Page: 1 1\n")
        fp.write("%%ImageData: %d %d " % im.size)
        fp.write("%d %d 0 1 1 \"%s\"\n" % operator)

    #
    # image header
    fp.write("gsave\n")
    fp.write("10 dict begin\n")
    fp.write("/buf %d string def\n" % (im.size[0] * operator[1]))
    fp.write("%d %d scale\n" % im.size)
    fp.write("%d %d 8\n" % im.size) # <= bits
    fp.write("[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1]))
    fp.write("{ currentfile buf readhexstring pop } bind\n")
    fp.write(operator[2] + "\n")
    fp.flush()

    ImageFile._save(im, base_fp, [("eps", (0,0)+im.size, 0, None)])

    fp.write("\n%%%%EndBinary\n")
    fp.write("grestore end\n")
    fp.flush()
Exemple #10
0
def _save(im, fp, filename, check=0):

    try:
        rawmode, bits, colors = SAVE[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as BMP" % im.mode)

    if check:
        return check

    info = im.encoderinfo

    dpi = info.get("dpi", (96, 96))

    # 1 meter == 39.3701 inches
    ppm = tuple(map(lambda x: int(x * 39.3701), dpi))

    stride = ((im.size[0] * bits + 7) // 8 + 3) & (~3)
    header = 40  # or 64 for OS/2 version 2
    offset = 14 + header + colors * 4
    image = stride * im.size[1]

    # bitmap header
    fp.write(
        b"BM" + o32(offset + image) + o32(0) + o32(offset)  # file type (magic)  # file size  # reserved
    )  # image data offset

    # bitmap info header
    fp.write(
        o32(header)
        + o32(im.size[0])  # info header size
        + o32(im.size[1])  # width
        + o16(1)  # height
        + o16(bits)  # planes
        + o32(0)  # depth
        + o32(image)  # compression (0=uncompressed)
        + o32(ppm[0])  # size of bitmap
        + o32(ppm[1])
        + o32(colors)  # resolution
        + o32(colors)  # colors used
    )  # colors important

    fp.write(b"\0" * (header - 40))  # padding (for OS/2 format)

    if im.mode == "1":
        for i in (0, 255):
            fp.write(o8(i) * 4)
    elif im.mode == "L":
        for i in range(256):
            fp.write(o8(i) * 4)
    elif im.mode == "P":
        fp.write(im.im.getpalette("RGB", "BGRX"))

    ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, stride, -1))])
Exemple #11
0
def _save(im, fp, filename):

    if _imaging_gif:
        # call external driver
        try:
            _imaging_gif.save(im, fp, filename)
            return
        except IOError:
            pass  # write uncompressed file

    if im.mode in RAWMODE:
        im_out = im
    else:
        # convert on the fly (EXPERIMENTAL -- I'm not sure PIL
        # should automatically convert images on save...)
        if Image.getmodebase(im.mode) == "RGB":
            palette_size = 256
            if im.palette:
                palette_size = len(im.palette.getdata()[1]) // 3
            im_out = im.convert("P", palette=1, colors=palette_size)
        else:
            im_out = im.convert("L")

    # header
    try:
        palette = im.encoderinfo["palette"]
    except KeyError:
        palette = None
        im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)

    header, used_palette_colors = getheader(im_out, palette, im.encoderinfo)
    for s in header:
        fp.write(s)

    flags = 0

    if get_interlace(im):
        flags = flags | 64

    # local image header
    get_local_header(fp, im, (0, 0), flags)

    im_out.encoderconfig = (8, get_interlace(im))
    ImageFile._save(im_out, fp, [("gif", (0, 0)+im.size, 0,
                                  RAWMODE[im_out.mode])])

    fp.write(b"\0")  # end of image data

    fp.write(b";")  # end of file

    try:
        fp.flush()
    except:
        pass
Exemple #12
0
def _save(im, fp, filename, check=0):

    try:
        version, bits, planes, rawmode = SAVE[im.mode]
    except KeyError:
        raise ValueError("Cannot save %s images as PCX" % im.mode)

    if check:
        return check

    # bytes per plane
    stride = (im.size[0] * bits + 7) // 8
    # stride should be even
    stride += stride % 2
    # Stride needs to be kept in sync with the PcxEncode.c version.
    # Ideally it should be passed in in the state, but the bytes value
    # gets overwritten. 


    if Image.DEBUG:
        print ("PcxImagePlugin._save: xwidth: %d, bits: %d, stride: %d" % (
            im.size[0], bits, stride))

    # under windows, we could determine the current screen size with
    # "Image.core.display_mode()[1]", but I think that's overkill...

    screen = im.size

    dpi = 100, 100

    # PCX header
    fp.write(
        o8(10) + o8(version) + o8(1) + o8(bits) + o16(0) +
        o16(0) + o16(im.size[0]-1) + o16(im.size[1]-1) + o16(dpi[0]) +
        o16(dpi[1]) + b"\0"*24 + b"\xFF"*24 + b"\0" + o8(planes) +
        o16(stride) + o16(1) + o16(screen[0]) + o16(screen[1]) +
        b"\0"*54
        )

    assert fp.tell() == 128

    ImageFile._save(im, fp, [("pcx", (0,0)+im.size, 0,
                              (rawmode, bits*planes))])

    if im.mode == "P":
        # colour palette
        fp.write(o8(12))
        fp.write(im.im.getpalette("RGB", "RGB")) # 768 bytes
    elif im.mode == "L":
        # greyscale palette
        fp.write(o8(12))
        for i in range(256):
            fp.write(o8(i)*3)
def _save(im, fp, filename):

    try:
        rawmode = RAWMODE[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as JPEG" % im.mode)

    info = im.encoderinfo

    dpi = info.get("dpi", (0, 0))

    subsampling = info.get("subsampling", -1)
    if subsampling == "4:4:4":
        subsampling = 0
    elif subsampling == "4:2:2":
        subsampling = 1
    elif subsampling == "4:1:1":
        subsampling = 2

    extra = ""

    icc_profile = info.get("icc_profile")
    if icc_profile:
        ICC_OVERHEAD_LEN = 14
        MAX_BYTES_IN_MARKER = 65533
        MAX_DATA_BYTES_IN_MARKER = MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN
        markers = []
        while icc_profile:
            markers.append(icc_profile[:MAX_DATA_BYTES_IN_MARKER])
            icc_profile = icc_profile[MAX_DATA_BYTES_IN_MARKER:]
        i = 1
        for marker in markers:
            size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker))
            extra = extra + ("\xFF\xE2" + size + "ICC_PROFILE\0" + chr(i) + chr(len(markers)) + marker)
            i = i + 1

    # get keyword arguments
    im.encoderconfig = (
        info.get("quality", 0),
        # "progressive" is the official name, but older documentation
        # says "progression"
        # FIXME: issue a warning if the wrong form is used (post-1.1.7)
        info.has_key("progressive") or info.has_key("progression"),
        info.get("smooth", 0),
        info.has_key("optimize"),
        info.get("streamtype", 0),
        dpi[0], dpi[1],
        subsampling,
        extra,
        )

    ImageFile._save(im, fp, [("jpeg", (0,0)+im.size, 0, rawmode)])
Exemple #14
0
def _save(im, fp, filename):
    if im.mode[0] != "F":
        im = im.convert('F')

    hdr = makeSpiderHeader(im)
    if len(hdr) < 256:
        raise IOError("Error creating Spider header")

    # write the SPIDER header
    fp.writelines(hdr)

    rawmode = "F;32NF"  # 32-bit native floating point
    ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, 1))])
def _save(im, fp, filename):
    if im.mode == "1":
        rawmode, head = "1;I", b"P4"
    elif im.mode == "L":
        rawmode, head = "L", b"P5"
    elif im.mode == "RGB":
        rawmode, head = "RGB", b"P6"
    elif im.mode == "RGBA":
        rawmode, head = "RGB", b"P6"
    else:
        raise IOError("cannot write mode %s as PPM" % im.mode)
    fp.write(head + ("\n%d %d\n" % im.size).encode('ascii'))
    if head != b"P4":
        fp.write(b"255\n")
    ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, 0, 1))])
def _save(im, fp, filename):
    if im.mode != "1":
        raise IOError("cannot write mode %s as XBM" % im.mode)

    fp.write(("#define im_width %d\n" % im.size[0]).encode('ascii'))
    fp.write(("#define im_height %d\n" % im.size[1]).encode('ascii'))

    hotspot = im.encoderinfo.get("hotspot")
    if hotspot:
        fp.write(("#define im_x_hot %d\n" % hotspot[0]).encode('ascii'))
        fp.write(("#define im_y_hot %d\n" % hotspot[1]).encode('ascii'))

    fp.write(b"static char im_bits[] = {\n")

    ImageFile._save(im, fp, [("xbm", (0, 0) + im.size, 0, None)])

    fp.write(b"};\n")
def _save(im, fp, filename, check=0):

    try:
        rawmode, bits, colors = SAVE[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as BMP" % im.mode)

    if check:
        return check

    stride = ((im.size[0]*bits+7)//8+3)&(~3)
    header = 40 # or 64 for OS/2 version 2
    offset = 14 + header + colors * 4
    image  = stride * im.size[1]

    # bitmap header
    fp.write(b"BM" +                    # file type (magic)
             o32(offset+image) +        # file size
             o32(0) +                   # reserved
             o32(offset))               # image data offset

    # bitmap info header
    fp.write(o32(header) +              # info header size
             o32(im.size[0]) +          # width
             o32(im.size[1]) +          # height
             o16(1) +                   # planes
             o16(bits) +                # depth
             o32(0) +                   # compression (0=uncompressed)
             o32(image) +               # size of bitmap
             o32(1) + o32(1) +          # resolution
             o32(colors) +              # colors used
             o32(colors))               # colors important

    fp.write(b"\0" * (header - 40))    # padding (for OS/2 format)

    if im.mode == "1":
        for i in (0, 255):
            fp.write(o8(i) * 4)
    elif im.mode == "L":
        for i in range(256):
            fp.write(o8(i) * 4)
    elif im.mode == "P":
        fp.write(im.im.getpalette("RGB", "BGRX"))

    ImageFile._save(im, fp, [("raw", (0,0)+im.size, 0, (rawmode, stride, -1))])
def _save(im, fp, filename, check=0):

	# check if im.mode is compatible with MRC (see Bmp...)

	if check:
		return check

	header = MrcHeader()
	header['width'] = im.size[0]
	header['height'] = im.size[1]
	header['depth'] = 1
	header['mode'] = pilmode_mrcmode[im.mode]
	header.tofile(fp)

	rawmode = mrcmode_rawmode[header['mode']]
	tile = [("raw", (0,0)+im.size, header.headerlen, (rawmode, 0, 1))]
	print 'savetile:', tile
	ImageFile._save(im, fp, tile)
def _save(im, fp, filename):
    if filename.endswith('.j2k'):
        kind = 'j2k'
    else:
        kind = 'jp2'

    # Get the keyword arguments
    info = im.encoderinfo

    offset = info.get('offset', None)
    tile_offset = info.get('tile_offset', None)
    tile_size = info.get('tile_size', None)
    quality_mode = info.get('quality_mode', 'rates')
    quality_layers = info.get('quality_layers', None)
    num_resolutions = info.get('num_resolutions', 0)
    cblk_size = info.get('codeblock_size', None)
    precinct_size = info.get('precinct_size', None)
    irreversible = info.get('irreversible', False)
    progression = info.get('progression', 'LRCP')
    cinema_mode = info.get('cinema_mode', 'no')
    fd = -1

    if hasattr(fp, "fileno"):
        try:
            fd = fp.fileno()
        except:
            fd = -1
    
    im.encoderconfig = (
        offset,
        tile_offset,
        tile_size,
        quality_mode,
        quality_layers,
        num_resolutions,
        cblk_size,
        precinct_size,
        irreversible,
        progression,
        cinema_mode,
        fd
        )
        
    ImageFile._save(im, fp, [('jpeg2k', (0, 0)+im.size, 0, kind)])
def _save(im, fp, filename, check=0):

    try:
        version, bits, planes, rawmode = SAVE[im.mode]
    except KeyError:
        raise ValueError("Cannot save %s images as PCX" % im.mode)

    if check:
        return check

    # bytes per plane
    stride = (im.size[0] * bits + 7) // 8

    # under windows, we could determine the current screen size with
    # "Image.core.display_mode()[1]", but I think that's overkill...

    screen = im.size

    dpi = 100, 100

    # PCX header
    fp.write(
        o8(10) + o8(version) + o8(1) + o8(bits) + o16(0) +
        o16(0) + o16(im.size[0]-1) + o16(im.size[1]-1) + o16(dpi[0]) +
        o16(dpi[1]) + b"\0"*24 + b"\xFF"*24 + b"\0" + o8(planes) +
        o16(stride) + o16(1) + o16(screen[0]) + o16(screen[1]) +
        b"\0"*54
        )

    assert fp.tell() == 128

    ImageFile._save(im, fp, [("pcx", (0,0)+im.size, 0,
                              (rawmode, bits*planes))])

    if im.mode == "P":
        # colour palette
        fp.write(o8(12))
        fp.write(im.im.getpalette("RGB", "RGB")) # 768 bytes
    elif im.mode == "L":
        # greyscale palette
        fp.write(o8(12))
        for i in range(256):
            fp.write(o8(i)*3)
Exemple #21
0
def _save(im, fp, filename, check=0):

    try:
        rawmode, bits, colormaptype, imagetype = SAVE[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as TGA" % im.mode)

    if check:
        return check

    if colormaptype:
        colormapfirst, colormaplength, colormapentry = 0, 256, 24
    else:
        colormapfirst, colormaplength, colormapentry = 0, 0, 0

    if im.mode == "RGBA":
        flags = 8
    else:
        flags = 0

    orientation = im.info.get("orientation", -1)
    if orientation > 0:
        flags = flags | 0x20

    fp.write(
        b"\000"
        + o8(colormaptype)
        + o8(imagetype)
        + o16(colormapfirst)
        + o16(colormaplength)
        + o8(colormapentry)
        + o16(0)
        + o16(0)
        + o16(im.size[0])
        + o16(im.size[1])
        + o8(bits)
        + o8(flags)
    )

    if colormaptype:
        fp.write(im.im.getpalette("RGB", "BGR"))

    ImageFile._save(im, fp, [("raw", (0, 0) + im.size, 0, (rawmode, 0, orientation))])
Exemple #22
0
def _save(im, fp, filename):
    if im.mode[0] != "F":
        im = im.convert('F')

    hdr = makeSpiderHeader(im)
    if len(hdr) < 256:
        raise IOError("Error creating Spider header")

    # write the SPIDER header
    try:
        fp = open(filename, 'wb')
    except:
        raise IOError("Unable to open %s for writing" % filename)
    fp.writelines(hdr)

    rawmode = "F;32NF"  # 32-bit native floating point
    ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, 0, 1))])

    fp.close()
Exemple #23
0
def _save(im, fp, filename, chunk=putchunk, check=0):
    # save an image to disk (called by the save method)

    mode = im.mode

    if mode == "P":

        #
        # attempt to minimize storage requirements for palette images

        if "bits" in im.encoderinfo:

            # number of bits specified by user
            n = 1 << im.encoderinfo["bits"]

        else:

            # check palette contents
            n = 256  # FIXME

        if n <= 2:
            bits = 1
        elif n <= 4:
            bits = 2
        elif n <= 16:
            bits = 4
        else:
            bits = 8

        if bits != 8:
            mode = "%s;%d" % (mode, bits)

    # encoder options
    if "dictionary" in im.encoderinfo:
        dictionary = im.encoderinfo["dictionary"]
    else:
        dictionary = b""

    im.encoderconfig = ("optimize" in im.encoderinfo,
                        im.encoderinfo.get("compress_level", -1),
                        im.encoderinfo.get("compress_type", -1), dictionary)

    # get the corresponding PNG mode
    try:
        rawmode, mode = _OUTMODES[mode]
    except KeyError:
        raise IOError("cannot write mode %s as PNG" % mode)

    if check:
        return check

    #
    # write minimal PNG file

    fp.write(_MAGIC)

    chunk(
        fp,
        b"IHDR",
        o32(im.size[0]),
        o32(im.size[1]),  #  0: size
        mode,  #  8: depth/type
        b'\0',  # 10: compression
        b'\0',  # 11: filter category
        b'\0')  # 12: interlace flag

    if im.mode == "P":
        palette_bytes = (2**bits) * 3
        chunk(fp, b"PLTE", im.im.getpalette("RGB")[:palette_bytes])

    if "transparency" in im.encoderinfo:
        if im.mode == "P":
            # limit to actual palette size
            alpha_bytes = 2**bits
            if isinstance(im.encoderinfo["transparency"], bytes):
                chunk(fp, b"tRNS",
                      im.encoderinfo["transparency"][:alpha_bytes])
            else:
                transparency = max(0, min(255, im.encoderinfo["transparency"]))
                alpha = b'\xFF' * transparency + b'\0'
                chunk(fp, b"tRNS", alpha[:alpha_bytes])
        elif im.mode == "L":
            transparency = max(0, min(65535, im.encoderinfo["transparency"]))
            chunk(fp, b"tRNS", o16(transparency))
        elif im.mode == "RGB":
            red, green, blue = im.encoderinfo["transparency"]
            chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue))
        else:
            raise IOError("cannot use transparency for this mode")
    else:
        if im.mode == "P" and im.im.getpalettemode() == "RGBA":
            alpha = im.im.getpalette("RGBA", "A")
            alpha_bytes = 2**bits
            chunk(fp, b"tRNS", alpha[:alpha_bytes])

    if 0:
        # FIXME: to be supported some day
        chunk(fp, b"gAMA", o32(int(gamma * 100000.0)))

    dpi = im.encoderinfo.get("dpi")
    if dpi:
        chunk(fp, b"pHYs", o32(int(dpi[0] / 0.0254 + 0.5)),
              o32(int(dpi[1] / 0.0254 + 0.5)), b'\x01')

    info = im.encoderinfo.get("pnginfo")
    if info:
        for cid, data in info.chunks:
            chunk(fp, cid, data)

    # ICC profile writing support -- 2008-06-06 Florian Hoech
    if "icc_profile" in im.info:
        # ICC profile
        # according to PNG spec, the iCCP chunk contains:
        # Profile name  1-79 bytes (character string)
        # Null separator        1 byte (null character)
        # Compression method    1 byte (0)
        # Compressed profile    n bytes (zlib with deflate compression)
        try:
            import ICCProfile
            p = ICCProfile.ICCProfile(im.info["icc_profile"])
            name = p.tags.desc.get(
                "ASCII",
                p.tags.desc.get(
                    "Unicode",
                    p.tags.desc.get(
                        "Macintosh",
                        p.tags.desc.get("en",
                                        {}).get("US", "ICC Profile")))).encode(
                                            "latin1", "replace")[:79]
        except ImportError:
            name = b"ICC Profile"
        data = name + b"\0\0" + zlib.compress(im.info["icc_profile"])
        chunk(fp, b"iCCP", data)

    ImageFile._save(im, _idat(fp, chunk),
                    [("zip", (0, 0) + im.size, 0, rawmode)])

    chunk(fp, b"IEND", b"")

    try:
        fp.flush()
    except:
        pass
Exemple #24
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
def _save(im, fp, filename):

    try:
        rawmode = RAWMODE[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as JPEG" % im.mode)

    info = im.encoderinfo

    dpi = info.get("dpi", (0, 0))

    quality = info.get("quality", 0)
    subsampling = info.get("subsampling", -1)
    qtables = info.get("qtables")

    if quality == "keep":
        quality = 0
        subsampling = "keep"
        qtables = "keep"
    elif quality in presets:
        preset = presets[quality]
        quality = 0
        subsampling = preset.get('subsampling', -1)
        qtables = preset.get('quantization')
    elif not isinstance(quality, int):
        raise ValueError("Invalid quality setting")
    else:
        if subsampling in presets:
            subsampling = presets[subsampling].get('subsampling', -1)
        if isStringType(qtables) and qtables in presets:
            qtables = presets[qtables].get('quantization')

    if subsampling == "4:4:4":
        subsampling = 0
    elif subsampling == "4:2:2":
        subsampling = 1
    elif subsampling == "4:1:1":
        subsampling = 2
    elif subsampling == "keep":
        if im.format != "JPEG":
            raise ValueError(
                "Cannot use 'keep' when original image is not a JPEG")
        subsampling = get_sampling(im)

    def validate_qtables(qtables):
        if qtables is None:
            return qtables
        if isStringType(qtables):
            try:
                lines = [
                    int(num) for line in qtables.splitlines()
                    for num in line.split('#', 1)[0].split()
                ]
            except ValueError:
                raise ValueError("Invalid quantization table")
            else:
                qtables = [lines[s:s + 64] for s in range(0, len(lines), 64)]
        if isinstance(qtables, (tuple, list, dict)):
            if isinstance(qtables, dict):
                qtables = convert_dict_qtables(qtables)
            elif isinstance(qtables, tuple):
                qtables = list(qtables)
            if not (0 < len(qtables) < 5):
                raise ValueError("None or too many quantization tables")
            for idx, table in enumerate(qtables):
                try:
                    if len(table) != 64:
                        raise
                    table = array.array('b', table)
                except TypeError:
                    raise ValueError("Invalid quantization table")
                else:
                    qtables[idx] = list(table)
            return qtables

    if qtables == "keep":
        if im.format != "JPEG":
            raise ValueError(
                "Cannot use 'keep' when original image is not a JPEG")
        qtables = getattr(im, "quantization", None)
    qtables = validate_qtables(qtables)

    extra = b""

    icc_profile = info.get("icc_profile")
    if icc_profile:
        ICC_OVERHEAD_LEN = 14
        MAX_BYTES_IN_MARKER = 65533
        MAX_DATA_BYTES_IN_MARKER = MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN
        markers = []
        while icc_profile:
            markers.append(icc_profile[:MAX_DATA_BYTES_IN_MARKER])
            icc_profile = icc_profile[MAX_DATA_BYTES_IN_MARKER:]
        i = 1
        for marker in markers:
            size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker))
            extra += (b"\xFF\xE2" + size + b"ICC_PROFILE\0" + o8(i) +
                      o8(len(markers)) + marker)
            i += 1

    # get keyword arguments
    im.encoderconfig = (
        quality,
        # "progressive" is the official name, but older documentation
        # says "progression"
        # FIXME: issue a warning if the wrong form is used (post-1.1.7)
        "progressive" in info or "progression" in info,
        info.get("smooth", 0),
        "optimize" in info,
        info.get("streamtype", 0),
        dpi[0],
        dpi[1],
        subsampling,
        qtables,
        extra,
        info.get("exif", b""))

    # if we optimize, libjpeg needs a buffer big enough to hold the whole image
    # in a shot. Guessing on the size, at im.size bytes. (raw pizel size is
    # channels*size, this is a value that's been used in a django patch.
    # https://github.com/jdriscoll/django-imagekit/issues/50
    bufsize = 0
    if "optimize" in info or "progressive" in info or "progression" in info:
        # keep sets quality to 0, but the actual value may be high.
        if quality >= 95 or quality == 0:
            bufsize = 2 * im.size[0] * im.size[1]
        else:
            bufsize = im.size[0] * im.size[1]

    # The exif info needs to be written as one block, + APP1, + one spare byte.
    # Ensure that our buffer is big enough
    bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif", b"")) + 5)

    ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize)
Exemple #26
0
def _save(im, fp, filename):

    if _imaging_gif:
        # call external driver
        try:
            _imaging_gif.save(im, fp, filename)
            return
        except IOError:
            pass  # write uncompressed file

    try:
        rawmode = RAWMODE[im.mode]
        imOut = im
    except KeyError:
        # convert on the fly (EXPERIMENTAL -- I'm not sure PIL
        # should automatically convert images on save...)
        if Image.getmodebase(im.mode) == "RGB":
            imOut = im.convert("P")
            rawmode = "P"
        else:
            imOut = im.convert("L")
            rawmode = "L"

    # header
    try:
        palette = im.encoderinfo["palette"]
    except KeyError:
        palette = None

    header, usedPaletteColors = getheader(imOut, palette, im.encoderinfo)
    for s in header:
        fp.write(s)

    flags = 0

    try:
        interlace = im.encoderinfo["interlace"]
    except KeyError:
        interlace = 1

    # workaround for @PIL153
    if min(im.size) < 16:
        interlace = 0

    if interlace:
        flags = flags | 64

    try:
        transparency = im.encoderinfo["transparency"]
    except KeyError:
        pass
    else:
        transparency = int(transparency)
        # optimize the block away if transparent color is not used
        transparentColorExists = True
        # adjust the transparency index after optimize
        if usedPaletteColors is not None and len(usedPaletteColors) < 256:
            for i in range(len(usedPaletteColors)):
                if usedPaletteColors[i] == transparency:
                    transparency = i
                    transparentColorExists = True
                    break
                else:
                    transparentColorExists = False

        # transparency extension block
        if transparentColorExists:
            fp.write(b"!" + o8(249) +  # extension intro
                     o8(4) +  # length
                     o8(1) +  # transparency info present
                     o16(0) +  # duration
                     o8(transparency)  # transparency index
                     + o8(0))

    # local image header
    fp.write(b"," + o16(0) + o16(0) +  # bounding box
             o16(im.size[0]) +  # size
             o16(im.size[1]) + o8(flags) +  # flags
             o8(8))  # bits

    imOut.encoderconfig = (8, interlace)
    ImageFile._save(imOut, fp, [("gif", (0, 0) + im.size, 0, rawmode)])

    fp.write(b"\0")  # end of image data

    fp.write(b";")  # end of file

    try:
        fp.flush()
    except:
        pass
Exemple #27
0
def _save(im, fp, filename):
    resolution = im.encoderinfo.get("resolution", 72.0)

    #
    # make sure image data is available
    im.load()

    xref = [0] * (5 + 1)  # placeholders

    class TextWriter:
        def __init__(self, fp):
            self.fp = fp

        def __getattr__(self, name):
            return getattr(self.fp, name)

        def write(self, value):
            self.fp.write(value.encode('latin-1'))

    fp = TextWriter(fp)

    fp.write("%PDF-1.2\n")
    fp.write("% created by PIL PDF driver " + __version__ + "\n")

    #
    # Get image characteristics

    width, height = im.size

    # FIXME: Should replace ASCIIHexDecode with RunLengthDecode (packbits)
    # or LZWDecode (tiff/lzw compression).  Note that PDF 1.2 also supports
    # Flatedecode (zip compression).

    bits = 8
    params = None

    if im.mode == "1":
        filter = "/ASCIIHexDecode"
        colorspace = "/DeviceGray"
        procset = "/ImageB"  # grayscale
        bits = 1
    elif im.mode == "L":
        filter = "/DCTDecode"
        # params = "<< /Predictor 15 /Columns %d >>" % (width-2)
        colorspace = "/DeviceGray"
        procset = "/ImageB"  # grayscale
    elif im.mode == "P":
        filter = "/ASCIIHexDecode"
        colorspace = "[ /Indexed /DeviceRGB 255 <"
        palette = im.im.getpalette("RGB")
        for i in range(256):
            r = i8(palette[i * 3])
            g = i8(palette[i * 3 + 1])
            b = i8(palette[i * 3 + 2])
            colorspace = colorspace + "%02x%02x%02x " % (r, g, b)
        colorspace = colorspace + b"> ]"
        procset = "/ImageI"  # indexed color
    elif im.mode == "RGB":
        filter = "/DCTDecode"
        colorspace = "/DeviceRGB"
        procset = "/ImageC"  # color images
    elif im.mode == "CMYK":
        filter = "/DCTDecode"
        colorspace = "/DeviceCMYK"
        procset = "/ImageC"  # color images
    else:
        raise ValueError("cannot save mode %s" % im.mode)

    #
    # catalogue

    xref[1] = fp.tell()
    _obj(fp, 1, Type="/Catalog", Pages="2 0 R")
    _endobj(fp)

    #
    # pages

    xref[2] = fp.tell()
    _obj(fp, 2, Type="/Pages", Count=1, Kids="[4 0 R]")
    _endobj(fp)

    #
    # image

    op = io.BytesIO()

    if filter == "/ASCIIHexDecode":
        if bits == 1:
            # FIXME: the hex encoder doesn't support packed 1-bit
            # images; do things the hard way...
            data = im.tostring("raw", "1")
            im = Image.new("L", (len(data), 1), None)
            im.putdata(data)
        ImageFile._save(im, op, [("hex", (0, 0) + im.size, 0, im.mode)])
    elif filter == "/DCTDecode":
        Image.SAVE["JPEG"](im, op, filename)
    elif filter == "/FlateDecode":
        ImageFile._save(im, op, [("zip", (0, 0) + im.size, 0, im.mode)])
    elif filter == "/RunLengthDecode":
        ImageFile._save(im, op, [("packbits", (0, 0) + im.size, 0, im.mode)])
    else:
        raise ValueError("unsupported PDF filter (%s)" % filter)

    xref[3] = fp.tell()
    _obj(
        fp,
        3,
        Type="/XObject",
        Subtype="/Image",
        Width=width,  # * 72.0 / resolution,
        Height=height,  # * 72.0 / resolution,
        Length=len(op.getvalue()),
        Filter=filter,
        BitsPerComponent=bits,
        DecodeParams=params,
        ColorSpace=colorspace)

    fp.write("stream\n")
    fp.fp.write(op.getvalue())
    fp.write("\nendstream\n")

    _endobj(fp)

    #
    # page

    xref[4] = fp.tell()
    _obj(fp, 4)
    fp.write("<<\n/Type /Page\n/Parent 2 0 R\n"\
             "/Resources <<\n/ProcSet [ /PDF %s ]\n"\
             "/XObject << /image 3 0 R >>\n>>\n"\
             "/MediaBox [ 0 0 %d %d ]\n/Contents 5 0 R\n>>\n" %\
             (procset, int(width * 72.0 /resolution) , int(height * 72.0 / resolution)))
    _endobj(fp)

    #
    # page contents

    op = TextWriter(io.BytesIO())

    op.write("q %d 0 0 %d 0 0 cm /image Do Q\n" %
             (int(width * 72.0 / resolution), int(height * 72.0 / resolution)))

    xref[5] = fp.tell()
    _obj(fp, 5, Length=len(op.fp.getvalue()))

    fp.write("stream\n")
    fp.fp.write(op.fp.getvalue())
    fp.write("\nendstream\n")

    _endobj(fp)

    #
    # trailer
    startxref = fp.tell()
    fp.write("xref\n0 %d\n0000000000 65535 f \n" % len(xref))
    for x in xref[1:]:
        fp.write("%010d 00000 n \n" % x)
    fp.write("trailer\n<<\n/Size %d\n/Root 1 0 R\n>>\n" % len(xref))
    fp.write("startxref\n%d\n%%%%EOF\n" % startxref)
    fp.flush()
Exemple #28
0
def _save(im, fp, filename, save_all=False):

    im.encoderinfo.update(im.info)
    if _imaging_gif:
        # call external driver
        try:
            _imaging_gif.save(im, fp, filename)
            return
        except IOError:
            pass  # write uncompressed file

    if im.mode in RAWMODE:
        im_out = im.copy()
    else:
        im_out = _convert_mode(im, True)

    # header
    try:
        palette = im.encoderinfo["palette"]
    except KeyError:
        palette = None
        im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)

    if save_all:
        previous = None

        first_frame = None
        for im_frame in ImageSequence.Iterator(im):
            im_frame = _convert_mode(im_frame)

            # To specify duration, add the time in milliseconds to getdata(),
            # e.g. getdata(im_frame, duration=1000)
            if not previous:
                # global header
                first_frame = getheader(im_frame, palette, im.encoderinfo)[0]
                first_frame += getdata(im_frame, (0, 0), **im.encoderinfo)
            else:
                if first_frame:
                    for s in first_frame:
                        fp.write(s)
                    first_frame = None

                # delta frame
                delta = ImageChops.subtract_modulo(im_frame, previous.copy())
                bbox = delta.getbbox()

                if bbox:
                    # compress difference
                    for s in getdata(im_frame.crop(bbox), bbox[:2],
                                     **im.encoderinfo):
                        fp.write(s)
                else:
                    # FIXME: what should we do in this case?
                    pass
            previous = im_frame
        if first_frame:
            save_all = False
    if not save_all:
        header = getheader(im_out, palette, im.encoderinfo)[0]
        for s in header:
            fp.write(s)

        flags = 0

        if get_interlace(im):
            flags = flags | 64

        # local image header
        _get_local_header(fp, im, (0, 0), flags)

        im_out.encoderconfig = (8, get_interlace(im))
        ImageFile._save(im_out, fp,
                        [("gif", (0, 0) + im.size, 0, RAWMODE[im_out.mode])])

        fp.write(b"\0")  # end of image data

    fp.write(b";")  # end of file

    if hasattr(fp, "flush"):
        fp.flush()
Exemple #29
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
Exemple #30
0
def _save_frame(im, fp, cert_flag):
    # Return bytes for one frame
    try:
        info = im.encoderinfo
    except:
        im.encoderinfo = {}
        info = im.encoderinfo
    image_data = io.BytesIO()

    ns = im.header
    if im.mode == 'L':
        bit_depth = 8
    else:
        bit_depth = 24

    if ns['image_compression_algo'] == "RAW":
        im.encoderconfig = ()
        encoder = ('raw', (0, 0) + im.size, 0, (im.mode, 0, 1))
        bit_depth = 8
        ImageFile._save(im, image_data, [encoder])
    elif ns['image_compression_algo'] == "RAW_PACKED":
        im.encoderconfig()
        encoder = ('raw', (0, 0) + im.size, 0, (im.mode, 0, 1))
        bit_depth = 8
        ImageFile._save(im, image_data, [encoder])
    elif ns['image_compression_algo'] == "WSQ":
        im.encoderconfig()
        encoder = ('wsq', (0, 0) + im.size, 0, (12, ))
        bit_depth = 8
        ImageFile._save(im, image_data, [encoder])
    elif ns['image_compression_algo'] == "JPEG":
        info['quality'] = 'maximum'
        info['dpi'] = (im.header.get('horizontal_image_sampling_rate', 500),
                       im.header.get('vertical_image_sampling_rate', 500))
        PIL.JpegImagePlugin._save(im, image_data, "")
    elif ns['image_compression_algo'] == "JPEG2000_LOSSY":
        info['quality_mode'] = "rates"
        info['quality_layers'] = (15, )
        # XXX parameters needed? (up to 15 compression max according to the specs)
        PIL.Jpeg2KImagePlugin._save(im, image_data, "non.j2k")
    elif ns['image_compression_algo'] == "JPEG2000_LOSSLESS":
        info['quality_mode'] = "rates"
        info['quality_layers'] = (0, )
        # XXX parameters needed? (up to 15 compression max according to the specs)
        PIL.Jpeg2KImagePlugin._save(im, image_data, "non.j2k")
    else:
        raise SyntaxError("Unknown compression algo " +
                          ns['image_compression_algo'])
    image_data = image_data.getvalue()

    dt = ns.get('capture_datetime', datetime.datetime.now())
    rheader = b''
    rheader += struct.pack(">HBBBBBH", dt.year, dt.month, dt.day, dt.hour,
                           dt.minute, dt.second, int(dt.microsecond / 1000))
    rheader += struct.pack(">s2s2sB",
                           ns.get('capture_device_technology_id', b'\x00'),
                           ns.get('capture_device_vendor_id', b'\x00\x00'),
                           ns.get('capture_device_type_id', b'\x00\x00'),
                           len(ns.get('quality_records', [])))
    for q in ns.get('quality_records', []):
        rheader += struct.pack(">B2s2s", q.score, q.algo_vendor_id, q.algo_id)
    if cert_flag:
        rheader += struct.pack(">B", len(ns.get('certification_records', [])))
        for c in ns.get('certification_records', []):
            rheader += struct.pack(">2s1s", c.authority_id, c.scheme_id)

    rheader += struct.pack(
        ">BBBHHHHBBBHHI", POSITION[ns.get('position', 'UNKNOWN')],
        ns['number'], UNIT[ns.get('scale_units', 'PPI')],
        ns.get('horizontal_scan_sampling_rate', 500),
        ns.get('vertical_scan_sampling_rate', 500),
        ns.get('horizontal_image_sampling_rate', 500),
        ns.get('vertical_image_sampling_rate',
               500), bit_depth, COMPRESSION[ns.get('image_compression_algo',
                                                   'RAW')],
        IMPRESSION[ns.get('impression_type',
                          'UNKNOWN')], im.size[0], im.size[1], len(image_data))

    # Write the frame
    fp.write(struct.pack(">I", 4 + len(rheader) + len(image_data)))
    fp.write(rheader)
    fp.write(image_data)
Exemple #31
0
def _save(im, fp, filename, save_all=False):

    im.encoderinfo.update(im.info)
    if _imaging_gif:
        # call external driver
        try:
            _imaging_gif.save(im, fp, filename)
            return
        except IOError:
            pass  # write uncompressed file

    if im.mode in RAWMODE:
        im_out = im.copy()
    else:
        im_out = _convert_mode(im, True)

    # header
    try:
        palette = im.encoderinfo["palette"]
    except KeyError:
        palette = None
        im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)

    if save_all:
        previous = None

        first_frame = None
        append_images = im.encoderinfo.get("append_images", [])
        if "duration" in im.encoderinfo:
            duration = im.encoderinfo["duration"]
        else:
            duration = None
        frame_count = 0
        for imSequence in [im]+append_images:
            for im_frame in ImageSequence.Iterator(imSequence):
                encoderinfo = im.encoderinfo.copy()
                im_frame = _convert_mode(im_frame)
                if isinstance(duration, (list, tuple)):
                    encoderinfo["duration"] = duration[frame_count]
                frame_count += 1

                # To specify duration, add the time in milliseconds to getdata(),
                # e.g. getdata(im_frame, duration=1000)
                if not previous:
                    # global header
                    first_frame = getheader(im_frame, palette, encoderinfo)[0]
                    first_frame += getdata(im_frame, (0, 0), **encoderinfo)
                else:
                    if first_frame:
                        for s in first_frame:
                            fp.write(s)
                        first_frame = None

                    # delta frame
                    delta = ImageChops.subtract_modulo(im_frame, previous.copy())
                    bbox = delta.getbbox()

                    if bbox:
                        # compress difference
                        encoderinfo['include_color_table'] = True
                        for s in getdata(im_frame.crop(bbox),
                                         bbox[:2], **encoderinfo):
                            fp.write(s)
                    else:
                        # FIXME: what should we do in this case?
                        pass
                previous = im_frame
        if first_frame:
            save_all = False
    if not save_all:
        header = getheader(im_out, palette, im.encoderinfo)[0]
        for s in header:
            fp.write(s)

        flags = 0

        if get_interlace(im):
            flags = flags | 64

        # local image header
        _get_local_header(fp, im, (0, 0), flags)

        im_out.encoderconfig = (8, get_interlace(im))
        ImageFile._save(im_out, fp, [("gif", (0, 0)+im.size, 0,
                                      RAWMODE[im_out.mode])])

        fp.write(b"\0")  # end of image data

    fp.write(b";")  # end of file

    if hasattr(fp, "flush"):
        fp.flush()
def _save(im, fp, filename):

    try:
        rawmode = RAWMODE[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as JPEG" % im.mode)

    info = im.encoderinfo

    dpi = info.get("dpi", (0, 0))

    quality = info.get("quality", 0)
    subsampling = info.get("subsampling", -1)
    qtables = info.get("qtables")

    if quality == "keep":
        quality = 0
        subsampling = "keep"
        qtables = "keep"
    elif quality in presets:
        preset = presets[quality]
        quality = 0
        subsampling = preset.get('subsampling', -1)
        qtables = preset.get('quantization')
    elif not isinstance(quality, int):
        raise ValueError("Invalid quality setting")
    else:
        if subsampling in presets:
            subsampling = presets[subsampling].get('subsampling', -1)
        if qtables in presets:
            qtables = presets[qtables].get('quantization')

    if subsampling == "4:4:4":
        subsampling = 0
    elif subsampling == "4:2:2":
        subsampling = 1
    elif subsampling == "4:1:1":
        subsampling = 2
    elif subsampling == "keep":
        if im.format != "JPEG":
            raise ValueError(
                "Cannot use 'keep' when original image is not a JPEG")
        subsampling = get_sampling(im)

    def validate_qtables(qtables):
        if qtables is None:
            return qtables
        if isinstance(qtables, basestring):
            try:
                lines = [
                    int(num) for line in qtables.splitlines()
                    for num in line.split('#', 1)[0].split()
                ]
            except ValueError:
                raise ValueError("Invalid quantization table")
            else:
                qtables = [lines[s:s + 64] for s in xrange(0, len(lines), 64)]
        if isinstance(qtables, (tuple, list, dict)):
            if isinstance(qtables, dict):
                qtables = convert_dict_qtables(qtables)
            elif isinstance(qtables, tuple):
                qtables = list(qtables)
            if not (0 < len(qtables) < 5):
                raise ValueError("None or too many quantization tables")
            for idx, table in enumerate(qtables):
                try:
                    if len(table) != 64:
                        raise
                    table = array.array('b', table)
                except TypeError:
                    raise ValueError("Invalid quantization table")
                else:
                    qtables[idx] = list(table)
            return qtables

    if qtables == "keep":
        if im.format != "JPEG":
            raise ValueError(
                "Cannot use 'keep' when original image is not a JPEG")
        qtables = getattr(im, "quantization", None)
    qtables = validate_qtables(qtables)

    extra = b""

    icc_profile = info.get("icc_profile")
    if icc_profile:
        ICC_OVERHEAD_LEN = 14
        MAX_BYTES_IN_MARKER = 65533
        MAX_DATA_BYTES_IN_MARKER = MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN
        markers = []
        while icc_profile:
            markers.append(icc_profile[:MAX_DATA_BYTES_IN_MARKER])
            icc_profile = icc_profile[MAX_DATA_BYTES_IN_MARKER:]
        i = 1
        for marker in markers:
            size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker))
            extra = extra + (b"\xFF\xE2" + size + b"ICC_PROFILE\0" + o8(i) +
                             o8(len(markers)) + marker)
            i = i + 1

    # get keyword arguments
    im.encoderconfig = (
        quality,
        # "progressive" is the official name, but older documentation
        # says "progression"
        # FIXME: issue a warning if the wrong form is used (post-1.1.7)
        "progressive" in info or "progression" in info,
        info.get("smooth", 0),
        "optimize" in info,
        info.get("streamtype", 0),
        dpi[0],
        dpi[1],
        subsampling,
        qtables,
        extra,
        info.get("exif", b""))

    ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)])
Exemple #33
0
def _save(im, fp, filename):

    if _imaging_gif:
        # call external driver
        try:
            _imaging_gif.save(im, fp, filename)
            return
        except IOError:
            pass # write uncompressed file

    try:
        rawmode = RAWMODE[im.mode]
        imOut = im
    except KeyError:
        # convert on the fly (EXPERIMENTAL -- I'm not sure PIL
        # should automatically convert images on save...)
        if Image.getmodebase(im.mode) == "RGB":
            palette_size = 256
            if im.palette:
                palette_size = len(im.palette.getdata()[1]) // 3
            imOut = im.convert("P", palette=1, colors=palette_size)
            rawmode = "P"
        else:
            imOut = im.convert("L")
            rawmode = "L"

    # header
    try:
        palette = im.encoderinfo["palette"]
    except KeyError:
        palette = None
        im.encoderinfo["optimize"] = im.encoderinfo.get("optimize", True)
        if im.encoderinfo["optimize"]:
            # When the mode is L, and we optimize, we end up with
            # im.mode == P and rawmode = L, which fails.
            # If we're optimizing the palette, we're going to be
            # in a rawmode of P anyway. 
            rawmode = 'P'

    header, usedPaletteColors = getheader(imOut, palette, im.encoderinfo)
    for s in header:
        fp.write(s)

    flags = 0

    try:
        interlace = im.encoderinfo["interlace"]
    except KeyError:
        interlace = 1

    # workaround for @PIL153
    if min(im.size) < 16:
        interlace = 0

    if interlace:
        flags = flags | 64

    try:
        transparency = im.encoderinfo["transparency"]
    except KeyError:
        pass
    else:
        transparency = int(transparency)
        # optimize the block away if transparent color is not used
        transparentColorExists = True
        # adjust the transparency index after optimize
        if usedPaletteColors is not None and len(usedPaletteColors) < 256:
            for i in range(len(usedPaletteColors)):
                if usedPaletteColors[i] == transparency:
                    transparency = i
                    transparentColorExists = True
                    break
                else:
                    transparentColorExists = False

        # transparency extension block
        if transparentColorExists:
            fp.write(b"!" +
                     o8(249) +              # extension intro
                     o8(4) +                # length
                     o8(1) +                # transparency info present
                     o16(0) +               # duration
                     o8(transparency)       # transparency index
                     + o8(0))

    # local image header
    fp.write(b"," +
             o16(0) + o16(0) +          # bounding box
             o16(im.size[0]) +          # size
             o16(im.size[1]) +
             o8(flags) +                # flags
             o8(8))                     # bits

    imOut.encoderconfig = (8, interlace)
    ImageFile._save(imOut, fp, [("gif", (0,0)+im.size, 0, rawmode)])

    fp.write(b"\0") # end of image data

    fp.write(b";") # end of file

    try:
        fp.flush()
    except: pass
Exemple #34
0
def _save(im, fp, filename):

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

    ifd = ImageFileDirectory(BYTEORDER_TO_PREFIX[byteorder])

    #seb -- multi-page -- added `if`
    if 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))
        #seb debug  print "DEBUG: 000", fp.tell()

    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 im.tag.tagdata.has_key(key):
                ifd[key] = im.tag.tagdata.get(key)
    if im.encoderinfo.has_key("description"):
        ifd[IMAGEDESCRIPTION] = im.encoderinfo["description"]
    if im.encoderinfo.has_key("resolution"):
        ifd[X_RESOLUTION] = ifd[Y_RESOLUTION] \
                                = _cvt_res(im.encoderinfo["resolution"])
    if im.encoderinfo.has_key("x resolution"):
        ifd[X_RESOLUTION] = _cvt_res(im.encoderinfo["x resolution"])
    if im.encoderinfo.has_key("y resolution"):
        ifd[Y_RESOLUTION] = _cvt_res(im.encoderinfo["y resolution"])
    if im.encoderinfo.has_key("resolution unit"):
        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 im.encoderinfo.has_key("software"):
        ifd[SOFTWARE] = im.encoderinfo["software"]
    if im.encoderinfo.has_key("date time"):
        ifd[DATE_TIME] = im.encoderinfo["date time"]
    if im.encoderinfo.has_key("artist"):
        ifd[ARTIST] = im.encoderinfo["artist"]
    if im.encoderinfo.has_key("copyright"):
        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(map(lambda v: ord(v) * 256, 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] = 1  # no compression

    offset = ifd.save(fp)

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

    #seb -- multi-page --
    if im.encoderinfo.has_key("_debug_multipage"):
        #just to access o32 and o16 (using correct byte order)
        im._debug_multipage = ifd
Exemple #35
0
def _save(im, fp, filename, eps=1):
    """EPS Writer for the Python Imaging Library."""

    #
    # make sure image data is available
    im.load()

    #
    # determine postscript image mode
    if im.mode == "L":
        operator = (8, 1, "image")
    elif im.mode == "RGB":
        operator = (8, 3, "false 3 colorimage")
    elif im.mode == "CMYK":
        operator = (8, 4, "false 4 colorimage")
    else:
        raise ValueError("image mode is not supported")

    class NoCloseStream:
        def __init__(self, fp):
            self.fp = fp

        def __getattr__(self, name):
            return getattr(self.fp, name)

        def close(self):
            pass

    base_fp = fp
    fp = NoCloseStream(fp)
    if sys.version_info[0] > 2:
        fp = io.TextIOWrapper(fp, encoding='latin-1')

    if eps:
        #
        # write EPS header
        fp.write("%!PS-Adobe-3.0 EPSF-3.0\n")
        fp.write("%%Creator: PIL 0.1 EpsEncode\n")
        # fp.write("%%CreationDate: %s"...)
        fp.write("%%%%BoundingBox: 0 0 %d %d\n" % im.size)
        fp.write("%%Pages: 1\n")
        fp.write("%%EndComments\n")
        fp.write("%%Page: 1 1\n")
        fp.write("%%ImageData: %d %d " % im.size)
        fp.write("%d %d 0 1 1 \"%s\"\n" % operator)

    #
    # image header
    fp.write("gsave\n")
    fp.write("10 dict begin\n")
    fp.write("/buf %d string def\n" % (im.size[0] * operator[1]))
    fp.write("%d %d scale\n" % im.size)
    fp.write("%d %d 8\n" % im.size)  # <= bits
    fp.write("[%d 0 0 -%d 0 %d]\n" % (im.size[0], im.size[1], im.size[1]))
    fp.write("{ currentfile buf readhexstring pop } bind\n")
    fp.write(operator[2] + "\n")
    fp.flush()

    ImageFile._save(im, base_fp, [("eps", (0, 0)+im.size, 0, None)])

    fp.write("\n%%%%EndBinary\n")
    fp.write("grestore end\n")
    fp.flush()
Exemple #36
0
def _save(im, fp, filename, chunk=putchunk, check=0):
    # save an image to disk (called by the save method)

    mode = im.mode

    if mode == "P":

        #
        # attempt to minimize storage requirements for palette images

        if "bits" in im.encoderinfo:

            # number of bits specified by user
            n = 1 << im.encoderinfo["bits"]

        else:

            # check palette contents
            n = 256 # FIXME

        if n <= 2:
            bits = 1
        elif n <= 4:
            bits = 2
        elif n <= 16:
            bits = 4
        else:
            bits = 8

        if bits != 8:
            mode = "%s;%d" % (mode, bits)

    # encoder options
    if "dictionary" in im.encoderinfo:
        dictionary = im.encoderinfo["dictionary"]
    else:
        dictionary = b""

    im.encoderconfig = ("optimize" in im.encoderinfo, dictionary)

    # get the corresponding PNG mode
    try:
        rawmode, mode = _OUTMODES[mode]
    except KeyError:
        raise IOError("cannot write mode %s as PNG" % mode)

    if check:
        return check

    #
    # write minimal PNG file

    fp.write(_MAGIC)

    chunk(fp, b"IHDR",
          o32(im.size[0]), o32(im.size[1]),     #  0: size
          mode,                                 #  8: depth/type
          b'\0',                                # 10: compression
          b'\0',                                # 11: filter category
          b'\0')                                # 12: interlace flag

    if im.mode == "P":
        chunk(fp, b"PLTE", im.im.getpalette("RGB"))

    if "transparency" in im.encoderinfo:
        if im.mode == "P":
            transparency = max(0, min(255, im.encoderinfo["transparency"]))
            chunk(fp, b"tRNS", b'\xFF' * transparency + b'\0')
        elif im.mode == "L":
            transparency = max(0, min(65535, im.encoderinfo["transparency"]))
            chunk(fp, b"tRNS", o16(transparency))
        elif im.mode == "RGB":
            red, green, blue = im.encoderinfo["transparency"]
            chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue))
        else:
            raise IOError("cannot use transparency for this mode")

    if 0:
        # FIXME: to be supported some day
        chunk(fp, b"gAMA", o32(int(gamma * 100000.0)))

    dpi = im.encoderinfo.get("dpi")
    if dpi:
        chunk(fp, b"pHYs",
              o32(int(dpi[0] / 0.0254 + 0.5)),
              o32(int(dpi[1] / 0.0254 + 0.5)),
              b'\x01')

    info = im.encoderinfo.get("pnginfo")
    if info:
        for cid, data in info.chunks:
            chunk(fp, cid, data)

    # ICC profile writing support -- 2008-06-06 Florian Hoech
    if "icc_profile" in im.info:
        # ICC profile
        # according to PNG spec, the iCCP chunk contains:
        # Profile name  1-79 bytes (character string)
        # Null separator        1 byte (null character)
        # Compression method    1 byte (0)
        # Compressed profile    n bytes (zlib with deflate compression)
        try:
            import ICCProfile
            p = ICCProfile.ICCProfile(im.info["icc_profile"])
            name = p.tags.desc.get("ASCII", p.tags.desc.get("Unicode", p.tags.desc.get("Macintosh", p.tags.desc.get("en", {}).get("US", "ICC Profile")))).encode("latin1", "replace")[:79]
        except ImportError:
            name = b"ICC Profile"
        data = name + b"\0\0" + zlib.compress(im.info["icc_profile"])
        chunk(fp, b"iCCP", data)

    ImageFile._save(im, _idat(fp, chunk), [("zip", (0,0)+im.size, 0, rawmode)])

    chunk(fp, b"IEND", b"")

    try:
        fp.flush()
    except:
        pass
Exemple #37
0
def _save(im, fp, filename, chunk=putchunk, check=0):
    # save an image to disk (called by the save method)

    mode = im.mode

    if mode == "P":

        #
        # attempt to minimize storage requirements for palette images
        if "bits" in im.encoderinfo:
            # number of bits specified by user
            colors = 1 << im.encoderinfo["bits"]
        else:
            # check palette contents
            if im.palette:
                colors = max(min(len(im.palette.getdata()[1])//3, 256), 2)
            else:
                colors = 256

        if colors <= 2:
            bits = 1
        elif colors <= 4:
            bits = 2
        elif colors <= 16:
            bits = 4
        else:
            bits = 8
        if bits != 8:
            mode = "%s;%d" % (mode, bits)

    # encoder options
    if "dictionary" in im.encoderinfo:
        dictionary = im.encoderinfo["dictionary"]
    else:
        dictionary = b""

    im.encoderconfig = ("optimize" in im.encoderinfo,
                        im.encoderinfo.get("compress_level", -1),
                        im.encoderinfo.get("compress_type", -1),
                        dictionary)

    # get the corresponding PNG mode
    try:
        rawmode, mode = _OUTMODES[mode]
    except KeyError:
        raise IOError("cannot write mode %s as PNG" % mode)

    if check:
        return check

    #
    # write minimal PNG file

    fp.write(_MAGIC)

    chunk(fp, b"IHDR",
          o32(im.size[0]), o32(im.size[1]),     # 0: size
          mode,                                 # 8: depth/type
          b'\0',                                # 10: compression
          b'\0',                                # 11: filter category
          b'\0')                                # 12: interlace flag

    if im.mode == "P":
        palette_byte_number = (2 ** bits) * 3
        palette_bytes = im.im.getpalette("RGB")[:palette_byte_number]
        while len(palette_bytes) < palette_byte_number:
            palette_bytes += b'\0'
        chunk(fp, b"PLTE", palette_bytes)

    transparency = im.encoderinfo.get('transparency',
                                      im.info.get('transparency', None))

    if transparency or transparency == 0:
        if im.mode == "P":
            # limit to actual palette size
            alpha_bytes = 2**bits
            if isinstance(transparency, bytes):
                chunk(fp, b"tRNS", transparency[:alpha_bytes])
            else:
                transparency = max(0, min(255, transparency))
                alpha = b'\xFF' * transparency + b'\0'
                chunk(fp, b"tRNS", alpha[:alpha_bytes])
        elif im.mode == "L":
            transparency = max(0, min(65535, transparency))
            chunk(fp, b"tRNS", o16(transparency))
        elif im.mode == "RGB":
            red, green, blue = transparency
            chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue))
        else:
            if "transparency" in im.encoderinfo:
                # don't bother with transparency if it's an RGBA
                # and it's in the info dict. It's probably just stale.
                raise IOError("cannot use transparency for this mode")
    else:
        if im.mode == "P" and im.im.getpalettemode() == "RGBA":
            alpha = im.im.getpalette("RGBA", "A")
            alpha_bytes = 2**bits
            chunk(fp, b"tRNS", alpha[:alpha_bytes])

    dpi = im.encoderinfo.get("dpi")
    if dpi:
        chunk(fp, b"pHYs",
              o32(int(dpi[0] / 0.0254 + 0.5)),
              o32(int(dpi[1] / 0.0254 + 0.5)),
              b'\x01')

    info = im.encoderinfo.get("pnginfo")
    if info:
        for cid, data in info.chunks:
            chunk(fp, cid, data)

    # ICC profile writing support -- 2008-06-06 Florian Hoech
    if im.info.get("icc_profile"):
        # ICC profile
        # according to PNG spec, the iCCP chunk contains:
        # Profile name  1-79 bytes (character string)
        # Null separator        1 byte (null character)
        # Compression method    1 byte (0)
        # Compressed profile    n bytes (zlib with deflate compression)
        name = b"ICC Profile"
        data = name + b"\0\0" + zlib.compress(im.info["icc_profile"])
        chunk(fp, b"iCCP", data)

    ImageFile._save(im, _idat(fp, chunk),
                    [("zip", (0, 0)+im.size, 0, rawmode)])

    chunk(fp, b"IEND", b"")

    if hasattr(fp, "flush"):
        fp.flush()
def _save(im, fp, filename):

    if _imaging_gif:
        # call external driver
        try:
            _imaging_gif.save(im, fp, filename)
            return
        except IOError:
            pass  # write uncompressed file

    try:
        rawmode = RAWMODE[im.mode]
        imOut = im
    except KeyError:
        # convert on the fly (EXPERIMENTAL -- I'm not sure PIL
        # should automatically convert images on save...)
        if Image.getmodebase(im.mode) == "RGB":
            imOut = im.convert("P")
            rawmode = "P"
        else:
            imOut = im.convert("L")
            rawmode = "L"

    # header
    try:
        palette = im.encoderinfo["palette"]
    except KeyError:
        palette = None
        if im.palette:
            # use existing if possible
            palette = im.palette.getdata()[1]

    header, usedPaletteColors = getheader(imOut, palette, im.encoderinfo)
    for s in header:
        fp.write(s)

    flags = 0

    try:
        interlace = im.encoderinfo["interlace"]
    except KeyError:
        interlace = 1

    # workaround for @PIL153
    if min(im.size) < 16:
        interlace = 0

    if interlace:
        flags = flags | 64

    try:
        transparency = im.encoderinfo["transparency"]
    except KeyError:
        pass
    else:
        transparency = int(transparency)
        # optimize the block away if transparent color is not used
        transparentColorExists = True
        # adjust the transparency index after optimize
        if usedPaletteColors is not None and len(usedPaletteColors) < 256:
            for i in range(len(usedPaletteColors)):
                if usedPaletteColors[i] == transparency:
                    transparency = i
                    transparentColorExists = True
                    break
                else:
                    transparentColorExists = False

        # transparency extension block
        if transparentColorExists:
            fp.write(
                b"!"
                + o8(249)
                + o8(4)  # extension intro
                + o8(1)  # length
                + o16(0)  # transparency info present
                + o8(transparency)  # duration  # transparency index
                + o8(0)
            )

    # local image header
    fp.write(
        b"," + o16(0) + o16(0) + o16(im.size[0]) + o16(im.size[1]) + o8(flags) + o8(8)  # bounding box  # size  # flags
    )  # bits

    imOut.encoderconfig = (8, interlace)
    ImageFile._save(imOut, fp, [("gif", (0, 0) + im.size, 0, rawmode)])

    fp.write(b"\0")  # end of image data

    fp.write(b";")  # end of file

    try:
        fp.flush()
    except:
        pass
Exemple #39
0
def _save(im, fp, filename):

    try:
        rawmode = RAWMODE[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as JPEG" % im.mode)

    info = im.encoderinfo

    dpi = info.get("dpi", (0, 0))

    quality = info.get("quality", 0)
    subsampling = info.get("subsampling", -1)
    qtables = info.get("qtables")

    if quality == "keep":
        quality = 0
        subsampling = "keep"
        qtables = "keep"
    elif quality in presets:
        preset = presets[quality]
        quality = 0
        subsampling = preset.get("subsampling", -1)
        qtables = preset.get("quantization")
    elif not isinstance(quality, int):
        raise ValueError("Invalid quality setting")
    else:
        if subsampling in presets:
            subsampling = presets[subsampling].get("subsampling", -1)
        if qtables in presets:
            qtables = presets[qtables].get("quantization")

    if subsampling == "4:4:4":
        subsampling = 0
    elif subsampling == "4:2:2":
        subsampling = 1
    elif subsampling == "4:1:1":
        subsampling = 2
    elif subsampling == "keep":
        if im.format != "JPEG":
            raise ValueError("Cannot use 'keep' when original image is not a JPEG")
        subsampling = get_sampling(im)

    def validate_qtables(qtables):
        if qtables is None:
            return qtables
        if isStringType(qtables):
            try:
                lines = [int(num) for line in qtables.splitlines() for num in line.split("#", 1)[0].split()]
            except ValueError:
                raise ValueError("Invalid quantization table")
            else:
                qtables = [lines[s : s + 64] for s in xrange(0, len(lines), 64)]
        if isinstance(qtables, (tuple, list, dict)):
            if isinstance(qtables, dict):
                qtables = convert_dict_qtables(qtables)
            elif isinstance(qtables, tuple):
                qtables = list(qtables)
            if not (0 < len(qtables) < 5):
                raise ValueError("None or too many quantization tables")
            for idx, table in enumerate(qtables):
                try:
                    if len(table) != 64:
                        raise
                    table = array.array("b", table)
                except TypeError:
                    raise ValueError("Invalid quantization table")
                else:
                    qtables[idx] = list(table)
            return qtables

    if qtables == "keep":
        if im.format != "JPEG":
            raise ValueError("Cannot use 'keep' when original image is not a JPEG")
        qtables = getattr(im, "quantization", None)
    qtables = validate_qtables(qtables)

    extra = b""

    icc_profile = info.get("icc_profile")
    if icc_profile:
        ICC_OVERHEAD_LEN = 14
        MAX_BYTES_IN_MARKER = 65533
        MAX_DATA_BYTES_IN_MARKER = MAX_BYTES_IN_MARKER - ICC_OVERHEAD_LEN
        markers = []
        while icc_profile:
            markers.append(icc_profile[:MAX_DATA_BYTES_IN_MARKER])
            icc_profile = icc_profile[MAX_DATA_BYTES_IN_MARKER:]
        i = 1
        for marker in markers:
            size = struct.pack(">H", 2 + ICC_OVERHEAD_LEN + len(marker))
            extra = extra + (b"\xFF\xE2" + size + b"ICC_PROFILE\0" + o8(i) + o8(len(markers)) + marker)
            i = i + 1

    # get keyword arguments
    im.encoderconfig = (
        quality,
        # "progressive" is the official name, but older documentation
        # says "progression"
        # FIXME: issue a warning if the wrong form is used (post-1.1.7)
        "progressive" in info or "progression" in info,
        info.get("smooth", 0),
        "optimize" in info,
        info.get("streamtype", 0),
        dpi[0],
        dpi[1],
        subsampling,
        qtables,
        extra,
        info.get("exif", b""),
    )

    # if we optimize, libjpeg needs a buffer big enough to hold the whole image in a shot.
    # Guessing on the size, at im.size bytes. (raw pizel size is channels*size, this
    # is a value that's been used in a django patch.
    # https://github.com/jdriscoll/django-imagekit/issues/50
    bufsize = 0
    if "optimize" in info or "progressive" in info or "progression" in info:
        if quality >= 95:
            bufsize = 2 * im.size[0] * im.size[1]
        else:
            bufsize = im.size[0] * im.size[1]

    # The exif info needs to be written as one block, + APP1, + one spare byte.
    # Ensure that our buffer is big enough
    bufsize = max(ImageFile.MAXBLOCK, bufsize, len(info.get("exif", b"")) + 5)

    ImageFile._save(im, fp, [("jpeg", (0, 0) + im.size, 0, rawmode)], bufsize)
Exemple #40
0
def _save(im, fp, filename, chunk=putchunk, check=0):
    # save an image to disk (called by the save method)

    mode = im.mode

    if mode == "P":

        #
        # attempt to minimize storage requirements for palette images
        if "bits" in im.encoderinfo:
            # number of bits specified by user
            colors = 1 << im.encoderinfo["bits"]
        else:
            # check palette contents
            if im.palette:
                colors = max(min(len(im.palette.getdata()[1]) // 3, 256), 2)
            else:
                colors = 256

        if colors <= 2:
            bits = 1
        elif colors <= 4:
            bits = 2
        elif colors <= 16:
            bits = 4
        else:
            bits = 8
        if bits != 8:
            mode = "%s;%d" % (mode, bits)

    # encoder options
    if "dictionary" in im.encoderinfo:
        dictionary = im.encoderinfo["dictionary"]
    else:
        dictionary = b""

    im.encoderconfig = (
        "optimize" in im.encoderinfo,
        im.encoderinfo.get("compress_level", -1),
        im.encoderinfo.get("compress_type", -1),
        dictionary,
    )

    # get the corresponding PNG mode
    try:
        rawmode, mode = _OUTMODES[mode]
    except KeyError:
        raise IOError("cannot write mode %s as PNG" % mode)

    if check:
        return check

    #
    # write minimal PNG file

    fp.write(_MAGIC)

    chunk(
        fp,
        b"IHDR",
        o32(im.size[0]),
        o32(im.size[1]),  # 0: size
        mode,  # 8: depth/type
        b"\0",  # 10: compression
        b"\0",  # 11: filter category
        b"\0",
    )  # 12: interlace flag

    if im.mode == "P":
        palette_byte_number = (2 ** bits) * 3
        palette_bytes = im.im.getpalette("RGB")[:palette_byte_number]
        while len(palette_bytes) < palette_byte_number:
            palette_bytes += b"\0"
        chunk(fp, b"PLTE", palette_bytes)

    transparency = im.encoderinfo.get("transparency", im.info.get("transparency", None))

    if transparency or transparency == 0:
        if im.mode == "P":
            # limit to actual palette size
            alpha_bytes = 2 ** bits
            if isinstance(transparency, bytes):
                chunk(fp, b"tRNS", transparency[:alpha_bytes])
            else:
                transparency = max(0, min(255, transparency))
                alpha = b"\xFF" * transparency + b"\0"
                chunk(fp, b"tRNS", alpha[:alpha_bytes])
        elif im.mode == "L":
            transparency = max(0, min(65535, transparency))
            chunk(fp, b"tRNS", o16(transparency))
        elif im.mode == "RGB":
            red, green, blue = transparency
            chunk(fp, b"tRNS", o16(red) + o16(green) + o16(blue))
        else:
            if "transparency" in im.encoderinfo:
                # don't bother with transparency if it's an RGBA
                # and it's in the info dict. It's probably just stale.
                raise IOError("cannot use transparency for this mode")
    else:
        if im.mode == "P" and im.im.getpalettemode() == "RGBA":
            alpha = im.im.getpalette("RGBA", "A")
            alpha_bytes = 2 ** bits
            chunk(fp, b"tRNS", alpha[:alpha_bytes])

    dpi = im.encoderinfo.get("dpi")
    if dpi:
        chunk(fp, b"pHYs", o32(int(dpi[0] / 0.0254 + 0.5)), o32(int(dpi[1] / 0.0254 + 0.5)), b"\x01")

    info = im.encoderinfo.get("pnginfo")
    if info:
        for cid, data in info.chunks:
            chunk(fp, cid, data)

    # ICC profile writing support -- 2008-06-06 Florian Hoech
    if im.info.get("icc_profile"):
        # ICC profile
        # according to PNG spec, the iCCP chunk contains:
        # Profile name  1-79 bytes (character string)
        # Null separator        1 byte (null character)
        # Compression method    1 byte (0)
        # Compressed profile    n bytes (zlib with deflate compression)
        name = b"ICC Profile"
        data = name + b"\0\0" + zlib.compress(im.info["icc_profile"])
        chunk(fp, b"iCCP", data)

    ImageFile._save(im, _idat(fp, chunk), [("zip", (0, 0) + im.size, 0, rawmode)])

    chunk(fp, b"IEND", b"")

    if hasattr(fp, "flush"):
        fp.flush()
Exemple #41
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
Exemple #42
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
Exemple #43
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
def _save(im, fp, filename, check=0):
    try:
        rawmode, bits, colors = SAVE[im.mode]
    except KeyError:
        raise IOError("cannot write mode %s as BMP" % im.mode)

    if check:
        return check

    info = im.encoderinfo

    dpi = info.get("dpi", (96, 96))

    # 1 meter == 39.3701 inches
    ppm = tuple(map(lambda x: int(x * 39.3701), dpi))

    stride = ((im.size[0]*bits+7)//8+3) & (~3)
    header = 108 if im.mode == 'RGBA' else 40  # or 64 for OS/2 version 2
    offset = 14 + header + colors*4
    image = stride * im.size[1]

    red_mask = 0x00ff0000
    green_mask = 0x0000ff00
    blue_mask = 0x000000ff
    alpha_mask = 0xff000000

    # bitmap header
    fp.write(b"BM" +                      # file type (magic)
             o32(offset+image+16) +          # file size
             o32(0) +                     # reserved
             o32(offset+16))                 # image data offset

    width,height = im.size

    # bitmap info header
    fp.write(o32(header+16) +                # info header size
             o32(width) +            # width
             o32(height) +            # height
             o16(1) +                     # planes
             o16(bits) +                  # depth
             o32(3) +                     # compression (0=uncompressed)
             o32(image) +                 # size of bitmap
             o32(ppm[0]) + o32(ppm[1]) +  # resolution
             o32(colors) +                # colors used
             o32(colors)                # colors important
             #o32(red_mask) +              # red channel ma
             #o32(green_mask) +            # green channel mask
             #o32(blue_mask) +             # blue channel mask
             #o32(alpha_mask)
             )
    # This was commented out because although it works, some
    # decoders do not support images with a BI_BITFIELDS compression
    #
    if im.mode == 'RGBA':
        fp.write(o32(red_mask) +              # red channel mask
                 o32(green_mask) +            # green channel mask
                 o32(blue_mask) +             # blue channel mask
                 o32(alpha_mask) +            # alpha channel mask
                 'BGRs' +                     # Color Space
                 o8(0)*0x24 +                 # ciexyztriple color space endpoints
                 o32(0) +                     # red gamma
                 o32(0) +                     # green gamma
                 o32(0)                       # blue gamma
                 )

    fp.write(bytearray(16))

    if im.mode == "1":
        for i in (0, 255):
            fp.write(o8(i) * 4)
    elif im.mode == "L":
        for i in range(256):
            fp.write(o8(i) * 4)
    elif im.mode == "P":
        fp.write(im.im.getpalette("RGB", "BGRX"))

    #fp.write(
    ImageFile._save(im, fp, [("raw", (0, 0)+im.size, 0,
                    (rawmode, stride, -1))])
def _save(im, fp, filename, check=0):

    if im.mode == "P":

        # we assume this is a color Palm image with the standard colormap,
        # unless the "info" dict has a "custom-colormap" field

        rawmode = "P"
        bpp = 8
        version = 1

    elif (im.mode == "L" and
          "bpp" in im.encoderinfo and
          im.encoderinfo["bpp"] in (1, 2, 4)):

        # this is 8-bit grayscale, so we shift it to get the high-order bits,
        # and invert it because
        # Palm does greyscale from white (0) to black (1)
        bpp = im.encoderinfo["bpp"]
        im = im.point(
            lambda x, shift=8-bpp, maxval=(1 << bpp)-1: maxval - (x >> shift))
        # we ignore the palette here
        im.mode = "P"
        rawmode = "P;" + str(bpp)
        version = 1

    elif im.mode == "L" and "bpp" in im.info and im.info["bpp"] in (1, 2, 4):

        # here we assume that even though the inherent mode is 8-bit grayscale,
        # only the lower bpp bits are significant.
        # We invert them to match the Palm.
        bpp = im.info["bpp"]
        im = im.point(lambda x, maxval=(1 << bpp)-1: maxval - (x & maxval))
        # we ignore the palette here
        im.mode = "P"
        rawmode = "P;" + str(bpp)
        version = 1

    elif im.mode == "1":

        # monochrome -- write it inverted, as is the Palm standard
        rawmode = "1;I"
        bpp = 1
        version = 0

    else:

        raise IOError("cannot write mode %s as Palm" % im.mode)

    if check:
        return check

    #
    # make sure image data is available
    im.load()

    # write header

    cols = im.size[0]
    rows = im.size[1]

    rowbytes = int((cols + (16//bpp - 1)) / (16 // bpp)) * 2
    transparent_index = 0
    compression_type = _COMPRESSION_TYPES["none"]

    flags = 0
    if im.mode == "P" and "custom-colormap" in im.info:
        flags = flags & _FLAGS["custom-colormap"]
        colormapsize = 4 * 256 + 2
        colormapmode = im.palette.mode
        colormap = im.getdata().getpalette()
    else:
        colormapsize = 0

    if "offset" in im.info:
        offset = (rowbytes * rows + 16 + 3 + colormapsize) // 4
    else:
        offset = 0

    fp.write(o16b(cols) + o16b(rows) + o16b(rowbytes) + o16b(flags))
    fp.write(o8(bpp))
    fp.write(o8(version))
    fp.write(o16b(offset))
    fp.write(o8(transparent_index))
    fp.write(o8(compression_type))
    fp.write(o16b(0))   # reserved by Palm

    # now write colormap if necessary

    if colormapsize > 0:
        fp.write(o16b(256))
        for i in range(256):
            fp.write(o8(i))
            if colormapmode == 'RGB':
                fp.write(
                    o8(colormap[3 * i]) +
                    o8(colormap[3 * i + 1]) +
                    o8(colormap[3 * i + 2]))
            elif colormapmode == 'RGBA':
                fp.write(
                    o8(colormap[4 * i]) +
                    o8(colormap[4 * i + 1]) +
                    o8(colormap[4 * i + 2]))

    # now convert data to raw form
    ImageFile._save(
        im, fp, [("raw", (0, 0)+im.size, 0, (rawmode, rowbytes, 1))])

    fp.flush()