mirror of
https://github.com/python-pillow/Pillow.git
synced 2024-12-26 01:46:18 +03:00
initial merge of wiredfool/Python-Imaging-Library-G4-Tiff-Support
This commit is contained in:
parent
e782fe721e
commit
5ba6564e26
|
@ -50,6 +50,7 @@ from PIL import _binary
|
||||||
import array, sys
|
import array, sys
|
||||||
import collections
|
import collections
|
||||||
import itertools
|
import itertools
|
||||||
|
import os
|
||||||
|
|
||||||
II = b"II" # little-endian (intel-style)
|
II = b"II" # little-endian (intel-style)
|
||||||
MM = b"MM" # big-endian (motorola-style)
|
MM = b"MM" # big-endian (motorola-style)
|
||||||
|
@ -121,6 +122,8 @@ COMPRESSION_INFO = {
|
||||||
32773: "packbits"
|
32773: "packbits"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
COMPRESSION_INFO_REV = dict([(v,k) for (k,v) in COMPRESSION_INFO.items()])
|
||||||
|
|
||||||
OPEN_INFO = {
|
OPEN_INFO = {
|
||||||
# (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample,
|
# (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample,
|
||||||
# ExtraSamples) => mode, rawmode
|
# ExtraSamples) => mode, rawmode
|
||||||
|
@ -532,7 +535,12 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
self.__frame = -1
|
self.__frame = -1
|
||||||
self.__fp = self.fp
|
self.__fp = self.fp
|
||||||
|
|
||||||
# and load the first frame
|
if Image.DEBUG:
|
||||||
|
print "*** TiffImageFile._open ***"
|
||||||
|
print "- __first:", self.__first
|
||||||
|
print "- ifh: ", ifh
|
||||||
|
|
||||||
|
# and load the first frame
|
||||||
self._seek(0)
|
self._seek(0)
|
||||||
|
|
||||||
def seek(self, frame):
|
def seek(self, frame):
|
||||||
|
@ -567,7 +575,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
return self.__frame
|
return self.__frame
|
||||||
|
|
||||||
def _decoder(self, rawmode, layer):
|
def _decoder(self, rawmode, layer, tile=None):
|
||||||
"Setup decoder contexts"
|
"Setup decoder contexts"
|
||||||
|
|
||||||
args = None
|
args = None
|
||||||
|
@ -594,6 +602,63 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
|
|
||||||
return args
|
return args
|
||||||
|
|
||||||
|
def _load_libtiff(self):
|
||||||
|
""" Overload method triggered when we detect a g3/g4 tiff
|
||||||
|
Calls out to lib tiff """
|
||||||
|
|
||||||
|
pixel = Image.Image.load(self)
|
||||||
|
|
||||||
|
if self.tile is None:
|
||||||
|
raise IOError("cannot load this image")
|
||||||
|
if not self.tile:
|
||||||
|
return pixel
|
||||||
|
|
||||||
|
self.load_prepare()
|
||||||
|
|
||||||
|
if not len(self.tile) == 1:
|
||||||
|
raise IOError("Not exactly one tile")
|
||||||
|
|
||||||
|
d, e, o, a = self.tile[0]
|
||||||
|
d = Image._getdecoder(self.mode, d, a, self.decoderconfig)
|
||||||
|
try:
|
||||||
|
d.setimage(self.im, e)
|
||||||
|
except ValueError:
|
||||||
|
raise IOError("Couldn't set the image")
|
||||||
|
|
||||||
|
if hasattr(self.fp, "fileno"):
|
||||||
|
# we've got a actual file on disk, pass in the fp.
|
||||||
|
if Image.DEBUG:
|
||||||
|
print "have fileno, calling fileno version of the decoder."
|
||||||
|
self.fp.seek(0)
|
||||||
|
n,e = d.decode("fpfp") # 4 bytes, otherwise the trace might error out
|
||||||
|
elif hasattr(self.fp, "getvalue"):
|
||||||
|
# We've got a stringio like thing passed in. Yay for all in memory.
|
||||||
|
# The decoder needs the entire file in one shot, so there's not
|
||||||
|
# a lot we can do here other than give it the entire file.
|
||||||
|
# unless we could do something like get the address of the underlying
|
||||||
|
# string for stringio.
|
||||||
|
if Image.DEBUG:
|
||||||
|
print "have getvalue. just sending in a string from getvalue"
|
||||||
|
n,e = d.decode(self.fp.getvalue())
|
||||||
|
else:
|
||||||
|
# we have something else.
|
||||||
|
if Image.DEBUG:
|
||||||
|
print "don't have fileno or getvalue. just reading"
|
||||||
|
# UNDONE -- so much for that buffer size thing.
|
||||||
|
n, e = d.decode(self.fp.read())
|
||||||
|
|
||||||
|
|
||||||
|
self.tile = []
|
||||||
|
self.readonly = 0
|
||||||
|
self.fp = None # might be shared
|
||||||
|
|
||||||
|
if e < 0:
|
||||||
|
raise_ioerror(e)
|
||||||
|
|
||||||
|
self.load_end()
|
||||||
|
|
||||||
|
return Image.Image.load(self)
|
||||||
|
|
||||||
def _setup(self):
|
def _setup(self):
|
||||||
"Setup this image object based on current tags"
|
"Setup this image object based on current tags"
|
||||||
|
|
||||||
|
@ -669,20 +734,53 @@ class TiffImageFile(ImageFile.ImageFile):
|
||||||
self.tile = []
|
self.tile = []
|
||||||
if STRIPOFFSETS in self.tag:
|
if STRIPOFFSETS in self.tag:
|
||||||
# striped image
|
# striped image
|
||||||
|
offsets = self.tag[STRIPOFFSETS]
|
||||||
h = getscalar(ROWSPERSTRIP, ysize)
|
h = getscalar(ROWSPERSTRIP, ysize)
|
||||||
w = self.size[0]
|
w = self.size[0]
|
||||||
a = None
|
if self._compression in ["tiff_ccitt", "group3",
|
||||||
for o in self.tag[STRIPOFFSETS]:
|
"group4", "tiff_raw_16"]:
|
||||||
if not a:
|
if Image.DEBUG:
|
||||||
a = self._decoder(rawmode, l)
|
print "Activating g4 compression for whole file"
|
||||||
|
|
||||||
|
# Decoder expects entire file as one tile.
|
||||||
|
# There's a buffer size limit in load (64k)
|
||||||
|
# so large g4 images will fail if we use that
|
||||||
|
# function.
|
||||||
|
#
|
||||||
|
# Setup the one tile for the whole image, then
|
||||||
|
# replace the existing load function with our
|
||||||
|
# _load_libtiff function.
|
||||||
|
|
||||||
|
self.load = self._load_libtiff
|
||||||
|
|
||||||
|
# To be nice on memory footprint, if there's a
|
||||||
|
# file descriptor, use that instead of reading
|
||||||
|
# into a string in python.
|
||||||
|
|
||||||
|
# libtiff closes the file descriptor, so pass in a dup.
|
||||||
|
fp = hasattr(self.fp, "fileno") and os.dup(self.fp.fileno())
|
||||||
|
|
||||||
|
# Offset in the tile tuple is 0, we go from 0,0 to
|
||||||
|
# w,h, and we only do this once -- eds
|
||||||
|
a = (rawmode, self._compression, fp )
|
||||||
self.tile.append(
|
self.tile.append(
|
||||||
(self._compression,
|
(self._compression,
|
||||||
(0, min(y, ysize), w, min(y+h, ysize)),
|
(0, 0, w, ysize),
|
||||||
o, a))
|
0, a))
|
||||||
y = y + h
|
a = None
|
||||||
if y >= self.size[1]:
|
|
||||||
x = y = 0
|
else:
|
||||||
l = l + 1
|
for i in range(len(offsets)):
|
||||||
|
a = self._decoder(rawmode, l, i)
|
||||||
|
self.tile.append(
|
||||||
|
(self._compression,
|
||||||
|
(0, min(y, ysize), w, min(y+h, ysize)),
|
||||||
|
offsets[i], a))
|
||||||
|
print "tiles: %s" % self.tile
|
||||||
|
y = y + h
|
||||||
|
if y >= self.size[1]:
|
||||||
|
x = y = 0
|
||||||
|
l = l + 1
|
||||||
a = None
|
a = None
|
||||||
elif TILEOFFSETS in self.tag:
|
elif TILEOFFSETS in self.tag:
|
||||||
# tiled image
|
# tiled image
|
||||||
|
@ -764,8 +862,12 @@ def _save(im, fp, filename):
|
||||||
|
|
||||||
ifd = ImageFileDirectory(prefix)
|
ifd = ImageFileDirectory(prefix)
|
||||||
|
|
||||||
|
compression = im.info.get('compression','raw')
|
||||||
|
libtiff = compression in ["tiff_ccitt", "group3",
|
||||||
|
"group4", "tiff_raw_16"]
|
||||||
|
|
||||||
# -- multi-page -- skip TIFF header on subsequent pages
|
# -- multi-page -- skip TIFF header on subsequent pages
|
||||||
if fp.tell() == 0:
|
if not libtiff and fp.tell() == 0:
|
||||||
# tiff header (write via IFD to get everything right)
|
# tiff header (write via IFD to get everything right)
|
||||||
# PIL always starts the first IFD at offset 8
|
# PIL always starts the first IFD at offset 8
|
||||||
fp.write(ifd.prefix + ifd.o16(42) + ifd.o32(8))
|
fp.write(ifd.prefix + ifd.o16(42) + ifd.o32(8))
|
||||||
|
@ -842,13 +944,65 @@ def _save(im, fp, filename):
|
||||||
ifd[ROWSPERSTRIP] = im.size[1]
|
ifd[ROWSPERSTRIP] = im.size[1]
|
||||||
ifd[STRIPBYTECOUNTS] = stride * im.size[1]
|
ifd[STRIPBYTECOUNTS] = stride * im.size[1]
|
||||||
ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
|
ifd[STRIPOFFSETS] = 0 # this is adjusted by IFD writer
|
||||||
ifd[COMPRESSION] = 1 # no compression
|
ifd[COMPRESSION] = COMPRESSION_INFO_REV.get(compression,1) # no compression by default
|
||||||
|
|
||||||
offset = ifd.save(fp)
|
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())
|
||||||
|
|
||||||
ImageFile._save(im, fp, [
|
blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP, ICCPROFILE] # ICC Profile crashes.
|
||||||
("raw", (0,0)+im.size, offset, (rawmode, stride, 1))
|
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 --
|
# -- helper for multi-page save --
|
||||||
|
|
13
_imaging.c
13
_imaging.c
|
@ -3205,6 +3205,7 @@ extern PyObject* PyImaging_GifDecoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_HexDecoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_HexDecoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_JpegDecoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_JpegDecoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_TiffLzwDecoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_TiffLzwDecoderNew(PyObject* self, PyObject* args);
|
||||||
|
extern PyObject* PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_MspDecoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_MspDecoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_PackbitsDecoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_PackbitsDecoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_PcdDecoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_PcdDecoderNew(PyObject* self, PyObject* args);
|
||||||
|
@ -3223,6 +3224,7 @@ extern PyObject* PyImaging_PcxEncoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_RawEncoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_RawEncoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_XbmEncoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_XbmEncoderNew(PyObject* self, PyObject* args);
|
||||||
extern PyObject* PyImaging_ZipEncoderNew(PyObject* self, PyObject* args);
|
extern PyObject* PyImaging_ZipEncoderNew(PyObject* self, PyObject* args);
|
||||||
|
extern PyObject* PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args);
|
||||||
|
|
||||||
/* Display support etc (in display.c) */
|
/* Display support etc (in display.c) */
|
||||||
#ifdef WIN32
|
#ifdef WIN32
|
||||||
|
@ -3272,6 +3274,17 @@ static PyMethodDef functions[] = {
|
||||||
{"jpeg_encoder", (PyCFunction)PyImaging_JpegEncoderNew, 1},
|
{"jpeg_encoder", (PyCFunction)PyImaging_JpegEncoderNew, 1},
|
||||||
#endif
|
#endif
|
||||||
{"tiff_lzw_decoder", (PyCFunction)PyImaging_TiffLzwDecoderNew, 1},
|
{"tiff_lzw_decoder", (PyCFunction)PyImaging_TiffLzwDecoderNew, 1},
|
||||||
|
#ifdef HAVE_LIBTIFF
|
||||||
|
{"tiff_ccitt_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
|
||||||
|
{"group3_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
|
||||||
|
{"group4_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
|
||||||
|
{"tiff_raw_16_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
|
||||||
|
|
||||||
|
{"tiff_ccitt_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
|
||||||
|
{"group3_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
|
||||||
|
{"group4_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
|
||||||
|
{"tiff_raw_16_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
|
||||||
|
#endif
|
||||||
{"msp_decoder", (PyCFunction)PyImaging_MspDecoderNew, 1},
|
{"msp_decoder", (PyCFunction)PyImaging_MspDecoderNew, 1},
|
||||||
{"packbits_decoder", (PyCFunction)PyImaging_PackbitsDecoderNew, 1},
|
{"packbits_decoder", (PyCFunction)PyImaging_PackbitsDecoderNew, 1},
|
||||||
{"pcd_decoder", (PyCFunction)PyImaging_PcdDecoderNew, 1},
|
{"pcd_decoder", (PyCFunction)PyImaging_PcdDecoderNew, 1},
|
||||||
|
|
69
decode.c
69
decode.c
|
@ -388,6 +388,75 @@ PyImaging_TiffLzwDecoderNew(PyObject* self, PyObject* args)
|
||||||
return (PyObject*) decoder;
|
return (PyObject*) decoder;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* LibTiff */
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBTIFF
|
||||||
|
|
||||||
|
#include "Tiff.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef __WIN32__
|
||||||
|
#define strcasecmp(s1, s2) stricmp(s1, s2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PyObject*
|
||||||
|
PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
ImagingDecoderObject* decoder;
|
||||||
|
char* mode;
|
||||||
|
char* rawmode;
|
||||||
|
char* compname;
|
||||||
|
int compression;
|
||||||
|
int fp;
|
||||||
|
|
||||||
|
if (! PyArg_ParseTuple(args, "sssi", &mode, &rawmode, &compname, &fp))
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
TRACE(("new tiff decoder %s\n", compname));
|
||||||
|
|
||||||
|
/* UNDONE -- we can probably do almost any arbitrary compression here,
|
||||||
|
* since we're effective passing in the whole file in one shot and
|
||||||
|
* getting back the data row by row. V2 maybe
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (strcasecmp(compname, "tiff_ccitt") == 0) {
|
||||||
|
compression = COMPRESSION_CCITTRLE;
|
||||||
|
|
||||||
|
} else if (strcasecmp(compname, "group3") == 0) {
|
||||||
|
compression = COMPRESSION_CCITTFAX3;
|
||||||
|
|
||||||
|
} else if (strcasecmp(compname, "group4") == 0) {
|
||||||
|
compression = COMPRESSION_CCITTFAX4;
|
||||||
|
|
||||||
|
} else if (strcasecmp(compname, "tiff_raw_16") == 0) {
|
||||||
|
compression = COMPRESSION_CCITTRLEW;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "unknown compession");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder = PyImaging_DecoderNew(sizeof(TIFFSTATE));
|
||||||
|
if (decoder == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (get_unpacker(decoder, mode, rawmode) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (! ImagingLibTiffInit(&decoder->state, compression, fp)) {
|
||||||
|
Py_DECREF(decoder);
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
decoder->decode = ImagingLibTiffDecode;
|
||||||
|
|
||||||
|
return (PyObject*) decoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
/* -------------------------------------------------------------------- */
|
/* -------------------------------------------------------------------- */
|
||||||
/* MSP */
|
/* MSP */
|
||||||
|
|
130
encode.c
130
encode.c
|
@ -644,3 +644,133 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
|
||||||
}
|
}
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
/* LibTiff */
|
||||||
|
/* -------------------------------------------------------------------- */
|
||||||
|
|
||||||
|
#ifdef HAVE_LIBTIFF
|
||||||
|
|
||||||
|
#include "Tiff.h"
|
||||||
|
|
||||||
|
#include <string.h>
|
||||||
|
#ifdef __WIN32__
|
||||||
|
#define strcasecmp(s1, s2) stricmp(s1, s2)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
PyObject*
|
||||||
|
PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
|
||||||
|
{
|
||||||
|
ImagingEncoderObject* encoder;
|
||||||
|
|
||||||
|
char* mode;
|
||||||
|
char* rawmode;
|
||||||
|
char* compname;
|
||||||
|
char* filename;
|
||||||
|
int compression;
|
||||||
|
int fp;
|
||||||
|
|
||||||
|
PyObject *dir;
|
||||||
|
PyObject *key, *value;
|
||||||
|
Py_ssize_t pos = 0;
|
||||||
|
int status;
|
||||||
|
|
||||||
|
if (! PyArg_ParseTuple(args, "sssisO", &mode, &rawmode, &compname, &fp, &filename, &dir)) {
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!PyDict_Check(dir)) {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "Invalid Dictionary");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
TRACE(("new tiff encoder %s fp: %d, filename: %s \n", compname, fp, filename));
|
||||||
|
|
||||||
|
/* UNDONE -- we can probably do almost any arbitrary compression here,
|
||||||
|
* so long as we're doing row/stripe based actions and not tiles.
|
||||||
|
*/
|
||||||
|
|
||||||
|
if (strcasecmp(compname, "tiff_ccitt") == 0) {
|
||||||
|
compression = COMPRESSION_CCITTRLE;
|
||||||
|
|
||||||
|
} else if (strcasecmp(compname, "group3") == 0) {
|
||||||
|
compression = COMPRESSION_CCITTFAX3;
|
||||||
|
|
||||||
|
} else if (strcasecmp(compname, "group4") == 0) {
|
||||||
|
compression = COMPRESSION_CCITTFAX4;
|
||||||
|
|
||||||
|
} else if (strcasecmp(compname, "tiff_raw_16") == 0) {
|
||||||
|
compression = COMPRESSION_CCITTRLEW;
|
||||||
|
|
||||||
|
} else {
|
||||||
|
PyErr_SetString(PyExc_ValueError, "unknown compession");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder = PyImaging_EncoderNew(sizeof(TIFFSTATE));
|
||||||
|
if (encoder == NULL)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (get_packer(encoder, mode, rawmode) < 0)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
if (! ImagingLibTiffEncodeInit(&encoder->state, filename, fp)) {
|
||||||
|
Py_DECREF(encoder);
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
while (PyDict_Next(dir, &pos, &key, &value)) {
|
||||||
|
status = 0;
|
||||||
|
if (PyInt_Check(value)) {
|
||||||
|
TRACE(("Setting from Int: %d %ld \n", (int)PyInt_AsLong(key),PyInt_AsLong(value)));
|
||||||
|
status = ImagingLibTiffSetField(&encoder->state,
|
||||||
|
(ttag_t) PyInt_AsLong(key),
|
||||||
|
PyInt_AsLong(value));
|
||||||
|
} else if(PyString_Check(value)) {
|
||||||
|
TRACE(("Setting from String: %d, %s \n", (int)PyInt_AsLong(key),PyString_AsString(value)));
|
||||||
|
status = ImagingLibTiffSetField(&encoder->state,
|
||||||
|
(ttag_t) PyInt_AsLong(key),
|
||||||
|
PyString_AsString(value));
|
||||||
|
|
||||||
|
} else if(PyList_Check(value)) {
|
||||||
|
int len,i;
|
||||||
|
float *floatav;
|
||||||
|
TRACE(("Setting from List: %d \n", (int)PyInt_AsLong(key)));
|
||||||
|
len = (int)PyList_Size(value);
|
||||||
|
TRACE((" %d elements, setting as floats \n", len));
|
||||||
|
floatav = malloc(sizeof(float)*len);
|
||||||
|
if (floatav) {
|
||||||
|
for (i=0;i<len;i++) {
|
||||||
|
floatav[i] = (float)PyFloat_AsDouble(PyList_GetItem(value,i));
|
||||||
|
}
|
||||||
|
status = ImagingLibTiffSetField(&encoder->state,
|
||||||
|
(ttag_t) PyInt_AsLong(key),
|
||||||
|
floatav);
|
||||||
|
free(floatav);
|
||||||
|
}
|
||||||
|
} else if (PyFloat_Check(value)) {
|
||||||
|
TRACE(("Setting from String: %d, %f \n", (int)PyInt_AsLong(key),PyFloat_AsDouble(value)));
|
||||||
|
status = ImagingLibTiffSetField(&encoder->state,
|
||||||
|
(ttag_t) PyInt_AsLong(key),
|
||||||
|
(float)PyFloat_AsDouble(value));
|
||||||
|
} else {
|
||||||
|
TRACE(("Unhandled type for key %d : %s ",
|
||||||
|
(int)PyInt_AsLong(key),
|
||||||
|
PyString_AsString(PyObject_Str(value))));
|
||||||
|
}
|
||||||
|
if (!status) {
|
||||||
|
TRACE(("Error setting Field\n"));
|
||||||
|
Py_DECREF(encoder);
|
||||||
|
PyErr_SetString(PyExc_RuntimeError, "Error setting from dictionary");
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
encoder->encode = ImagingLibTiffEncode;
|
||||||
|
|
||||||
|
return (PyObject*) encoder;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
|
|
@ -420,6 +420,12 @@ extern int ImagingJpegEncode(Imaging im, ImagingCodecState state,
|
||||||
#endif
|
#endif
|
||||||
extern int ImagingLzwDecode(Imaging im, ImagingCodecState state,
|
extern int ImagingLzwDecode(Imaging im, ImagingCodecState state,
|
||||||
UINT8* buffer, int bytes);
|
UINT8* buffer, int bytes);
|
||||||
|
#ifdef HAVE_LIBTIFF
|
||||||
|
extern int ImagingLibTiffDecode(Imaging im, ImagingCodecState state,
|
||||||
|
UINT8* buffer, int bytes);
|
||||||
|
extern int ImagingLibTiffEncode(Imaging im, ImagingCodecState state,
|
||||||
|
UINT8* buffer, int bytes);
|
||||||
|
#endif
|
||||||
#ifdef HAVE_LIBMPEG
|
#ifdef HAVE_LIBMPEG
|
||||||
extern int ImagingMpegDecode(Imaging im, ImagingCodecState state,
|
extern int ImagingMpegDecode(Imaging im, ImagingCodecState state,
|
||||||
UINT8* buffer, int bytes);
|
UINT8* buffer, int bytes);
|
||||||
|
|
|
@ -186,6 +186,7 @@ if __name__ == "__main__":
|
||||||
check_module("TKINTER", "_imagingtk")
|
check_module("TKINTER", "_imagingtk")
|
||||||
check_codec("JPEG", "jpeg")
|
check_codec("JPEG", "jpeg")
|
||||||
check_codec("ZLIB (PNG/ZIP)", "zip")
|
check_codec("ZLIB (PNG/ZIP)", "zip")
|
||||||
|
check_codec("G4 TIFF", "group4")
|
||||||
check_module("FREETYPE2", "_imagingft")
|
check_module("FREETYPE2", "_imagingft")
|
||||||
check_module("LITTLECMS", "_imagingcms")
|
check_module("LITTLECMS", "_imagingcms")
|
||||||
print("-"*68)
|
print("-"*68)
|
||||||
|
@ -201,3 +202,4 @@ if __name__ == "__main__":
|
||||||
print("--- %s tests passed." % status[1])
|
print("--- %s tests passed." % status[1])
|
||||||
|
|
||||||
sys.exit(exit_status)
|
sys.exit(exit_status)
|
||||||
|
|
||||||
|
|
15
setup.py
15
setup.py
|
@ -26,7 +26,7 @@ _LIB_IMAGING = (
|
||||||
"QuantHeap", "PcdDecode", "PcxDecode", "PcxEncode", "Point",
|
"QuantHeap", "PcdDecode", "PcxDecode", "PcxEncode", "Point",
|
||||||
"RankFilter", "RawDecode", "RawEncode", "Storage", "SunRleDecode",
|
"RankFilter", "RawDecode", "RawEncode", "Storage", "SunRleDecode",
|
||||||
"TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask", "XbmDecode",
|
"TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask", "XbmDecode",
|
||||||
"XbmEncode", "ZipDecode", "ZipEncode")
|
"XbmEncode", "ZipDecode", "ZipEncode", "TiffDecode")
|
||||||
|
|
||||||
|
|
||||||
def _add_directory(path, dir, where=None):
|
def _add_directory(path, dir, where=None):
|
||||||
|
@ -76,7 +76,7 @@ PIL_VERSION = '1.1.7'
|
||||||
TCL_ROOT = None
|
TCL_ROOT = None
|
||||||
JPEG_ROOT = None
|
JPEG_ROOT = None
|
||||||
ZLIB_ROOT = None
|
ZLIB_ROOT = None
|
||||||
TIFF_ROOT = None
|
TIFF_ROOT = None
|
||||||
FREETYPE_ROOT = None
|
FREETYPE_ROOT = None
|
||||||
LCMS_ROOT = None
|
LCMS_ROOT = None
|
||||||
|
|
||||||
|
@ -156,6 +156,7 @@ class pil_build_ext(build_ext):
|
||||||
#
|
#
|
||||||
# locate tkinter libraries
|
# locate tkinter libraries
|
||||||
|
|
||||||
|
|
||||||
if _tkinter:
|
if _tkinter:
|
||||||
TCL_VERSION = _tkinter.TCL_VERSION[:3]
|
TCL_VERSION = _tkinter.TCL_VERSION[:3]
|
||||||
|
|
||||||
|
@ -183,6 +184,7 @@ class pil_build_ext(build_ext):
|
||||||
break
|
break
|
||||||
else:
|
else:
|
||||||
TCL_ROOT = None
|
TCL_ROOT = None
|
||||||
|
|
||||||
|
|
||||||
#
|
#
|
||||||
# add standard directories
|
# add standard directories
|
||||||
|
@ -229,6 +231,10 @@ class pil_build_ext(build_ext):
|
||||||
|
|
||||||
if _find_library_file(self, "tiff"):
|
if _find_library_file(self, "tiff"):
|
||||||
feature.tiff = "tiff"
|
feature.tiff = "tiff"
|
||||||
|
if sys.platform == "win32" and find_library_file(self, "libtiff"):
|
||||||
|
feature.tiff = "libtiff"
|
||||||
|
if sys.platform == "darwin" and find_library_file(self, "libtiff"):
|
||||||
|
feature.tiff = "libtiff"
|
||||||
|
|
||||||
if _find_library_file(self, "freetype"):
|
if _find_library_file(self, "freetype"):
|
||||||
# look for freetype2 include files
|
# look for freetype2 include files
|
||||||
|
@ -284,6 +290,9 @@ class pil_build_ext(build_ext):
|
||||||
if feature.zlib:
|
if feature.zlib:
|
||||||
libs.append(feature.zlib)
|
libs.append(feature.zlib)
|
||||||
defs.append(("HAVE_LIBZ", None))
|
defs.append(("HAVE_LIBZ", None))
|
||||||
|
if feature.tiff:
|
||||||
|
libs.append(feature.tiff)
|
||||||
|
defs.append(("HAVE_LIBTIFF", None))
|
||||||
if sys.platform == "win32":
|
if sys.platform == "win32":
|
||||||
libs.extend(["kernel32", "user32", "gdi32"])
|
libs.extend(["kernel32", "user32", "gdi32"])
|
||||||
if struct.unpack("h", "\0\1".encode('ascii'))[0] == 1:
|
if struct.unpack("h", "\0\1".encode('ascii'))[0] == 1:
|
||||||
|
@ -373,7 +382,7 @@ class pil_build_ext(build_ext):
|
||||||
(feature.tcl and feature.tk, "TKINTER"),
|
(feature.tcl and feature.tk, "TKINTER"),
|
||||||
(feature.jpeg, "JPEG"),
|
(feature.jpeg, "JPEG"),
|
||||||
(feature.zlib, "ZLIB (PNG/ZIP)"),
|
(feature.zlib, "ZLIB (PNG/ZIP)"),
|
||||||
# (feature.tiff, "experimental TIFF G3/G4 read"),
|
(feature.tiff, "experimental TIFF G3/G4 read"),
|
||||||
(feature.freetype, "FREETYPE2"),
|
(feature.freetype, "FREETYPE2"),
|
||||||
(feature.lcms, "LITTLECMS"),
|
(feature.lcms, "LITTLECMS"),
|
||||||
]
|
]
|
||||||
|
|
Loading…
Reference in New Issue
Block a user