Merge pull request #1789 from zwhfly/tiff

Add Support for 2/4 bpp Tiff Grayscale Images
This commit is contained in:
wiredfool 2016-04-03 12:07:48 -07:00
commit 14f3b45f46
12 changed files with 212 additions and 18 deletions

View File

@ -141,34 +141,56 @@ OPEN_INFO = {
(MM, 0, (1,), 1, (1,), ()): ("1", "1;I"),
(II, 0, (1,), 2, (1,), ()): ("1", "1;IR"),
(MM, 0, (1,), 2, (1,), ()): ("1", "1;IR"),
(II, 1, (1,), 1, (1,), ()): ("1", "1"),
(MM, 1, (1,), 1, (1,), ()): ("1", "1"),
(II, 1, (1,), 2, (1,), ()): ("1", "1;R"),
(MM, 1, (1,), 2, (1,), ()): ("1", "1;R"),
(II, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
(MM, 0, (1,), 1, (2,), ()): ("L", "L;2I"),
(II, 0, (1,), 2, (2,), ()): ("L", "L;2IR"),
(MM, 0, (1,), 2, (2,), ()): ("L", "L;2IR"),
(II, 1, (1,), 1, (2,), ()): ("L", "L;2"),
(MM, 1, (1,), 1, (2,), ()): ("L", "L;2"),
(II, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
(MM, 1, (1,), 2, (2,), ()): ("L", "L;2R"),
(II, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
(MM, 0, (1,), 1, (4,), ()): ("L", "L;4I"),
(II, 0, (1,), 2, (4,), ()): ("L", "L;4IR"),
(MM, 0, (1,), 2, (4,), ()): ("L", "L;4IR"),
(II, 1, (1,), 1, (4,), ()): ("L", "L;4"),
(MM, 1, (1,), 1, (4,), ()): ("L", "L;4"),
(II, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
(MM, 1, (1,), 2, (4,), ()): ("L", "L;4R"),
(II, 0, (1,), 1, (8,), ()): ("L", "L;I"),
(MM, 0, (1,), 1, (8,), ()): ("L", "L;I"),
(II, 0, (1,), 2, (8,), ()): ("L", "L;IR"),
(MM, 0, (1,), 2, (8,), ()): ("L", "L;IR"),
(II, 0, (3,), 1, (32,), ()): ("F", "F;32F"),
(MM, 0, (3,), 1, (32,), ()): ("F", "F;32BF"),
(II, 1, (1,), 1, (1,), ()): ("1", "1"),
(MM, 1, (1,), 1, (1,), ()): ("1", "1"),
(II, 1, (1,), 1, (4,), ()): ("L", "L;4"),
# ?
(II, 1, (1,), 2, (1,), ()): ("1", "1;R"),
(MM, 1, (1,), 2, (1,), ()): ("1", "1;R"),
(II, 1, (1,), 1, (8,), ()): ("L", "L"),
(MM, 1, (1,), 1, (8,), ()): ("L", "L"),
(II, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
(MM, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
(II, 1, (1,), 2, (8,), ()): ("L", "L;R"),
(MM, 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"),
(MM, 1, (1,), 1, (16,), ()): ("I;16B", "I;16B"),
(II, 1, (2,), 1, (16,), ()): ("I;16S", "I;16S"),
(MM, 1, (2,), 1, (16,), ()): ("I;16BS", "I;16BS"),
(II, 0, (3,), 1, (32,), ()): ("F", "F;32F"),
(MM, 0, (3,), 1, (32,), ()): ("F", "F;32BF"),
(II, 1, (1,), 1, (32,), ()): ("I", "I;32N"),
(II, 1, (2,), 1, (32,), ()): ("I", "I;32S"),
(MM, 1, (2,), 1, (32,), ()): ("I;32BS", "I;32BS"),
(II, 1, (3,), 1, (32,), ()): ("F", "F;32F"),
(MM, 1, (3,), 1, (32,), ()): ("F", "F;32BF"),
(II, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
(MM, 1, (1,), 1, (8, 8), (2,)): ("LA", "LA"),
(II, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
(MM, 2, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
(II, 2, (1,), 2, (8, 8, 8), ()): ("RGB", "RGB;R"),
@ -183,6 +205,7 @@ OPEN_INFO = {
(MM, 2, (1,), 1, (8, 8, 8, 8), (2,)): ("RGBA", "RGBA"),
(II, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
(MM, 2, (1,), 1, (8, 8, 8, 8), (999,)): ("RGBA", "RGBA"), # Corel Draw 10
(II, 3, (1,), 1, (1,), ()): ("P", "P;1"),
(MM, 3, (1,), 1, (1,), ()): ("P", "P;1"),
(II, 3, (1,), 2, (1,), ()): ("P", "P;1R"),
@ -201,10 +224,13 @@ OPEN_INFO = {
(MM, 3, (1,), 1, (8, 8), (2,)): ("PA", "PA"),
(II, 3, (1,), 2, (8,), ()): ("P", "P;R"),
(MM, 3, (1,), 2, (8,), ()): ("P", "P;R"),
(II, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
(MM, 5, (1,), 1, (8, 8, 8, 8), ()): ("CMYK", "CMYK"),
(II, 6, (1,), 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
(MM, 6, (1,), 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
(II, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
(MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
}

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

Binary file not shown.

View File

@ -419,6 +419,39 @@ class TestFileLibTiff(LibTiffTestCase):
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, 7.3)
def test_gray_semibyte_per_pixel(self):
test_files = (
(
24.8,#epsilon
(#group
"Tests/images/tiff_gray_2_4_bpp/hopper2.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2I.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2R.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2IR.tif",
)
),
(
7.3,#epsilon
(#group
"Tests/images/tiff_gray_2_4_bpp/hopper4.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4I.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4R.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4IR.tif",
)
),
)
original = hopper("L")
for epsilon, group in test_files:
im = Image.open(group[0])
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, epsilon)
for file in group[1:]:
im2 = Image.open(file)
self.assertEqual(im2.size, (128, 128))
self.assertEqual(im2.mode, "L")
self.assert_image_equal(im, im2)
def test_save_bytesio(self):
# PR 1011
# Test TIFF saving to io.BytesIO() object.

View File

@ -337,6 +337,39 @@ class TestFileTiff(PillowTestCase):
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, 7.3)
def test_gray_semibyte_per_pixel(self):
test_files = (
(
24.8,#epsilon
(#group
"Tests/images/tiff_gray_2_4_bpp/hopper2.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2I.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2R.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper2IR.tif",
)
),
(
7.3,#epsilon
(#group
"Tests/images/tiff_gray_2_4_bpp/hopper4.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4I.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4R.tif",
"Tests/images/tiff_gray_2_4_bpp/hopper4IR.tif",
)
),
)
original = hopper("L")
for epsilon, group in test_files:
im = Image.open(group[0])
self.assertEqual(im.size, (128, 128))
self.assertEqual(im.mode, "L")
self.assert_image_similar(im, original, epsilon)
for file in group[1:]:
im2 = Image.open(file)
self.assertEqual(im2.size, (128, 128))
self.assertEqual(im2.mode, "L")
self.assert_image_equal(im, im2)
def test_page_number_x_0(self):
# Issue 973
# Test TIFF with tag 297 (Page Number) having value of 0 0.

View File

@ -191,14 +191,64 @@ unpack1IR(UINT8* out, const UINT8* in, int pixels)
static void
unpackL2(UINT8* out, const UINT8* in, int pixels)
{
/* nibbles */
/* nibbles (msb first, white is non-zero) */
while (pixels > 0) {
UINT8 byte = *in++;
switch (pixels) {
default: *out++ = ((byte >> 6) & 3) * 255 / 3; byte <<= 2;
case 3: *out++ = ((byte >> 6) & 3) * 255 / 3; byte <<= 2;
case 2: *out++ = ((byte >> 6) & 3) * 255 / 3; byte <<= 2;
case 1: *out++ = ((byte >> 6) & 3) * 255 / 3;
default: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
case 3: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
case 2: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
case 1: *out++ = ((byte >> 6) & 0x03U) * 0x55U;
}
pixels -= 4;
}
}
static void
unpackL2I(UINT8* out, const UINT8* in, int pixels)
{
/* nibbles (msb first, white is zero) */
while (pixels > 0) {
UINT8 byte = *in++;
switch (pixels) {
default: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
case 3: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
case 2: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
case 1: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
}
pixels -= 4;
}
}
static void
unpackL2R(UINT8* out, const UINT8* in, int pixels)
{
/* nibbles (bit order reversed, white is non-zero) */
while (pixels > 0) {
UINT8 byte = *in++;
byte = BITFLIP[byte];
switch (pixels) {
default: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
case 3: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
case 2: *out++ = ((byte >> 6) & 0x03U) * 0x55U; byte <<= 2;
case 1: *out++ = ((byte >> 6) & 0x03U) * 0x55U;
}
pixels -= 4;
}
}
static void
unpackL2IR(UINT8* out, const UINT8* in, int pixels)
{
/* nibbles (bit order reversed, white is zero) */
while (pixels > 0) {
UINT8 byte = *in++;
byte = BITFLIP[byte];
switch (pixels) {
default: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
case 3: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
case 2: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U); byte <<= 2;
case 1: *out++ = 0xFFU - (UINT8)(((byte >> 6) & 0x03U) * 0x55U);
}
pixels -= 4;
}
@ -207,12 +257,56 @@ unpackL2(UINT8* out, const UINT8* in, int pixels)
static void
unpackL4(UINT8* out, const UINT8* in, int pixels)
{
/* nibbles */
/* nibbles (msb first, white is non-zero) */
while (pixels > 0) {
UINT8 byte = *in++;
switch (pixels) {
default: *out++ = ((byte >> 4) & 15) * 255 / 15; byte <<= 4;
case 1: *out++ = ((byte >> 4) & 15) * 255 / 15;
default: *out++ = ((byte >> 4) & 0x0FU) * 0x11U; byte <<= 4;
case 1: *out++ = ((byte >> 4) & 0x0FU) * 0x11U;
}
pixels -= 2;
}
}
static void
unpackL4I(UINT8* out, const UINT8* in, int pixels)
{
/* nibbles (msb first, white is zero) */
while (pixels > 0) {
UINT8 byte = *in++;
switch (pixels) {
default: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); byte <<= 4;
case 1: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U);
}
pixels -= 2;
}
}
static void
unpackL4R(UINT8* out, const UINT8* in, int pixels)
{
/* nibbles (bit order reversed, white is non-zero) */
while (pixels > 0) {
UINT8 byte = *in++;
byte = BITFLIP[byte];
switch (pixels) {
default: *out++ = ((byte >> 4) & 0x0FU) * 0x11U; byte <<= 4;
case 1: *out++ = ((byte >> 4) & 0x0FU) * 0x11U;
}
pixels -= 2;
}
}
static void
unpackL4IR(UINT8* out, const UINT8* in, int pixels)
{
/* nibbles (bit order reversed, white is zero) */
while (pixels > 0) {
UINT8 byte = *in++;
byte = BITFLIP[byte];
switch (pixels) {
default: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U); byte <<= 4;
case 1: *out++ = 0xFFU - (UINT8)(((byte >> 4) & 0x0FU) * 0x11U);
}
pixels -= 2;
}
@ -1053,7 +1147,15 @@ static struct {
/* greyscale */
{"L", "L;2", 2, unpackL2},
{"L", "L;2I", 2, unpackL2I},
{"L", "L;2R", 2, unpackL2R},
{"L", "L;2IR", 2, unpackL2IR},
{"L", "L;4", 4, unpackL4},
{"L", "L;4I", 4, unpackL4I},
{"L", "L;4R", 4, unpackL4R},
{"L", "L;4IR", 4, unpackL4IR},
{"L", "L", 8, copy1},
{"L", "L;I", 8, unpackLI},
{"L", "L;R", 8, unpackLR},