[SCM] exiv2 packaging branch, master, updated. debian/0.25-3.1-3734-gdcbc29a

Maximiliano Curia maxy at moszumanska.debian.org
Thu Jul 13 17:35:58 UTC 2017


Gitweb-URL: http://git.debian.org/?p=pkg-kde/kde-extras/exiv2.git;a=commitdiff;h=552ce41

The following commit has been merged in the master branch:
commit 552ce410d82e37ecee3e19c12d7a2a6e4f30a18e
Author: Andreas Huggel <ahuggel at gmx.net>
Date:   Wed Jan 28 04:10:42 2004 +0000

    Implemented readTiffImage and various fixes and additions
---
 src/exif.cpp     | 298 +++++++++++++++++++++++++++++++++++++------------------
 src/exif.hpp     | 197 ++++++++++++++++++++++++++----------
 src/exiftest.cpp | 113 +++------------------
 3 files changed, 363 insertions(+), 245 deletions(-)

diff --git a/src/exif.cpp b/src/exif.cpp
index 71f79b4..93fb738 100644
--- a/src/exif.cpp
+++ b/src/exif.cpp
@@ -20,7 +20,7 @@
  */
 /*
   File:      exif.cpp
-  Version:   $Name:  $ $Revision: 1.10 $
+  Version:   $Name:  $ $Revision: 1.11 $
   Author(s): Andreas Huggel (ahu) <ahuggel at gmx.net>
   History:   26-Jan-04, ahu: created
  */
@@ -39,16 +39,6 @@
 #include <cstring>
 
 // *****************************************************************************
-// local declarations
-namespace {
-
-    // Compare two IFD entries by offset, taking care of special cases
-    // where one or both of the entries don't have an offset.
-    bool cmpOffset(const Exif::Ifd::Entry& lhs, const Exif::Ifd::Entry& rhs);
-
-}
-
-// *****************************************************************************
 // class member definitions
 namespace Exif {
 
@@ -139,8 +129,8 @@ namespace Exif {
         return 0;
     } // JpegImage::readExifData
 
-    TiffHeader::TiffHeader() 
-        : byteOrder_(littleEndian), tag_(0x002a), offset_(0x00000008)
+    TiffHeader::TiffHeader(ByteOrder byteOrder) 
+        : byteOrder_(byteOrder), tag_(0x002a), offset_(0x00000008)
     {
     }
 
@@ -361,7 +351,7 @@ namespace Exif {
         return *this;
     } // Metadatum::operator=
     
-    void Metadatum::setValue(Value* value)
+    void Metadatum::setValue(const Value* value)
     {
         delete value_;
         value_ = value->clone();
@@ -374,8 +364,8 @@ namespace Exif {
     }
 
     Ifd::Entry::Entry() 
-        : ifdIdx_(-1), tag_(0), type_(0), count_(0), offset_(0),
-          data_(0), size_(0)
+        : ifdId_(ifdIdNotSet), ifdIdx_(-1), tag_(0), type_(0), count_(0), 
+          offset_(0), data_(0), size_(0)
     {
     }
 
@@ -385,8 +375,8 @@ namespace Exif {
     }
 
     Ifd::Entry::Entry(const Entry& rhs)
-        : ifdIdx_(rhs.ifdIdx_), tag_(rhs.tag_), type_(rhs.type_),
-          count_(rhs.count_), offset_(rhs.offset_), 
+        : ifdId_(rhs.ifdId_), ifdIdx_(rhs.ifdIdx_), tag_(rhs.tag_),
+          type_(rhs.type_), count_(rhs.count_), offset_(rhs.offset_), 
           data_(0), size_(rhs.size_)
     {
         if (rhs.data_) {
@@ -398,6 +388,7 @@ namespace Exif {
     Ifd::Entry::Entry& Ifd::Entry::operator=(const Entry& rhs)
     {
         if (this == &rhs) return *this;
+        ifdId_ = rhs.ifdId_;
         ifdIdx_ = rhs.ifdIdx_;
         tag_ = rhs.tag_;
         type_ = rhs.type_;
@@ -414,7 +405,7 @@ namespace Exif {
     }
 
     Ifd::Ifd(IfdId ifdId)
-        : ifdId_(ifdId), offset_(0), next_(0), size_(0)
+        : ifdId_(ifdId), offset_(0), next_(0)
     {
     }
 
@@ -427,6 +418,7 @@ namespace Exif {
         entries_.clear();
         for (int i=0; i<n; ++i) {
             Entry e;
+            e.ifdId_ = ifdId_;
             e.ifdIdx_ = i;
             e.tag_ = getUShort(buf+o, byteOrder);
             e.type_ = getUShort(buf+o+2, byteOrder);
@@ -439,21 +431,20 @@ namespace Exif {
             o += 12;
         }
         next_ = getULong(buf+o, byteOrder);
-        size_ = 2 + 12 * entries_.size() + 4;
 
         // Guess the offset if it was not given. The guess is based 
         // on the assumption that the smallest offset points to a data 
         // buffer directly following the IFD.
         // Subsequently all offsets of IFD entries need to be recalculated.
-        const Entries::iterator eb = entries_.begin();
-        const Entries::iterator ee = entries_.end();
-        Entries::iterator i = eb;
+        const iterator eb = entries_.begin();
+        const iterator ee = entries_.end();
+        iterator i = eb;
         if (offset_ == 0 && i != ee) {
             // Find the entry with the smallest offset
             i = std::min_element(eb, ee, cmpOffset);
             // Set the guessed IFD offset
             if (i->size_ > 4) {
-                offset_ = i->offset_ - size_;
+                offset_ = i->offset_ - size();
             }
         }
 
@@ -475,24 +466,29 @@ namespace Exif {
         return 0;
     } // Ifd::read
 
-    Ifd::Entries::const_iterator Ifd::findTag(uint16 tag) const 
+    Ifd::const_iterator Ifd::findTag(uint16 tag) const 
     {
         return std::find_if(entries_.begin(), entries_.end(),
                             FindEntryByTag(tag));
     }
 
-    Ifd::Entries::iterator Ifd::findTag(uint16 tag)
+    Ifd::iterator Ifd::findTag(uint16 tag)
     {
         return std::find_if(entries_.begin(), entries_.end(),
                             FindEntryByTag(tag));
     }
 
+    void Ifd::sortByTag()
+    {
+        sort(entries_.begin(), entries_.end(), cmpTag);
+    }
+
     int Ifd::readSubIfd(
         Ifd& dest, const char* buf, ByteOrder byteOrder, uint16 tag
     ) const
     {
         int rc = 0;
-        Entries::const_iterator pos = findTag(tag);
+        const_iterator pos = findTag(tag);
         if (pos != entries_.end()) {
             rc = dest.read(buf + pos->offset_, byteOrder, pos->offset_);
         }
@@ -509,15 +505,15 @@ namespace Exif {
 
         // Add all directory entries to the data buffer
         long dataSize = 0;
-        const Entries::const_iterator b = entries_.begin();
-        const Entries::const_iterator e = entries_.end();
-        Entries::const_iterator i = b;
+        const const_iterator b = entries_.begin();
+        const const_iterator e = entries_.end();
+        const_iterator i = b;
         for (; i != e; ++i) {
             us2Data(buf+o, i->tag_, byteOrder);
             us2Data(buf+o+2, i->type_, byteOrder);
             ul2Data(buf+o+4, i->count_, byteOrder);
             if (i->size_ > 4) {
-                ul2Data(buf+o+8, offset + size_ + dataSize, byteOrder);
+                ul2Data(buf+o+8, offset + size() + dataSize, byteOrder);
                 dataSize += i->size_;
             }
             else {
@@ -529,7 +525,7 @@ namespace Exif {
         // Add the offset to the next IFD to the data buffer pointing
         // directly behind this IFD and its data
         if (next_ != 0) {
-            ul2Data(buf+o, offset + size_ + dataSize, byteOrder);
+            ul2Data(buf+o, offset + size() + dataSize, byteOrder);
         }
         else {
             ul2Data(buf+o, 0, byteOrder);
@@ -545,7 +541,59 @@ namespace Exif {
         }
 
         return o;
-    } // Ifd::data
+    } // Ifd::copy
+
+    void Ifd::add(Metadata::const_iterator begin, 
+                  Metadata::const_iterator end,
+                  ByteOrder byteOrder)
+    {
+        for (Metadata::const_iterator i = begin; i != end; ++i) {
+            // add only metadata with matching IFD id
+            if (i->ifdId() == ifdId_) {
+                add(*i, byteOrder);
+            }
+        }
+    } // Ifd::add
+
+    void Ifd::add(const Metadatum& metadatum, ByteOrder byteOrder)
+    {
+        Entry e;
+        e.ifdId_ = metadatum.ifdId();
+        e.ifdIdx_ = metadatum.ifdIdx();
+        e.tag_ = metadatum.tag();
+        e.type_ = metadatum.typeId();
+        e.count_ = metadatum.count();
+        e.offset_ = 0; // will be calculated when the IFD is written
+        long len = std::max(metadatum.size(), long(4));
+        e.data_ = new char[len];
+        ::memset(e.data_, 0x0, len);
+        metadatum.copy(e.data_, byteOrder);
+        e.size_ = metadatum.size();
+
+        erase(metadatum.tag());
+        entries_.push_back(e);        
+    }
+
+    void Ifd::erase(uint16 tag)
+    {
+        iterator pos = findTag(tag);
+        if (pos != end()) erase(pos); 
+    }
+
+    void Ifd::erase(iterator pos)
+    {
+        entries_.erase(pos);
+    }
+
+    long Ifd::dataSize() const
+    {
+        long dataSize = 0;
+        const_iterator end = this->end();
+        for (const_iterator i = begin(); i != end; ++i) {
+            if (i->size_ > 4) dataSize += i->size_;
+        }
+        return dataSize;
+    }
 
     void Ifd::print(std::ostream& os, const std::string& prefix) const
     {
@@ -560,9 +608,9 @@ namespace Exif {
            << prefix << "Entry     Tag  Format   (Bytes each)  Number  Offset
"
            << prefix << "-----  ------  ---------------------  ------  -----------
";
 
-        const Entries::const_iterator b = entries_.begin();
-        const Entries::const_iterator e = entries_.end();
-        Entries::const_iterator i = b;
+        const const_iterator b = entries_.begin();
+        const const_iterator e = entries_.end();
+        const_iterator i = b;
         for (; i != e; ++i) {
             std::ostringstream offset;
             if (i->size_ <= 4) {
@@ -605,43 +653,110 @@ namespace Exif {
 
     } // Ifd::print
 
-    // Todo: Finish the implementation (TIFF thumbnails)
-    //       - do we need to sum up the strips??
-    int Thumbnail::read(
-        const char* buf, const ExifData& exifData, ByteOrder byteOrder
-    )
+    int Thumbnail::read(const char* buf,
+                        const ExifData& exifData,
+                        ByteOrder byteOrder)
     {
+        int rc = 0;
         std::string key = "Thumbnail.ImageStructure.Compression";
         ExifData::const_iterator pos = exifData.findKey(key);
-        if (pos == exifData.end()) return 1;
+        if (pos == exifData.end()) return -1; // no thumbnail
         long compression = pos->toLong();
         if (compression == 6) {
-            key = "Thumbnail.RecordingOffset.JPEGInterchangeFormat";
-            pos = exifData.findKey(key);
-            if (pos == exifData.end()) return 2;
-            long offset = pos->toLong();
-            key = "Thumbnail.RecordingOffset.JPEGInterchangeFormatLength";
-            pos = exifData.findKey(key);
-            if (pos == exifData.end()) return 3;
-            long size = pos->toLong();
-            thumbnail_ = std::string(buf + offset, size);
-        }
-        else if (compression == 1) {
-            // Todo: implement me!
-            return 4;
+            rc = readJpegImage(buf, exifData);
         }
         else {
-            // invalid compression value
-            return 5;
+            rc = readTiffImage(buf, exifData, byteOrder);
         }
+        return rc;
+    } // Thumbnail::read
+
+    int Thumbnail::readJpegImage(const char* buf, const ExifData& exifData) 
+    {
+        std::string key = "Thumbnail.RecordingOffset.JPEGInterchangeFormat";
+        ExifData::const_iterator pos = exifData.findKey(key);
+        if (pos == exifData.end()) return 1;
+        long offset = pos->toLong();
+        key = "Thumbnail.RecordingOffset.JPEGInterchangeFormatLength";
+        pos = exifData.findKey(key);
+        if (pos == exifData.end()) return 1;
+        long size = pos->toLong();
+        image_ = std::string(buf + offset, size);
+        type_ = JPEG;
         return 0;
     }
 
+    int Thumbnail::readTiffImage(const char* buf,
+                                 const ExifData& exifData,
+                                 ByteOrder byteOrder)
+    {
+        char* data = new char[64*1024];     // temporary buffer Todo: handle larger
+        ::memset(data, 0x0, 64*1024);       // images (which violate the Exif Std)
+        long len = 0;                       // number of bytes in the buffer
+
+        // Copy the TIFF header
+        TiffHeader tiffHeader(byteOrder);
+        len += tiffHeader.copy(data);
+
+        // Create IFD (without Exif and GPS tags) from metadata
+        Ifd ifd1(ifd1);
+        ifd1.add(exifData.begin(), exifData.end(), tiffHeader.byteOrder());
+        Ifd::iterator i = ifd1.findTag(0x8769);
+        if (i != ifd1.end()) ifd1.erase(i);
+        i = ifd1.findTag(0x8825);
+        if (i != ifd1.end()) ifd1.erase(i);
+
+        // Do not copy the IFD yet, remember the location and leave a gap
+        long ifdOffset = len;
+        len += ifd1.size() + ifd1.dataSize();
+
+        // Copy thumbnail image data, remember the offsets used
+        std::string key = "Thumbnail.RecordingOffset.StripOffsets";
+        ExifData::const_iterator offsets = exifData.findKey(key);
+        if (offsets == exifData.end()) return 2;
+        key = "Thumbnail.RecordingOffset.StripByteCounts";
+        ExifData::const_iterator sizes = exifData.findKey(key);
+        if (sizes == exifData.end()) return 2;
+        std::ostringstream os;                  // for the new strip offsets
+        for (long k = 0; k < offsets->count(); ++k) {
+            long offset = offsets->toLong(k);
+            long size = sizes->toLong(k);
+            ::memcpy(data + len, buf + offset, size);
+            os << len << " ";
+            len += size;
+        }
+
+        // Update the IFD with the actual strip offsets (replace existing entry)
+        Metadatum newOffsets(*offsets);
+        newOffsets.setValue(os.str());
+        ifd1.add(newOffsets, tiffHeader.byteOrder());
+
+        // Finally, sort and copy the IFD
+        ifd1.sortByTag();
+        ifd1.copy(data + ifdOffset, tiffHeader.byteOrder(), ifdOffset);
+
+        image_ = std::string(data, len);
+        delete[] data;
+        type_ = TIFF;
+
+        return 0;
+    }
+
+
     int Thumbnail::write(const std::string& path) const
     {
-        std::ofstream file(path.c_str(), std::ios::binary | std::ios::out);
+        std::string p;
+        switch (type_) {
+        case JPEG: 
+            p = path + ".jpg";
+            break;
+        case TIFF:
+            p = path + ".tif";
+            break;
+        }
+        std::ofstream file(p.c_str(), std::ios::binary | std::ios::out);
         if (!file) return 1;
-        file.write(thumbnail_.data(), thumbnail_.size());
+        file.write(image_.data(), image_.size());
         if (!file.good()) return 2;
         return 0;
     }
@@ -706,14 +821,14 @@ namespace Exif {
 
         // Copy all entries from the IFDs to the internal metadata
         metadata_.clear();
-        add(ifd0, byteOrder());
-        add(exifIfd, byteOrder());
-        add(iopIfd, byteOrder()); 
-        add(gpsIfd, byteOrder());
-        add(ifd1, byteOrder());
-        add(ifd1ExifIfd, byteOrder());
-        add(ifd1IopIfd, byteOrder());
-        add(ifd1GpsIfd, byteOrder());
+        add(ifd0.begin(), ifd0.end(), byteOrder());
+        add(exifIfd.begin(), exifIfd.end(), byteOrder());
+        add(iopIfd.begin(), iopIfd.end(), byteOrder()); 
+        add(gpsIfd.begin(), gpsIfd.end(), byteOrder());
+        add(ifd1.begin(), ifd1.end(), byteOrder());
+        add(ifd1ExifIfd.begin(), ifd1ExifIfd.end(), byteOrder());
+        add(ifd1IopIfd.begin(), ifd1IopIfd.end(), byteOrder());
+        add(ifd1GpsIfd.begin(), ifd1GpsIfd.end(), byteOrder());
 
         // Read the thumbnail
         thumbnail_.read(buf, *this, byteOrder());
@@ -733,42 +848,36 @@ namespace Exif {
         return 0;
     }
 
-    void ExifData::add(const Ifd& ifd, ByteOrder byteOrder)
+    void ExifData::add(Ifd::const_iterator begin, 
+                       Ifd::const_iterator end,
+                       ByteOrder byteOrder)
     {
-        Ifd::const_iterator i = ifd.begin();
-        Ifd::const_iterator end = ifd.end(); 
+        Ifd::const_iterator i = begin;
         for (; i != end; ++i) {
             Value* value = Value::create(TypeId(i->type_));
             value->read(i->data_, i->size_, byteOrder);
-            Metadatum md(i->tag_, i->type_, ifd.ifdId(), i->ifdIdx_);
-            iterator k = findKey(md.key());
-            if (k != this->end()) {
-                k->setValue(value);
-            }
-            else {
-                md.setValue(value);
-                add(md);
-            }
+            Metadatum md(i->tag_, i->type_, i->ifdId_, i->ifdIdx_, value);
             delete value;
+            add(md);
         }
     }
 
     void ExifData::add(const std::string& key, Value* value)
     {
-        iterator i = findKey(key);
+        add(Metadatum(key, value));
+    }
+
+    void ExifData::add(const Metadatum& metadatum)
+    {
+        iterator i = findKey(metadatum.key());
         if (i != end()) {
-            i->setValue(value);
+            i->setValue(&metadatum.value());
         }
         else {
-            add(Metadatum(key, value));
+            metadata_.push_back(metadatum);
         }
     }
 
-    void ExifData::add(const Metadatum& src)
-    {
-        metadata_.push_back(src);
-    }
-
     ExifData::const_iterator ExifData::findKey(const std::string& key) const
     {
         return std::find_if(metadata_.begin(), metadata_.end(),
@@ -950,13 +1059,7 @@ namespace Exif {
         os << std::dec << std::setfill(' ');
     }
 
-}                                       // namespace Exif
-
-// *****************************************************************************
-// local definitions
-namespace {
-
-    bool cmpOffset(const Exif::Ifd::Entry& lhs, const Exif::Ifd::Entry& rhs)
+    bool cmpOffset(const Ifd::Entry& lhs, const Ifd::Entry& rhs)
     {
         // We need to ignore entries with size <= 4, so by definition,
         // entries with size <= 4 are greater than those with size > 4
@@ -970,4 +1073,9 @@ namespace {
         return lhs.offset_ < rhs.offset_;
     }
 
-}
+    bool cmpTag(const Ifd::Entry& lhs, const Ifd::Entry& rhs)
+    {
+        return lhs.tag_ < rhs.tag_;
+    }
+
+}                                       // namespace Exif
diff --git a/src/exif.hpp b/src/exif.hpp
index e4fd0f4..0895e13 100644
--- a/src/exif.hpp
+++ b/src/exif.hpp
@@ -21,7 +21,7 @@
 /*!
   @file    exif.hpp
   @brief   Encoding and decoding of %Exif data
-  @version $Name:  $ $Revision: 1.11 $
+  @version $Name:  $ $Revision: 1.12 $
   @author  Andreas Huggel (ahu)
            <a href="mailto:ahuggel at gmx.net">ahuggel at gmx.net</a>
   @date    09-Jan-04, ahu: created
@@ -127,19 +127,22 @@ namespace Exif {
     //! Type to express the byte order (little or big endian)
     enum ByteOrder { littleEndian, bigEndian };
 
-    //! Helper class modelling the Tiff header structure.
+    //! Helper class modelling the TIFF header structure.
     class TiffHeader {
     public:
-        //! Default constructor.
-        TiffHeader();
-        //! Read the Tiff header from a data buffer. Returns 0 if successful.
+        /*!
+          @brief Default constructor. Optionally sets the byte order 
+                 (default: little endian).
+         */
+        explicit TiffHeader(ByteOrder byteOrder =littleEndian);
+        //! Read the TIFF header from a data buffer. Returns 0 if successful.
         int read(const char* buf);
         /*!
-          @brief Write the Tiff header into buf as a data string, return number 
+          @brief Write the TIFF header into buf as a data string, return number 
                  of bytes copied.
          */
         long copy(char* buf) const;
-        //! Return the lengths of the Tiff header in bytes.
+        //! Return the lengths of the TIFF header in bytes.
         long size() const { return 8; }
         //! @name Accessors
         //@{
@@ -148,9 +151,9 @@ namespace Exif {
         //! Return the tag value.
         uint16 tag() const { return tag_; }
         /*!
-          @brief Return the offset to IFD0 from the start of the Tiff header.
+          @brief Return the offset to IFD0 from the start of the TIFF header.
                  The offset is 0x00000008 if IFD0 begins immediately after the 
-                 Tiff header.
+                 TIFF header.
          */
         uint32 offset() const { return offset_; }
         //@}
@@ -441,7 +444,7 @@ namespace Exif {
         /*!
           @brief Set the value. This method copies (clones) the value.
          */
-        void setValue(Value* value);
+        void setValue(const Value* value);
         /*!
           @brief Set the value to the string buf. 
                  Uses Value::read(const std::string& buf). If the metadatum does
@@ -493,6 +496,19 @@ namespace Exif {
         //! Return the value as a string.
         std::string toString() const 
             { return value_ == 0 ? "" : value_->toString(); }
+        /*!
+          @brief Write value to a character data buffer and return the number
+                 of characters (bytes) written.
+
+          The user must ensure that the buffer has enough memory. Otherwise
+          the call results in undefined behaviour.
+
+          @param buf Data buffer to write to.
+          @param byteOrder Applicable byte order (little or big endian).
+          @return Number of characters written.
+        */
+        long copy(char* buf, ByteOrder byteOrder) const 
+            { return value_ == 0 ? 0 : value_->copy(buf, byteOrder); }
         //! Return the IFD id
         IfdId ifdId() const { return ifdId_; }
         //! Return the position in the IFD (-1: not set)
@@ -576,6 +592,8 @@ namespace Exif {
             const char* typeName() const 
                 { return ExifTags::typeName(TypeId(type_)); }
 
+            //! The IFD id (redundant, it is also at the IFD itself)
+            IfdId ifdId_;
             //! Position in the IFD
             int ifdIdx_;
             //! Tag
@@ -607,6 +625,33 @@ namespace Exif {
         iterator begin() { return entries_.begin(); }
         //! End of the entries
         iterator end() { return entries_.end(); }
+        //! Find an IFD entry by tag, return a const iterator into the entries list
+        const_iterator findTag(uint16 tag) const;
+        //! Find an IFD entry by tag, return an iterator into the entries list
+        iterator findTag(uint16 tag);
+        //! Sort the IFD entries by tag
+        void sortByTag();
+        //! Delete the directory entry with the given tag
+        void erase(uint16 tag);
+        //! Delete the directory entry at iterator position pos
+        void erase(iterator pos);
+        /*!
+          @brief Add all metadata in the range from iterator position begin to
+                 iterator position end, which have an IFD id matching that of
+                 this IFD to the list of directory entries. Checks for
+                 duplicates: if an entry with the same tag already exists, the
+                 entry is overwritten.
+         */
+        void add(Metadata::const_iterator begin, 
+                 Metadata::const_iterator end,
+                 ByteOrder byteOrder);
+        /*!
+          @brief Add the metadatum to the list of directory entries. Does not
+                 check for a matching IFD id.  Checks for duplicates: if an
+                 entry with the same tag already exists, the entry is
+                 overwritten.
+         */
+        void add(const Metadatum& metadatum, ByteOrder byteOrder);
 
         //! Unary predicate that matches an Entry with a given tag
         class FindEntryByTag {
@@ -628,9 +673,9 @@ namespace Exif {
           @brief Read a complete IFD and its data from a data buffer
 
           @param buf Pointer to the data to decode. The buffer must start with the 
-                     IFD data (as opposed to readSubIfd).
+                     IFD data (unlike the readSubIfd() method).
           @param byteOrder Applicable byte order (little or big endian).
-          @param offset (Optional) offset of the IFD from the start of the Tiff
+          @param offset (Optional) offset of the IFD from the start of the TIFF
                  header, if known. If not given, the offset will be guessed
                  using the assumption that the smallest offset of all IFD
                  directory entries points to a data buffer immediately follwing
@@ -645,7 +690,7 @@ namespace Exif {
 
           @param dest References the destination IFD.
           @param buf The data buffer to read from. The buffer must contain all Exif 
-                     data starting from the Tiff header (as opposed to read).
+                     data starting from the TIFF header (unlike the read() method).
           @param byteOrder Applicable byte order (little or big endian).
           @param tag Tag to look for.
 
@@ -655,64 +700,93 @@ namespace Exif {
             Ifd& dest, const char* buf, ByteOrder byteOrder, uint16 tag
         ) const;
         /*!
-          @brief Copy the IFD to a data array, returns a reference to the
-                 data buffer. The pointer to the next IFD will be adjusted to an
-                 offset from the start of the Tiff header to the position
-                 immediately following the converted IFD.
+          @brief Copy the IFD to a data array, returns the number of bytes
+                 written. If the pointer to the next IFD is not 0, it will be
+                 adjusted to an offset from the start of the TIFF header to the
+                 position immediately following this IFD.
 
           @param buf    Pointer to the data buffer.
           @param byteOrder Applicable byte order (little or big endian).
-          @param offset Target offset from the start of the Tiff header of the
+          @param offset Target offset from the start of the TIFF header of the
                         data array. The IFD offsets will be adjusted as
                         necessary. If not given, then it is assumed that the IFD
-                        will remain at its original position.
+                        will remain at its original position, i.e., the offset 
+                        of the IFD will be used.
           @return       Returns the number of characters written.
          */
         long copy(char* buf, ByteOrder byteOrder, long offset =0) const;
-        /*!
-          @brief Print the IFD in human readable format to the given stream;
-                 begin each line with prefix.
-         */
-        void print(std::ostream& os, const std::string& prefix ="") const;
         //! @name Accessors
         //@{
         //! Ifd id of the IFD
         IfdId ifdId() const { return ifdId_; }
         //! Offset of the IFD from SOI
         long offset() const { return offset_; }
-        //! Find an IFD entry by tag, return a const iterator into the entries list
-        Entries::const_iterator findTag(uint16 tag) const;
-        //! Find an IFD entry by tag, return an iterator into the entries list
-        Entries::iterator findTag(uint16 tag);
-        //! Get the offset to the next IFD from the start of the Tiff header
+        //! Get the offset to the next IFD from the start of the TIFF header
         long next() const { return next_; }
-        //! Get the size of this IFD in bytes (IFD only, without data)
-        long size() const { return size_; }
         //@}
+        //! Get the size of this IFD in bytes (IFD only, without data)
+        long size() const { return 2 + 12 * entries_.size() + 4; }
+        /*!
+          @brief Return the total size of the data of this IFD in bytes,
+                 sums the size of all directory entries where size is greater
+                 than four (i.e., only data that requires memory outside the 
+                 IFD directory entries is counted).
+         */
+        long dataSize() const;
+        /*!
+          @brief Print the IFD in human readable format to the given stream;
+                 begin each line with prefix.
+         */
+        void print(std::ostream& os, const std::string& prefix ="") const;
 
     private:
         Entries entries_;                // IFD entries
 
         IfdId ifdId_;                    // IFD Id
         long offset_;                    // offset of the IFD from the start of 
-                                         // Tiff header
+                                         // TIFF header
         long next_;                      // offset of next IFD from the start of 
-                                         // the Tiff header
-        long size_;                      // size of the IFD in bytes
+                                         // the TIFF header
 
     }; // class Ifd
 
     //! %Thumbnail data Todo: implement this properly
     class Thumbnail {
     public:
-        //! Read the thumbnail from the data buffer, return 0 if successfull
-        int read(const char* buf, const ExifData& exifData, ByteOrder byteOrder);
-
+        //! %Thumbnail image types
+        enum Type { JPEG, TIFF };
+        /*!
+          @brief Read the thumbnail from the data buffer buf, using %Exif
+                 metadata exifData. Return 0 if successful. 
+
+          @param buf Data buffer containing the thumbnail data. The buffer must
+                 start with the TIFF header.  
+          @param exifData %Exif data corresponding to the data buffer.
+          @param byteOrder The byte order used for the encoding of TIFF
+                 thumbnails. It determines the byte order of the resulting
+                 thumbnail image, if it is in TIFF format. For JPEG thumbnails
+                 the byte order is not used.
+          @return 0 if successful<br>
+                 -1 if there is no thumbnail image according to the %Exif data<br>
+                  1 in case of inconsistent JPEG thumbnail %Exif data<br>
+                  2 in case of inconsistent TIFF thumbnail %Exif data<br>
+         */
+        int read(const char* buf, 
+                 const ExifData& exifData,
+                 ByteOrder byteOrder =littleEndian);
         //! Write thumbnail to file path, return 0 if successful
         int write(const std::string& path) const;
 
     private:
-        std::string thumbnail_;
+        //! Read a compressed (JPEG) thumbnail image from the data buffer
+        int readJpegImage(const char* buf, const ExifData& exifData);
+        //! Read an uncompressed (TIFF) thumbnail image from the data buffer
+        int readTiffImage(const char* buf,
+                          const ExifData& exifData,
+                          ByteOrder byteOrder);
+
+        std::string image_;
+        Type type_;
     }; // class Thumbnail
 
     /*!
@@ -728,7 +802,6 @@ namespace Exif {
 
       Todo:
       - A constructor which creates a minimal valid set of %Exif data
-      - Support to add, delete, edit, read data (maybe also in Metadata)
     */
     class ExifData {
     public:
@@ -752,16 +825,19 @@ namespace Exif {
         int read(const char* buf, long len);
         //! Write %Exif data to a data buffer, return number of bytes written
         long copy(char* buf) const;
-        //! Returns the size of all %Exif data (Tiff header plus metadata)
+        //! Returns the size of all %Exif data (TIFF header plus metadata)
         long size() const;
-        //! Returns the byte order as specified in the Tiff header
+        //! Returns the byte order as specified in the TIFF header
         ByteOrder byteOrder() const { return tiffHeader_.byteOrder(); }
         /*!
-          @brief Add all entries of an IFD to the Exif metadata. Checks for 
-                 duplicates: if a metadatum already exists, its value is 
+          @brief Add all IFD entries in the range from iterator position begin
+                 to iterator position end to the Exif metadata. Checks for
+                 duplicates: if a metadatum already exists, its value is
                  overwritten.
          */
-        void add(const Ifd& ifd, ByteOrder byteOrder);
+        void add(Ifd::const_iterator begin, 
+                 Ifd::const_iterator end,
+                 ByteOrder byteOrder);
         /*!
           @brief Add a metadatum from the supplied key and value pair.
                  This method copies (clones) the value. If a metadatum with the
@@ -769,6 +845,13 @@ namespace Exif {
                  metadatum is added.
          */
         void add(const std::string& key, Value* value);
+        /*! 
+          @brief Add a copy of the metadatum to the Exif metadata. If a
+                 metadatum with the given key already exists, its value is
+                 overwritten and no new metadatum is added.
+         */
+        void add(const Metadatum& metadatum);
+
         //! Metadata iterator type
         typedef Metadata::iterator iterator;
         //! Metadata const iterator type
@@ -790,17 +873,15 @@ namespace Exif {
         //! Delete the metadatum at iterator position pos
         void erase(iterator pos);
 
-        //! Write the thumbnail image to a file
+        /*!
+          @brief Write the thumbnail image to a file. The filename extension
+                 will be set according to the image type of the thumbnail, so
+                 the path should not include an extension.
+         */
         int writeThumbnail(const std::string& path) const 
             { return thumbnail_.write(path); }
 
     private:
-        /*!
-          @brief Add metadatum src to the Exif metadata. No duplicate check
-                 is done. (That's why the method is private.)
-         */
-        void add(const Metadatum& src);
-
         long offset_;                   // Original abs offset of the Exif data
         TiffHeader tiffHeader_;
         Metadata metadata_;
@@ -858,6 +939,20 @@ namespace Exif {
     //! Print len bytes from buf in hex and ASCII format to the given stream
     void hexdump(std::ostream& os, const char* buf, long len);
 
+    /*! 
+      @brief Compare two IFD entries by offset, taking care of special cases
+             where one or both of the entries don't have an offset.  Return true
+             if the offset of entry lhs is less than that of rhs, else false. By
+             definition, entries without an offset are greater than those with
+             an offset.
+     */
+    bool cmpOffset(const Ifd::Entry& lhs, const Ifd::Entry& rhs);        
+    /*!
+      @brief Compare two IFD entries by tag. Return true if the tag of entry
+             lhs is less than that of rhs.
+     */
+    bool cmpTag(const Ifd::Entry& lhs, const Ifd::Entry& rhs);
+
 // *****************************************************************************
 // template and inline definitions
 
diff --git a/src/exiftest.cpp b/src/exiftest.cpp
index 4359021..1af1a69 100644
--- a/src/exiftest.cpp
+++ b/src/exiftest.cpp
@@ -1,29 +1,9 @@
 // ***************************************************************** -*- C++ -*-
 /*
- * Copyright (C) 2004 Andreas Huggel <ahuggel at gmx.net>
- * 
- * This program is part of the Exiv2 distribution.
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- * 
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- * 
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA  02111-1307, USA.
- */
-/*
-  Abstract : Sample code to add, modify and delete Exif metadata
+  Abstract : This is playground code, do what you want with it.
 
   Author(s): Andreas Huggel (ahu) <ahuggel at gmx.net>
-  Version  : $Name:  $ $Revision: 1.8 $
-  History  : 26-Jan-04, ahu: created
+  Version  : $Name:  $ $Revision: 1.9 $
  */
 // *****************************************************************************
 // included header files
@@ -40,88 +20,23 @@ void exifPrint(const ExifData& exifData);
 
 // *****************************************************************************
 // Main
-int main()
+int main(int argc, char* const argv[])
 try {
-    // ExifData is the container for all metadata
     ExifData exifData;
 
-    // *************************************************************************
-    // Add metadata to the Exif data
-
-    // Create a value of the required type
-    Value* v = Value::create(asciiString);
-    // Set the value to a string
-    v->read("1999:12:31 23:59:59");
-    // Add the value together with its key to the Exif data container
-    std::string key = "Image.DateTime.DateTimeOriginal";
-    exifData.add(key, v);
-
-    std::cout << "Added key \"" << key << "\", value \"" << *v << "\"
";
-    // Delete the memory allocated by Value::create
-    delete v;
-
-    // Now create a more interesting value
-    v = Value::create(unsignedRational);
-    // Set two rational components from a string
-    v->read("1/2 1/3");
-    // Downcast the Value to its actual type
-    URationalValue* rv = dynamic_cast<URationalValue*>(v);
-    if (rv == 0) throw Error("Downcast failed");
-    // Add more elements through the extended interface of the actual type
-    rv->value_.push_back(std::make_pair(2,3));
-    rv->value_.push_back(std::make_pair(3,4));
-    // Add the key and value pair to the Exif data
-    key = "Image.ImageCharacteristics.PrimaryChromaticities";
-    exifData.add(key, rv);
-
-    std::cout << "Added key \"" << key << "\", value \"" << *v << "\"
";
-    // Delete the memory allocated by Value::create
-    delete v;
-
-    // *************************************************************************
-    // Modify Exif data
-
-    // Find a metadatum by its key
-    key = "Image.DateTime.DateTimeOriginal";
-    ExifData::iterator pos = exifData.findKey(key);
-    if (pos == exifData.end()) throw Error("Key not found");
-    // Set the new value
-    pos->setValue("2000:01:01 00:00:00"); 
-
-    // Find another key
-    key = "Image.ImageCharacteristics.PrimaryChromaticities";
-    pos = exifData.findKey(key);
-    if (pos == exifData.end()) throw Error("Key not found");
-    // Get a pointer to a copy of the value
-    v = pos->getValue();
-    // Downcast the Value to its actual type
-    rv = dynamic_cast<URationalValue*>(v);
-    if (rv == 0) throw Error("Downcast failed");
-    // Modify elements through the extended interface of the actual type
-    rv->value_[2] = std::make_pair(88,77);
-    // Set the value of the metadatum to the modified value
-    pos->setValue(rv);
-    // Delete the memory allocated by getValue
-    delete v;
-
-    exifPrint(exifData);
-
-    // *************************************************************************
-    // Delete metadata from the Exif data container
-
-    // Delete a metadatum by its key
-    key = "Image.DateTime.DateTimeOriginal";
-    exifData.erase(key);
-
-    // Delete the metadatum at iterator position pos
-    key = "Image.ImageCharacteristics.PrimaryChromaticities";
-    pos = exifData.findKey(key);
-    if (pos == exifData.end()) throw Error("Key not found");
-    exifData.erase(pos);
+    if (argc != 2) {
+        std::cout << "Usage: exiftest file
";
+        return 1;
+    }
 
+    int rc = exifData.read(argv[1]);
+    if (rc) throw Error("Reading Exif data failed");
+    
     exifPrint(exifData);
+    
+    exifData.writeThumbnail("thumb");
 
-    return 0;
+    return rc;
 }
 catch (Error& e) {
     std::cout << "Caught Exif exception '" << e << "'
";
@@ -149,7 +64,7 @@ void exifPrint(const ExifData& exifData)
                   << i->count() << "   " 
                   << std::dec << i->value() 
 
-                  << " | " << i->key() 
+//                  << " | " << i->key() 
                   << " | " << i->ifdName()
                   << " | " << i->ifdIdx()
 

-- 
exiv2 packaging



More information about the pkg-kde-commits mailing list