Merge from 12-bit-tiff

This commit is contained in:
wiredfool 2013-11-21 21:41:54 -08:00
commit 94e3c75179
20 changed files with 168 additions and 138 deletions

View File

@ -475,7 +475,7 @@ class Image:
new.mode = im.mode new.mode = im.mode
new.size = im.size new.size = im.size
new.palette = self.palette new.palette = self.palette
if im.mode == "P": if im.mode == "P" and not new.palette:
from PIL import ImagePalette from PIL import ImagePalette
new.palette = ImagePalette.ImagePalette() new.palette = ImagePalette.ImagePalette()
try: try:

View File

@ -54,6 +54,10 @@ 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)
@ -147,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"),
@ -617,8 +622,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)
@ -633,7 +638,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:
@ -759,11 +764,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"
@ -810,7 +815,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
@ -917,11 +922,12 @@ 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", libtiff = WRITE_LIBTIFF or compression in ["tiff_ccitt", "group3", "group4",
"tiff_thunderscan", "tiff_deflate", "tiff_jpeg", "tiff_adobe_deflate",
"tiff_sgilog", "tiff_sgilog24", "tiff_thunderscan", "tiff_deflate",
"tiff_raw_16"] "tiff_sgilog", "tiff_sgilog24",
"tiff_raw_16"]
# required for color libtiff images # required for color libtiff images
ifd[PLANAR_CONFIGURATION] = getattr(im, '_planar_configuration', 1) ifd[PLANAR_CONFIGURATION] = getattr(im, '_planar_configuration', 1)
@ -1057,8 +1063,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'):
@ -1066,7 +1072,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

@ -27,3 +27,22 @@ def test_optimize():
return len(file.getvalue()) return len(file.getvalue())
assert_equal(test(0), 800) assert_equal(test(0), 800)
assert_equal(test(1), 38) assert_equal(test(1), 38)
def test_roundtrip():
out = tempfile('temp.gif')
im = lena()
im.save(out)
reread = Image.open(out)
assert_image_similar(reread.convert('RGB'), im, 50)
def test_roundtrip2():
#see https://github.com/python-imaging/Pillow/issues/403
out = 'temp.gif'#tempfile('temp.gif')
im = Image.open('Images/lena.gif')
im2 = im.copy()
im2.save(out)
reread = Image.open(out)
assert_image_similar(reread.convert('RGB'), lena(), 50)

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):
@ -118,7 +118,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')
@ -143,7 +143,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')
@ -178,6 +178,31 @@ 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(): def test_blur():
# test case from irc, how to do blur on b/w image and save to compressed tif. # test case from irc, how to do blur on b/w image and save to compressed tif.

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

@ -3316,27 +3316,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;

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 */
}; };