[prev in list] [next in list] [prev in thread] [next in thread] 

List:       kde-commits
Subject:    extragear/libs/libkexiv2/libkexiv2
From:       Marcel Wiesweg <marcel.wiesweg () gmx ! de>
Date:       2007-08-31 20:30:13
Message-ID: 1188592213.281650.26180.nullmailer () svn ! kde ! org
[Download RAW message or body]

SVN commit 707039 by mwiesweg:

Add four methods to libkexiv2:
- two methods to set and get an exif value as a QVariant
- one method which allows to get the user-readable output when the name of the \
orignal exif  tag is known and the raw data is provided
- one method to convert a double to a rational with different properties than the \
existing one.  The one method has its strength when you have a double that was \
originally created from a rational.  In that case, the original denominator will be \
retrieved.


 M  +279 -0    kexiv2.cpp  
 M  +36 -4     kexiv2.h  


--- trunk/extragear/libs/libkexiv2/libkexiv2/kexiv2.cpp #707038:707039
@@ -31,6 +31,7 @@
 #include <cstdio>
 #include <cassert>
 #include <cmath>
+#include <cfloat>
 #include <iostream>
 #include <iomanip>
 
@@ -1384,6 +1385,87 @@
     return false;
 }
 
+QString KExiv2::createExifTagStringFromValue(const char *exifTagName, const QVariant \
&val, bool escapeCR) +{
+    try
+    {
+        Exiv2::ExifKey key(exifTagName);
+        Exiv2::Exifdatum datum(key);
+        switch (val.type())
+        {
+            case QVariant::Int:
+            case QVariant::Bool:
+            case QVariant::LongLong:
+            case QVariant::ULongLong:
+                datum = (int32_t)val.toInt();
+                break;
+            case QVariant::UInt:
+                datum = (uint32_t)val.toUInt();
+                break;
+
+            case QVariant::Double:
+            {
+                long num, den;
+                convertToRationalSmallDenominator(val.toDouble(), &num, &den);
+                Exiv2::Rational rational;
+                rational.first  = num;
+                rational.second = den;
+                datum = rational;
+                break;
+            }
+            case QVariant::List:
+            {
+                long num = 0, den = 1;
+                QList<QVariant> list = val.toList();
+                if (list.size() >= 1)
+                    num = list[0].toInt();
+                if (list.size() >= 2)
+                    den = list[1].toInt();
+                Exiv2::Rational rational;
+                rational.first  = num;
+                rational.second = den;
+                datum = rational;
+                break;
+            }
+
+            case QVariant::Date:
+            case QVariant::DateTime:
+            {
+                QDateTime dateTime = val.toDateTime();
+                if(!dateTime.isValid())
+                    break;
+
+                const std::string \
&exifdatetime(dateTime.toString(QString("yyyy:MM:dd \
hh:mm:ss")).toAscii().constData()); +                datum = exifdatetime;
+                break;
+            }
+
+            case QVariant::String:
+            case QVariant::Char:
+                datum = (std::string)val.toString().toAscii().constData();
+                break;
+            default:
+                break;
+        }
+
+        std::ostringstream os;
+        os << datum;
+        QString tagValue = QString::fromLocal8Bit(os.str().c_str());
+
+        if (escapeCR)
+            tagValue.replace("\n", " ");
+
+        return tagValue;
+    }
+    catch( Exiv2::Error &e )
+    {
+        printExiv2ExceptionError("Cannot set Iptc tag string into image using Exiv2 \
", e); +    }
+
+    return QString();
+}
+
+
 bool KExiv2::getExifTagLong(const char* exifTagName, long &val) const
 {
     try
@@ -1430,6 +1512,74 @@
     return QByteArray();
 }
 
+QVariant KExiv2::getExifTagVariant(const char *exifTagName, bool \
rationalAsListOfInts, bool stringEscapeCR) const +{
+    try
+    {
+        Exiv2::ExifKey exifKey(exifTagName);
+        Exiv2::ExifData exifData(d->exifMetadata);
+        Exiv2::ExifData::iterator it = exifData.findKey(exifKey);
+        if (it != exifData.end())
+        {
+            switch (it->typeId())
+            {
+                case Exiv2::unsignedByte:
+                case Exiv2::unsignedShort:
+                case Exiv2::unsignedLong:
+                case Exiv2::signedShort:
+                case Exiv2::signedLong:
+                    return QVariant((int)it->toLong());
+                case Exiv2::unsignedRational:
+                case Exiv2::signedRational:
+                    if (rationalAsListOfInts)
+                    {
+                        QList<QVariant> list;
+                        list << (*it).toRational(0).first;
+                        list << (*it).toRational(0).second;
+                        return QVariant(list);
+                    }
+                    else
+                    {
+                        // prefer double precision
+                        double num = (*it).toRational(0).first;
+                        double den = (*it).toRational(0).second;
+                        if (den == 0.0)
+                            return QVariant();
+                        return QVariant(num / den);
+                    }
+                case Exiv2::date:
+                case Exiv2::time:
+                {
+                    QDateTime dateTime = \
QDateTime::fromString(it->toString().c_str(), Qt::ISODate); +                    \
return QVariant(dateTime); +                }
+                case Exiv2::asciiString:
+                case Exiv2::comment:
+                case Exiv2::string:
+                {
+                    std::ostringstream os;
+                    os << *it;
+                    QString tagValue = QString::fromLocal8Bit(os.str().c_str());
+
+                    if (stringEscapeCR)
+                        tagValue.replace("\n", " ");
+
+                    return QVariant(tagValue);
+                }
+                default:
+                    return QVariant();
+            }
+        }
+    }
+    catch( Exiv2::Error &e )
+    {
+        printExiv2ExceptionError(QString("Cannot find Exif key '%1' in the image \
using Exiv2 ") +                                 .arg(exifTagName), e);
+    }
+
+    return false;
+}
+
 QByteArray KExiv2::getIptcTagData(const char *iptcTagName) const
 {
     try
@@ -1535,6 +1685,71 @@
     return false;
 }
 
+bool KExiv2::setExifTagVariant(const char *exifTagName, const QVariant& val, bool \
rationalWantSmallDenominator, bool setProgramName) +{
+    switch (val.type())
+    {
+        case QVariant::Int:
+        case QVariant::UInt:
+        case QVariant::Bool:
+        case QVariant::LongLong:
+        case QVariant::ULongLong:
+            return setExifTagLong(exifTagName, val.toInt(), setProgramName);
+
+        case QVariant::Double:
+        {
+            long num, den;
+            if (rationalWantSmallDenominator)
+                convertToRationalSmallDenominator(val.toDouble(), &num, &den);
+            else
+                convertToRational(val.toDouble(), &num, &den, 4);
+            return setExifTagRational(exifTagName, num, den, setProgramName);
+        }
+        case QVariant::List:
+        {
+            long num = 0, den = 1;
+            QList<QVariant> list = val.toList();
+            if (list.size() >= 1)
+                num = list[0].toInt();
+            if (list.size() >= 2)
+                den = list[1].toInt();
+            return setExifTagRational(exifTagName, num, den, setProgramName);
+        }
+
+        case QVariant::Date:
+        case QVariant::DateTime:
+        {
+            QDateTime dateTime = val.toDateTime();
+            if(!dateTime.isValid())
+                return false;
+
+            if (!setProgramId(setProgramName))
+                return false;
+
+            try
+            {
+                const std::string \
&exifdatetime(dateTime.toString(QString("yyyy:MM:dd \
hh:mm:ss")).toAscii().constData()); +                d->exifMetadata[exifTagName] = \
exifdatetime; +            }
+            catch( Exiv2::Error &e )
+            {
+                printExiv2ExceptionError("Cannot set Date & Time in image using \
Exiv2 ", e); +            }
+            return false;
+        }
+
+        case QVariant::String:
+        case QVariant::Char:
+            return setExifTagString(exifTagName, val.toString(), setProgramName);
+
+        case QVariant::ByteArray:
+            return setExifTagData(exifTagName, val.toByteArray(), setProgramName);
+        default:
+            break;
+    }
+    return false;
+}
+
 bool KExiv2::setIptcTagData(const char *iptcTagName, const QByteArray& data, bool \
setProgramName)  {
     if (data.isEmpty())
@@ -2215,6 +2430,70 @@
     *denominator = (int)denTemp;
 }
 
+void KExiv2::convertToRationalSmallDenominator(double number, long int* numerator, \
long int* denominator) +{
+    // This function converts the given decimal number
+    // to a rational (fractional) number.
+    //
+    // This method, in contrast to the method above, will retrieve the smallest \
possible +    // denominator. It is tested to retrieve the correct value for 1/x, \
with 0 < x <= 1000000. +    // Note: This requires double precision, storing in float \
breaks some numbers (49, 59, 86,...) +
+    // Split up the number.
+    double whole      = trunc(number);
+    double fractional = number - whole;
+
+    /*
+     * Find best rational approximation to a double
+     * by C.B. Falconer, 2006-09-07. Released to public domain.
+     *
+     * Newsgroups: comp.lang.c, comp.programming
+     * From: CBFalconer <cbfalconer@yahoo.com>
+     * Date: Thu, 07 Sep 2006 17:35:30 -0400
+     * Subject: Rational approximations
+     */
+    int lastnum = 500; // this is _not_ the largest possible denominator
+    long int num, approx, bestnum=0, bestdenom=1;
+    double   value, error, leasterr, criterion;
+
+    value = fractional;
+
+    if (value == 0.0)
+    {
+        *numerator   = (long int)whole;
+        *denominator = 1;
+        return;
+    }
+
+    criterion = 2 * value * DBL_EPSILON;
+    for (leasterr = value, num = 1; num < lastnum; num++) {
+        approx = (int)(num / value + 0.5);
+        error  = fabs((double)num / approx - value);
+        if (error < leasterr) {
+            bestnum = num;
+            bestdenom = approx;
+            leasterr = error;
+            if (leasterr <= criterion) break;
+        }
+    }
+
+    // add whole number part
+    if (bestdenom * whole > (double)INT_MAX)
+    {
+        // In some cases, we would generate an integer overflow.
+        // Fall back to Gilles's code which is better suited for such numbers.
+        convertToRational(number, numerator, denominator, 5);
+    }
+    else
+    {
+        bestnum += bestdenom * (long int)whole;
+
+        *numerator   = bestnum;
+        *denominator = bestdenom;
+    }
+}
+
+
 QStringList KExiv2::getImageKeywords() const
 {
     try
--- trunk/extragear/libs/libkexiv2/libkexiv2/kexiv2.h #707038:707039
@@ -42,6 +42,7 @@
 #include <QtCore/QDateTime>
 #include <QtCore/QMap>
 #include <QtCore/QStringList>
+#include <QtCore/QVariant>
 
 // Local includes.
 
@@ -364,7 +365,24 @@
 
     /** Set an Exif tag content using a bytes array. Return true if tag is set \
                successfully. */
     bool setExifTagData(const char *exifTagName, const QByteArray& data, bool \
                setProgramName=true);
-    
+
+    /** Get an Exif tags content as a QVariant. Returns a null QVariant if the Exif
+        tag cannot be found.
+        For string and integer values the matching QVariant types will be used,
+        for date and time values QVariant::DateTime.
+        Rationals will be returned as QVariant::List with two integer QVariants \
(numerator, denominator) +        if rationalAsListOfInts is true, as double if \
rationalAsListOfInts is false. +     */
+    QVariant getExifTagVariant(const char *exifTagName, bool rationalAsListOfInts = \
true, bool escapeCR=true) const; +
+    /** Set an Exif tag content using a QVariant. Returns true if tag is set \
successfully. +        All types described for the above method are supported.
+        Calling with a QVariant of type ByteArray is equivalent to calling \
setExifTagData. +        For the meaning of rationalWantSmallDenominator, see the \
documentation of the convertToRational methods. +     */
+    bool setExifTagVariant(const char *exifTagName, const QVariant& data,
+                           bool rationalWantSmallDenominator=true, bool \
setProgramName=true); +
     /** Get an Iptc tags content like a string. If 'escapeCR' parameter is true, the \
                CR characters
         will be removed. If Iptc tag cannot be found a null string is returned. */
     QString getIptcTagString(const char* iptcTagName, bool escapeCR=true) const;
@@ -463,10 +481,24 @@
 
     //-- Advanced methods to convert and decode data -------------------------
 
-    /** This method convert 'number' like a rational value, returned in 'numerator' \
                and 
-        'denominator' parameters. Set the precision using 'rounding' parameter. */
-    static void convertToRational(double number, long int* numerator, 
+    static QString createExifTagStringFromValue(const char *exifTagName, const \
QVariant &val, bool escapeCR=true); +
+    /** This method converts 'number' to a rational value, returned in the \
'numerator' and +        'denominator' parameters. Set the precision using 'rounding' \
parameter. +        Use this method if you want to retrieve a most exact rational for \
a number +        without further properties, without any requirements to the \
denominator. +     */
+    static void convertToRational(double number, long int* numerator,
                                   long int* denominator, int rounding);
+    /** This method convert a'number' to a rational value, returned in 'numerator' \
and +        'denominator' parameters.
+        This method will be able to retrieve a rational number from a double - if \
you +        constructed your double with 1.0 / 4786.0, this method will retrieve 1 / \
4786. +        If your number is not expected to be rational, use the method above \
which is just as +        exact with rounding = 4 and more exact with rounding > 4.
+     */
+    static void convertToRationalSmallDenominator(double number, long int* \
numerator, +                                  long int* denominator);
 
     /** Wrapper method to convert a Comments content to a QString. */ 
     static QString convertCommentValue(const Exiv2::Exifdatum &comment);


[prev in list] [next in list] [prev in thread] [next in thread] 

Configure | About | News | Add a list | Sponsored by KoreLogic