src/plugins/imageformats/tiff/qtiffhandler.cpp
changeset 3 41300fa6a67c
parent 0 1918ee327afb
child 4 3b1da2848fc7
equal deleted inserted replaced
2:56cd8111b7f7 3:41300fa6a67c
   190         || !TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric)) {
   190         || !TIFFGetField(tiff, TIFFTAG_PHOTOMETRIC, &photometric)) {
   191         TIFFClose(tiff);
   191         TIFFClose(tiff);
   192         return false;
   192         return false;
   193     }
   193     }
   194 
   194 
   195     if (photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE) {
   195     uint16 bitPerSample;
       
   196     if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample)) {
       
   197         TIFFClose(tiff);
       
   198         return false;
       
   199     }
       
   200 
       
   201     bool grayscale = photometric == PHOTOMETRIC_MINISBLACK || photometric == PHOTOMETRIC_MINISWHITE;
       
   202     if (grayscale && bitPerSample == 1) {
   196         if (image->size() != QSize(width, height) || image->format() != QImage::Format_Mono)
   203         if (image->size() != QSize(width, height) || image->format() != QImage::Format_Mono)
   197             *image = QImage(width, height, QImage::Format_Mono);
   204             *image = QImage(width, height, QImage::Format_Mono);
   198         QVector<QRgb> colortable(2);
   205         QVector<QRgb> colortable(2);
   199         if (photometric == PHOTOMETRIC_MINISBLACK) {
   206         if (photometric == PHOTOMETRIC_MINISBLACK) {
   200             colortable[0] = 0xff000000;
   207             colortable[0] = 0xff000000;
   206         image->setColorTable(colortable);
   213         image->setColorTable(colortable);
   207 
   214 
   208         if (!image->isNull()) {
   215         if (!image->isNull()) {
   209             for (uint32 y=0; y<height; ++y) {
   216             for (uint32 y=0; y<height; ++y) {
   210                 if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
   217                 if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
   211                         TIFFClose(tiff);
   218                     TIFFClose(tiff);
   212                         return false;
   219                     return false;
   213                 }
   220                 }
   214             }
   221             }
   215         }
   222         }
   216     } else {
   223     } else {
   217         uint16 bitPerSample;
   224         if ((grayscale || photometric == PHOTOMETRIC_PALETTE) && bitPerSample == 8) {
   218         if (!TIFFGetField(tiff, TIFFTAG_BITSPERSAMPLE, &bitPerSample)) {
       
   219             TIFFClose(tiff);
       
   220             return false;
       
   221         }
       
   222         if (photometric == PHOTOMETRIC_PALETTE && bitPerSample == 8) {
       
   223             if (image->size() != QSize(width, height) || image->format() != QImage::Format_Indexed8)
   225             if (image->size() != QSize(width, height) || image->format() != QImage::Format_Indexed8)
   224                 *image = QImage(width, height, QImage::Format_Indexed8);
   226                 *image = QImage(width, height, QImage::Format_Indexed8);
   225             if (!image->isNull()) {
   227             if (!image->isNull()) {
   226                 // create the color table
       
   227                 const uint16 tableSize = 256;
   228                 const uint16 tableSize = 256;
   228                 uint16 *redTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
       
   229                 uint16 *greenTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
       
   230                 uint16 *blueTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
       
   231                 if (!redTable || !greenTable || !blueTable) {
       
   232                     TIFFClose(tiff);
       
   233                     return false;
       
   234                 }
       
   235                 if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) {
       
   236                     TIFFClose(tiff);
       
   237                     return false;
       
   238                 }
       
   239 
       
   240                 QVector<QRgb> qtColorTable(tableSize);
   229                 QVector<QRgb> qtColorTable(tableSize);
   241                 for (int i = 0; i<tableSize ;++i) {
   230                 if (grayscale) {
   242                     const int red = redTable[i] / 257;
   231                     for (int i = 0; i<tableSize; ++i) {
   243                     const int green = greenTable[i] / 257;
   232                         const int c = (photometric == PHOTOMETRIC_MINISBLACK) ? i : (255 - i);
   244                     const int blue = blueTable[i] / 257;
   233                         qtColorTable[i] = qRgb(c, c, c);
   245                     qtColorTable[i] = qRgb(red, green, blue);
   234                     }
   246 
   235                 } else {
       
   236                     // create the color table
       
   237                     uint16 *redTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
       
   238                     uint16 *greenTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
       
   239                     uint16 *blueTable = static_cast<uint16 *>(qMalloc(tableSize * sizeof(uint16)));
       
   240                     if (!redTable || !greenTable || !blueTable) {
       
   241                         TIFFClose(tiff);
       
   242                         return false;
       
   243                     }
       
   244                     if (!TIFFGetField(tiff, TIFFTAG_COLORMAP, &redTable, &greenTable, &blueTable)) {
       
   245                         TIFFClose(tiff);
       
   246                         return false;
       
   247                     }
       
   248 
       
   249                     for (int i = 0; i<tableSize ;++i) {
       
   250                         const int red = redTable[i] / 257;
       
   251                         const int green = greenTable[i] / 257;
       
   252                         const int blue = blueTable[i] / 257;
       
   253                         qtColorTable[i] = qRgb(red, green, blue);
       
   254                     }
   247                 }
   255                 }
   248 
   256 
   249                 image->setColorTable(qtColorTable);
   257                 image->setColorTable(qtColorTable);
   250                 for (uint32 y=0; y<height; ++y) {
   258                 for (uint32 y=0; y<height; ++y) {
   251                     if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
   259                     if (TIFFReadScanline(tiff, image->scanLine(y), y, 0) < 0) {
   369 
   377 
   370     TIFFClose(tiff);
   378     TIFFClose(tiff);
   371     return true;
   379     return true;
   372 }
   380 }
   373 
   381 
       
   382 static bool checkGrayscale(const QVector<QRgb> &colorTable)
       
   383 {
       
   384     if (colorTable.size() != 256)
       
   385         return false;
       
   386 
       
   387     const bool increasing = (colorTable.at(0) == 0xff000000);
       
   388     for (int i = 0; i < 256; ++i) {
       
   389         if (increasing && colorTable.at(i) != qRgb(i, i, i)
       
   390             || !increasing && colorTable.at(i) != qRgb(255 - i, 255 - i, 255 - i))
       
   391             return false;
       
   392     }
       
   393     return true;
       
   394 }
       
   395 
   374 bool QTiffHandler::write(const QImage &image)
   396 bool QTiffHandler::write(const QImage &image)
   375 {
   397 {
   376     if (!device()->isWritable())
   398     if (!device()->isWritable())
   377         return false;
   399         return false;
   378 
   400 
   423     if (format == QImage::Format_Mono || format == QImage::Format_MonoLSB) {
   445     if (format == QImage::Format_Mono || format == QImage::Format_MonoLSB) {
   424         uint16 photometric = PHOTOMETRIC_MINISBLACK;
   446         uint16 photometric = PHOTOMETRIC_MINISBLACK;
   425         if (image.colorTable().at(0) == 0xffffffff)
   447         if (image.colorTable().at(0) == 0xffffffff)
   426             photometric = PHOTOMETRIC_MINISWHITE;
   448             photometric = PHOTOMETRIC_MINISWHITE;
   427         if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
   449         if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
   428             || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE)) {
   450             || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_CCITTRLE)
       
   451             || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 1)) {
   429             TIFFClose(tiff);
   452             TIFFClose(tiff);
   430             return false;
   453             return false;
   431         }
   454         }
   432 
   455 
   433         // try to do the conversion in chunks no greater than 16 MB
   456         // try to do the conversion in chunks no greater than 16 MB
   448                 ++y;
   471                 ++y;
   449             }
   472             }
   450         }
   473         }
   451         TIFFClose(tiff);
   474         TIFFClose(tiff);
   452     } else if (format == QImage::Format_Indexed8) {
   475     } else if (format == QImage::Format_Indexed8) {
   453         if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE)
       
   454             || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS)
       
   455             || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
       
   456             TIFFClose(tiff);
       
   457             return false;
       
   458         }
       
   459         //// write the color table
       
   460         // allocate the color tables
       
   461         uint16 *redTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
       
   462         uint16 *greenTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
       
   463         uint16 *blueTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
       
   464         if (!redTable || !greenTable || !blueTable) {
       
   465             TIFFClose(tiff);
       
   466             return false;
       
   467         }
       
   468 
       
   469         // set the color table
       
   470         const QVector<QRgb> colorTable = image.colorTable();
   476         const QVector<QRgb> colorTable = image.colorTable();
   471 
   477         bool isGrayscale = checkGrayscale(colorTable);
   472         const int tableSize = colorTable.size();
   478         if (isGrayscale) {
   473         Q_ASSERT(tableSize <= 256);
   479             uint16 photometric = PHOTOMETRIC_MINISBLACK;
   474         for (int i = 0; i<tableSize; ++i) {
   480             if (image.colorTable().at(0) == 0xffffffff)
   475             const QRgb color = colorTable.at(i);
   481                 photometric = PHOTOMETRIC_MINISWHITE;
   476             redTable[i] = qRed(color) * 257;
   482             if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, photometric)
   477             greenTable[i] = qGreen(color) * 257;
   483                     || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS)
   478             blueTable[i] = qBlue(color) * 257;
   484                     || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
   479         }
   485                 TIFFClose(tiff);
   480 
   486                 return false;
   481         const bool setColorTableSuccess = TIFFSetField(tiff, TIFFTAG_COLORMAP, redTable, greenTable, blueTable);
   487             }
   482 
   488         } else {
   483         qFree(redTable);
   489             if (!TIFFSetField(tiff, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_PALETTE)
   484         qFree(greenTable);
   490                     || !TIFFSetField(tiff, TIFFTAG_COMPRESSION, compression == NoCompression ? COMPRESSION_NONE : COMPRESSION_PACKBITS)
   485         qFree(blueTable);
   491                     || !TIFFSetField(tiff, TIFFTAG_BITSPERSAMPLE, 8)) {
   486 
   492                 TIFFClose(tiff);
   487         if (!setColorTableSuccess) {
   493                 return false;
   488             TIFFClose(tiff);
   494             }
   489             return false;
   495             //// write the color table
       
   496             // allocate the color tables
       
   497             uint16 *redTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
       
   498             uint16 *greenTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
       
   499             uint16 *blueTable = static_cast<uint16 *>(qMalloc(256 * sizeof(uint16)));
       
   500             if (!redTable || !greenTable || !blueTable) {
       
   501                 TIFFClose(tiff);
       
   502                 return false;
       
   503             }
       
   504 
       
   505             // set the color table
       
   506             const int tableSize = colorTable.size();
       
   507             Q_ASSERT(tableSize <= 256);
       
   508             for (int i = 0; i<tableSize; ++i) {
       
   509                 const QRgb color = colorTable.at(i);
       
   510                 redTable[i] = qRed(color) * 257;
       
   511                 greenTable[i] = qGreen(color) * 257;
       
   512                 blueTable[i] = qBlue(color) * 257;
       
   513             }
       
   514 
       
   515             const bool setColorTableSuccess = TIFFSetField(tiff, TIFFTAG_COLORMAP, redTable, greenTable, blueTable);
       
   516 
       
   517             qFree(redTable);
       
   518             qFree(greenTable);
       
   519             qFree(blueTable);
       
   520 
       
   521             if (!setColorTableSuccess) {
       
   522                 TIFFClose(tiff);
       
   523                 return false;
       
   524             }
   490         }
   525         }
   491 
   526 
   492         //// write the data
   527         //// write the data
   493         // try to do the conversion in chunks no greater than 16 MB
   528         // try to do the conversion in chunks no greater than 16 MB
   494         int chunks = (width * height/ (1024 * 1024 * 16)) + 1;
   529         int chunks = (width * height/ (1024 * 1024 * 16)) + 1;