Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Allow access of signed 16-bit TIFF pixel data as NumPy arrays #2577

Closed
wants to merge 4 commits into from
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions PIL/ImImagePlugin.py
Original file line number Diff line number Diff line change
Expand Up @@ -310,6 +310,7 @@ def tell(self):
"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"),
Expand Down
2 changes: 1 addition & 1 deletion PIL/Image.py
Original file line number Diff line number Diff line change
Expand Up @@ -223,7 +223,7 @@ def isImageType(t):
"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...

Expand Down
1 change: 1 addition & 0 deletions PIL/ImageMode.py
Original file line number Diff line number Diff line change
Expand Up @@ -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]
6 changes: 6 additions & 0 deletions Tests/test_mode_i16.py
Original file line number Diff line number Diff line change
Expand Up @@ -79,6 +79,7 @@ def basic(mode):
basic("I;16")
basic("I;16B")
basic("I;16L")
basic("I;16S")

basic("I")

Expand All @@ -92,6 +93,7 @@ def tobytes(mode):
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):
Expand All @@ -106,6 +108,10 @@ def test_convert(self):
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()
1 change: 1 addition & 0 deletions libImaging/Access.c
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand Down
60 changes: 59 additions & 1 deletion libImaging/Convert.c
Original file line number Diff line number Diff line change
Expand Up @@ -51,7 +51,7 @@

#ifndef round
double round(double x) {
return floor(x+0.5);
return floor(x+0.5);
}
#endif

Expand Down Expand Up @@ -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)
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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)
{
Expand All @@ -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;
Expand Down Expand Up @@ -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 }
};
Expand Down
1 change: 1 addition & 0 deletions libImaging/Pack.c
Original file line number Diff line number Diff line change
Expand Up @@ -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},
Expand Down
3 changes: 2 additions & 1 deletion libImaging/Storage.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
1 change: 1 addition & 0 deletions libImaging/Unpack.c
Original file line number Diff line number Diff line change
Expand Up @@ -1349,6 +1349,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, unpackI16N_I16}, // LibTiff native->image endian.
{"I;16L", "I;16N", 16, unpackI16N_I16}, // LibTiff native->image endian.
Expand Down