diff --git a/Tests/images/tiff_strip_planar_16bit_RGB.tiff b/Tests/images/tiff_strip_planar_16bit_RGB.tiff new file mode 100644 index 00000000000..360b4c16533 Binary files /dev/null and b/Tests/images/tiff_strip_planar_16bit_RGB.tiff differ diff --git a/Tests/images/tiff_strip_planar_16bit_RGBa.tiff b/Tests/images/tiff_strip_planar_16bit_RGBa.tiff new file mode 100644 index 00000000000..b8c3dcf6438 Binary files /dev/null and b/Tests/images/tiff_strip_planar_16bit_RGBa.tiff differ diff --git a/Tests/images/tiff_strip_planar_lzw.tiff b/Tests/images/tiff_strip_planar_lzw.tiff new file mode 100644 index 00000000000..8145703f430 Binary files /dev/null and b/Tests/images/tiff_strip_planar_lzw.tiff differ diff --git a/Tests/images/tiff_tiled_planar_16bit_RGB.tiff b/Tests/images/tiff_tiled_planar_16bit_RGB.tiff new file mode 100644 index 00000000000..0376e90a7be Binary files /dev/null and b/Tests/images/tiff_tiled_planar_16bit_RGB.tiff differ diff --git a/Tests/images/tiff_tiled_planar_16bit_RGBa.tiff b/Tests/images/tiff_tiled_planar_16bit_RGBa.tiff new file mode 100644 index 00000000000..ae777386704 Binary files /dev/null and b/Tests/images/tiff_tiled_planar_16bit_RGBa.tiff differ diff --git a/Tests/images/tiff_tiled_planar_lzw.tiff b/Tests/images/tiff_tiled_planar_lzw.tiff new file mode 100644 index 00000000000..57cd6094a28 Binary files /dev/null and b/Tests/images/tiff_tiled_planar_lzw.tiff differ diff --git a/Tests/test_file_libtiff.py b/Tests/test_file_libtiff.py index 7d3e10c2491..3b684b46d29 100644 --- a/Tests/test_file_libtiff.py +++ b/Tests/test_file_libtiff.py @@ -843,6 +843,52 @@ def test_tiled_ycbcr_jpeg_2x2_sampling(self): with Image.open(infile) as im: assert_image_similar_tofile(im, "Tests/images/flower.jpg", 0.5) + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_strip_planar_rgb(self): + # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_strip_raw.tif tiff_strip_planar_lzw.tiff + infile = "Tests/images/tiff_strip_planar_lzw.tiff" + with Image.open(infile) as im: + assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") + + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_tiled_planar_rgb(self): + # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_tiled_raw.tif tiff_tiled_planar_lzw.tiff + infile = "Tests/images/tiff_tiled_planar_lzw.tiff" + with Image.open(infile) as im: + assert_image_equal_tofile(im, "Tests/images/tiff_adobe_deflate.png") + + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_tiled_planar_16bit_RGB(self): + # gdal_translate -co TILED=yes -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_16bit_RGB.tiff tiff_tiled_planar_16bit_RGB.tiff + with Image.open("Tests/images/tiff_tiled_planar_16bit_RGB.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") + + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_strip_planar_16bit_RGB(self): + # gdal_translate -co TILED=no -co INTERLEAVE=BAND -co COMPRESS=LZW \ + # tiff_16bit_RGB.tiff tiff_strip_planar_16bit_RGB.tiff + with Image.open("Tests/images/tiff_strip_planar_16bit_RGB.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGB_target.png") + + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_tiled_planar_16bit_RGBa(self): + # gdal_translate -co TILED=yes \ + # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ + # tiff_16bit_RGBa.tiff tiff_tiled_planar_16bit_RGBa.tiff + with Image.open("Tests/images/tiff_tiled_planar_16bit_RGBa.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") + + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") + def test_strip_planar_16bit_RGBa(self): + # gdal_translate -co TILED=no \ + # -co INTERLEAVE=BAND -co COMPRESS=LZW -co ALPHA=PREMULTIPLIED \ + # tiff_16bit_RGBa.tiff tiff_strip_planar_16bit_RGBa.tiff + with Image.open("Tests/images/tiff_strip_planar_16bit_RGBa.tiff") as im: + assert_image_equal_tofile(im, "Tests/images/tiff_16bit_RGBa_target.png") + @pytest.mark.xfail(is_big_endian(), reason="Fails on big-endian") def test_old_style_jpeg(self): infile = "Tests/images/old-style-jpeg-compression.tif" diff --git a/Tests/test_lib_pack.py b/Tests/test_lib_pack.py index 8a146034672..af7eae935f6 100644 --- a/Tests/test_lib_pack.py +++ b/Tests/test_lib_pack.py @@ -320,6 +320,23 @@ def test_RGB(self): self.assert_unpack("RGB", "G", 1, (0, 1, 0), (0, 2, 0), (0, 3, 0)) self.assert_unpack("RGB", "B", 1, (0, 0, 1), (0, 0, 2), (0, 0, 3)) + self.assert_unpack("RGB", "R;16B", 2, (1, 0, 0), (3, 0, 0), (5, 0, 0)) + self.assert_unpack("RGB", "G;16B", 2, (0, 1, 0), (0, 3, 0), (0, 5, 0)) + self.assert_unpack("RGB", "B;16B", 2, (0, 0, 1), (0, 0, 3), (0, 0, 5)) + + self.assert_unpack("RGB", "R;16L", 2, (2, 0, 0), (4, 0, 0), (6, 0, 0)) + self.assert_unpack("RGB", "G;16L", 2, (0, 2, 0), (0, 4, 0), (0, 6, 0)) + self.assert_unpack("RGB", "B;16L", 2, (0, 0, 2), (0, 0, 4), (0, 0, 6)) + + if sys.byteorder == "little": + self.assert_unpack("RGB", "R;16N", 2, (2, 0, 0), (4, 0, 0), (6, 0, 0)) + self.assert_unpack("RGB", "G;16N", 2, (0, 2, 0), (0, 4, 0), (0, 6, 0)) + self.assert_unpack("RGB", "B;16N", 2, (0, 0, 2), (0, 0, 4), (0, 0, 6)) + else: + self.assert_unpack("RGB", "R;16N", 2, (1, 0, 0), (3, 0, 0), (5, 0, 0)) + self.assert_unpack("RGB", "G;16N", 2, (0, 1, 0), (0, 3, 0), (0, 5, 0)) + self.assert_unpack("RGB", "B;16N", 2, (0, 0, 1), (0, 0, 3), (0, 0, 5)) + def test_RGBA(self): self.assert_unpack("RGBA", "LA", 2, (1, 1, 1, 2), (3, 3, 3, 4), (5, 5, 5, 6)) self.assert_unpack( @@ -450,6 +467,43 @@ def test_RGBA(self): self.assert_unpack("RGBA", "B", 1, (0, 0, 1, 0), (0, 0, 2, 0), (0, 0, 3, 0)) self.assert_unpack("RGBA", "A", 1, (0, 0, 0, 1), (0, 0, 0, 2), (0, 0, 0, 3)) + self.assert_unpack("RGBA", "R;16B", 2, (1, 0, 0, 0), (3, 0, 0, 0), (5, 0, 0, 0)) + self.assert_unpack("RGBA", "G;16B", 2, (0, 1, 0, 0), (0, 3, 0, 0), (0, 5, 0, 0)) + self.assert_unpack("RGBA", "B;16B", 2, (0, 0, 1, 0), (0, 0, 3, 0), (0, 0, 5, 0)) + self.assert_unpack("RGBA", "A;16B", 2, (0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5)) + + self.assert_unpack("RGBA", "R;16L", 2, (2, 0, 0, 0), (4, 0, 0, 0), (6, 0, 0, 0)) + self.assert_unpack("RGBA", "G;16L", 2, (0, 2, 0, 0), (0, 4, 0, 0), (0, 6, 0, 0)) + self.assert_unpack("RGBA", "B;16L", 2, (0, 0, 2, 0), (0, 0, 4, 0), (0, 0, 6, 0)) + self.assert_unpack("RGBA", "A;16L", 2, (0, 0, 0, 2), (0, 0, 0, 4), (0, 0, 0, 6)) + + if sys.byteorder == "little": + self.assert_unpack( + "RGBA", "R;16N", 2, (2, 0, 0, 0), (4, 0, 0, 0), (6, 0, 0, 0) + ) + self.assert_unpack( + "RGBA", "G;16N", 2, (0, 2, 0, 0), (0, 4, 0, 0), (0, 6, 0, 0) + ) + self.assert_unpack( + "RGBA", "B;16N", 2, (0, 0, 2, 0), (0, 0, 4, 0), (0, 0, 6, 0) + ) + self.assert_unpack( + "RGBA", "A;16N", 2, (0, 0, 0, 2), (0, 0, 0, 4), (0, 0, 0, 6) + ) + else: + self.assert_unpack( + "RGBA", "R;16N", 2, (1, 0, 0, 0), (3, 0, 0, 0), (5, 0, 0, 0) + ) + self.assert_unpack( + "RGBA", "G;16N", 2, (0, 1, 0, 0), (0, 3, 0, 0), (0, 5, 0, 0) + ) + self.assert_unpack( + "RGBA", "B;16N", 2, (0, 0, 1, 0), (0, 0, 3, 0), (0, 0, 5, 0) + ) + self.assert_unpack( + "RGBA", "A;16N", 2, (0, 0, 0, 1), (0, 0, 0, 3), (0, 0, 0, 5) + ) + def test_RGBa(self): self.assert_unpack( "RGBa", "RGBa", 4, (1, 2, 3, 4), (5, 6, 7, 8), (9, 10, 11, 12) diff --git a/src/libImaging/TiffDecode.c b/src/libImaging/TiffDecode.c index f33cbc6bd61..329f80fefcc 100644 --- a/src/libImaging/TiffDecode.c +++ b/src/libImaging/TiffDecode.c @@ -181,7 +181,7 @@ int ImagingLibTiffInit(ImagingCodecState state, int fp, uint32 offset) { } -int ReadTile(TIFF* tiff, UINT32 col, UINT32 row, UINT32* buffer) { +int ReadTile(TIFF* tiff, UINT32 col, UINT32 row, UINT8 plane, UINT32* buffer) { uint16 photometric = 0; TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); @@ -228,7 +228,7 @@ int ReadTile(TIFF* tiff, UINT32 col, UINT32 row, UINT32* buffer) { return 0; } - if (TIFFReadTile(tiff, (tdata_t)buffer, col, row, 0, 0) == -1) { + if (TIFFReadTile(tiff, (tdata_t)buffer, col, row, 0, plane) == -1) { TRACE(("Decode Error, Tile at %dx%d\n", col, row)); return -1; } @@ -238,7 +238,7 @@ int ReadTile(TIFF* tiff, UINT32 col, UINT32 row, UINT32* buffer) { return 0; } -int ReadStrip(TIFF* tiff, UINT32 row, UINT32* buffer) { +int ReadStrip(TIFF* tiff, UINT32 row, UINT8 plane, UINT32* buffer) { uint16 photometric = 0; // init to not PHOTOMETRIC_YCBCR TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); @@ -259,6 +259,8 @@ int ReadStrip(TIFF* tiff, UINT32 row, UINT32* buffer) { if (TIFFRGBAImageOK(tiff, emsg) && TIFFRGBAImageBegin(&img, tiff, 0, emsg)) { TRACE(("Initialized RGBAImage\n")); + // Using TIFFRGBAImageGet instead of TIFFReadRGBAStrip + // just to get strip in TOP_LEFT orientation img.req_orientation = ORIENTATION_TOPLEFT; img.row_offset = row; img.col_offset = 0; @@ -281,7 +283,7 @@ int ReadStrip(TIFF* tiff, UINT32 row, UINT32* buffer) { return 0; } - if (TIFFReadEncodedStrip(tiff, TIFFComputeStrip(tiff, row, 0), (tdata_t)buffer, -1) == -1) { + if (TIFFReadEncodedStrip(tiff, TIFFComputeStrip(tiff, row, plane), (tdata_t)buffer, -1) == -1) { TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, row, 0))); return -1; } @@ -294,6 +296,10 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ char *filename = "tempfile.tif"; char *mode = "r"; TIFF *tiff; + uint16 photometric = 0; // init to not PHOTOMETRIC_YCBCR + UINT8 planarconfig; + UINT8 planes = 1; + ImagingShuffler unpackers[4]; /* buffer is the encoded file, bytes is the length of the encoded file */ /* it all ends up in state->buffer, which is a uint8* from Imaging.h */ @@ -350,8 +356,38 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ rv = TIFFSetSubDirectory(tiff, ifdoffset); if (!rv){ TRACE(("error in TIFFSetSubDirectory")); + state->errcode = IMAGING_CODEC_BROKEN; + TIFFClose(tiff); + return -1; + } + } + + TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric); + TIFFGetFieldDefaulted(tiff, TIFFTAG_PLANARCONFIG, &planarconfig); + // YCbCr data is read as RGB by libtiff and we don't need to worry about planar storage in that case + // if number of bands is 1, there is no difference with contig case + if (planarconfig == PLANARCONFIG_SEPARATE && im->bands > 1 && photometric != PHOTOMETRIC_YCBCR) { + uint16 bps = 8; + + TIFFGetFieldDefaulted(tiff, TIFFTAG_BITSPERSAMPLE, &bps); + if (bps != 8 && bps != 16) { + TRACE(("Invalid value for bits per sample: %d\n", bps)); + state->errcode = IMAGING_CODEC_BROKEN; + TIFFClose(tiff); return -1; } + + planes = im->bands; + + // We'll pick appropriate set of unpackers depending on planar_configuration + // It does not matter if data is RGB(A), CMYK or LUV really, + // we just copy it plane by plane + unpackers[0] = ImagingFindUnpacker("RGBA", bps == 16 ? "R;16N" : "R", NULL); + unpackers[1] = ImagingFindUnpacker("RGBA", bps == 16 ? "G;16N" : "G", NULL); + unpackers[2] = ImagingFindUnpacker("RGBA", bps == 16 ? "B;16N" : "B", NULL); + unpackers[3] = ImagingFindUnpacker("RGBA", bps == 16 ? "A;16N" : "A", NULL); + } else { + unpackers[0] = state->shuffle; } if (TIFFIsTiled(tiff)) { @@ -370,7 +406,7 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ } // We could use TIFFTileSize, but for YCbCr data it returns subsampled data size - row_byte_size = (tile_width * state->bits + 7) / 8; + row_byte_size = (tile_width * state->bits / planes + 7) / 8; /* overflow check for realloc */ if (INT_MAX / row_byte_size < tile_length) { @@ -378,11 +414,11 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ TIFFClose(tiff); return -1; } - + state->bytes = row_byte_size * tile_length; if (TIFFTileSize(tiff) > state->bytes) { - // If the strip size as expected by LibTiff isn't what we're expecting, abort. + // If the tile size as expected by LibTiff isn't what we're expecting, abort. state->errcode = IMAGING_CODEC_MEMORY; TIFFClose(tiff); return -1; @@ -402,29 +438,33 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ TRACE(("TIFFTileSize: %d\n", state->bytes)); for (y = state->yoff; y < state->ysize; y += tile_length) { - for (x = state->xoff; x < state->xsize; x += tile_width) { - if (ReadTile(tiff, x, y, (UINT32*) state->buffer) == -1) { - TRACE(("Decode Error, Tile at %dx%d\n", x, y)); - state->errcode = IMAGING_CODEC_BROKEN; - TIFFClose(tiff); - return -1; - } - - TRACE(("Read tile at %dx%d; \n\n", x, y)); - - current_tile_width = min((INT32) tile_width, state->xsize - x); - - // iterate over each line in the tile and stuff data into image - for (tile_y = 0; tile_y < min((INT32) tile_length, state->ysize - y); tile_y++) { - TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width)); - - // UINT8 * bbb = state->buffer + tile_y * row_byte_size; - // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); - - state->shuffle((UINT8*) im->image[tile_y + y] + x * im->pixelsize, - state->buffer + tile_y * row_byte_size, - current_tile_width - ); + UINT8 plane; + for (plane = 0; plane < planes; plane++) { + ImagingShuffler shuffler = unpackers[plane]; + for (x = state->xoff; x < state->xsize; x += tile_width) { + if (ReadTile(tiff, x, y, plane, (UINT32*) state->buffer) == -1) { + TRACE(("Decode Error, Tile at %dx%d\n", x, y)); + state->errcode = IMAGING_CODEC_BROKEN; + TIFFClose(tiff); + return -1; + } + + TRACE(("Read tile at %dx%d; \n\n", x, y)); + + current_tile_width = min((INT32) tile_width, state->xsize - x); + + // iterate over each line in the tile and stuff data into image + for (tile_y = 0; tile_y < min((INT32) tile_length, state->ysize - y); tile_y++) { + TRACE(("Writing tile data at %dx%d using tile_width: %d; \n", tile_y + y, x, current_tile_width)); + + // UINT8 * bbb = state->buffer + tile_y * row_byte_size; + // TRACE(("chars: %x%x%x%x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); + + shuffler((UINT8*) im->image[tile_y + y] + x * im->pixelsize, + state->buffer + tile_y * row_byte_size, + current_tile_width + ); + } } } } @@ -441,7 +481,7 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ TRACE(("RowsPerStrip: %u \n", rows_per_strip)); // We could use TIFFStripSize, but for YCbCr data it returns subsampled data size - row_byte_size = (state->xsize * state->bits + 7) / 8; + row_byte_size = (state->xsize * state->bits / planes + 7) / 8; /* overflow check for realloc */ if (INT_MAX / row_byte_size < rows_per_strip) { @@ -476,26 +516,55 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, Py_ state->buffer = new_data; for (; state->y < state->ysize; state->y += rows_per_strip) { - if (ReadStrip(tiff, state->y, (UINT32 *)state->buffer) == -1) { - TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0))); - state->errcode = IMAGING_CODEC_BROKEN; - TIFFClose(tiff); - return -1; - } + UINT8 plane; + for (plane = 0; plane < planes; plane++) { + ImagingShuffler shuffler = unpackers[plane]; + if (ReadStrip(tiff, state->y, plane, (UINT32 *)state->buffer) == -1) { + TRACE(("Decode Error, strip %d\n", TIFFComputeStrip(tiff, state->y, 0))); + state->errcode = IMAGING_CODEC_BROKEN; + TIFFClose(tiff); + return -1; + } - TRACE(("Decoded strip for row %d \n", state->y)); + TRACE(("Decoded strip for row %d \n", state->y)); - // iterate over each row in the strip and stuff data into image - for (strip_row = 0; strip_row < min((INT32) rows_per_strip, state->ysize - state->y); strip_row++) { + // iterate over each row in the strip and stuff data into image + for (strip_row = 0; strip_row < min((INT32) rows_per_strip, state->ysize - state->y); strip_row++) { TRACE(("Writing data into line %d ; \n", state->y + strip_row)); - // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip); - // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); + // UINT8 * bbb = state->buffer + strip_row * (state->bytes / rows_per_strip); + // TRACE(("chars: %x %x %x %x\n", ((UINT8 *)bbb)[0], ((UINT8 *)bbb)[1], ((UINT8 *)bbb)[2], ((UINT8 *)bbb)[3])); + + shuffler((UINT8*) im->image[state->y + state->yoff + strip_row] + + state->xoff * im->pixelsize, + state->buffer + strip_row * row_byte_size, + state->xsize); + } + } + } + } + + + // Check if raw mode was RGBa and it was stored on separate planes + // so we have to convert it to RGBA + if (planes > 3 && strcmp(im->mode, "RGBA") == 0) { + uint16 extrasamples; + uint16* sampleinfo; + ImagingShuffler shuffle; + INT32 y; + + TIFFGetFieldDefaulted(tiff, TIFFTAG_EXTRASAMPLES, &extrasamples, &sampleinfo); + + if (extrasamples >= 1 && + (sampleinfo[0] == EXTRASAMPLE_UNSPECIFIED || sampleinfo[0] == EXTRASAMPLE_ASSOCALPHA) + ) { + shuffle = ImagingFindUnpacker("RGBA", "RGBa", NULL); + + for (y = state->yoff; y < state->ysize; y++) { + UINT8* ptr = (UINT8*) im->image[y + state->yoff] + + state->xoff * im->pixelsize; - state->shuffle((UINT8*) im->image[state->y + state->yoff + strip_row] + - state->xoff * im->pixelsize, - state->buffer + strip_row * row_byte_size, - state->xsize); + shuffle(ptr, ptr, state->xsize); } } } diff --git a/src/libImaging/Unpack.c b/src/libImaging/Unpack.c index 917da6ab32e..48d3ce50a0c 100644 --- a/src/libImaging/Unpack.c +++ b/src/libImaging/Unpack.c @@ -1263,6 +1263,94 @@ band3I(UINT8* out, const UINT8* in, int pixels) } } +static void +band016B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 0 only, big endian */ + for (i = 0; i < pixels; i++) { + out[0] = in[0]; + out += 4; in += 2; + } +} + +static void +band116B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 1 only, big endian */ + for (i = 0; i < pixels; i++) { + out[1] = in[0]; + out += 4; in += 2; + } +} + +static void +band216B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 2 only, big endian */ + for (i = 0; i < pixels; i++) { + out[2] = in[0]; + out += 4; in += 2; + } +} + +static void +band316B(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 3 only, big endian */ + for (i = 0; i < pixels; i++) { + out[3] = in[0]; + out += 4; in += 2; + } +} + +static void +band016L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 0 only, little endian */ + for (i = 0; i < pixels; i++) { + out[0] = in[1]; + out += 4; in += 2; + } +} + +static void +band116L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 1 only, little endian */ + for (i = 0; i < pixels; i++) { + out[1] = in[1]; + out += 4; in += 2; + } +} + +static void +band216L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 2 only, little endian */ + for (i = 0; i < pixels; i++) { + out[2] = in[1]; + out += 4; in += 2; + } +} + +static void +band316L(UINT8* out, const UINT8* in, int pixels) +{ + int i; + /* band 3 only, little endian */ + for (i = 0; i < pixels; i++) { + out[3] = in[1]; + out += 4; in += 2; + } +} + static struct { const char* mode; const char* rawmode; @@ -1348,6 +1436,12 @@ static struct { {"RGB", "R", 8, band0}, {"RGB", "G", 8, band1}, {"RGB", "B", 8, band2}, + {"RGB", "R;16L", 16, band016L}, + {"RGB", "G;16L", 16, band116L}, + {"RGB", "B;16L", 16, band216L}, + {"RGB", "R;16B", 16, band016B}, + {"RGB", "G;16B", 16, band116B}, + {"RGB", "B;16B", 16, band216B}, /* true colour w. alpha */ {"RGBA", "LA", 16, unpackRGBALA}, @@ -1376,17 +1470,45 @@ static struct { {"RGBA", "G", 8, band1}, {"RGBA", "B", 8, band2}, {"RGBA", "A", 8, band3}, + {"RGBA", "R;16L", 16, band016L}, + {"RGBA", "G;16L", 16, band116L}, + {"RGBA", "B;16L", 16, band216L}, + {"RGBA", "A;16L", 16, band316L}, + {"RGBA", "R;16B", 16, band016B}, + {"RGBA", "G;16B", 16, band116B}, + {"RGBA", "B;16B", 16, band216B}, + {"RGBA", "A;16B", 16, band316B}, #ifdef WORDS_BIGENDIAN {"RGB", "RGB;16N", 48, unpackRGB16B}, {"RGBA", "RGBa;16N", 64, unpackRGBa16B}, {"RGBA", "RGBA;16N", 64, unpackRGBA16B}, {"RGBX", "RGBX;16N", 64, unpackRGBA16B}, + + {"RGB", "R;16N", 16, band016B}, + {"RGB", "G;16N", 16, band116B}, + {"RGB", "B;16N", 16, band216B}, + + {"RGBA", "R;16N", 16, band016B}, + {"RGBA", "G;16N", 16, band116B}, + {"RGBA", "B;16N", 16, band216B}, + {"RGBA", "A;16N", 16, band316B}, #else {"RGB", "RGB;16N", 48, unpackRGB16L}, {"RGBA", "RGBa;16N", 64, unpackRGBa16L}, {"RGBA", "RGBA;16N", 64, unpackRGBA16L}, - {"RGBX", "RGBX;16N", 64, unpackRGBA16B}, + {"RGBX", "RGBX;16N", 64, unpackRGBA16L}, + + + {"RGB", "R;16N", 16, band016L}, + {"RGB", "G;16N", 16, band116L}, + {"RGB", "B;16N", 16, band216L}, + + + {"RGBA", "R;16N", 16, band016L}, + {"RGBA", "G;16N", 16, band116L}, + {"RGBA", "B;16N", 16, band216L}, + {"RGBA", "A;16N", 16, band316L}, #endif /* true colour w. alpha premultiplied */