Handle Grayscale8 TIFFs

Correctly read and write Grayscale8 image format.

Change-Id: I537c68f94077458c69ee1de08b5b37986b54aa26
Reviewed-by: Ivan Komissarov <ABBAPOH@gmail.com>
Reviewed-by: Gunnar Sletta <gunnar@sletta.org>
This commit is contained in:
Allan Sandfeld Jensen 2015-04-21 13:07:11 +02:00
parent 40e9ba00a0
commit 454fb13c46
2 changed files with 45 additions and 18 deletions

View File

@ -245,6 +245,8 @@ bool QTiffHandlerPrivate::openForRead(QIODevice *device)
if (grayscale && bitPerSample == 1 && samplesPerPixel == 1) if (grayscale && bitPerSample == 1 && samplesPerPixel == 1)
format = QImage::Format_Mono; format = QImage::Format_Mono;
else if (photometric == PHOTOMETRIC_MINISBLACK && bitPerSample == 8 && samplesPerPixel == 1)
format = QImage::Format_Grayscale8;
else if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8 && samplesPerPixel == 1) else if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8 && samplesPerPixel == 1)
format = QImage::Format_Indexed8; format = QImage::Format_Indexed8;
else if (samplesPerPixel < 4) else if (samplesPerPixel < 4)
@ -366,6 +368,15 @@ bool QTiffHandler::read(QImage *image)
// free redTable, greenTable and greenTable done by libtiff // 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;
}
}
}
} else { } else {
if (!image->isNull()) { if (!image->isNull()) {
const int stopOnError = 1; const int stopOnError = 1;
@ -428,6 +439,29 @@ static bool checkGrayscale(const QVector<QRgb> &colorTable)
return true; return true;
} }
static QVector<QRgb> effectiveColorTable(const QImage &image)
{
QVector<QRgb> colors;
switch (image.format()) {
case QImage::Format_Indexed8:
colors = image.colorTable();
break;
case QImage::Format_Alpha8:
colors.resize(256);
for (int i = 0; i < 256; ++i)
colors[i] = qRgba(0, 0, 0, i);
break;
case QImage::Format_Grayscale8:
colors.resize(256);
for (int i = 0; i < 256; ++i)
colors[i] = qRgb(i, i, i);
break;
default:
Q_UNREACHABLE();
}
return colors;
}
bool QTiffHandler::write(const QImage &image) bool QTiffHandler::write(const QImage &image)
{ {
if (!device()->isWritable()) if (!device()->isWritable())
@ -515,12 +549,14 @@ bool QTiffHandler::write(const QImage &image)
} }
} }
TIFFClose(tiff); TIFFClose(tiff);
} else if (format == QImage::Format_Indexed8) { } else if (format == QImage::Format_Indexed8
const QVector<QRgb> colorTable = image.colorTable(); || format == QImage::Format_Grayscale8
|| format == QImage::Format_Alpha8) {
QVector<QRgb> colorTable = effectiveColorTable(image);
bool isGrayscale = checkGrayscale(colorTable); bool isGrayscale = checkGrayscale(colorTable);
if (isGrayscale) { if (isGrayscale) {
uint16 photometric = PHOTOMETRIC_MINISBLACK; uint16 photometric = PHOTOMETRIC_MINISBLACK;
if (image.colorTable().at(0) == 0xffffffff) if (colorTable.at(0) == 0xffffffff)
photometric = PHOTOMETRIC_MINISWHITE; photometric = PHOTOMETRIC_MINISWHITE;
if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric) if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
|| !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS) || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS)
@ -579,7 +615,6 @@ bool QTiffHandler::write(const QImage &image)
} }
} }
TIFFClose(tiff); TIFFClose(tiff);
} else if (!image.hasAlphaChannel()) { } else if (!image.hasAlphaChannel()) {
if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB) if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB)
|| !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW) || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_LZW)

View File

@ -364,31 +364,23 @@ void tst_qtiff::readWriteNonDestructive_data()
{ {
QTest::addColumn<QImage::Format>("format"); QTest::addColumn<QImage::Format>("format");
QTest::addColumn<QImage::Format>("expectedFormat"); QTest::addColumn<QImage::Format>("expectedFormat");
QTest::addColumn<bool>("grayscale");
QTest::addColumn<QImageIOHandler::Transformation>("transformation"); QTest::addColumn<QImageIOHandler::Transformation>("transformation");
QTest::newRow("tiff mono") << QImage::Format_Mono << QImage::Format_Mono << false << QImageIOHandler::TransformationNone; QTest::newRow("tiff mono") << QImage::Format_Mono << QImage::Format_Mono << QImageIOHandler::TransformationNone;
QTest::newRow("tiff indexed") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << false << QImageIOHandler::TransformationMirror; QTest::newRow("tiff indexed") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << QImageIOHandler::TransformationMirror;
QTest::newRow("tiff argb32pm") << QImage::Format_ARGB32_Premultiplied << QImage::Format_ARGB32_Premultiplied << false << QImageIOHandler::TransformationRotate90; QTest::newRow("tiff argb32pm") << QImage::Format_ARGB32_Premultiplied << QImage::Format_ARGB32_Premultiplied << QImageIOHandler::TransformationRotate90;
QTest::newRow("tiff rgb32") << QImage::Format_RGB32 << QImage::Format_RGB32 << false << QImageIOHandler::TransformationRotate270; QTest::newRow("tiff rgb32") << QImage::Format_RGB32 << QImage::Format_RGB32 << QImageIOHandler::TransformationRotate270;
QTest::newRow("tiff grayscale") << QImage::Format_Indexed8 << QImage::Format_Indexed8 << true << QImageIOHandler::TransformationFlip; QTest::newRow("tiff grayscale") << QImage::Format_Grayscale8 << QImage::Format_Grayscale8 << QImageIOHandler::TransformationFlip;
} }
void tst_qtiff::readWriteNonDestructive() void tst_qtiff::readWriteNonDestructive()
{ {
QFETCH(QImage::Format, format); QFETCH(QImage::Format, format);
QFETCH(QImage::Format, expectedFormat); QFETCH(QImage::Format, expectedFormat);
QFETCH(bool, grayscale);
QFETCH(QImageIOHandler::Transformation, transformation); QFETCH(QImageIOHandler::Transformation, transformation);
QImage image = QImage(prefix + "colorful.bmp").convertToFormat(format); QImage image = QImage(prefix + "colorful.bmp").convertToFormat(format);
QVERIFY(!image.isNull()); QVERIFY(!image.isNull());
if (grayscale) {
QVector<QRgb> colors;
for (int i = 0; i < 256; ++i)
colors << qRgb(i, i, i);
image.setColorTable(colors);
}
QByteArray output; QByteArray output;
QBuffer buf(&output); QBuffer buf(&output);
QVERIFY(buf.open(QIODevice::WriteOnly)); QVERIFY(buf.open(QIODevice::WriteOnly));