mirror of
https://github.com/python-pillow/Pillow.git
synced 2025-02-03 05:04:24 +03:00
Adding support to reading tiled and YcbCr jpegs tiffs through libtiff
This commit is contained in:
parent
4c47628900
commit
f0436a4ddc
|
@ -257,14 +257,14 @@ OPEN_INFO = {
|
|||
(II, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"),
|
||||
(MM, 5, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0)): ("CMYK", "CMYKXX"),
|
||||
|
||||
(II, 6, (1,), 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
|
||||
(MM, 6, (1,), 1, (8, 8, 8), ()): ("YCbCr", "YCbCr"),
|
||||
(II, 6, (1,), 1, (8, 8, 8, 8), (0,)): ("YCbCr", "YCbCrX"),
|
||||
(MM, 6, (1,), 1, (8, 8, 8, 8), (0,)): ("YCbCr", "YCbCrX"),
|
||||
(II, 6, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("YCbCr", "YCbCrXX"),
|
||||
(MM, 6, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("YCbCr", "YCbCrXX"),
|
||||
(II, 6, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("YCbCr", "YCbCrXXX"),
|
||||
(MM, 6, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("YCbCr", "YCbCrXXX"),
|
||||
(II, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
|
||||
(MM, 6, (1,), 1, (8, 8, 8), ()): ("RGB", "RGB"),
|
||||
(II, 6, (1,), 1, (8, 8, 8, 8), (0,)): ("RGB", "RGBX"),
|
||||
(MM, 6, (1,), 1, (8, 8, 8, 8), (0,)): ("RGB", "RGBX"),
|
||||
(II, 6, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("RGB", "RGBXX"),
|
||||
(MM, 6, (1,), 1, (8, 8, 8, 8, 8), (0, 0)): ("RGB", "RGBXX"),
|
||||
(II, 6, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGB", "RGBXXX"),
|
||||
(MM, 6, (1,), 1, (8, 8, 8, 8, 8, 8), (0, 0, 0)): ("RGB", "RGBXXX"),
|
||||
|
||||
(II, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
|
||||
(MM, 8, (1,), 1, (8, 8, 8), ()): ("LAB", "LAB"),
|
||||
|
@ -1062,6 +1062,8 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
compression = self._compression
|
||||
if compression == "raw":
|
||||
args = (rawmode, 0, 1)
|
||||
if compression == "jpeg":
|
||||
args = ("RGB", "")
|
||||
elif compression == "packbits":
|
||||
args = rawmode
|
||||
|
||||
|
@ -1187,6 +1189,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
print("- photometric_interpretation:", photo)
|
||||
print("- planar_configuration:", self._planar_configuration)
|
||||
print("- fill_order:", fillorder)
|
||||
print("- YCbCr subsampling:", self.tag.get(530))
|
||||
|
||||
# size
|
||||
xsize = self.tag_v2.get(IMAGEWIDTH)
|
||||
|
@ -1258,87 +1261,71 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
# build tile descriptors
|
||||
x = y = layer = 0
|
||||
self.tile = []
|
||||
self.use_load_libtiff = False
|
||||
if STRIPOFFSETS in self.tag_v2:
|
||||
self.use_load_libtiff = self._compression != 'raw'
|
||||
if self.use_load_libtiff:
|
||||
# Decoder expects entire file as one tile.
|
||||
# There's a buffer size limit in load (64k)
|
||||
# so large g4 images will fail if we use that
|
||||
# function.
|
||||
#
|
||||
# Setup the one tile for the whole image, then
|
||||
# use the _load_libtiff function.
|
||||
|
||||
# libtiff handles the fillmode for us, so 1;IR should
|
||||
# actually be 1;I. Including the R double reverses the
|
||||
# bits, so stripes of the image are reversed. See
|
||||
# https://github.com/python-pillow/Pillow/issues/279
|
||||
if fillorder == 2:
|
||||
key = (
|
||||
self.tag_v2.prefix, photo, sampleFormat, 1,
|
||||
self.tag_v2.get(BITSPERSAMPLE, (1,)),
|
||||
self.tag_v2.get(EXTRASAMPLES, ())
|
||||
)
|
||||
if DEBUG:
|
||||
print("format key:", key)
|
||||
# this should always work, since all the
|
||||
# fillorder==2 modes have a corresponding
|
||||
# fillorder=1 mode
|
||||
self.mode, rawmode = OPEN_INFO[key]
|
||||
# libtiff always returns the bytes in native order.
|
||||
# we're expecting image byte order. So, if the rawmode
|
||||
# contains I;16, we need to convert from native to image
|
||||
# byte order.
|
||||
if rawmode == 'I;16':
|
||||
rawmode = 'I;16N'
|
||||
if ';16B' in rawmode:
|
||||
rawmode = rawmode.replace(';16B', ';16N')
|
||||
if ';16L' in rawmode:
|
||||
rawmode = rawmode.replace(';16L', ';16N')
|
||||
|
||||
# Offset in the tile tuple is 0, we go from 0,0 to
|
||||
# w,h, and we only do this once -- eds
|
||||
a = (rawmode, self._compression, False)
|
||||
self.tile.append(
|
||||
(self._compression,
|
||||
(0, 0, xsize, ysize),
|
||||
0, a))
|
||||
|
||||
elif STRIPOFFSETS in self.tag_v2 or TILEOFFSETS in self.tag_v2:
|
||||
# striped image
|
||||
offsets = self.tag_v2[STRIPOFFSETS]
|
||||
h = self.tag_v2.get(ROWSPERSTRIP, ysize)
|
||||
w = self.size[0]
|
||||
if READ_LIBTIFF or self._compression != 'raw':
|
||||
# Decoder expects entire file as one tile.
|
||||
# There's a buffer size limit in load (64k)
|
||||
# so large g4 images will fail if we use that
|
||||
# function.
|
||||
#
|
||||
# Setup the one tile for the whole image, then
|
||||
# use the _load_libtiff function.
|
||||
|
||||
self.use_load_libtiff = True
|
||||
|
||||
# libtiff handles the fillmode for us, so 1;IR should
|
||||
# actually be 1;I. Including the R double reverses the
|
||||
# bits, so stripes of the image are reversed. See
|
||||
# https://github.com/python-pillow/Pillow/issues/279
|
||||
if fillorder == 2:
|
||||
key = (
|
||||
self.tag_v2.prefix, photo, sampleFormat, 1,
|
||||
self.tag_v2.get(BITSPERSAMPLE, (1,)),
|
||||
self.tag_v2.get(EXTRASAMPLES, ())
|
||||
)
|
||||
if DEBUG:
|
||||
print("format key:", key)
|
||||
# this should always work, since all the
|
||||
# fillorder==2 modes have a corresponding
|
||||
# fillorder=1 mode
|
||||
self.mode, rawmode = OPEN_INFO[key]
|
||||
# libtiff always returns the bytes in native order.
|
||||
# we're expecting image byte order. So, if the rawmode
|
||||
# contains I;16, we need to convert from native to image
|
||||
# byte order.
|
||||
if rawmode == 'I;16':
|
||||
rawmode = 'I;16N'
|
||||
if ';16B' in rawmode:
|
||||
rawmode = rawmode.replace(';16B', ';16N')
|
||||
if ';16L' in rawmode:
|
||||
rawmode = rawmode.replace(';16L', ';16N')
|
||||
|
||||
# Offset in the tile tuple is 0, we go from 0,0 to
|
||||
# w,h, and we only do this once -- eds
|
||||
a = (rawmode, self._compression, False)
|
||||
self.tile.append(
|
||||
(self._compression,
|
||||
(0, 0, w, ysize),
|
||||
0, a))
|
||||
a = None
|
||||
|
||||
if STRIPOFFSETS in self.tag_v2:
|
||||
offsets = self.tag_v2[STRIPOFFSETS]
|
||||
h = self.tag_v2.get(ROWSPERSTRIP, ysize)
|
||||
w = self.size[0]
|
||||
else:
|
||||
for i, offset in enumerate(offsets):
|
||||
a = self._decoder(rawmode, layer, i)
|
||||
self.tile.append(
|
||||
(self._compression,
|
||||
(0, min(y, ysize), w, min(y+h, ysize)),
|
||||
offset, a))
|
||||
if DEBUG:
|
||||
print("tiles: ", self.tile)
|
||||
y = y + h
|
||||
if y >= self.size[1]:
|
||||
x = y = 0
|
||||
layer += 1
|
||||
a = None
|
||||
elif TILEOFFSETS in self.tag_v2:
|
||||
# tiled image
|
||||
w = self.tag_v2.get(322)
|
||||
h = self.tag_v2.get(323)
|
||||
# tiled image
|
||||
offsets = self.tag_v2[TILEOFFSETS]
|
||||
w = self.tag_v2.get(322)
|
||||
h = self.tag_v2.get(323)
|
||||
|
||||
a = None
|
||||
for o in self.tag_v2[TILEOFFSETS]:
|
||||
for offset in offsets:
|
||||
if not a:
|
||||
a = self._decoder(rawmode, layer)
|
||||
# FIXME: this doesn't work if the image size
|
||||
# is not a multiple of the tile size...
|
||||
self.tile.append(
|
||||
(self._compression,
|
||||
(x, y, x+w, y+h),
|
||||
o, a))
|
||||
(min(x, xsize), min(y, ysize), min(x+w, xsize), min(y+h, ysize)),
|
||||
offset, a))
|
||||
x = x + w
|
||||
if x >= self.size[0]:
|
||||
x, y = 0, y + h
|
||||
|
@ -1346,6 +1333,7 @@ class TiffImageFile(ImageFile.ImageFile):
|
|||
x = y = 0
|
||||
layer += 1
|
||||
a = None
|
||||
self.tile_prefix = self.tag_v2.get(JPEGTABLES, b"")
|
||||
else:
|
||||
if DEBUG:
|
||||
print("- unsupported data organization")
|
||||
|
|
|
@ -173,7 +173,6 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int
|
|||
char *filename = "tempfile.tif";
|
||||
char *mode = "r";
|
||||
TIFF *tiff;
|
||||
tsize_t size;
|
||||
|
||||
|
||||
/* buffer is the encoded file, bytes is the length of the encoded file */
|
||||
|
@ -235,36 +234,96 @@ int ImagingLibTiffDecode(Imaging im, ImagingCodecState state, UINT8* buffer, int
|
|||
}
|
||||
}
|
||||
|
||||
size = TIFFScanlineSize(tiff);
|
||||
TRACE(("ScanlineSize: %d \n", size));
|
||||
if (size > state->bytes) {
|
||||
TRACE(("Error, scanline size > buffer size\n"));
|
||||
state->errcode = IMAGING_CODEC_BROKEN;
|
||||
TIFFClose(tiff);
|
||||
return -1;
|
||||
}
|
||||
TIFFSetField(tiff, TIFFTAG_JPEGCOLORMODE, JPEGCOLORMODE_RGB);
|
||||
|
||||
// Have to do this row by row and shove stuff into the buffer that way,
|
||||
// with shuffle. (or, just alloc a buffer myself, then figure out how to get it
|
||||
// back in. Can't use read encoded stripe.
|
||||
if (TIFFIsTiled(tiff)) {
|
||||
state->bytes = TIFFTileSize(tiff);
|
||||
|
||||
// This thing pretty much requires that I have the whole image in one shot.
|
||||
// Perhaps a stub version would work better???
|
||||
while(state->y < state->ysize){
|
||||
if (TIFFReadScanline(tiff, (tdata_t)state->buffer, (uint32)state->y, 0) == -1) {
|
||||
TRACE(("Decode Error, row %d\n", state->y));
|
||||
state->errcode = IMAGING_CODEC_BROKEN;
|
||||
TIFFClose(tiff);
|
||||
return -1;
|
||||
}
|
||||
/* TRACE(("Decoded row %d \n", state->y)); */
|
||||
state->shuffle((UINT8*) im->image[state->y + state->yoff] +
|
||||
state->xoff * im->pixelsize,
|
||||
state->buffer,
|
||||
state->xsize);
|
||||
/* overflow check for malloc */
|
||||
if (state->bytes > INT_MAX - 1) {
|
||||
state->errcode = IMAGING_CODEC_MEMORY;
|
||||
TIFFClose(tiff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
state->y++;
|
||||
}
|
||||
/* realloc to fit whole tile */
|
||||
UINT8 *new = realloc (state->buffer, state->bytes);
|
||||
if (!new) {
|
||||
state->errcode = IMAGING_CODEC_MEMORY;
|
||||
TIFFClose(tiff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
state->buffer = new;
|
||||
|
||||
TRACE(("TIFFTileSize: %d\n", state->bytes));
|
||||
|
||||
uint32 x, y, tile_y;
|
||||
uint32 tileWidth, tileLength;
|
||||
|
||||
TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tileWidth);
|
||||
TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tileLength);
|
||||
|
||||
for (y = state->yoff; y < state->ysize; y += tileLength) {
|
||||
for (x = state->xoff; x < state->xsize; x += tileWidth) {
|
||||
if (TIFFReadTile(tiff, (tdata_t)state->buffer, x, y, 0, 0) == -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));
|
||||
|
||||
// iterate over each line in the tile and stuff data into image
|
||||
for (tile_y = 0; tile_y < min(tileLength, state->ysize - y); tile_y++) {
|
||||
|
||||
TRACE(("Writing tile data at %dx%d using tilwWidth: %d; \n", tile_y + y, x, min(tileWidth, state->xsize - x)));
|
||||
|
||||
// UINT8 * bbb = state->buffer + tile_y * (state->bytes / tileLength);
|
||||
// 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 * (state->bytes / tileLength),
|
||||
min(tileWidth, state->xsize - x)
|
||||
);
|
||||
}
|
||||
}
|
||||
}
|
||||
} else {
|
||||
tsize_t size;
|
||||
|
||||
size = TIFFScanlineSize(tiff);
|
||||
TRACE(("ScanlineSize: %lu \n", size));
|
||||
if (size > state->bytes) {
|
||||
TRACE(("Error, scanline size > buffer size\n"));
|
||||
state->errcode = IMAGING_CODEC_BROKEN;
|
||||
TIFFClose(tiff);
|
||||
return -1;
|
||||
}
|
||||
|
||||
// Have to do this row by row and shove stuff into the buffer that way,
|
||||
// with shuffle. (or, just alloc a buffer myself, then figure out how to get it
|
||||
// back in. Can't use read encoded stripe.
|
||||
|
||||
// This thing pretty much requires that I have the whole image in one shot.
|
||||
// Perhaps a stub version would work better???
|
||||
while(state->y < state->ysize){
|
||||
if (TIFFReadScanline(tiff, (tdata_t)state->buffer, (uint32)state->y, 0) == -1) {
|
||||
TRACE(("Decode Error, row %d\n", state->y));
|
||||
state->errcode = IMAGING_CODEC_BROKEN;
|
||||
TIFFClose(tiff);
|
||||
return -1;
|
||||
}
|
||||
/* TRACE(("Decoded row %d \n", state->y)); */
|
||||
state->shuffle((UINT8*) im->image[state->y + state->yoff] +
|
||||
state->xoff * im->pixelsize,
|
||||
state->buffer,
|
||||
state->xsize);
|
||||
|
||||
state->y++;
|
||||
}
|
||||
}
|
||||
|
||||
TIFFClose(tiff);
|
||||
TRACE(("Done Decoding, Returning \n"));
|
||||
|
|
Loading…
Reference in New Issue
Block a user