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 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)
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,8), (2,)): ("LA", "LA"),
(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, 2, 1, (16,), ()): ("I;16S", "I;16S"),
(II, 1, 1, 1, (32,), ()): ("I", "I;32N"),
@ -675,8 +678,8 @@ 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 """
""" Overload method triggered when we detect a compressed tiff
Calls out to libtiff """
pixel = Image.Image.load(self)
@ -691,7 +694,7 @@ class TiffImageFile(ImageFile.ImageFile):
raise IOError("Not exactly one tile")
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:
d.setimage(self.im, e)
except ValueError:
@ -817,11 +820,11 @@ class TiffImageFile(ImageFile.ImageFile):
offsets = self.tag[STRIPOFFSETS]
h = getscalar(ROWSPERSTRIP, ysize)
w = self.size[0]
if self._compression in ["tiff_ccitt", "group3", "group4",
"tiff_jpeg", "tiff_adobe_deflate",
"tiff_thunderscan", "tiff_deflate",
"tiff_sgilog", "tiff_sgilog24",
"tiff_raw_16"]:
if READ_LIBTIFF or self._compression in ["tiff_ccitt", "group3", "group4",
"tiff_jpeg", "tiff_adobe_deflate",
"tiff_thunderscan", "tiff_deflate",
"tiff_sgilog", "tiff_sgilog24",
"tiff_raw_16"]:
## if Image.DEBUG:
## 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
# contains I;16, we need to convert from native to image
# 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'
# 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)
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
if not libtiff and fp.tell() == 0:
# 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.
atts={}
# bits per sample is a single short in the tiff directory, not a list.
atts[BITSPERSAMPLE] = bits[0]
# Merge the ones that we have with (optional) more bits from
# the original file, e.g x,y resolution so that we can
# save(load('')) == original file.
@ -1100,8 +1109,8 @@ def _save(im, fp, filename):
continue
if type(v) == tuple and len(v) > 2:
# List of ints?
# BitsPerSample is one example, I get (8,8,8)
# UNDONE
if type(v[0]) in (int, float):
atts[k] = list(v)
continue
if type(v) == tuple and len(v) == 2:
# one rational tuple
@ -1121,8 +1130,8 @@ def _save(im, fp, filename):
if Image.DEBUG:
print (atts)
# libtiff always returns the bytes in native order.
# we're expecting image byte order. So, if the rawmode
# libtiff always expects the bytes in native order.
# we're storing image byte order. So, if the rawmode
# contains I;16, we need to convert from native to image
# byte order.
if im.mode in ('I;16B', 'I;16'):
@ -1130,7 +1139,7 @@ def _save(im, fp, filename):
a = (rawmode, compression, _fp, filename, atts)
# 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)
while 1:
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 PIL import Image
from PIL import Image, TiffImagePlugin
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")
def _assert_noerr(im):
@ -141,7 +141,7 @@ def test_g3_compression():
assert_image_equal(reread, i)
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.mode, 'I;16')
@ -156,7 +156,7 @@ def test_little_endian():
out = tempfile("temp.tif")
out = "temp.le.tif"
#out = "temp.le.tif"
im.save(out)
reread = Image.open(out)
@ -166,7 +166,7 @@ def test_little_endian():
# on big endian, we'll get back mode = 'I;16B' here.
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.mode, 'I;16B')
@ -201,4 +201,87 @@ def test_g4_string_info():
reread = Image.open(out)
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)
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")
""" 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():
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.mode, 'I;16')
@ -89,7 +89,7 @@ def test_little_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.mode, 'I;16B')
@ -102,3 +102,29 @@ def test_big_endian():
else:
assert_equal(b[0], b'\x01')
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')
_test_float_conversion(im.convert('L'))
def test_12bit():
im = Image.open('Tests/images/12bit.cropped.tif')
def test_16bit():
im = Image.open('Tests/images/16bit.cropped.tif')
_test_float_conversion(im)
def test_12bit_workaround():
im = Image.open('Tests/images/12bit.cropped.tif')
def test_16bit_workaround():
im = Image.open('Tests/images/16bit.cropped.tif')
_test_float_conversion(im.convert('I'))

View File

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

View File

@ -3317,27 +3317,8 @@ static PyMethodDef functions[] = {
#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_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},
{"libtiff_decoder", (PyCFunction)PyImaging_LibTiffDecoderNew, 1},
{"libtiff_encoder", (PyCFunction)PyImaging_LibTiffEncoderNew, 1},
#endif
{"msp_decoder", (PyCFunction)PyImaging_MspDecoderNew, 1},
{"packbits_decoder", (PyCFunction)PyImaging_PackbitsDecoderNew, 1},

View File

@ -427,7 +427,6 @@ PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
char* mode;
char* rawmode;
char* compname;
int compression;
int 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));
/* 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));
if (decoder == NULL)
return NULL;
@ -482,7 +441,7 @@ PyImaging_LibTiffDecoderNew(PyObject* self, PyObject* args)
if (get_unpacker(decoder, mode, rawmode) < 0)
return NULL;
if (! ImagingLibTiffInit(&decoder->state, compression, fp)) {
if (! ImagingLibTiffInit(&decoder->state, fp)) {
Py_DECREF(decoder);
PyErr_SetString(PyExc_RuntimeError, "tiff codec initialization failed");
return NULL;

View File

@ -673,7 +673,6 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
char* rawmode;
char* compname;
char* filename;
int compression;
int fp;
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));
/* 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));
if (encoder == NULL)
return NULL;
@ -780,18 +738,35 @@ PyImaging_LibTiffEncoderNew(PyObject* self, PyObject* args)
} else if(PyList_Check(value)) {
int len,i;
float *floatav;
int *intav;
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));
if (len) {
if (PyInt_Check(PyList_GetItem(value,0))) {
TRACE((" %d elements, setting as ints \n", len));
intav = malloc(sizeof(int)*len);
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)) {
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;
}
int ImagingLibTiffInit(ImagingCodecState state, int compression, int fp) {
int ImagingLibTiffInit(ImagingCodecState state, int fp) {
TIFFSTATE *clientstate = (TIFFSTATE *)state->context;
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,
state->x, state->y, state->ystep));
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 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
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;16B", "I;16N", 16, unpackI16N_I16B},
{"I;16", "I;12", 12, unpackI12_I16}, // 12 bit Tiffs stored in 16bits.
{NULL} /* sentinel */
};