bool KIPIWriteImage::write2TIFF(const QString& destPath) { uint32 w = d->width; uint32 h = d->height; uchar* const data = (uchar*)d->data.data(); // TIFF error handling. If an errors/warnings occurs during reading, // libtiff will call these methods TIFFSetWarningHandler(kipi_tiff_warning); TIFFSetErrorHandler(kipi_tiff_error); // Open target file TIFF* const tif = TIFFOpen((const char*)(QFile::encodeName(destPath)).constData(), "w"); if (!tif) { qDebug() << "Failed to open TIFF file for writing" ; return false; } int bitsDepth = d->sixteenBit ? 16 : 8; TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, w); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, h); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE); TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE); TIFFSetField(tif, TIFFTAG_ZIPQUALITY, 9); // NOTE : this tag values aren't defined in libtiff 3.6.1. '2' is PREDICTOR_HORIZONTAL. // Use horizontal differencing for images which are // likely to be continuous tone. The TIFF spec says that this // usually leads to better compression. // See this url for more details: // http://www.awaresystems.be/imaging/tiff/tifftags/predictor.html TIFFSetField(tif, TIFFTAG_PREDICTOR, 2); uint16 sampleinfo[1]; if (d->hasAlpha) { sampleinfo[0] = EXTRASAMPLE_ASSOCALPHA; TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4); TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, 1, sampleinfo); } else { TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); } TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (uint16)bitsDepth); TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, 0)); QString libtiffver(QLatin1String(TIFFLIB_VERSION_STR)); libtiffver.replace(QLatin1Char('\n'), QLatin1Char(' ')); TIFFSetField(tif, TIFFTAG_SOFTWARE, (const char*)libtiffver.toLatin1().data()); // Write full image data in tiff directory IFD0 uchar* pixel=0; double alpha_factor; uint32 x, y; uint8 r8, g8, b8, a8=0; uint16 r16, g16, b16, a16=0; int i=0; uint8* const buf = (uint8 *)_TIFFmalloc(TIFFScanlineSize(tif)); if (!buf) { qDebug() << "Cannot allocate memory buffer for main TIFF image." ; TIFFClose(tif); return false; } for (y = 0; y < h; ++y) { if (cancel()) { _TIFFfree(buf); TIFFClose(tif); return false; } i = 0; for (x = 0; x < w; ++x) { pixel = &data[((y * w) + x) * bytesDepth()]; if ( d->sixteenBit ) // 16 bits image. { b16 = (uint16)(pixel[0]+256*pixel[1]); g16 = (uint16)(pixel[2]+256*pixel[3]); r16 = (uint16)(pixel[4]+256*pixel[5]); if (d->hasAlpha) { // TIFF makes you pre-multiply the rgb components by alpha a16 = (uint16)(pixel[6]+256*pixel[7]); alpha_factor = ((double)a16 / 65535.0); r16 = (uint16)(r16*alpha_factor); g16 = (uint16)(g16*alpha_factor); b16 = (uint16)(b16*alpha_factor); } // This might be endian dependent buf[i++] = (uint8)(r16); buf[i++] = (uint8)(r16 >> 8); buf[i++] = (uint8)(g16); buf[i++] = (uint8)(g16 >> 8); buf[i++] = (uint8)(b16); buf[i++] = (uint8)(b16 >> 8); if (d->hasAlpha) { buf[i++] = (uint8)(a16) ; buf[i++] = (uint8)(a16 >> 8) ; } } else // 8 bits image. {
bool KPWriteImage::write2TIFF(const QString& destPath) { uint32 w = d->width; uint32 h = d->height; uchar* data = (uchar*)d->data.data(); // TIFF error handling. If an errors/warnings occurs during reading, // libtiff will call these methods TIFFSetWarningHandler(kipi_tiff_warning); TIFFSetErrorHandler(kipi_tiff_error); // Open target file TIFF *tif = TIFFOpen(QFile::encodeName(destPath), "w"); if (!tif) { kDebug( 51000 ) << "Failed to open TIFF file for writing" << endl; return false; } int bitsDepth = d->sixteenBit ? 16 : 8; TIFFSetField(tif, TIFFTAG_IMAGEWIDTH, w); TIFFSetField(tif, TIFFTAG_IMAGELENGTH, h); TIFFSetField(tif, TIFFTAG_PHOTOMETRIC, PHOTOMETRIC_RGB); TIFFSetField(tif, TIFFTAG_PLANARCONFIG, PLANARCONFIG_CONTIG); TIFFSetField(tif, TIFFTAG_ORIENTATION, ORIENTATION_TOPLEFT); TIFFSetField(tif, TIFFTAG_RESOLUTIONUNIT, RESUNIT_NONE); TIFFSetField(tif, TIFFTAG_COMPRESSION, COMPRESSION_ADOBE_DEFLATE); TIFFSetField(tif, TIFFTAG_ZIPQUALITY, 9); // NOTE : this tag values aren't defined in libtiff 3.6.1. '2' is PREDICTOR_HORIZONTAL. // Use horizontal differencing for images which are // likely to be continuous tone. The TIFF spec says that this // usually leads to better compression. // See this url for more details: // http://www.awaresystems.be/imaging/tiff/tifftags/predictor.html TIFFSetField(tif, TIFFTAG_PREDICTOR, 2); if (d->hasAlpha) { TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 4); TIFFSetField(tif, TIFFTAG_EXTRASAMPLES, EXTRASAMPLE_ASSOCALPHA); } else { TIFFSetField(tif, TIFFTAG_SAMPLESPERPIXEL, 3); } TIFFSetField(tif, TIFFTAG_BITSPERSAMPLE, (uint16)bitsDepth); TIFFSetField(tif, TIFFTAG_ROWSPERSTRIP, TIFFDefaultStripSize(tif, 0)); // Store Iptc data. QByteArray ba2 = d->metadata.getIptc(true); #if defined(TIFFTAG_PHOTOSHOP) TIFFSetField (tif, TIFFTAG_PHOTOSHOP, (uint32)ba2.size(), (uchar *)ba2.data()); #endif // Store Xmp data. QByteArray ba3 = d->metadata.getXmp(); #if defined(TIFFTAG_XMLPACKET) TIFFSetField(tif, TIFFTAG_XMLPACKET, (uint32)ba3.size(), (uchar *)ba3.data()); #endif // Standard Exif Ascii tags (available with libtiff 3.6.1) tiffSetExifAsciiTag(tif, TIFFTAG_DOCUMENTNAME, d->metadata, "Exif.Image.DocumentName"); tiffSetExifAsciiTag(tif, TIFFTAG_IMAGEDESCRIPTION, d->metadata, "Exif.Image.ImageDescription"); tiffSetExifAsciiTag(tif, TIFFTAG_MAKE, d->metadata, "Exif.Image.Make"); tiffSetExifAsciiTag(tif, TIFFTAG_MODEL, d->metadata, "Exif.Image.Model"); tiffSetExifAsciiTag(tif, TIFFTAG_DATETIME, d->metadata, "Exif.Image.DateTime"); tiffSetExifAsciiTag(tif, TIFFTAG_ARTIST, d->metadata, "Exif.Image.Artist"); tiffSetExifAsciiTag(tif, TIFFTAG_COPYRIGHT, d->metadata, "Exif.Image.Copyright"); QString libtiffver(TIFFLIB_VERSION_STR); libtiffver.replace('\n', ' '); QString soft = d->kipipluginsVer; soft.append(QString(" ( %1 )").arg(libtiffver)); TIFFSetField(tif, TIFFTAG_SOFTWARE, (const char*)soft.toAscii().data()); // Write ICC profil. if (!d->iccProfile.isEmpty()) { #if defined(TIFFTAG_ICCPROFILE) TIFFSetField(tif, TIFFTAG_ICCPROFILE, (uint32)d->iccProfile.size(), (uchar *)d->iccProfile.data()); #endif } // Write full image data in tiff directory IFD0 uchar *pixel; double alpha_factor; uint32 x, y; uint8 r8, g8, b8, a8=0; uint16 r16, g16, b16, a16=0; int i=0; uint8 *buf = (uint8 *)_TIFFmalloc(TIFFScanlineSize(tif)); if (!buf) { kDebug( 51000 ) << "Cannot allocate memory buffer for main TIFF image." << endl; TIFFClose(tif); return false; } for (y = 0; y < h; y++) { if (cancel()) { _TIFFfree(buf); TIFFClose(tif); return false; } i = 0; for (x = 0; x < w; x++) { pixel = &data[((y * w) + x) * bytesDepth()]; if ( d->sixteenBit ) // 16 bits image. { b16 = (uint16)(pixel[0]+256*pixel[1]); g16 = (uint16)(pixel[2]+256*pixel[3]); r16 = (uint16)(pixel[4]+256*pixel[5]); if (d->hasAlpha) { // TIFF makes you pre-mutiply the rgb components by alpha a16 = (uint16)(pixel[6]+256*pixel[7]); alpha_factor = ((double)a16 / 65535.0); r16 = (uint16)(r16*alpha_factor); g16 = (uint16)(g16*alpha_factor); b16 = (uint16)(b16*alpha_factor); } // This might be endian dependent buf[i++] = (uint8)(r16); buf[i++] = (uint8)(r16 >> 8); buf[i++] = (uint8)(g16); buf[i++] = (uint8)(g16 >> 8); buf[i++] = (uint8)(b16); buf[i++] = (uint8)(b16 >> 8); if (d->hasAlpha) { buf[i++] = (uint8)(a16) ; buf[i++] = (uint8)(a16 >> 8) ; } } else // 8 bits image. {