bool RawDecodingIface::loadedFromDcraw(const QString& filePath, QString& destPath, SaveSettingsWidget::OutputFormat outputFileFormat, const QByteArray& imageData, int width, int height, int rgbmax, const KDcrawIface::RawDecodingSettings& rawDecodingSettings) { bool sixteenBits = rawDecodingSettings.sixteenBitsImage; uchar* sptr = (uchar*)imageData.data(); float factor = 65535.0 / rgbmax; uchar tmp8[2]; unsigned short tmp16[3]; // Set RGB color components. for (int i = 0 ; i < width * height ; i++) { if (!sixteenBits) // 8 bits color depth image. { // Swap Red and Blue tmp8[0] = sptr[2]; tmp8[1] = sptr[0]; sptr[0] = tmp8[0]; sptr[2] = tmp8[1]; sptr += 3; } else // 16 bits color depth image. { // Swap Red and Blue and re-ajust color component values #if KDCRAW_VERSION < 0x000400 tmp16[0] = (unsigned short)((sptr[4]*256 + sptr[5]) * factor); // Blue tmp16[1] = (unsigned short)((sptr[2]*256 + sptr[3]) * factor); // Green tmp16[2] = (unsigned short)((sptr[0]*256 + sptr[1]) * factor); // Red #else tmp16[0] = (unsigned short)((sptr[5]*256 + sptr[4]) * factor); // Blue tmp16[1] = (unsigned short)((sptr[3]*256 + sptr[2]) * factor); // Green tmp16[2] = (unsigned short)((sptr[1]*256 + sptr[0]) * factor); // Red #endif memcpy(&sptr[0], &tmp16[0], 6); sptr += 6; } } #if KDCRAW_VERSION < 0x000400 // Special case: RAW decoded image is a linear-histogram image with 16 bits color depth. // No auto white balance and no gamma adjustemnts are performed. Image is a black hole. // We need to reproduce all dcraw 8 bits color depth adjustements here. if (sixteenBits && rawDecodingSettings.outputColorSpace != KDcrawIface::RawDecodingSettings::RAWCOLOR) { // Compute histogram. unsigned short* image = (unsigned short*)imageData.data(); int histogram[3][65536]; memset(histogram, 0, sizeof(histogram)); for (int i = 0 ; i < width * height ; i++) { for (int c = 0 ; c < 3 ; c++) histogram[c][image[c]]++; image += 3; } // Search 99th percentile white level. int perc, val, total; float white=0.0, r; unsigned short lut[65536]; perc = (int)(width * height * 0.01); kDebug( 51000 ) << "White Level: " << perc << endl; for (int c =0 ; c < 3 ; c++) { total = 0; for (val = 65535 ; val > 256 ; --val) if ((total += histogram[c][val]) > perc) break; if (white < val) white = (float)val; } white *= 1.0 / rawDecodingSettings.brightness; kDebug( 51000 ) << "White Point: " << white << endl; // Compute the Gamma lut accordingly. for (int i=0; i < 65536; i++) { r = i / white; val = (int)(65536.0 * (r <= 0.018 ? r*4.5 : pow(r,0.45)*1.099-0.099)); if (val > 65535) val = 65535; lut[i] = val; } // Apply Gamma lut to the whole image. unsigned short *im = (unsigned short *)imageData.data(); for (int i = 0; i < width*height; i++) { im[0] = lut[im[0]]; // Blue im[1] = lut[im[1]]; // Green im[2] = lut[im[2]]; // Red im += 3; } } #endif // Use a QImage instance to write IPTC preview and Exif thumbnail // and adapt color component order to KPWriteImage data format (RGB ==> BGR) QImage img(width, height, QImage::Format_ARGB32); uint* dptr = (uint*)img.bits(); uchar* sptr8 = (uchar*)imageData.data(); unsigned short* sptr16 = (unsigned short*)imageData.data(); for (int i = 0 ; i < width * height ; i++) { if (!sixteenBits) // 8 bits color depth image. { *dptr++ = qRgba(sptr8[2], sptr8[1], sptr8[0], 0xFF); sptr8 += 3; } else // 16 bits color depth image. { *dptr++ = qRgba((uchar)((sptr16[2] * 255UL)/65535UL), (uchar)((sptr16[1] * 255UL)/65535UL), (uchar)((sptr16[0] * 255UL)/65535UL), 0xFF); sptr16 += 3; } } QImage iptcPreview = img.scaled(1280, 1024, Qt::KeepAspectRatio); QImage exifThumbnail = iptcPreview.scaled(160, 120, Qt::KeepAspectRatio); // -- Write image data into destination file ------------------------------- QByteArray prof = KIPIPlugins::KPWriteImage::getICCProfilFromFile(m_rawDecodingSettings.outputColorSpace); QString soft = QString("Kipi Raw Converter v.%1").arg(kipiplugins_version); QFileInfo fi(filePath); destPath = fi.absolutePath() + QString("/") + ".kipi-rawconverter-tmp-" + QString::number(QDateTime::currentDateTime().toTime_t()); // Metadata restoration and update. KExiv2Iface::KExiv2 meta; #if KEXIV2_VERSION >= 0x000600 meta.setUpdateFileTimeStamp(m_updateFileTimeStamp); #endif meta.load(filePath); meta.setImageProgramId(QString("Kipi-plugins"), QString(kipiplugins_version)); meta.setImageDimensions(QSize(width, height)); meta.setExifThumbnail(exifThumbnail); // Update Iptc preview. // NOTE: see B.K.O #130525. a JPEG segment is limited to 64K. If the IPTC byte array is // bigger than 64K duing of image preview tag size, the target JPEG image will be // broken. Note that IPTC image preview tag is limited to 256K!!! // There is no limitation with TIFF and PNG about IPTC byte array size. if (outputFileFormat != SaveSettingsWidget::OUTPUT_JPEG) meta.setImagePreview(iptcPreview); meta.setExifTagString("Exif.Image.DocumentName", fi.fileName()); meta.setXmpTagString("Xmp.tiff.Make", meta.getExifTagString("Exif.Image.Make")); meta.setXmpTagString("Xmp.tiff.Model", meta.getExifTagString("Exif.Image.Model")); KIPIPlugins::KPWriteImage wImageIface; wImageIface.setImageData(imageData, width, height, sixteenBits, false, prof, meta); wImageIface.setCancel(&m_cancel); switch(outputFileFormat) { case SaveSettingsWidget::OUTPUT_JPEG: { if (!wImageIface.write2JPEG(destPath)) return false; break; } case SaveSettingsWidget::OUTPUT_PNG: { if (!wImageIface.write2PNG(destPath)) return false; break; } case SaveSettingsWidget::OUTPUT_TIFF: { if (!wImageIface.write2TIFF(destPath)) return false; break; } case SaveSettingsWidget::OUTPUT_PPM: { if (!wImageIface.write2PPM(destPath)) return false; break; } default: { kDebug( 51000 ) << "Invalid output file format" << endl; return false; } } if (m_cancel) { ::remove(QFile::encodeName(destPath)); return false; } return true; }
bool Utils::updateMetadataImageMagick(const QString& src, QString& err) { QFileInfo finfo(src); if (src.isEmpty() || !finfo.isReadable()) { err = i18n("unable to open source file"); return false; } QImage img(src); QImage iptcPreview = img.scaled(1280, 1024, Qt::KeepAspectRatio, Qt::SmoothTransformation); QImage exifThumbnail = iptcPreview.scaled(160, 120, Qt::KeepAspectRatio, Qt::SmoothTransformation); KExiv2Iface::KExiv2 meta; meta.load(src); meta.setImageOrientation(KExiv2Iface::KExiv2::ORIENTATION_NORMAL); meta.setImageProgramId(QString("Kipi-plugins"), QString(kipiplugins_version)); meta.setImageDimensions(img.size()); meta.setExifThumbnail(exifThumbnail); meta.setImagePreview(iptcPreview); #if KEXIV2_VERSION >= 0x010000 QByteArray exifData = meta.getExifEncoded(true); #else QByteArray exifData = meta.getExif(true); #endif QByteArray iptcData = meta.getIptc(true); QByteArray xmpData = meta.getXmp(); KTemporaryFile exifTemp; exifTemp.setSuffix(QString("kipipluginsexif.app1")); exifTemp.setAutoRemove(true); if ( !exifTemp.open() ) { err = i18n("unable to open temp file"); return false; } QString exifFile = exifTemp.fileName(); QDataStream streamExif( &exifTemp ); streamExif.writeRawData(exifData.data(), exifData.size()); exifTemp.close(); KTemporaryFile iptcTemp; iptcTemp.setSuffix(QString("kipipluginsiptc.8bim")); iptcTemp.setAutoRemove(true); iptcTemp.open(); if ( !iptcTemp.open() ) { err = i18n("Cannot rotate: unable to open temp file"); return false; } QString iptcFile = iptcTemp.fileName(); QDataStream streamIptc( &iptcTemp ); streamIptc.writeRawData(iptcData.data(), iptcData.size()); iptcTemp.close(); KTemporaryFile xmpTemp; xmpTemp.setSuffix(QString("kipipluginsxmp.xmp")); xmpTemp.setAutoRemove(true); if ( !xmpTemp.open() ) { err = i18n("unable to open temp file"); return false; } QString xmpFile = xmpTemp.fileName(); QDataStream streamXmp( &xmpTemp ); streamXmp.writeRawData(xmpData.data(), xmpData.size()); xmpTemp.close(); KProcess process; process.clearProgram(); process << "mogrify"; process << "-profile"; process << exifFile; process << "-profile"; process << iptcFile; process << "-profile"; process << xmpFile; process << src + QString("[0]"); kDebug() << "ImageMagick Command line: " << process.program(); process.start(); if (!process.waitForFinished()) return false; if (process.exitStatus() != QProcess::NormalExit) return false; switch (process.exitCode()) { case 0: // Process finished successfully ! { return true; break; } case 15: // process aborted ! { return false; break; } } // Processing error ! m_stdErr = process.readAllStandardError(); err = i18n("Cannot update metadata: %1", m_stdErr.replace('\n', ' ')); return false; }