Example #1
0
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;
}
Example #2
0
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;
}
Example #3
0
bool ImageResize::imageResize(const EmailSettingsContainer& settings,
                              const KUrl& orgUrl, const QString& destName, QString& err)
{
    EmailSettingsContainer emailSettings = settings;
    QFileInfo fi(orgUrl.path());

    if (!fi.exists() || !fi.isReadable())
    {
        err = i18n("Error opening input file");
        return false;
    }

    QFileInfo tmp(destName);
    QFileInfo tmpDir(tmp.dir().absolutePath());

    kDebug() << "tmpDir: " << tmp.dir().absolutePath();

    if (!tmpDir.exists() || !tmpDir.isWritable())
    {
        err = i18n("Error opening temporary folder");
        return false;
    }

    QImage img;

    // Check if RAW file.
    QString rawFilesExt(KDcrawIface::KDcraw::rawFiles());
    if (rawFilesExt.toUpper().contains( fi.suffix().toUpper() ))
        KDcrawIface::KDcraw::loadDcrawPreview(img, orgUrl.path());
    else
        img.load(orgUrl.path());

    int sizeFactor = emailSettings.size();

    if ( !img.isNull() )
    {
        int w = img.width();
        int h = img.height();

        if( w > sizeFactor || h > sizeFactor )
        {
            if( w > h )
            {
                h = (int)( (double)( h * sizeFactor ) / w );

                if ( h == 0 ) h = 1;

                w = sizeFactor;
                Q_ASSERT( h <= sizeFactor );
            }
            else
            {
                w = (int)( (double)( w * sizeFactor ) / h );

                if ( w == 0 ) w = 1;

                h = sizeFactor;
                Q_ASSERT( w <= sizeFactor );
            }

            const QImage scaledImg(img.scaled(w, h, Qt::IgnoreAspectRatio, Qt::SmoothTransformation));

            if ( scaledImg.width() != w || scaledImg.height() != h )
            {
                err = i18n("Cannot resize image. Aborting.");
                return false;
            }

            img = scaledImg;
        }

        QString destPath = destName;

        KExiv2Iface::KExiv2 meta;

        meta.load(orgUrl.path());
        meta.setImageProgramId(QString("Kipi-plugins"), QString(kipiplugins_version));
        meta.setImageDimensions(img.size());

        if (emailSettings.format() == QString("JPEG"))
        {
            if ( !img.save(destPath, emailSettings.format().toLatin1(), emailSettings.imageCompression) )
            {
                err = i18n("Cannot save resized image (JPEG). Aborting.");
                return false;
            }
            else
            {
                meta.save(destPath);
            }
        }
        else if (emailSettings.format() == QString("PNG"))
        {
            QByteArray data((const char*)img.bits(), img.numBytes());
            KIPIPlugins::KPWriteImage wImageIface;
            wImageIface.setImageData(data, img.width(), img.height(), false, true, QByteArray(), meta);
            if ( !wImageIface.write2PNG(destPath) )
            {
                err = i18n("Cannot save resized image (PNG). Aborting.");
                return false;
            }
        }

        return true;
    }

    return false;
}