mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-01-26 17:24:31 +03:00
commit
62bb9aaaa2
|
@ -50,6 +50,7 @@ from PIL import _binary
|
|||
import array, sys
|
||||
import collections
|
||||
import itertools
|
||||
import os
|
||||
|
||||
II = b"II" # little-endian (intel-style)
|
||||
MM = b"MM" # big-endian (motorola-style)
|
||||
|
@ -121,6 +122,8 @@ COMPRESSION_INFO = {
|
|||
32773: "packbits"
|
||||
}
|
||||
|
||||
COMPRESSION_INFO_REV = dict([(v,k) for (k,v) in COMPRESSION_INFO.items()])
|
||||
|
||||
OPEN_INFO = {
|
||||
# (ByteOrder, PhotoInterpretation, SampleFormat, FillOrder, BitsPerSample,
|
||||
# ExtraSamples) => mode, rawmode
|
||||
|
@ -532,7 +535,12 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
self.__frame = -1
|
||||
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)
|
||||
|
||||
def seek(self, frame):
|
||||
|
@ -567,7 +575,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
|
||||
return self.__frame
|
||||
|
||||
def _decoder(self, rawmode, layer):
|
||||
def _decoder(self, rawmode, layer, tile=None):
|
||||
"Setup decoder contexts"
|
||||
|
||||
args = None
|
||||
|
@ -594,6 +602,63 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
|
||||
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):
|
||||
"Setup this image object based on current tags"
|
||||
|
||||
|
@ -669,20 +734,54 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
self.tile = []
|
||||
if STRIPOFFSETS in self.tag:
|
||||
# striped image
|
||||
offsets = self.tag[STRIPOFFSETS]
|
||||
h = getscalar(ROWSPERSTRIP, ysize)
|
||||
w = self.size[0]
|
||||
a = None
|
||||
for o in self.tag[STRIPOFFSETS]:
|
||||
if not a:
|
||||
a = self._decoder(rawmode, l)
|
||||
if self._compression in ["tiff_ccitt", "group3",
|
||||
"group4", "tiff_raw_16"]:
|
||||
## if Image.DEBUG:
|
||||
## 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._compression,
|
||||
(0, min(y, ysize), w, min(y+h, ysize)),
|
||||
o, a))
|
||||
y = y + h
|
||||
if y >= self.size[1]:
|
||||
x = y = 0
|
||||
l = l + 1
|
||||
(0, 0, w, ysize),
|
||||
0, a))
|
||||
a = None
|
||||
|
||||
else:
|
||||
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))
|
||||
if Image.DEBUG:
|
||||
print ("tiles: ", self.tile)
|
||||
y = y + h
|
||||
if y >= self.size[1]:
|
||||
x = y = 0
|
||||
l = l + 1
|
||||
a = None
|
||||
elif TILEOFFSETS in self.tag:
|
||||
# tiled image
|
||||
|
@ -764,8 +863,12 @@ def _save(im, fp, filename):
|
|||
|
||||
ifd = ImageFileDirectory(prefix)
|
||||
|
||||
compression = im.info.get('compression','raw')
|
||||
libtiff = compression in ["tiff_ccitt", "group3",
|
||||
"group4", "tiff_raw_16"]
|
||||
|
||||
# -- multi-page -- skip TIFF header on subsequent pages
|
||||
if fp.tell() == 0:
|
||||
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))
|
||||
|
@ -842,13 +945,65 @@ def _save(im, fp, filename):
|
|||
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
|
||||
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, [
|
||||
("raw", (0,0)+im.size, offset, (rawmode, stride, 1))
|
||||
])
|
||||
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 --
|
||||
|
|
BIN
Tests/images/lena_bw.png
Normal file
BIN
Tests/images/lena_bw.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 1.9 KiB |
BIN
Tests/images/lena_bw_500.png
Normal file
BIN
Tests/images/lena_bw_500.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 18 KiB |
BIN
Tests/images/lena_g4.tif
Normal file
BIN
Tests/images/lena_g4.tif
Normal file
Binary file not shown.
BIN
Tests/images/lena_g4_500.tif
Normal file
BIN
Tests/images/lena_g4_500.tif
Normal file
Binary file not shown.
BIN
Tests/images/pport_g4.tif
Normal file
BIN
Tests/images/pport_g4.tif
Normal file
Binary file not shown.
|
@ -2,6 +2,9 @@ from tester import *
|
|||
|
||||
from PIL import Image
|
||||
|
||||
import StringIO
|
||||
import random
|
||||
|
||||
def test_sanity():
|
||||
|
||||
file = tempfile("temp.tif")
|
||||
|
@ -55,3 +58,98 @@ def test_gimp_tiff():
|
|||
('jpeg', (0, 192, 256, 256), 3890, ('RGB', '')),
|
||||
])
|
||||
assert_no_exception(lambda: im.load())
|
||||
|
||||
def _assert_noerr(im):
|
||||
"""Helper tests that assert basic sanity about the g4 tiff reading"""
|
||||
#1 bit
|
||||
assert_equal(im.mode, "1")
|
||||
|
||||
# Does the data actually load
|
||||
assert_no_exception(lambda: im.load())
|
||||
assert_no_exception(lambda: im.getdata())
|
||||
|
||||
try:
|
||||
assert_equal(im._compression, 'group4')
|
||||
except:
|
||||
print "No _compression"
|
||||
print (dir(im))
|
||||
|
||||
# can we write it back out, in a different form.
|
||||
out = tempfile("temp.png")
|
||||
assert_no_exception(lambda: im.save(out))
|
||||
|
||||
def test_g4_tiff():
|
||||
"""Test the ordinary file path load path"""
|
||||
|
||||
file = "Tests/images/lena_g4_500.tif"
|
||||
im = Image.open(file)
|
||||
|
||||
assert_equal(im.size, (500,500))
|
||||
_assert_noerr(im)
|
||||
|
||||
def test_g4_large():
|
||||
file = "Tests/images/pport_g4.tif"
|
||||
im = Image.open(file)
|
||||
_assert_noerr(im)
|
||||
|
||||
def test_g4_tiff_file():
|
||||
"""Testing the string load path"""
|
||||
|
||||
file = "Tests/images/lena_g4_500.tif"
|
||||
with open(file,'rb') as f:
|
||||
im = Image.open(f)
|
||||
|
||||
assert_equal(im.size, (500,500))
|
||||
_assert_noerr(im)
|
||||
|
||||
def test_g4_tiff_stringio():
|
||||
"""Testing the stringio loading code path"""
|
||||
|
||||
file = "Tests/images/lena_g4_500.tif"
|
||||
s = StringIO.StringIO()
|
||||
with open(file,'rb') as f:
|
||||
s.write(f.read())
|
||||
s.seek(0)
|
||||
im = Image.open(s)
|
||||
|
||||
assert_equal(im.size, (500,500))
|
||||
_assert_noerr(im)
|
||||
|
||||
def test_g4_tiff_fail(): # UNDONE fails badly, unknown reason
|
||||
"""The 128x128 lena image fails for some reason. Investigating"""
|
||||
|
||||
Image.DEBUG = True
|
||||
file = "Tests/images/lena_g4.tif"
|
||||
im = Image.open(file)
|
||||
|
||||
assert_equal(im.size, (128,128))
|
||||
_assert_noerr(im)
|
||||
Image.DEBUG = False
|
||||
|
||||
def test_g4_eq_png():
|
||||
""" Checking that we're actually getting the data that we expect"""
|
||||
png = Image.open('Tests/images/lena_bw_500.png')
|
||||
g4 = Image.open('Tests/images/lena_g4_500.tif')
|
||||
|
||||
assert_image_equal(g4, png)
|
||||
|
||||
def test_g4_write():
|
||||
"""Checking to see that the saved image is the same as what we wrote"""
|
||||
Image.DEBUG = True
|
||||
|
||||
file = "Tests/images/lena_g4_500.tif"
|
||||
orig = Image.open(file)
|
||||
|
||||
out = "temp.tif"
|
||||
rot = orig.transpose(Image.ROTATE_90)
|
||||
assert_equal(rot.size,(500,500))
|
||||
rot.save(out)
|
||||
|
||||
reread = Image.open(out)
|
||||
assert_equal(reread.size,(500,500))
|
||||
_assert_noerr(reread)
|
||||
assert_image_equal(reread, rot)
|
||||
|
||||
assert_false(orig.tobytes() == reread.tobytes())
|
||||
|
||||
Image.DEBUG = False
|
||||
|
|
13
_imaging.c
13
_imaging.c
|
@ -3236,6 +3236,7 @@ extern PyObject* PyImaging_GifDecoderNew(PyObject* self, PyObject* args);
|
|||
extern PyObject* PyImaging_HexDecoderNew(PyObject* self, PyObject* args);
|
||||
extern PyObject* PyImaging_JpegDecoderNew(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_PackbitsDecoderNew(PyObject* self, PyObject* args);
|
||||
extern PyObject* PyImaging_PcdDecoderNew(PyObject* self, PyObject* args);
|
||||
|
@ -3254,6 +3255,7 @@ extern PyObject* PyImaging_PcxEncoderNew(PyObject* self, PyObject* args);
|
|||
extern PyObject* PyImaging_RawEncoderNew(PyObject* self, PyObject* args);
|
||||
extern PyObject* PyImaging_XbmEncoderNew(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) */
|
||||
#ifdef WIN32
|
||||
|
@ -3303,6 +3305,17 @@ static PyMethodDef functions[] = {
|
|||
{"jpeg_encoder", (PyCFunction)PyImaging_JpegEncoderNew, 1},
|
||||
#endif
|
||||
{"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},
|
||||
{"packbits_decoder", (PyCFunction)PyImaging_PackbitsDecoderNew, 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;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
/* 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 */
|
||||
|
|
151
encode.c
151
encode.c
|
@ -650,3 +650,154 @@ PyImaging_JpegEncoderNew(PyObject* self, PyObject* args)
|
|||
}
|
||||
|
||||
#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;
|
||||
|
||||
Py_ssize_t d_size;
|
||||
PyObject *keys, *values;
|
||||
|
||||
|
||||
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;
|
||||
} else {
|
||||
d_size = PyDict_Size(dir);
|
||||
TRACE(("dict size: %d\n", (int)d_size));
|
||||
keys = PyDict_Keys(dir);
|
||||
values = PyDict_Values(dir);
|
||||
for (pos=0;pos<d_size;pos++){
|
||||
TRACE((" key: %d\n", (int)PyInt_AsLong(PyList_GetItem(keys,pos))));
|
||||
}
|
||||
pos = 0;
|
||||
}
|
||||
|
||||
|
||||
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;
|
||||
}
|
||||
|
||||
TRACE(("Found compression: %d\n", compression));
|
||||
|
||||
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 failes on 64 bit machines, complains that pos is an int instead of a Py_ssize_t
|
||||
// while (PyDict_Next(dir, &pos, &key, &value)) {
|
||||
for (pos=0;pos<d_size;pos++){
|
||||
key = PyList_GetItem(keys,pos);
|
||||
value = PyList_GetItem(values,pos);
|
||||
status = 0;
|
||||
TRACE(("Attempting to set key: %d\n", (int)PyInt_AsLong(key)));
|
||||
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(PyBytes_Check(value)) {
|
||||
TRACE(("Setting from String: %d, %s \n", (int)PyInt_AsLong(key),PyBytes_AsString(value)));
|
||||
status = ImagingLibTiffSetField(&encoder->state,
|
||||
(ttag_t) PyInt_AsLong(key),
|
||||
PyBytes_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),
|
||||
PyBytes_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
|
||||
extern int ImagingLzwDecode(Imaging im, ImagingCodecState state,
|
||||
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
|
||||
extern int ImagingMpegDecode(Imaging im, ImagingCodecState state,
|
||||
UINT8* buffer, int bytes);
|
||||
|
|
57
libImaging/Tiff.h
Normal file
57
libImaging/Tiff.h
Normal file
|
@ -0,0 +1,57 @@
|
|||
/*
|
||||
* The Python Imaging Library.
|
||||
* $Id: //modules/pil/libImaging/Tiff.h#1 $
|
||||
*
|
||||
* declarations for the LibTiff-based Group3 and Group4 decoder
|
||||
*
|
||||
*/
|
||||
|
||||
#ifndef _TIFFIO_
|
||||
#include <tiffio.h>
|
||||
#endif
|
||||
#ifndef _TIFF_
|
||||
#include <tiff.h>
|
||||
#endif
|
||||
|
||||
#ifndef min
|
||||
#define min(x,y) (( x > y ) ? y : x )
|
||||
#define max(x,y) (( x < y ) ? y : x )
|
||||
#endif
|
||||
|
||||
#ifndef _PIL_LIBTIFF_
|
||||
#define _PIL_LIBTIFF_
|
||||
|
||||
typedef struct {
|
||||
tdata_t data; /* tdata_t == void* */
|
||||
toff_t loc; /* toff_t == uint32 */
|
||||
tsize_t size; /* tsize_t == int32 */
|
||||
int fp;
|
||||
TIFF *tiff; /* Used in write */
|
||||
toff_t eof;
|
||||
int flrealloc; /* may we realloc */
|
||||
} TIFFSTATE;
|
||||
|
||||
|
||||
|
||||
extern int ImagingLibTiffInit(ImagingCodecState state, int compression, int fp);
|
||||
extern int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp);
|
||||
extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...);
|
||||
|
||||
|
||||
#if defined(_MSC_VER) && (_MSC_VER == 1310)
|
||||
/* VS2003/py2.4 can't use varargs. Skipping trace for now.*/
|
||||
#define TRACE(args)
|
||||
#else
|
||||
|
||||
|
||||
#define VA_ARGS(...) __VA_ARGS__
|
||||
#define TRACE(args) fprintf(stderr, VA_ARGS args)
|
||||
|
||||
/*
|
||||
#define TRACE(args)
|
||||
*/
|
||||
#endif
|
||||
|
||||
|
||||
|
||||
#endif
|
417
libImaging/TiffDecode.c
Normal file
417
libImaging/TiffDecode.c
Normal file
|
@ -0,0 +1,417 @@
|
|||
/*
|
||||
* The Python Imaging Library.
|
||||
* $Id: //modules/pil/libImaging/TiffDecode.c#1 $
|
||||
*
|
||||
* LibTiff-based Group3 and Group4 decoder
|
||||
*
|
||||
*
|
||||
* started modding to use non-private tiff functions to port to libtiff 4.x
|
||||
* eds 3/12/12
|
||||
*
|
||||
*/
|
||||
|
||||
#include "Imaging.h"
|
||||
|
||||
#ifdef HAVE_LIBTIFF
|
||||
|
||||
#ifndef uint
|
||||
#define uint uint32
|
||||
#endif
|
||||
|
||||
#include "Tiff.h"
|
||||
|
||||
void dump_state(const TIFFSTATE *state){
|
||||
TRACE(("State: Location %u size %d eof %d data: %p \n", (uint)state->loc,
|
||||
(int)state->size, (uint)state->eof, state->data));
|
||||
}
|
||||
|
||||
/*
|
||||
procs for TIFFOpenClient
|
||||
*/
|
||||
|
||||
tsize_t _tiffReadProc(thandle_t hdata, tdata_t buf, tsize_t size) {
|
||||
TIFFSTATE *state = (TIFFSTATE *)hdata;
|
||||
tsize_t to_read;
|
||||
|
||||
TRACE(("_tiffReadProc: %d \n", (int)size));
|
||||
dump_state(state);
|
||||
|
||||
to_read = min(size, min(state->size, (tsize_t)state->eof) - (tsize_t)state->loc);
|
||||
TRACE(("to_read: %d\n", (int)to_read));
|
||||
|
||||
_TIFFmemcpy(buf, (UINT8 *)state->data + state->loc, to_read);
|
||||
state->loc += (toff_t)to_read;
|
||||
|
||||
TRACE( ("location: %u\n", (uint)state->loc));
|
||||
return to_read;
|
||||
}
|
||||
|
||||
tsize_t _tiffWriteProc(thandle_t hdata, tdata_t buf, tsize_t size) {
|
||||
TIFFSTATE *state = (TIFFSTATE *)hdata;
|
||||
tsize_t to_write;
|
||||
|
||||
TRACE(("_tiffWriteProc: %d \n", (int)size));
|
||||
dump_state(state);
|
||||
|
||||
to_write = min(size, state->size - (tsize_t)state->loc);
|
||||
if (state->flrealloc && size>to_write) {
|
||||
tdata_t new;
|
||||
tsize_t newsize=state->size;
|
||||
while (newsize < (size + state->size)) {
|
||||
newsize += 64*1024;
|
||||
// newsize*=2; // UNDONE, by 64k chunks?
|
||||
}
|
||||
TRACE(("Reallocing in write to %d bytes\n", (int)newsize));
|
||||
new = realloc(state->data, newsize);
|
||||
if (!new) {
|
||||
// fail out
|
||||
return 0;
|
||||
}
|
||||
state->data = new;
|
||||
state->size = newsize;
|
||||
to_write = size;
|
||||
}
|
||||
|
||||
TRACE(("to_write: %d\n", (int)to_write));
|
||||
|
||||
_TIFFmemcpy((UINT8 *)state->data + state->loc, buf, to_write);
|
||||
state->loc += (toff_t)to_write;
|
||||
state->eof = max(state->loc, state->eof);
|
||||
|
||||
dump_state(state);
|
||||
return to_write;
|
||||
}
|
||||
|
||||
toff_t _tiffSeekProc(thandle_t hdata, toff_t off, int whence) {
|
||||
TIFFSTATE *state = (TIFFSTATE *)hdata;
|
||||
|
||||
TRACE(("_tiffSeekProc: off: %u whence: %d \n", (uint)off, whence));
|
||||
dump_state(state);
|
||||
switch (whence) {
|
||||
case 0:
|
||||
state->loc = off;
|
||||
break;
|
||||
case 1:
|
||||
state->loc += off;
|
||||
break;
|
||||
case 2:
|
||||
state->loc = state->eof + off;
|
||||
break;
|
||||
}
|
||||
dump_state(state);
|
||||
return state->loc;
|
||||
}
|
||||
|
||||
int _tiffCloseProc(thandle_t hdata) {
|
||||
TIFFSTATE *state = (TIFFSTATE *)hdata;
|
||||
|
||||
TRACE(("_tiffCloseProc \n"));
|
||||
dump_state(state);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
toff_t _tiffSizeProc(thandle_t hdata) {
|
||||
TIFFSTATE *state = (TIFFSTATE *)hdata;
|
||||
|
||||
TRACE(("_tiffSizeProc \n"));
|
||||
dump_state(state);
|
||||
|
||||
return (toff_t)state->size;
|
||||
}
|
||||
int _tiffMapProc(thandle_t hdata, tdata_t* pbase, toff_t* psize) {
|
||||
TIFFSTATE *state = (TIFFSTATE *)hdata;
|
||||
|
||||
TRACE(("_tiffMapProc input size: %u, data: %p\n", (uint)*psize, *pbase));
|
||||
dump_state(state);
|
||||
|
||||
*pbase = state->data;
|
||||
*psize = state->size;
|
||||
TRACE(("_tiffMapProc returning size: %u, data: %p\n", (uint)*psize, *pbase));
|
||||
return (1);
|
||||
}
|
||||
|
||||
int _tiffNullMapProc(thandle_t hdata, tdata_t* pbase, toff_t* psize) {
|
||||
(void) hdata; (void) pbase; (void) psize;
|
||||
return (0);
|
||||
}
|
||||
|
||||
void _tiffUnmapProc(thandle_t hdata, tdata_t base, toff_t size) {
|
||||
TRACE(("_tiffUnMapProc\n"));
|
||||
(void) hdata; (void) base; (void) size;
|
||||
}
|
||||
|
||||
int ImagingLibTiffInit(ImagingCodecState state, int compression, int fp) {
|
||||
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
|
||||
|
||||
TRACE(("initing libtiff\n"));
|
||||
TRACE(("Compression: %d, filepointer: %d \n", compression, fp));
|
||||
TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
|
||||
state->x, state->y, state->ystep));
|
||||
TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,
|
||||
state->xoff, state->yoff));
|
||||
TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
|
||||
TRACE(("State: context %p \n", state->context));
|
||||
|
||||
clientstate->loc = 0;
|
||||
clientstate->size = 0;
|
||||
clientstate->data = 0;
|
||||
clientstate->fp = fp;
|
||||
clientstate->eof = 0;
|
||||
|
||||
return 1;
|
||||
}
|
||||
|
||||
int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes) {
|
||||
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
|
||||
char *filename = "tempfile.tif";
|
||||
char *mode = "r";
|
||||
TIFF *tiff;
|
||||
int size;
|
||||
|
||||
|
||||
/* buffer is the encoded file, bytes is the length of the encoded file */
|
||||
/* it all ends up in state->buffer, which is a uint8* from Imaging.h */
|
||||
|
||||
TRACE(("in decoder: bytes %d\n", bytes));
|
||||
TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
|
||||
state->x, state->y, state->ystep));
|
||||
TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,
|
||||
state->xoff, state->yoff));
|
||||
TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
|
||||
TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3]));
|
||||
TRACE(("State->Buffer: %c%c%c%c\n", (char)state->buffer[0], (char)state->buffer[1],(char)state->buffer[2], (char)state->buffer[3]));
|
||||
TRACE(("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n",
|
||||
im->mode, im->type, im->bands, im->xsize, im->ysize));
|
||||
TRACE(("Image: image8 %p, image32 %p, image %p, block %p \n",
|
||||
im->image8, im->image32, im->image, im->block));
|
||||
TRACE(("Image: pixelsize: %d, linesize %d \n",
|
||||
im->pixelsize, im->linesize));
|
||||
|
||||
dump_state(clientstate);
|
||||
clientstate->size = bytes;
|
||||
clientstate->eof = clientstate->size;
|
||||
clientstate->loc = 0;
|
||||
clientstate->data = (tdata_t)buffer;
|
||||
clientstate->flrealloc = 0;
|
||||
|
||||
dump_state(clientstate);
|
||||
if (clientstate->fp) {
|
||||
TRACE(("Opening using fd: %d\n",clientstate->fp));
|
||||
tiff = TIFFFdOpen(clientstate->fp, filename, mode);
|
||||
} else {
|
||||
TRACE(("Opening from string\n"));
|
||||
tiff = TIFFClientOpen(filename, mode,
|
||||
(thandle_t) clientstate,
|
||||
_tiffReadProc, _tiffWriteProc,
|
||||
_tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
|
||||
_tiffMapProc, _tiffUnmapProc);
|
||||
}
|
||||
|
||||
if (!tiff){
|
||||
TRACE(("Error, didn't get the tiff\n"));
|
||||
state->errcode = IMAGING_CODEC_BROKEN;
|
||||
return -1;
|
||||
}
|
||||
|
||||
size = TIFFScanlineSize(tiff);
|
||||
TRACE(("ScanlineSize: %d \n", size));
|
||||
if (size > state->bytes) {
|
||||
TRACE(("Error, scanline size > buffer size\n"));
|
||||
state->errcode = IMAGING_CODEC_BROKEN;
|
||||
TIFFClose(tiff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Have to do this row by row and shove stuff into the buffer that way,
|
||||
// with shuffle. (or, just alloc a buffer myself, then figure out how to get it
|
||||
// back in. Can't use read encoded stripe.
|
||||
|
||||
// This thing pretty much requires that I have the whole image in one shot.
|
||||
// Prehaps a stub version would work better???
|
||||
while(state->y < state->ysize){
|
||||
if (TIFFReadScanline(tiff, (tdata_t)state->buffer, (uint32)state->y, 0) == -1) {
|
||||
TRACE(("Decode Error, row %d\n", state->y));
|
||||
state->errcode = IMAGING_CODEC_BROKEN;
|
||||
TIFFClose(tiff);
|
||||
return -1;
|
||||
}
|
||||
/* TRACE(("Decoded row %d \n", state->y)); */
|
||||
state->shuffle((UINT8*) im->image[state->y + state->yoff] +
|
||||
state->xoff * im->pixelsize,
|
||||
state->buffer,
|
||||
state->xsize);
|
||||
|
||||
state->y++;
|
||||
}
|
||||
|
||||
TIFFClose(tiff);
|
||||
TRACE(("Done Decoding, Returning \n"));
|
||||
// Returning -1 here to force ImageFile.load to break, rather than
|
||||
// even think about looping back around.
|
||||
return -1;
|
||||
}
|
||||
|
||||
int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp) {
|
||||
// Open the FD or the pointer as a tiff file, for writing.
|
||||
// We may have to do some monkeying around to make this really work.
|
||||
// If we have a fp, then we're good.
|
||||
// If we have a memory string, we're probably going to have to malloc, then
|
||||
// shuffle bytes into the writescanline process.
|
||||
// Going to have to deal with the directory as well.
|
||||
|
||||
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
|
||||
int bufsize = 64*1024;
|
||||
char *mode = "w";
|
||||
|
||||
TRACE(("initing libtiff\n"));
|
||||
TRACE(("Filename %s, filepointer: %d \n", filename, fp));
|
||||
TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
|
||||
state->x, state->y, state->ystep));
|
||||
TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,
|
||||
state->xoff, state->yoff));
|
||||
TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
|
||||
TRACE(("State: context %p \n", state->context));
|
||||
|
||||
clientstate->loc = 0;
|
||||
clientstate->size = 0;
|
||||
clientstate->eof =0;
|
||||
clientstate->data = 0;
|
||||
clientstate->flrealloc = 0;
|
||||
clientstate->fp = fp;
|
||||
|
||||
state->state = 0;
|
||||
|
||||
if (fp) {
|
||||
TRACE(("Opening using fd: %d for writing \n",clientstate->fp));
|
||||
clientstate->tiff = TIFFFdOpen(clientstate->fp, filename, mode);
|
||||
} else {
|
||||
// malloc a buffer to write the tif, we're going to need to realloc or something if we need bigger.
|
||||
TRACE(("Opening a buffer for writing \n"));
|
||||
clientstate->data = malloc(bufsize);
|
||||
clientstate->size = bufsize;
|
||||
clientstate->flrealloc=1;
|
||||
|
||||
if (!clientstate->data) {
|
||||
TRACE(("Error, couldn't allocate a buffer of size %d\n", bufsize));
|
||||
return 0;
|
||||
}
|
||||
|
||||
clientstate->tiff = TIFFClientOpen(filename, mode,
|
||||
(thandle_t) clientstate,
|
||||
_tiffReadProc, _tiffWriteProc,
|
||||
_tiffSeekProc, _tiffCloseProc, _tiffSizeProc,
|
||||
_tiffNullMapProc, _tiffUnmapProc); /*force no mmap*/
|
||||
|
||||
}
|
||||
|
||||
if (!clientstate->tiff) {
|
||||
TRACE(("Error, couldn't open tiff file\n"));
|
||||
return 0;
|
||||
}
|
||||
|
||||
return 1;
|
||||
|
||||
}
|
||||
|
||||
int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...){
|
||||
// after tif_dir.c->TIFFSetField.
|
||||
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
|
||||
va_list ap;
|
||||
int status;
|
||||
|
||||
va_start(ap, tag);
|
||||
status = TIFFVSetField(clientstate->tiff, tag, ap);
|
||||
va_end(ap);
|
||||
return status;
|
||||
}
|
||||
|
||||
|
||||
int ImagingLibTiffEncode(Imaging im, ImagingCodecState state, UINT8* buffer, int bytes) {
|
||||
/* One shot encoder. Encode everything to the tiff in the clientstate.
|
||||
If we're running off of a FD, then run once, we're good, everything
|
||||
ends up in the file, we close and we're done.
|
||||
|
||||
If we're going to memory, then we need to write the whole file into memory, then
|
||||
parcel it back out to the pystring buffer bytes at a time.
|
||||
|
||||
*/
|
||||
|
||||
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
|
||||
TIFF *tiff = clientstate->tiff;
|
||||
|
||||
TRACE(("in encoder: bytes %d\n", bytes));
|
||||
TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
|
||||
state->x, state->y, state->ystep));
|
||||
TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,
|
||||
state->xoff, state->yoff));
|
||||
TRACE(("State: bits %d, bytes %d \n", state->bits, state->bytes));
|
||||
TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3]));
|
||||
TRACE(("State->Buffer: %c%c%c%c\n", (char)state->buffer[0], (char)state->buffer[1],(char)state->buffer[2], (char)state->buffer[3]));
|
||||
TRACE(("Image: mode %s, type %d, bands: %d, xsize %d, ysize %d \n",
|
||||
im->mode, im->type, im->bands, im->xsize, im->ysize));
|
||||
TRACE(("Image: image8 %p, image32 %p, image %p, block %p \n",
|
||||
im->image8, im->image32, im->image, im->block));
|
||||
TRACE(("Image: pixelsize: %d, linesize %d \n",
|
||||
im->pixelsize, im->linesize));
|
||||
|
||||
dump_state(clientstate);
|
||||
|
||||
if (state->state == 0) {
|
||||
TRACE(("Encoding line bt line"));
|
||||
while(state->y < state->ysize){
|
||||
state->shuffle(state->buffer,
|
||||
(UINT8*) im->image[state->y + state->yoff] +
|
||||
state->xoff * im->pixelsize,
|
||||
state->xsize);
|
||||
|
||||
if (TIFFWriteScanline(tiff, (tdata_t)(state->buffer), (uint32)state->y, 0) == -1) {
|
||||
TRACE(("Encode Error, row %d\n", state->y));
|
||||
state->errcode = IMAGING_CODEC_BROKEN;
|
||||
TIFFClose(tiff);
|
||||
if (!clientstate->fp){
|
||||
free(clientstate->data);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
state->y++;
|
||||
}
|
||||
|
||||
if (state->y == state->ysize) {
|
||||
state->state=1;
|
||||
|
||||
TRACE(("Flushing \n"));
|
||||
if (!TIFFFlush(tiff)) {
|
||||
TRACE(("Error flushing the tiff"));
|
||||
// likely reason is memory.
|
||||
state->errcode = IMAGING_CODEC_MEMORY;
|
||||
TIFFClose(tiff);
|
||||
if (!clientstate->fp){
|
||||
free(clientstate->data);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
TRACE(("Closing \n"));
|
||||
TIFFClose(tiff);
|
||||
// reset the clientstate metadata to use it to read out the buffer.
|
||||
clientstate->loc = 0;
|
||||
clientstate->size = clientstate->eof; // redundant?
|
||||
}
|
||||
}
|
||||
|
||||
if (state->state == 1 && !clientstate->fp) {
|
||||
int read = (int)_tiffReadProc(clientstate, (tdata_t)buffer, (tsize_t)bytes);
|
||||
TRACE(("Buffer: %p: %c%c%c%c\n", buffer, (char)buffer[0], (char)buffer[1],(char)buffer[2], (char)buffer[3]));
|
||||
if (clientstate->loc == clientstate->eof) {
|
||||
TRACE(("Hit EOF, calling an end, freeing data"));
|
||||
state->errcode = IMAGING_CODEC_END;
|
||||
free(clientstate->data);
|
||||
}
|
||||
return read;
|
||||
}
|
||||
|
||||
state->errcode = IMAGING_CODEC_END;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
|
@ -186,6 +186,7 @@ if __name__ == "__main__":
|
|||
check_module("TKINTER", "_imagingtk")
|
||||
check_codec("JPEG", "jpeg")
|
||||
check_codec("ZLIB (PNG/ZIP)", "zip")
|
||||
check_codec("G4 TIFF", "group4")
|
||||
check_module("FREETYPE2", "_imagingft")
|
||||
check_module("LITTLECMS", "_imagingcms")
|
||||
print("-"*68)
|
||||
|
@ -201,3 +202,4 @@ if __name__ == "__main__":
|
|||
print("--- %s tests passed." % status[1])
|
||||
|
||||
sys.exit(exit_status)
|
||||
|
||||
|
|
15
setup.py
15
setup.py
|
@ -26,7 +26,7 @@ _LIB_IMAGING = (
|
|||
"QuantHeap", "PcdDecode", "PcxDecode", "PcxEncode", "Point",
|
||||
"RankFilter", "RawDecode", "RawEncode", "Storage", "SunRleDecode",
|
||||
"TgaRleDecode", "Unpack", "UnpackYCC", "UnsharpMask", "XbmDecode",
|
||||
"XbmEncode", "ZipDecode", "ZipEncode")
|
||||
"XbmEncode", "ZipDecode", "ZipEncode", "TiffDecode")
|
||||
|
||||
|
||||
def _add_directory(path, dir, where=None):
|
||||
|
@ -76,7 +76,7 @@ PIL_VERSION = '1.1.7'
|
|||
TCL_ROOT = None
|
||||
JPEG_ROOT = None
|
||||
ZLIB_ROOT = None
|
||||
TIFF_ROOT = None
|
||||
TIFF_ROOT = None
|
||||
FREETYPE_ROOT = None
|
||||
LCMS_ROOT = None
|
||||
|
||||
|
@ -156,6 +156,7 @@ class pil_build_ext(build_ext):
|
|||
#
|
||||
# locate tkinter libraries
|
||||
|
||||
|
||||
if _tkinter:
|
||||
TCL_VERSION = _tkinter.TCL_VERSION[:3]
|
||||
|
||||
|
@ -183,6 +184,7 @@ class pil_build_ext(build_ext):
|
|||
break
|
||||
else:
|
||||
TCL_ROOT = None
|
||||
|
||||
|
||||
#
|
||||
# add standard directories
|
||||
|
@ -229,6 +231,10 @@ class pil_build_ext(build_ext):
|
|||
|
||||
if _find_library_file(self, "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"):
|
||||
# look for freetype2 include files
|
||||
|
@ -288,6 +294,9 @@ class pil_build_ext(build_ext):
|
|||
if feature.zlib:
|
||||
libs.append(feature.zlib)
|
||||
defs.append(("HAVE_LIBZ", None))
|
||||
if feature.tiff:
|
||||
libs.append(feature.tiff)
|
||||
defs.append(("HAVE_LIBTIFF", None))
|
||||
if sys.platform == "win32":
|
||||
libs.extend(["kernel32", "user32", "gdi32"])
|
||||
if struct.unpack("h", "\0\1".encode('ascii'))[0] == 1:
|
||||
|
@ -382,7 +391,7 @@ class pil_build_ext(build_ext):
|
|||
(feature.tcl and feature.tk, "TKINTER"),
|
||||
(feature.jpeg, "JPEG"),
|
||||
(feature.zlib, "ZLIB (PNG/ZIP)"),
|
||||
# (feature.tiff, "experimental TIFF G3/G4 read"),
|
||||
(feature.tiff, "experimental TIFF G3/G4 read"),
|
||||
(feature.freetype, "FREETYPE2"),
|
||||
(feature.lcms, "LITTLECMS"),
|
||||
(feature.webp, "WEBP"),
|
||||
|
|
Loading…
Reference in New Issue
Block a user