From 5a3bf848046cc7c7ab5ae602d0da507c691039c9 Mon Sep 17 00:00:00 2001 From: Tom Goddard Date: Tue, 13 Jun 2017 18:24:07 -0700 Subject: [PATCH 1/4] Add basic support for TIFF 16-bit signed integer pixels (mode I;16S). Only small additions needed to access the pixel data as numpy arrays were made. Code to convert to other pixel types such as 32-bit integers are not included. --- libImaging/Access.c | 1 + libImaging/Pack.c | 1 + libImaging/Storage.c | 3 ++- libImaging/Unpack.c | 2 ++ 4 files changed, 6 insertions(+), 1 deletion(-) diff --git a/libImaging/Access.c b/libImaging/Access.c index 292968f1c..05eb10c7c 100644 --- a/libImaging/Access.c +++ b/libImaging/Access.c @@ -227,6 +227,7 @@ ImagingAccessInit() ADD("I;16", line_16, get_pixel_16L, put_pixel_16L); ADD("I;16L", line_16, get_pixel_16L, put_pixel_16L); ADD("I;16B", line_16, get_pixel_16B, put_pixel_16B); + ADD("I;16S", line_16, get_pixel_16L, put_pixel_16L); ADD("I;32L", line_32, get_pixel_32L, put_pixel_32L); ADD("I;32B", line_32, get_pixel_32B, put_pixel_32B); ADD("F", line_32, get_pixel_32, put_pixel_32); diff --git a/libImaging/Pack.c b/libImaging/Pack.c index 621936351..a0193246e 100644 --- a/libImaging/Pack.c +++ b/libImaging/Pack.c @@ -613,6 +613,7 @@ static struct { {"I;16", "I;16", 16, copy2}, {"I;16B", "I;16B", 16, copy2}, {"I;16L", "I;16L", 16, copy2}, + {"I;16S", "I;16S", 16, copy2}, {"I;16", "I;16N", 16, packI16N_I16}, // LibTiff native->image endian. {"I;16L", "I;16N", 16, packI16N_I16}, {"I;16B", "I;16N", 16, packI16N_I16B}, diff --git a/libImaging/Storage.c b/libImaging/Storage.c index fb27572d3..aae03ade5 100644 --- a/libImaging/Storage.c +++ b/libImaging/Storage.c @@ -117,7 +117,8 @@ ImagingNewPrologueSubtype(const char *mode, int xsize, int ysize, im->type = IMAGING_TYPE_INT32; } else if (strcmp(mode, "I;16") == 0 || strcmp(mode, "I;16L") == 0 \ - || strcmp(mode, "I;16B") == 0 || strcmp(mode, "I;16N") == 0) { + || strcmp(mode, "I;16B") == 0 || strcmp(mode, "I;16N") == 0 \ + || strcmp(mode, "I;16S") == 0) { /* EXPERIMENTAL */ /* 16-bit raw integer images */ im->bands = 1; diff --git a/libImaging/Unpack.c b/libImaging/Unpack.c index dfc8a4d7e..ca34acdd8 100644 --- a/libImaging/Unpack.c +++ b/libImaging/Unpack.c @@ -1349,10 +1349,12 @@ static struct { {"I;16", "I;16", 16, copy2}, {"I;16B", "I;16B", 16, copy2}, {"I;16L", "I;16L", 16, copy2}, + {"I;16S", "I;16S", 16, copy2}, {"I;16", "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;16S", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian. {"I;16", "I;12", 12, unpackI12_I16}, // 12 bit Tiffs stored in 16bits. From effb3cbd25059425f35f5a4e31a8b7c2b875efaf Mon Sep 17 00:00:00 2001 From: Tom Goddard Date: Tue, 13 Jun 2017 19:21:00 -0700 Subject: [PATCH 2/4] Removed test code. --- libImaging/Unpack.c | 1 - 1 file changed, 1 deletion(-) diff --git a/libImaging/Unpack.c b/libImaging/Unpack.c index ca34acdd8..ec0e85732 100644 --- a/libImaging/Unpack.c +++ b/libImaging/Unpack.c @@ -1354,7 +1354,6 @@ static struct { {"I;16", "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;16S", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian. {"I;16", "I;12", 12, unpackI12_I16}, // 12 bit Tiffs stored in 16bits. From 02f0ee5dc49c2e46fc96701d4f95453b0f569d4d Mon Sep 17 00:00:00 2001 From: Tom Goddard Date: Thu, 15 Jun 2017 13:21:54 -0700 Subject: [PATCH 3/4] Added conversions between I;16S and modes I, L, and unit test for I;16S. --- PIL/ImImagePlugin.py | 1 + PIL/Image.py | 2 +- PIL/ImageMode.py | 1 + Tests/test_mode_i16.py | 6 +++++ libImaging/Convert.c | 58 ++++++++++++++++++++++++++++++++++++++++++ 5 files changed, 67 insertions(+), 1 deletion(-) diff --git a/PIL/ImImagePlugin.py b/PIL/ImImagePlugin.py index 3371b303f..388015b7f 100644 --- a/PIL/ImImagePlugin.py +++ b/PIL/ImImagePlugin.py @@ -310,6 +310,7 @@ SAVE = { "I;16": ("L 16", "I;16"), "I;16L": ("L 16L", "I;16L"), "I;16B": ("L 16B", "I;16B"), + "I;16S": ("L 16S", "I;16S"), "F": ("L 32F", "F;32F"), "RGB": ("RGB", "RGB;L"), "RGBA": ("RGBA", "RGBA;L"), diff --git a/PIL/Image.py b/PIL/Image.py index c22ab3955..5205bbf42 100644 --- a/PIL/Image.py +++ b/PIL/Image.py @@ -223,7 +223,7 @@ _MODEINFO = { "LAB": ("RGB", "L", ("L", "A", "B")), "HSV": ("RGB", "L", ("H", "S", "V")), - # Experimental modes include I;16, I;16L, I;16B, RGBa, BGR;15, and + # Experimental modes include I;16, I;16L, I;16B, I;16S, RGBa, BGR;15, and # BGR;24. Use these modes only if you know exactly what you're # doing... diff --git a/PIL/ImageMode.py b/PIL/ImageMode.py index b227f2127..3f638d5f5 100644 --- a/PIL/ImageMode.py +++ b/PIL/ImageMode.py @@ -50,6 +50,7 @@ def getmode(mode): modes["I;16"] = ModeDescriptor("I;16", "I", "L", "L") modes["I;16L"] = ModeDescriptor("I;16L", "I", "L", "L") modes["I;16B"] = ModeDescriptor("I;16B", "I", "L", "L") + modes["I;16S"] = ModeDescriptor("I;16S", "I", "L", "L") # set global mode cache atomically _modes = modes return _modes[mode] diff --git a/Tests/test_mode_i16.py b/Tests/test_mode_i16.py index d51847199..b150126f0 100644 --- a/Tests/test_mode_i16.py +++ b/Tests/test_mode_i16.py @@ -79,6 +79,7 @@ class TestModeI16(PillowTestCase): basic("I;16") basic("I;16B") basic("I;16L") + basic("I;16S") basic("I") @@ -92,6 +93,7 @@ class TestModeI16(PillowTestCase): self.assertEqual(tobytes("L"), b"\x01") self.assertEqual(tobytes("I;16"), b"\x01\x00") self.assertEqual(tobytes("I;16B"), b"\x00\x01") + self.assertEqual(tobytes("I;16S"), b"\x01\x00") self.assertEqual(tobytes("I"), b"\x01\x00\x00\x00"[::order]) def test_convert(self): @@ -106,6 +108,10 @@ class TestModeI16(PillowTestCase): self.verify(im.convert("I;16B").convert("L")) self.verify(im.convert("I;16B").convert("I")) + self.verify(im.convert("I;16S")) + self.verify(im.convert("I;16S").convert("L")) + self.verify(im.convert("I;16S").convert("I")) + if __name__ == '__main__': unittest.main() diff --git a/libImaging/Convert.c b/libImaging/Convert.c index 0ec5ef864..19337a3e4 100644 --- a/libImaging/Convert.c +++ b/libImaging/Convert.c @@ -693,6 +693,17 @@ I_I16B(UINT8* out, const UINT8* in_, int xsize) } } +static void +I_I16S(UINT8* out, const UINT8* in_, int xsize) +{ + int x, v; + INT32* in = (INT32*) in_; + for (x = 0; x < xsize; x++, in++) { + v = CLIP16(*in); + *out++ = (UINT8) v; + *out++ = (UINT8) (v >> 8); + } +} static void I16L_I(UINT8* out_, const UINT8* in, int xsize) @@ -713,6 +724,15 @@ I16B_I(UINT8* out_, const UINT8* in, int xsize) *out++ = in[1] + ((int) in[0] << 8); } +static void +I16S_I(UINT8* out_, const UINT8* in, int xsize) +{ + int x; + INT32* out = (INT32*) out_; + for (x = 0; x < xsize; x++, in += 2) + *out++ = (INT16)(in[0] + ((int) in[1] << 8)); +} + static void I16L_F(UINT8* out_, const UINT8* in, int xsize) { @@ -732,6 +752,15 @@ I16B_F(UINT8* out_, const UINT8* in, int xsize) *out++ = (FLOAT32) (in[1] + ((int) in[0] << 8)); } +static void +I16S_F(UINT8* out_, const UINT8* in, int xsize) +{ + int x; + FLOAT32* out = (FLOAT32*) out_; + for (x = 0; x < xsize; x++, in += 2) + *out++ = (FLOAT32) (INT16) (in[0] + ((int) in[1] << 8)); +} + static void L_I16L(UINT8* out, const UINT8* in, int xsize) { @@ -752,6 +781,16 @@ L_I16B(UINT8* out, const UINT8* in, int xsize) } } +static void +L_I16S(UINT8* out, const UINT8* in, int xsize) +{ + int x; + for (x = 0; x < xsize; x++, in++) { + *out++ = *in; + *out++ = 0; + } +} + static void I16L_L(UINT8* out, const UINT8* in, int xsize) { @@ -774,6 +813,19 @@ I16B_L(UINT8* out, const UINT8* in, int xsize) *out++ = in[1]; } +static void +I16S_L(UINT8* out, const UINT8* in, int xsize) +{ + int x; + for (x = 0; x < xsize; x++, in += 2) + if (in[1] & 0x80) + *out++ = 0; /* Negative -> 0 */ + else if (in[1] != 0) + *out++ = 255; /* Greater than 255 -> 255 */ + else + *out++ = in[0]; +} + static struct { const char* from; const char* to; @@ -872,9 +924,15 @@ static struct { { "L", "I;16B", L_I16B }, { "I;16B", "L", I16B_L }, + { "I", "I;16S", I_I16S }, + { "I;16S", "I", I16S_I }, + { "L", "I;16S", L_I16S }, + { "I;16S", "L", I16S_L }, + { "I;16", "F", I16L_F }, { "I;16L", "F", I16L_F }, { "I;16B", "F", I16B_F }, + { "I;16S", "F", I16S_F }, { NULL } }; From 34c8cbfc0e73640a11bf595def0320d7d89ee59f Mon Sep 17 00:00:00 2001 From: Tom Goddard Date: Mon, 11 Sep 2017 11:02:41 -0700 Subject: [PATCH 4/4] Fixed indentation to use 4 spaces. --- libImaging/Convert.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/libImaging/Convert.c b/libImaging/Convert.c index 19337a3e4..1b49f9d41 100644 --- a/libImaging/Convert.c +++ b/libImaging/Convert.c @@ -51,7 +51,7 @@ #ifndef round double round(double x) { - return floor(x+0.5); + return floor(x+0.5); } #endif @@ -730,7 +730,7 @@ I16S_I(UINT8* out_, const UINT8* in, int xsize) int x; INT32* out = (INT32*) out_; for (x = 0; x < xsize; x++, in += 2) - *out++ = (INT16)(in[0] + ((int) in[1] << 8)); + *out++ = (INT16)(in[0] + ((int) in[1] << 8)); } static void @@ -819,9 +819,9 @@ I16S_L(UINT8* out, const UINT8* in, int xsize) int x; for (x = 0; x < xsize; x++, in += 2) if (in[1] & 0x80) - *out++ = 0; /* Negative -> 0 */ + *out++ = 0; /* Negative -> 0 */ else if (in[1] != 0) - *out++ = 255; /* Greater than 255 -> 255 */ + *out++ = 255; /* Greater than 255 -> 255 */ else *out++ = in[0]; }