Extend support for tiled tiff files to all color formats

This commit extends the recently added support for tiled tiff images
of color index format to also cover grayscale and mono images. RGB
images were already covered, since the libtiff API used for those
handles tiled images transparently.

This commit also simplifies the tiff read() function by sharing
common code among the different formats.

[ChangeLog][TIFF] Extend support for tiled tiff files to all color formats

Change-Id: I13f94bbca65dd6a35384a415906034e245ad8b79
Reviewed-by: Allan Sandfeld Jensen <allan.jensen@qt.io>
This commit is contained in:
Eirik Aavitsland 2017-03-16 14:13:57 +01:00
parent 30301436b5
commit c7a6a451a5
14 changed files with 108 additions and 107 deletions

View File

@ -329,22 +329,88 @@ bool QTiffHandler::read(QImage *image)
if (image->size() != d->size || image->format() != format)
*image = QImage(d->size, format);
if (image->isNull()) {
d->close();
return false;
}
TIFF *const tiff = d->tiff;
const uint32 width = d->size.width();
const uint32 height = d->size.height();
if (format == QImage::Format_Mono) {
QVector<QRgb> colortable(2);
if (d->photometric == PHOTOMETRIC_MINISBLACK) {
colortable[0] = 0xff000000;
colortable[1] = 0xffffffff;
} else {
colortable[0] = 0xffffffff;
colortable[1] = 0xff000000;
}
image->setColorTable(colortable);
if (format == QImage::Format_Mono || format == QImage::Format_Indexed8 || format == QImage::Format_Grayscale8) {
if (format == QImage::Format_Mono) {
QVector<QRgb> colortable(2);
if (d->photometric == PHOTOMETRIC_MINISBLACK) {
colortable[0] = 0xff000000;
colortable[1] = 0xffffffff;
} else {
colortable[0] = 0xffffffff;
colortable[1] = 0xff000000;
}
image->setColorTable(colortable);
} else if (format == QImage::Format_Indexed8) {
const uint16 tableSize = 256;
QVector<QRgb> qtColorTable(tableSize);
if (d->grayscale) {
for (int i = 0; i<tableSize; ++i) {
const int c = (d->photometric == PHOTOMETRIC_MINISBLACK) ? i : (255 - i);
qtColorTable[i] = qRgb(c, c, c);
}
} else {
// create the color table
uint16 *redTable = 0;
uint16 *greenTable = 0;
uint16 *blueTable = 0;
if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) {
d->close();
return false;
}
if (!redTable || !greenTable || !blueTable) {
d->close();
return false;
}
if (!image->isNull()) {
for (int i = 0; i<tableSize ;++i) {
const int red = redTable[i] / 257;
const int green = greenTable[i] / 257;
const int blue = blueTable[i] / 257;
qtColorTable[i] = qRgb(red, green, blue);
}
}
image->setColorTable(qtColorTable);
// free redTable, greenTable and greenTable done by libtiff
}
if (TIFFIsTiled(tiff)) {
quint32 tileWidth, tileLength;
TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tileWidth);
TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tileLength);
uchar *buf = (uchar *)_TIFFmalloc(TIFFTileSize(tiff));
if (!tileWidth || !tileLength || !buf) {
_TIFFfree(buf);
d->close();
return false;
}
quint32 byteWidth = (format == QImage::Format_Mono) ? (width + 7)/8 : width;
quint32 byteTileWidth = (format == QImage::Format_Mono) ? tileWidth/8 : tileWidth;
for (quint32 y = 0; y < height; y += tileLength) {
for (quint32 x = 0; x < width; x += tileWidth) {
if (TIFFReadTile(tiff, buf, x, y, 0, 0) < 0) {
_TIFFfree(buf);
d->close();
return false;
}
quint32 linesToCopy = qMin(tileLength, height - y);
quint32 byteOffset = (format == QImage::Format_Mono) ? x/8 : x;
quint32 widthToCopy = qMin(byteTileWidth, byteWidth - byteOffset);
for (quint32 i = 0; i < linesToCopy; i++) {
::memcpy(image->scanLine(y + i) + byteOffset, buf + (i * byteTileWidth), widthToCopy);
}
}
}
_TIFFfree(buf);
} else {
for (uint32 y=0; y<height; ++y) {
if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
d->close();
@ -353,101 +419,16 @@ bool QTiffHandler::read(QImage *image)
}
}
} else {
if (format == QImage::Format_Indexed8) {
if (!image->isNull()) {
const uint16 tableSize = 256;
QVector<QRgb> qtColorTable(tableSize);
if (d->grayscale) {
for (int i = 0; i<tableSize; ++i) {
const int c = (d->photometric == PHOTOMETRIC_MINISBLACK) ? i : (255 - i);
qtColorTable[i] = qRgb(c, c, c);
}
} else {
// create the color table
uint16 *redTable = 0;
uint16 *greenTable = 0;
uint16 *blueTable = 0;
if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) {
d->close();
return false;
}
if (!redTable || !greenTable || !blueTable) {
d->close();
return false;
}
for (int i = 0; i<tableSize ;++i) {
const int red = redTable[i] / 257;
const int green = greenTable[i] / 257;
const int blue = blueTable[i] / 257;
qtColorTable[i] = qRgb(red, green, blue);
}
}
image->setColorTable(qtColorTable);
if (TIFFIsTiled(tiff)) {
quint32 tileWidth, tileLength;
TIFFGetField(tiff, TIFFTAG_TILEWIDTH, &tileWidth);
TIFFGetField(tiff, TIFFTAG_TILELENGTH, &tileLength);
uchar *buf = (uchar *)_TIFFmalloc(TIFFTileSize(tiff));
if (!tileWidth || !tileLength || !buf) {
_TIFFfree(buf);
d->close();
return false;
}
for (quint32 y = 0; y < height; y += tileLength) {
for (quint32 x = 0; x < width; x += tileWidth) {
if (TIFFReadTile(tiff, buf, x, y, 0, 0) < 0) {
_TIFFfree(buf);
d->close();
return false;
}
quint32 linesToCopy = qMin(tileLength, height - y);
quint32 widthToCopy = qMin(tileWidth, width - x);
for (quint32 i = 0; i < linesToCopy; i++)
::memcpy(image->scanLine(y + i) + x, buf + (i * tileWidth), widthToCopy);
}
}
_TIFFfree(buf);
} else {
for (uint32 y=0; y<height; ++y) {
if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
d->close();
return false;
}
}
}
// free redTable, greenTable and greenTable done by libtiff
}
} else if (format == QImage::Format_Grayscale8) {
if (!image->isNull()) {
for (uint32 y = 0; y < height; ++y) {
if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
d->close();
return false;
}
}
}
const int stopOnError = 1;
if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), qt2Exif(d->transformation), stopOnError)) {
for (uint32 y=0; y<height; ++y)
convert32BitOrder(image->scanLine(y), width);
} else {
if (!image->isNull()) {
const int stopOnError = 1;
if (TIFFReadRGBAImageOriented(tiff, width, height, reinterpret_cast<uint32 *>(image->bits()), qt2Exif(d->transformation), stopOnError)) {
for (uint32 y=0; y<height; ++y)
convert32BitOrder(image->scanLine(y), width);
} else {
d->close();
return false;
}
}
d->close();
return false;
}
}
if (image->isNull()) {
d->close();
return false;
}
float resX = 0;
float resY = 0;

View File

@ -139,6 +139,7 @@ void tst_qtiff::readImage_data()
QTest::newRow("mono_orientation_7") << QString("mono_orientation_7.tiff") << QSize(64, 64);
QTest::newRow("mono_orientation_8") << QString("mono_orientation_8.tiff") << QSize(64, 64);
QTest::newRow("original_indexed") << QString("original_indexed.tiff") << QSize(64, 64);
QTest::newRow("original_grayscale") << QString("original_grayscale.tiff") << QSize(64, 64);
QTest::newRow("original_mono") << QString("original_mono.tiff") << QSize(64, 64);
QTest::newRow("original_rgb") << QString("original_rgb.tiff") << QSize(64, 64);
QTest::newRow("rgba_adobedeflate_littleendian") << QString("rgba_adobedeflate_littleendian.tif") << QSize(200, 200);
@ -156,8 +157,14 @@ void tst_qtiff::readImage_data()
QTest::newRow("rgb_orientation_7") << QString("rgb_orientation_7.tiff") << QSize(64, 64);
QTest::newRow("rgb_orientation_8") << QString("rgb_orientation_8.tiff") << QSize(64, 64);
QTest::newRow("teapot") << QString("teapot.tiff") << QSize(256, 256);
QTest::newRow("indexed_nontiled") << QString("indexed_nontiled.tif") << QSize(512, 384);
QTest::newRow("indexed_tiled") << QString("indexed_tiled.tif") << QSize(512, 384);
QTest::newRow("oddsize_grayscale") << QString("oddsize_grayscale.tiff") << QSize(59, 71);
QTest::newRow("oddsize_mono") << QString("oddsize_mono.tiff") << QSize(59, 71);
QTest::newRow("tiled_rgb") << QString("tiled_rgb.tiff") << QSize(64, 64);
QTest::newRow("tiled_indexed") << QString("tiled_indexed.tiff") << QSize(64, 64);
QTest::newRow("tiled_grayscale") << QString("tiled_grayscale.tiff") << QSize(64, 64);
QTest::newRow("tiled_mono") << QString("tiled_mono.tiff") << QSize(64, 64);
QTest::newRow("tiled_oddsize_grayscale") << QString("tiled_oddsize_grayscale.tiff") << QSize(59, 71);
QTest::newRow("tiled_oddsize_mono") << QString("tiled_oddsize_mono.tiff") << QSize(59, 71);
}
void tst_qtiff::readImage()
@ -566,7 +573,12 @@ void tst_qtiff::tiled_data()
{
QTest::addColumn<QString>("expectedFile");
QTest::addColumn<QString>("tiledFile");
QTest::newRow("Indexed") << "indexed_nontiled.tif" << "indexed_tiled.tif";
QTest::newRow("RGB") << "original_rgb.tiff" << "tiled_rgb.tiff";
QTest::newRow("Indexed") << "original_indexed.tiff" << "tiled_indexed.tiff";
QTest::newRow("Grayscale") << "original_grayscale.tiff" << "tiled_grayscale.tiff";
QTest::newRow("Mono") << "original_mono.tiff" << "tiled_mono.tiff";
QTest::newRow("Oddsize (Grayscale)") << "oddsize_grayscale.tiff" << "tiled_oddsize_grayscale.tiff";
QTest::newRow("Oddsize (Mono)") << "oddsize_mono.tiff" << "tiled_oddsize_mono.tiff";
}
void tst_qtiff::tiled()
@ -576,6 +588,7 @@ void tst_qtiff::tiled()
QImage expectedImage(prefix + expectedFile);
QImage tiledImage(prefix + tiledFile);
QVERIFY(!tiledImage.isNull());
QCOMPARE(expectedImage, tiledImage);
}

View File

@ -41,7 +41,14 @@
<file>tiff/rgb_orientation_8.tiff</file>
<file>tiff/teapot.tiff</file>
<file>tiff/colorful.bmp</file>
<file>tiff/indexed_tiled.tif</file>
<file>tiff/indexed_nontiled.tif</file>
<file>tiff/tiled_grayscale.tiff</file>
<file>tiff/tiled_oddsize_grayscale.tiff</file>
<file>tiff/oddsize_grayscale.tiff</file>
<file>tiff/original_grayscale.tiff</file>
<file>tiff/tiled_indexed.tiff</file>
<file>tiff/tiled_mono.tiff</file>
<file>tiff/tiled_oddsize_mono.tiff</file>
<file>tiff/oddsize_mono.tiff</file>
<file>tiff/tiled_rgb.tiff</file>
</qresource>
</RCC>

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.

Binary file not shown.