Merge pull request #417 from wiredfool/libtiff-save2

Updates for saving color tiffs w/compression using libtiff
This commit is contained in:
Alex Clark ☺ 2013-12-28 05:47:47 -08:00
commit f5fb2d7e7d
18 changed files with 239 additions and 150 deletions

View File

@ -54,7 +54,9 @@ import collections
import itertools import itertools
import os import os
# Set these to true to force use of libtiff for reading or writing.
READ_LIBTIFF = False
WRITE_LIBTIFF= False
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)
@ -149,6 +151,7 @@ OPEN_INFO = {
(II, 1, 1, 1, (8,), ()): ("L", "L"), (II, 1, 1, 1, (8,), ()): ("L", "L"),
(II, 1, 1, 1, (8,8), (2,)): ("LA", "LA"), (II, 1, 1, 1, (8,8), (2,)): ("LA", "LA"),
(II, 1, 1, 2, (8,), ()): ("L", "L;R"), (II, 1, 1, 2, (8,), ()): ("L", "L;R"),
(II, 1, 1, 1, (12,), ()): ("I;16", "I;12"),
(II, 1, 1, 1, (16,), ()): ("I;16", "I;16"), (II, 1, 1, 1, (16,), ()): ("I;16", "I;16"),
(II, 1, 2, 1, (16,), ()): ("I;16S", "I;16S"), (II, 1, 2, 1, (16,), ()): ("I;16S", "I;16S"),
(II, 1, 1, 1, (32,), ()): ("I", "I;32N"), (II, 1, 1, 1, (32,), ()): ("I", "I;32N"),
@ -675,8 +678,8 @@ class TiffImageFile(ImageFile.ImageFile):
return args return args
def _load_libtiff(self): def _load_libtiff(self):
""" Overload method triggered when we detect a g3/g4 tiff """ Overload method triggered when we detect a compressed tiff
Calls out to lib tiff """ Calls out to libtiff """
pixel = Image.Image.load(self) pixel = Image.Image.load(self)
@ -691,7 +694,7 @@ class TiffImageFile(ImageFile.ImageFile):
raise IOError("Not exactly one tile") raise IOError("Not exactly one tile")
d, e, o, a = self.tile[0] d, e, o, a = self.tile[0]
d = Image._getdecoder(self.mode, d, a, self.decoderconfig) d = Image._getdecoder(self.mode, 'libtiff', a, self.decoderconfig)
try: try:
d.setimage(self.im, e) d.setimage(self.im, e)
except ValueError: except ValueError:
@ -817,11 +820,11 @@ class TiffImageFile(ImageFile.ImageFile):
offsets = self.tag[STRIPOFFSETS] offsets = self.tag[STRIPOFFSETS]
h = getscalar(ROWSPERSTRIP, ysize) h = getscalar(ROWSPERSTRIP, ysize)
w = self.size[0] w = self.size[0]
if self._compression in ["tiff_ccitt", "group3", "group4", if READ_LIBTIFF or self._compression in ["tiff_ccitt", "group3", "group4",
"tiff_jpeg", "tiff_adobe_deflate", "tiff_jpeg", "tiff_adobe_deflate",
"tiff_thunderscan", "tiff_deflate", "tiff_thunderscan", "tiff_deflate",
"tiff_sgilog", "tiff_sgilog24", "tiff_sgilog", "tiff_sgilog24",
"tiff_raw_16"]: "tiff_raw_16"]:
## if Image.DEBUG: ## if Image.DEBUG:
## print "Activating g4 compression for whole file" ## print "Activating g4 compression for whole file"
@ -868,7 +871,7 @@ class TiffImageFile(ImageFile.ImageFile):
# we're expecting image byte order. So, if the rawmode # we're expecting image byte order. So, if the rawmode
# contains I;16, we need to convert from native to image # contains I;16, we need to convert from native to image
# byte order. # byte order.
if self.mode in ('I;16B', 'I;16'): if self.mode in ('I;16B', 'I;16') and 'I;16' in rawmode:
rawmode = 'I;16N' rawmode = 'I;16N'
# Offset in the tile tuple is 0, we go from 0,0 to # Offset in the tile tuple is 0, we go from 0,0 to
@ -975,12 +978,16 @@ def _save(im, fp, filename):
ifd = ImageFileDirectory(prefix) ifd = ImageFileDirectory(prefix)
compression = im.encoderinfo.get('compression',im.info.get('compression','raw')) compression = im.encoderinfo.get('compression',im.info.get('compression','raw'))
libtiff = compression in ["tiff_ccitt", "group3", "group4",
"tiff_jpeg", "tiff_adobe_deflate",
"tiff_thunderscan", "tiff_deflate",
"tiff_sgilog", "tiff_sgilog24",
"tiff_raw_16"]
libtiff = WRITE_LIBTIFF or compression in ["tiff_ccitt", "group3", "group4",
"tiff_jpeg", "tiff_adobe_deflate",
"tiff_thunderscan", "tiff_deflate",
"tiff_sgilog", "tiff_sgilog24",
"tiff_raw_16"]
# required for color libtiff images
ifd[PLANAR_CONFIGURATION] = getattr(im, '_planar_configuration', 1)
# -- multi-page -- skip TIFF header on subsequent pages # -- multi-page -- skip TIFF header on subsequent pages
if not libtiff and 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)
@ -1083,6 +1090,8 @@ def _save(im, fp, filename):
blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP, ICCPROFILE] # ICC Profile crashes. blocklist = [STRIPOFFSETS, STRIPBYTECOUNTS, ROWSPERSTRIP, ICCPROFILE] # ICC Profile crashes.
atts={} 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 # Merge the ones that we have with (optional) more bits from
# the original file, e.g x,y resolution so that we can # the original file, e.g x,y resolution so that we can
# save(load('')) == original file. # save(load('')) == original file.
@ -1100,8 +1109,8 @@ def _save(im, fp, filename):
continue continue
if type(v) == tuple and len(v) > 2: if type(v) == tuple and len(v) > 2:
# List of ints? # List of ints?
# BitsPerSample is one example, I get (8,8,8) if type(v[0]) in (int, float):
# UNDONE atts[k] = list(v)
continue continue
if type(v) == tuple and len(v) == 2: if type(v) == tuple and len(v) == 2:
# one rational tuple # one rational tuple
@ -1121,8 +1130,8 @@ def _save(im, fp, filename):
if Image.DEBUG: if Image.DEBUG:
print (atts) print (atts)
# libtiff always returns the bytes in native order. # libtiff always expects the bytes in native order.
# we're expecting image byte order. So, if the rawmode # we're storing image byte order. So, if the rawmode
# contains I;16, we need to convert from native to image # contains I;16, we need to convert from native to image
# byte order. # byte order.
if im.mode in ('I;16B', 'I;16'): if im.mode in ('I;16B', 'I;16'):
@ -1130,7 +1139,7 @@ def _save(im, fp, filename):
a = (rawmode, compression, _fp, filename, atts) a = (rawmode, compression, _fp, filename, atts)
# print (im.mode, compression, a, im.encoderconfig) # print (im.mode, compression, a, im.encoderconfig)
e = Image._getencoder(im.mode, compression, a, im.encoderconfig) e = Image._getencoder(im.mode, 'libtiff', a, im.encoderconfig)
e.setimage(im.im, (0,0)+im.size) e.setimage(im.im, (0,0)+im.size)
while 1: while 1:
l, s, d = e.encode(16*1024) # undone, change to self.decodermaxblock l, s, d = e.encode(16*1024) # undone, change to self.decodermaxblock

Binary file not shown.

BIN
Tests/images/12in16bit.tif Normal file

Binary file not shown.

Binary file not shown.

View File

@ -1,10 +1,10 @@
from tester import * from tester import *
from PIL import Image from PIL import Image, TiffImagePlugin
codecs = dir(Image.core) codecs = dir(Image.core)
if "group4_encoder" not in codecs or "group4_decoder" not in codecs: if "libtiff_encoder" not in codecs or "libtiff_decoder" not in codecs:
skip("tiff support not available") skip("tiff support not available")
def _assert_noerr(im): def _assert_noerr(im):
@ -141,7 +141,7 @@ def test_g3_compression():
assert_image_equal(reread, i) assert_image_equal(reread, i)
def test_little_endian(): def test_little_endian():
im = Image.open('Tests/images/12bit.deflate.tif') im = Image.open('Tests/images/16bit.deflate.tif')
assert_equal(im.getpixel((0,0)), 480) assert_equal(im.getpixel((0,0)), 480)
assert_equal(im.mode, 'I;16') assert_equal(im.mode, 'I;16')
@ -156,7 +156,7 @@ def test_little_endian():
out = tempfile("temp.tif") out = tempfile("temp.tif")
out = "temp.le.tif" #out = "temp.le.tif"
im.save(out) im.save(out)
reread = Image.open(out) reread = Image.open(out)
@ -166,7 +166,7 @@ def test_little_endian():
# on big endian, we'll get back mode = 'I;16B' here. # on big endian, we'll get back mode = 'I;16B' here.
def test_big_endian(): def test_big_endian():
im = Image.open('Tests/images/12bit.MM.deflate.tif') im = Image.open('Tests/images/16bit.MM.deflate.tif')
assert_equal(im.getpixel((0,0)), 480) assert_equal(im.getpixel((0,0)), 480)
assert_equal(im.mode, 'I;16B') assert_equal(im.mode, 'I;16B')
@ -201,4 +201,87 @@ def test_g4_string_info():
reread = Image.open(out) reread = Image.open(out)
assert_equal('temp.tif', reread.tag[269]) assert_equal('temp.tif', reread.tag[269])
def test_12bit_rawmode():
""" Are we generating the same interpretation of the image as Imagemagick is? """
TiffImagePlugin.READ_LIBTIFF = True
#Image.DEBUG = True
im = Image.open('Tests/images/12bit.cropped.tif')
im.load()
TiffImagePlugin.READ_LIBTIFF = False
# to make the target --
# convert 12bit.cropped.tif -depth 16 tmp.tif
# convert tmp.tif -evaluate RightShift 4 12in16bit2.tif
# imagemagick will auto scale so that a 12bit FFF is 16bit FFF0,
# so we need to unshift so that the integer values are the same.
im2 = Image.open('Tests/images/12in16bit.tif')
if Image.DEBUG:
print (im.getpixel((0,0)))
print (im.getpixel((0,1)))
print (im.getpixel((0,2)))
print (im2.getpixel((0,0)))
print (im2.getpixel((0,1)))
print (im2.getpixel((0,2)))
assert_image_equal(im, im2)
def test_blur():
# test case from irc, how to do blur on b/w image and save to compressed tif.
from PIL import ImageFilter
out = tempfile('temp.tif')
im = Image.open('Tests/images/pport_g4.tif')
im = im.convert('L')
im=im.filter(ImageFilter.GaussianBlur(4))
im.save(out, compression='tiff_adobe_deflate')
im2 = Image.open(out)
im2.load()
assert_image_equal(im, im2)
def test_compressions():
im = lena('RGB')
out = tempfile('temp.tif')
TiffImagePlugin.READ_LIBTIFF = True
TiffImagePlugin.WRITE_LIBTIFF = True
for compression in ('packbits', 'tiff_lzw'):
im.save(out, compression=compression)
im2 = Image.open(out)
assert_image_equal(im, im2)
im.save(out, compression='jpeg')
im2 = Image.open(out)
assert_image_similar(im, im2, 30)
TiffImagePlugin.READ_LIBTIFF = False
TiffImagePlugin.WRITE_LIBTIFF = False
def test_cmyk_save():
im = lena('CMYK')
out = tempfile('temp.tif')
im.save(out, compression='tiff_adobe_deflate')
im2 = Image.open(out)
assert_image_equal(im, im2)
def xtest_bw_compression_wRGB():
""" This test passes, but when running all tests causes a failure due to
output on stderr from the error thrown by libtiff. We need to capture that
but not now"""
im = lena('RGB')
out = tempfile('temp.tif')
assert_exception(IOError, lambda: im.save(out, compression='tiff_ccitt'))
assert_exception(IOError, lambda: im.save(out, compression='group3'))
assert_exception(IOError, lambda: im.save(out, compression='group4'))

View File

@ -6,7 +6,7 @@ from test_file_libtiff import _assert_noerr
codecs = dir(Image.core) codecs = dir(Image.core)
if "group4_encoder" not in codecs or "group4_decoder" not in codecs: if "libtiff_encoder" not in codecs or "libtiff_decoder" not in codecs:
skip("tiff support not available") skip("tiff support not available")
""" The small lena image was failing on open in the libtiff """ The small lena image was failing on open in the libtiff

View File

@ -74,7 +74,7 @@ def test_xyres_tiff():
def test_little_endian(): def test_little_endian():
im = Image.open('Tests/images/12bit.cropped.tif') im = Image.open('Tests/images/16bit.cropped.tif')
assert_equal(im.getpixel((0,0)), 480) assert_equal(im.getpixel((0,0)), 480)
assert_equal(im.mode, 'I;16') assert_equal(im.mode, 'I;16')
@ -89,7 +89,7 @@ def test_little_endian():
def test_big_endian(): def test_big_endian():
im = Image.open('Tests/images/12bit.MM.cropped.tif') im = Image.open('Tests/images/16bit.MM.cropped.tif')
assert_equal(im.getpixel((0,0)), 480) assert_equal(im.getpixel((0,0)), 480)
assert_equal(im.mode, 'I;16B') assert_equal(im.mode, 'I;16B')
@ -102,3 +102,29 @@ def test_big_endian():
else: else:
assert_equal(b[0], b'\x01') assert_equal(b[0], b'\x01')
assert_equal(b[1], b'\xe0') assert_equal(b[1], b'\xe0')
def test_12bit_rawmode():
""" Are we generating the same interpretation of the image as Imagemagick is? """
#Image.DEBUG = True
im = Image.open('Tests/images/12bit.cropped.tif')
# to make the target --
# convert 12bit.cropped.tif -depth 16 tmp.tif
# convert tmp.tif -evaluate RightShift 4 12in16bit2.tif
# imagemagick will auto scale so that a 12bit FFF is 16bit FFF0,
# so we need to unshift so that the integer values are the same.
im2 = Image.open('Tests/images/12in16bit.tif')
if Image.DEBUG:
print (im.getpixel((0,0)))
print (im.getpixel((0,1)))
print (im.getpixel((0,2)))
print (im2.getpixel((0,0)))
print (im2.getpixel((0,1)))
print (im2.getpixel((0,2)))
assert_image_equal(im, im2)

View File

@ -38,12 +38,12 @@ def test_8bit():
im = Image.open('Images/lena.jpg') im = Image.open('Images/lena.jpg')
_test_float_conversion(im.convert('L')) _test_float_conversion(im.convert('L'))
def test_12bit(): def test_16bit():
im = Image.open('Tests/images/12bit.cropped.tif') im = Image.open('Tests/images/16bit.cropped.tif')
_test_float_conversion(im) _test_float_conversion(im)
def test_12bit_workaround(): def test_16bit_workaround():
im = Image.open('Tests/images/12bit.cropped.tif') im = Image.open('Tests/images/16bit.cropped.tif')
_test_float_conversion(im.convert('I')) _test_float_conversion(im.convert('I'))

View File

@ -75,7 +75,7 @@ def _test_img_equals_nparray(img, np):
def test_16bit(): def test_16bit():
img = Image.open('Tests/images/12bit.cropped.tif') img = Image.open('Tests/images/16bit.cropped.tif')
np_img = numpy.array(img) np_img = numpy.array(img)
_test_img_equals_nparray(img, np_img) _test_img_equals_nparray(img, np_img)
assert_equal(np_img.dtype, numpy.dtype('<u2')) assert_equal(np_img.dtype, numpy.dtype('<u2'))

View File

@ -3317,27 +3317,8 @@ static PyMethodDef functions[] = {
#endif #endif
{"tiff_lzw_decoder", (PyCFunction)PyImaging_TiffLzwDecoderNew, 1}, {"tiff_lzw_decoder", (PyCFunction)PyImaging_TiffLzwDecoderNew, 1},
#ifdef HAVE_LIBTIFF #ifdef HAVE_LIBTIFF
{"tiff_ccitt_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1}, {"libtiff_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
{"group3_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1}, {"libtiff_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
{"group4_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
{"tiff_jpeg_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
{"tiff_adobe_deflate_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
{"tiff_thunderscan_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
{"tiff_deflate_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
{"tiff_sgilog_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
{"tiff_sgilog24_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_jpeg_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
{"tiff_adobe_deflate_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
{"tiff_thunderscan_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
{"tiff_deflate_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
{"tiff_sgilog_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
{"tiff_sgilog24_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
{"tiff_raw_16_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
#endif #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},

View File

@ -427,7 +427,6 @@ PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
char* mode; char* mode;
char* rawmode; char* rawmode;
char* compname; char* compname;
int compression;
int fp; int fp;
if (! PyArg_ParseTuple(args, "sssi", &mode, &rawmode, &compname, &fp)) if (! PyArg_ParseTuple(args, "sssi", &mode, &rawmode, &compname, &fp))
@ -435,46 +434,6 @@ PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
TRACE(("new tiff decoder %s\n", compname)); 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_jpeg") == 0) {
compression = COMPRESSION_OJPEG;
} else if (strcasecmp(compname, "tiff_adobe_deflate") == 0) {
compression = COMPRESSION_ADOBE_DEFLATE;
} else if (strcasecmp(compname, "tiff_thunderscan") == 0) {
compression = COMPRESSION_THUNDERSCAN;
} else if (strcasecmp(compname, "tiff_deflate") == 0) {
compression = COMPRESSION_DEFLATE;
} else if (strcasecmp(compname, "tiff_sgilog") == 0) {
compression = COMPRESSION_SGILOG;
} else if (strcasecmp(compname, "tiff_sgilog24") == 0) {
compression = COMPRESSION_SGILOG24;
} 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)); decoder = PyImaging_DecoderNew(sizeof(TIFFSTATE));
if (decoder == NULL) if (decoder == NULL)
return NULL; return NULL;
@ -482,7 +441,7 @@ PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
if (get_unpacker(decoder, mode, rawmode) < 0) if (get_unpacker(decoder, mode, rawmode) < 0)
return NULL; return NULL;
if (! ImagingLibTiffInit(&decoder->state, compression, fp)) { if (! ImagingLibTiffInit(&decoder->state, fp)) {
Py_DECREF(decoder); Py_DECREF(decoder);
PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed"); PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed");
return NULL; return NULL;

View File

@ -673,7 +673,6 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
char* rawmode; char* rawmode;
char* compname; char* compname;
char* filename; char* filename;
int compression;
int fp; int fp;
PyObject *dir; PyObject *dir;
@ -706,47 +705,6 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
TRACE(("new tiff encoder %s fp: %d, filename: %s \n", compname, fp, filename)); 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_jpeg") == 0) {
compression = COMPRESSION_OJPEG;
} else if (strcasecmp(compname, "tiff_adobe_deflate") == 0) {
compression = COMPRESSION_ADOBE_DEFLATE;
} else if (strcasecmp(compname, "tiff_thunderscan") == 0) {
compression = COMPRESSION_THUNDERSCAN;
} else if (strcasecmp(compname, "tiff_deflate") == 0) {
compression = COMPRESSION_DEFLATE;
} else if (strcasecmp(compname, "tiff_sgilog") == 0) {
compression = COMPRESSION_SGILOG;
} else if (strcasecmp(compname, "tiff_sgilog24") == 0) {
compression = COMPRESSION_SGILOG24;
} 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)); encoder = PyImaging_EncoderNew(sizeof(TIFFSTATE));
if (encoder == NULL) if (encoder == NULL)
return NULL; return NULL;
@ -780,18 +738,35 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
} else if(PyList_Check(value)) { } else if(PyList_Check(value)) {
int len,i; int len,i;
float *floatav; float *floatav;
int *intav;
TRACE(("Setting from List: %d \n", (int)PyInt_AsLong(key))); TRACE(("Setting from List: %d \n", (int)PyInt_AsLong(key)));
len = (int)PyList_Size(value); len = (int)PyList_Size(value);
TRACE((" %d elements, setting as floats \n", len)); if (len) {
floatav = malloc(sizeof(float)*len); if (PyInt_Check(PyList_GetItem(value,0))) {
if (floatav) { TRACE((" %d elements, setting as ints \n", len));
for (i=0;i<len;i++) { intav = malloc(sizeof(int)*len);
floatav[i] = (float)PyFloat_AsDouble(PyList_GetItem(value,i)); if (intav) {
for (i=0;i<len;i++) {
intav[i] = (int)PyInt_AsLong(PyList_GetItem(value,i));
}
status = ImagingLibTiffSetField(&encoder->state,
(ttag_t) PyInt_AsLong(key),
intav);
free(intav);
}
} else {
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);
}
} }
status = ImagingLibTiffSetField(&encoder->state,
(ttag_t) PyInt_AsLong(key),
floatav);
free(floatav);
} }
} else if (PyFloat_Check(value)) { } else if (PyFloat_Check(value)) {
TRACE(("Setting from Float: %d, %f \n", (int)PyInt_AsLong(key),PyFloat_AsDouble(value))); TRACE(("Setting from Float: %d, %f \n", (int)PyInt_AsLong(key),PyFloat_AsDouble(value)));

View File

@ -142,11 +142,11 @@ void _tiffUnmapProc(thandle_t hdata, tdata_t base, toff_t size) {
(void) hdata; (void) base; (void) size; (void) hdata; (void) base; (void) size;
} }
int ImagingLibTiffInit(ImagingCodecState state, int compression, int fp) { int ImagingLibTiffInit(ImagingCodecState state, int fp) {
TIFFSTATE *clientstate = (TIFFSTATE *)state->context; TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
TRACE(("initing libtiff\n")); TRACE(("initing libtiff\n"));
TRACE(("Compression: %d, filepointer: %d \n", compression, fp)); TRACE(("filepointer: %d \n", fp));
TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state, TRACE(("State: count %d, state %d, x %d, y %d, ystep %d\n", state->count, state->state,
state->x, state->y, state->ystep)); state->x, state->y, state->ystep));
TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize, TRACE(("State: xsize %d, ysize %d, xoff %d, yoff %d \n", state->xsize, state->ysize,

View File

@ -38,7 +38,7 @@ typedef struct {
extern int ImagingLibTiffInit(ImagingCodecState state, int compression, int fp); extern int ImagingLibTiffInit(ImagingCodecState state, int fp);
extern int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp); extern int ImagingLibTiffEncodeInit(ImagingCodecState state, char *filename, int fp);
extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...); extern int ImagingLibTiffSetField(ImagingCodecState state, ttag_t tag, ...);

View File

@ -795,6 +795,60 @@ unpackI16N_I16(UINT8* out, const UINT8* in, int pixels){
} }
} }
static void
unpackI12_I16(UINT8* out, const UINT8* in, int pixels){
/* Fillorder 1/MSB -> LittleEndian, for 12bit integer greyscale tiffs.
According to the TIFF spec:
FillOrder = 2 should be used only when BitsPerSample = 1 and
the data is either uncompressed or compressed using CCITT 1D
or 2D compression, to avoid potentially ambigous situations.
Yeah. I thought so. We'll see how well people read the spec.
We've got several fillorder=2 modes in TiffImagePlugin.py
There's no spec I can find. It appears that the in storage
layout is: 00 80 00 ... -> (128 , 0 ...). The samples are
stored in a single big bitian 12bit block, but need to be
pulled out to little endian format to be stored in a 2 byte
int.
*/
int i;
UINT16 pixel;
#ifdef WORDS_BIGENDIAN
UINT8* tmp = (UINT8 *)&pixel;
#endif
UINT16* out16 = (UINT16 *)out;
for (i = 0; i < pixels-1; i+=2) {
pixel = (((UINT16) in[0]) << 4 ) + (in[1] >>4);
#ifdef WORDS_BIGENDIAN
out[0] = tmp[1]; out[1] = tmp[0];
#else
out16[0] = pixel;
#endif
pixel = (((UINT16) (in[1] & 0x0F)) << 8) + in[2];
#ifdef WORDS_BIGENDIAN
out[2] = tmp[1]; out[3] = tmp[0];
#else
out16[1] = pixel;
#endif
in += 3; out16 += 2; out+=4;
}
if (i == pixels-1) {
pixel = (((UINT16) in[0]) << 4 ) + (in[1] >>4);
#ifdef WORDS_BIGENDIAN
out[0] = tmp[1]; out[1] = tmp[0];
#else
out16[0] = pixel;
#endif
}
}
static void static void
copy1(UINT8* out, const UINT8* in, int pixels) copy1(UINT8* out, const UINT8* in, int pixels)
{ {
@ -1163,6 +1217,8 @@ static struct {
{"I;16L", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian. {"I;16L", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian.
{"I;16B", "I;16N", 16, unpackI16N_I16B}, {"I;16B", "I;16N", 16, unpackI16N_I16B},
{"I;16", "I;12", 12, unpackI12_I16}, // 12 bit Tiffs stored in 16bits.
{NULL} /* sentinel */ {NULL} /* sentinel */
}; };