[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=3917205

The following commit has been merged in the master branch:
commit 39172050a8ee03e38638596dbd9a7f74ee812a9b
Author: Andreas Huggel <ahuggel at gmx.net>
Date:   Tue Feb 3 12:24:35 2004 +0000

    Implemented ExifData::copy() and related Thumbnail stuff
---
 src/exif.cpp     | 330 +++++++++++++++++++++++++++++++++++++--------
 src/exif.hpp     | 402 ++++++++++++++++++++++++++++++++-----------------------
 src/exiftest.cpp |  17 ++-
 3 files changed, 525 insertions(+), 224 deletions(-)

diff --git a/src/exif.cpp b/src/exif.cpp
index 612b35d..5d73ffa 100644
--- a/src/exif.cpp
+++ b/src/exif.cpp
@@ -20,13 +20,13 @@
  */
 /*
   File:      exif.cpp
-  Version:   $Name:  $ $Revision: 1.13 $
+  Version:   $Name:  $ $Revision: 1.14 $
   Author(s): Andreas Huggel (ahu) <ahuggel at gmx.net>
   History:   26-Jan-04, ahu: created
  */
 // *****************************************************************************
 #include "rcsid.hpp"
-EXIV2_RCSID("@(#) $Name:  $ $Revision: 1.13 $ $RCSfile: exif.cpp,v $")
+EXIV2_RCSID("@(#) $Name:  $ $Revision: 1.14 $ $RCSfile: exif.cpp,v $")
 
 // *****************************************************************************
 // included header files
@@ -297,11 +297,11 @@ namespace Exif {
         return os << value_;
     }
 
-    Metadatum::Metadatum(uint16 tag, uint16 type, 
-                         IfdId ifdId, int ifdIdx, Value* value)
-        : tag_(tag), ifdId_(ifdId), ifdIdx_(ifdIdx), value_(0)
+    Metadatum::Metadatum(const Entry& e, ByteOrder byteOrder)
+        : tag_(e.tag()), ifdId_(e.ifdId()), ifdIdx_(e.ifdIdx()), value_(0)
     {
-        if (value) value_ = value->clone();
+        value_ = Value::create(TypeId(e.type()));
+        value_->read(e.data(), e.size(), byteOrder);
 
         key_ = std::string(ifdItem()) 
             + "." + std::string(sectionName()) 
@@ -368,21 +368,21 @@ namespace Exif {
         value_->read(buf);
     }
 
-    Ifd::RawEntry::RawEntry()
+    RawEntry::RawEntry()
         : ifdId_(ifdIdNotSet), ifdIdx_(-1),
           tag_(0), type_(0), count_(0), offset_(0), size_(0)
     {
         memset(offsetData_, 0x0, 4);
     }
 
-    Ifd::Entry::Entry(bool alloc)
+    Entry::Entry(bool alloc)
         : alloc_(alloc), status_(valid), ifdId_(ifdIdNotSet), ifdIdx_(-1),
           tag_(0), type_(0), count_(0), offset_(0), size_(0), data_(0)
     {
         memset(offsetData_, 0x0, 4);
     }
 
-    Ifd::Entry::Entry(const RawEntry& e, char* buf, bool alloc)
+    Entry::Entry(const RawEntry& e, const char* buf, bool alloc)
         : alloc_(alloc), status_(valid), ifdId_(e.ifdId_), ifdIdx_(e.ifdIdx_),
           tag_(e.tag_), type_(e.type_), count_(e.count_), offset_(e.offset_), 
           size_(e.size_), data_(0)
@@ -393,7 +393,7 @@ namespace Exif {
                 memcpy(data_, buf + offset_, size_);
             }
             else {
-                data_ = buf + offset_;
+                data_ = const_cast<char*>(buf) + offset_;
             }
         }
         else {
@@ -401,12 +401,12 @@ namespace Exif {
         }
     }
 
-    Ifd::Entry::~Entry()
+    Entry::~Entry()
     {
         if (alloc_) delete[] data_;
     }
 
-    Ifd::Entry::Entry(const Entry& rhs)
+    Entry::Entry(const Entry& rhs)
         : alloc_(rhs.alloc_), status_(rhs.status_), ifdId_(rhs.ifdId_),
           ifdIdx_(rhs.ifdIdx_), tag_(rhs.tag_), type_(rhs.type_), 
           count_(rhs.count_), offset_(rhs.offset_), size_(rhs.size_), data_(0)
@@ -423,7 +423,7 @@ namespace Exif {
         }
     }
 
-    Ifd::Entry::Entry& Ifd::Entry::operator=(const Entry& rhs)
+    Entry::Entry& Entry::operator=(const Entry& rhs)
     {
         if (this == &rhs) return *this;
         alloc_ = rhs.alloc_;
@@ -448,20 +448,30 @@ namespace Exif {
             data_ = rhs.data_;
         }
         return *this;
-    } // Ifd::Entry::operator=
+    } // Entry::operator=
 
-    const char* Ifd::Entry::data() const
+    const char* Entry::data() const
     {
         if (size_ > 4) return data_;
         return offsetData_;
     }
 
-    Ifd::Ifd(IfdId ifdId, bool alloc)
-        : alloc_(alloc), ifdId_(ifdId), offset_(0), next_(0)
+    void Entry::setOffset(uint32 offset, ByteOrder byteOrder)
     {
+        if (size_ > 4) {
+            offset_ = offset;
+        }
+        else {
+            ul2Data(offsetData_, offset, byteOrder);
+        }
     }
 
-    int Ifd::read(char* buf, ByteOrder byteOrder, long offset)
+    Ifd::Ifd(IfdId ifdId, uint32 offset, bool alloc)
+        : alloc_(alloc), ifdId_(ifdId), offset_(offset), next_(0)
+    {
+    }
+
+    int Ifd::read(const char* buf, ByteOrder byteOrder, long offset)
     {
         offset_ = offset;
         int n = getUShort(buf, byteOrder);
@@ -574,15 +584,8 @@ namespace Exif {
             o += 12;
         }
 
-        // 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);
-        }
-        else {
-            ul2Data(buf+o, 0, byteOrder);
-        }
-        o += 4;
+        // Add the offset to the next IFD to the data buffer
+        o += ul2Data(buf+o, next_, byteOrder);
 
         // Add the data of all IFD entries to the data buffer
         for (i = b; i != e; ++i) {
@@ -649,6 +652,30 @@ namespace Exif {
         }
     }
 
+    void Ifd::setOffset(uint16 tag, uint32 offset, ByteOrder byteOrder)
+    {
+        iterator pos = findTag(tag);
+        if (pos == entries_.end()) {
+            RawEntry e;
+            e.ifdId_ = ifdId_;
+            e.ifdIdx_ = 0;
+            e.tag_ = tag;
+            e.type_ = unsignedLong;
+            e.count_ = 1;
+            e.offset_ = 0;
+            e.size_ = 4;
+            entries_.push_back(Entry(e, 0, alloc_));
+            pos = findTag(tag);
+        }
+        pos->setOffset(offset, byteOrder);
+    } // Ifd::setOffset
+
+    long Ifd::size() const
+    {
+        if (entries_.size() == 0) return 0;
+        return 2 + 12 * entries_.size() + 4; 
+    }
+
     long Ifd::dataSize() const
     {
         long dataSize = 0;
@@ -748,7 +775,7 @@ namespace Exif {
         image_ = std::string(buf + offset, size);
         type_ = JPEG;
         return 0;
-    }
+    } // Thumbnail::readJpegImage
 
     int Thumbnail::readTiffImage(const char* buf,
                                  const ExifData& exifData,
@@ -795,9 +822,6 @@ namespace Exif {
         newOffsets.setValue(os.str());
         ifd1.add(newOffsets, tiffHeader.byteOrder());
 
-// ahu: Todo: remove this
-        ifd1.print(std::cout);
-
         // Finally, sort and copy the IFD
         ifd1.sortByTag();
         ifd1.copy(data + ifdOffset, tiffHeader.byteOrder(), ifdOffset);
@@ -807,7 +831,7 @@ namespace Exif {
         type_ = TIFF;
 
         return 0;
-    }
+    } // Thumbnail::readTiffImage
 
     int Thumbnail::write(const std::string& path) const
     {
@@ -825,8 +849,152 @@ namespace Exif {
         file.write(image_.data(), image_.size());
         if (!file.good()) return 2;
         return 0;
+    } // Thumbnail::write
+
+    void Thumbnail::update(ExifData& exifData) const
+    {
+        // Todo: properly synchronize the Exif data with the actual thumbnail,
+        //       i.e., synch all relevant metadata
+
+        switch (type_) {
+        case JPEG: 
+            updateJpegImage(exifData);
+            break;
+        case TIFF:
+            updateTiffImage(exifData);
+            break;
+        }
+
+    } // Thumbnail::update
+
+    void Thumbnail::updateJpegImage(ExifData& exifData) const
+    {
+        std::string key = "Thumbnail.RecordingOffset.JPEGInterchangeFormat";
+        ExifData::iterator pos = exifData.findKey(key);
+        if (pos == exifData.end()) {
+            Value *value = Value::create(unsignedLong);
+            exifData.add(key, value);
+            delete value;
+            pos = exifData.findKey(key);
+        }
+        pos->setValue("0");
+
+        key = "Thumbnail.RecordingOffset.JPEGInterchangeFormatLength";
+        pos = exifData.findKey(key);
+        if (pos == exifData.end()) {
+            Value *value = Value::create(unsignedLong);
+            exifData.add(key, value);
+            delete value;            
+            pos = exifData.findKey(key);
+        }
+        std::ostringstream os;
+        os << image_.size();
+        pos->setValue(os.str());
+
+    } // Thumbnail::updateJpegImage
+
+    void Thumbnail::updateTiffImage(ExifData& exifData) const
+    {
+        TiffHeader tiffHeader;
+        tiffHeader.read(image_.data());
+        long offset = tiffHeader.offset();
+        Ifd ifd1(ifd1);
+        ifd1.read(image_.data() + offset, tiffHeader.byteOrder(), offset);
+
+        // Create metadata from the StripOffsets and StripByteCounts entries
+        // and add these to the Exif data, replacing existing entries
+        Ifd::const_iterator pos = ifd1.findTag(0x0111);
+        if (pos == ifd1.end()) throw Error("Bad thumbnail (0x0111)");
+        exifData.add(Metadatum(*pos, tiffHeader.byteOrder()));
+
+        pos = ifd1.findTag(0x0117);
+        if (pos == ifd1.end()) throw Error("Bad thumbnail (0x0117)");
+        exifData.add(Metadatum(*pos, tiffHeader.byteOrder()));
+
+    } // Thumbnail::updateTiffImage
+
+    long Thumbnail::copy(char* buf) const
+    {
+        long ret = 0;
+        switch (type_) {
+        case JPEG: 
+            ret = copyJpegImage(buf);
+            break;
+        case TIFF:
+            ret = copyTiffImage(buf);
+            break;
+        }
+        return ret;
+    }
+
+    long Thumbnail::copyJpegImage(char* buf) const
+    {
+        memcpy(buf, image_.data(), image_.size());
+        return image_.size();
+    }
+
+    long Thumbnail::copyTiffImage(char* buf) const
+    {
+        // Read the TIFF header and IFD from the thumbnail image
+        TiffHeader tiffHeader;
+        tiffHeader.read(image_.data());
+        long offset = tiffHeader.offset();
+        Ifd thumbIfd(ifd1);
+        thumbIfd.read(image_.data() + offset, tiffHeader.byteOrder(), offset);
+
+
+        offset = thumbIfd.offset() + thumbIfd.size() + thumbIfd.dataSize();
+        long size = image_.size() - offset;
+        memcpy(buf, image_.data() + offset, size);
+        return size;
+    }
+
+    void Thumbnail::setOffsets(Ifd& ifd1, ByteOrder byteOrder) const
+    {
+        switch (type_) {
+        case JPEG: 
+            setJpegImageOffsets(ifd1, byteOrder);
+            break;
+        case TIFF:
+            setTiffImageOffsets(ifd1, byteOrder);
+            break;
+        }        
+    }
+
+    void Thumbnail::setJpegImageOffsets(Ifd& ifd1, ByteOrder byteOrder) const
+    {
+        Ifd::iterator pos = ifd1.findTag(0x0201);
+        if (pos == ifd1.end()) throw Error("Bad thumbnail (0x0201)");
+        pos->setOffset(ifd1.offset() + ifd1.size() + ifd1.dataSize(), byteOrder);
     }
 
+    void Thumbnail::setTiffImageOffsets(Ifd& ifd1, ByteOrder byteOrder) const
+    {
+        // Read the TIFF header and IFD from the thumbnail image
+        TiffHeader tiffHeader;
+        tiffHeader.read(image_.data());
+        long offset = tiffHeader.offset();
+        Ifd thumbIfd(ifd1);
+        thumbIfd.read(image_.data() + offset, tiffHeader.byteOrder(), offset);
+
+        // Adjust the StripOffsets, assuming that the existing TIFF strips
+        // start immediately after the thumbnail IFD
+        long shift = ifd1.offset() + ifd1.size() + ifd1.dataSize() 
+            - thumbIfd.offset() - thumbIfd.size() - thumbIfd.dataSize();
+        Ifd::const_iterator pos = thumbIfd.findTag(0x0111);
+        if (pos == thumbIfd.end()) throw Error("Bad thumbnail (0x0111)");
+        Metadatum offsets(*pos, tiffHeader.byteOrder());
+        std::ostringstream os;
+        for (long k = 0; k < offsets.count(); ++k) {
+            os << offsets.toLong(k) + shift << " ";
+        }
+        offsets.setValue(os.str());
+
+        // Write the offsets to IFD1, encoded in the corresponding byte order
+        ifd1.add(offsets, byteOrder);
+
+    } // Thumbnail::setTiffImageOffsets
+
     ExifData::ExifData() 
         : ifd0_(ifd0, false), exifIfd_(exifIfd, false), iopIfd_(iopIfd, false), 
           gpsIfd_(gpsIfd, false), ifd1_(ifd1, false), valid_(false), 
@@ -852,7 +1020,7 @@ namespace Exif {
         // Copy the data buffer
         delete[] data_;
         data_ = new char[len];
-        ::memcpy(data_, buf, len);
+        memcpy(data_, buf, len);
         size_ = len;
         valid_ = true;
 
@@ -908,30 +1076,82 @@ namespace Exif {
         return ret;
     } // ExifData::read
 
-    long ExifData::copy(char* buf) const
+    long ExifData::copy(char* buf)
     {
-        // Todo: decide if we can just dump the buffer that we 
-        //       should have somewhere
+        // Todo: Check if the internal IFDs, i.e., the data buffer, are valid;
+        //       if they are, update the IFDs and use the buffer
+
+        // Else do it the hard way...
 
         // Copy the TIFF header
-        // Todo: What about the offset??
-//         len += tiffHeader_.copy(buf);
+        long ifd0Offset = tiffHeader_.copy(buf);
 
-//         // 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);
+        // Build IFD0
+        Ifd ifd0(ifd0, ifd0Offset);
+        ifd0.add(begin(), end(), byteOrder());
 
-        // Copy all IFDs
+        // Build Exif IFD from metadata
+        long exifIfdOffset = ifd0Offset + ifd0.size() + ifd0.dataSize();
+        Ifd exifIfd(exifIfd, exifIfdOffset);
+        exifIfd.add(begin(), end(), byteOrder());
 
+        // Set the offset to the Exif IFD in IFD0
+        ifd0.erase(0x8769);
+        if (exifIfd.size() > 0) {
+            ifd0.setOffset(0x8769, exifIfdOffset, byteOrder());
+        }
 
-        // Copy thumbnail data
+        // Build Interoperability IFD from metadata
+        long iopIfdOffset = exifIfdOffset + exifIfd.size() + exifIfd.dataSize();
+        Ifd iopIfd(iopIfd, iopIfdOffset);
+        iopIfd.add(begin(), end(), byteOrder());
 
-        return 0;
-    }
+        // Set the offset to the Interoperability IFD in Exif IFD
+        exifIfd.erase(0xa005);
+        if (iopIfd.size() > 0) {
+            exifIfd.setOffset(0xa005, iopIfdOffset, byteOrder());
+        }
+
+        // Build GPSInfo IFD from metadata
+        long gpsIfdOffset = iopIfdOffset + iopIfd.size() + iopIfd.dataSize();
+        Ifd gpsIfd(gpsIfd, gpsIfdOffset);
+        gpsIfd.add(begin(), end(), byteOrder());
+
+        // Set the offset to the GPSInfo IFD in IFD0
+        ifd0.erase(0x8825);
+        if (gpsIfd.size() > 0) {
+            ifd0.setOffset(0x8825, gpsIfdOffset, byteOrder());
+        }
+
+        // Update Exif data from thumbnail, build IFD1 from updated metadata
+        thumbnail_.update(*this);
+        long ifd1Offset = gpsIfdOffset + gpsIfd.size() + gpsIfd.dataSize();
+        Ifd ifd1(ifd1, ifd1Offset);
+        ifd1.add(begin(), end(), byteOrder());
+        thumbnail_.setOffsets(ifd1, byteOrder());
+        long thumbOffset = ifd1Offset + ifd1.size() + ifd1.dataSize();
+
+        // Set the offset to IFD1 in IFD0
+        if (ifd1.size() > 0) {
+            ifd0.setNext(ifd1Offset);
+        }
+
+        // Copy all IFDs and the thumbnail image to the data buffer
+        ifd0.sortByTag();
+        ifd0.copy(buf + ifd0Offset, byteOrder(), ifd0Offset);
+        exifIfd.sortByTag();
+        exifIfd.copy(buf + exifIfdOffset, byteOrder(), exifIfdOffset);
+        iopIfd.sortByTag();
+        iopIfd.copy(buf + iopIfdOffset, byteOrder(), iopIfdOffset);
+        gpsIfd.sortByTag();
+        gpsIfd.copy(buf + gpsIfdOffset, byteOrder(), gpsIfdOffset);
+        ifd1.sortByTag();
+        ifd1.copy(buf + ifd1Offset, byteOrder(), ifd1Offset);
+        long len = thumbnail_.copy(buf + thumbOffset);
+
+        return len + thumbOffset;
+
+    } // ExifData::copy
 
     long ExifData::size() const
     {
@@ -945,11 +1165,7 @@ namespace Exif {
     {
         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(), i->ifdId(), i->ifdIdx(), value);
-            delete value;
-            add(md);
+            add(Metadatum(*i, byteOrder));
         }
     }
 
@@ -1148,9 +1364,9 @@ namespace Exif {
             os << (width > pos ? "" : align.substr(width)) << ss.str() << "
";
         }
         os << std::dec << std::setfill(' ');
-    }
+    } // hexdump
 
-    bool cmpOffset(const Ifd::RawEntry& lhs, const Ifd::RawEntry& rhs)
+    bool cmpOffset(const RawEntry& lhs, const RawEntry& rhs)
     {
         // We need to ignore entries with size <= 4, so by definition,
         // entries with size <= 4 are greater than those with size > 4
@@ -1164,7 +1380,7 @@ namespace Exif {
         return lhs.offset_ < rhs.offset_;
     }
 
-    bool cmpTag(const Ifd::Entry& lhs, const Ifd::Entry& rhs)
+    bool cmpTag(const Entry& lhs, const Entry& rhs)
     {
         return lhs.tag() < rhs.tag();
     }
diff --git a/src/exif.hpp b/src/exif.hpp
index 2ad3e70..5e92e90 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.13 $
+  @version $Name:  $ $Revision: 1.14 $
   @author  Andreas Huggel (ahu)
            <a href="mailto:ahuggel at gmx.net">ahuggel at gmx.net</a>
   @date    09-Jan-04, ahu: created
@@ -47,6 +47,7 @@ namespace Exif {
 // *****************************************************************************
 // class declarations
     class ExifData;
+    class Entry;
 
 // *****************************************************************************
 // class definitions
@@ -416,12 +417,9 @@ namespace Exif {
     class Metadatum {
     public:
         /*!
-          @brief Constructor for tag data read from an IFD, when all 
-                 information is available. %Metadatum copies (clones) the value 
-                 if one is provided.
+          @brief Constructor to build a metadatum from an IFD entry.
          */
-        Metadatum(uint16 tag, uint16 type, 
-                  IfdId ifdId, int ifdIdx, Value* value =0);
+        Metadatum(const Entry& e, ByteOrder byteOrder);
         /*!
           @brief Constructor for new tags created by an application, which only
                  needs to provide a key / value pair. %Metadatum copies (clones)
@@ -569,7 +567,153 @@ namespace Exif {
     private:
         std::string key_;
         
-    }; // class FindEntryByTag
+    }; // class FindMetadatumByTag
+
+    /*!
+      @brief Simple structure for 'raw' IFD directory entries (without any data
+             greater than four bytes)
+     */
+    struct RawEntry {
+        //! Default constructor
+        RawEntry();
+        //! The IFD id 
+        IfdId ifdId_;
+        //! Position in the IFD
+        int ifdIdx_;
+        //! Tag
+        uint16 tag_;
+        //! Type
+        uint16 type_;
+        //! Number of components
+        uint32 count_;
+        //! Offset, unprocessed
+        uint32 offset_;
+        //! Data from the IFD offset field if size is less or equal to four
+        char offsetData_[4];
+        //! Size of the data in bytes
+        long size_;
+    }; // struct RawEntry
+
+    //! Container type to hold 'raw' IFD directory entries
+    typedef std::vector<RawEntry> RawEntries;
+
+    /*!
+      @brief Data structure for one IFD directory entry. See the description of
+             class Ifd for an explanation of the supported modes for memory
+             allocation.
+    */
+    class Entry {
+    public:
+        /*! 
+          @brief The status of an Entry for entries without memory management.
+
+          <TABLE BORDER=0>
+          <TR><TD>valid:</TD>
+          <TD>The entry is valid, including in particular, the data 
+          pointed to is valid and up to date.</TD></TR>
+          <TR><TD>invalid:</TD>
+          <TD>The entry is not valid, it has been invalidated by a 
+          modification of the corresponding metadata, which did not 
+          fit into the original data buffer.</TD></TR>
+          <TR><TD>erased:</TD>
+          <TD>The entry has been deleted.</TD></TR>
+          </TABLE>
+        */
+        enum Status { valid, invalid, erased };
+
+        /*!
+          @brief Default constructor. The entry allocates memory for its 
+          data if alloc is true (the default), otherwise it remembers
+          just the pointers into a read and writeable data buffer which
+          it doesn't allocate or delete.
+        */ 
+        explicit Entry(bool alloc =true);
+        /*!
+          @brief Constructor to create an %Entry from a raw entry structure
+          and a data buffer. 
+
+          @param e 'Raw' entry structure filled with the relevant data. The 
+          offset_ field will only be used if size_ is greater than four.
+          @param buf Character buffer with the data of the tag. If size_ is 
+          less or equal four, the data from the original IFD offset 
+          field must be available in the field offsetData_. The buf is
+          not needed in this case and can be 0.
+          @param alloc Determines if memory management is required. If alloc
+          is true, a data buffer will be allocated to store data
+          of more than four bytes, else only the pointer will be 
+          stored. Data less or equal than four bytes is stored
+          locally in the %Entry.
+        */
+        Entry(const RawEntry& e, const char* buf, bool alloc =true);
+        //! Destructor
+        ~Entry();
+        //! Copy constructor
+        Entry(const Entry& rhs);
+        //! Assignment operator
+        Entry& operator=(const Entry& rhs);
+        //! @name Accessors
+        //@{
+        //! Return the status
+        Status status() const { return status_; }
+        //! Return the IFD id
+        IfdId ifdId() const { return ifdId_; }
+        //! Return the index in the IFD
+        int ifdIdx() const { return ifdIdx_; }
+        //! Return the tag
+        uint16 tag() const { return tag_; }
+        //! Return the type id.
+        uint16 type() const { return type_; }
+        //! Return the number of components in the value
+        uint32 count() const { return count_; }
+        //! Return the offset from the start of the IFD
+        uint32 offset() const { return offset_; }
+        //! Return the size of the value in bytes
+        long size() const { return size_; }
+        /*!
+          @brief Return a pointer to the data area. Do not attempt to write
+          to this pointer.
+        */
+        const char* data() const;
+        //@}
+
+        //! Return the size in bytes of one element of this type
+        long typeSize() const
+            { return ExifTags::typeSize(TypeId(type_)); }
+        //! Return the name of the type
+        const char* typeName() const 
+            { return ExifTags::typeName(TypeId(type_)); }
+
+        /*!
+          @brief Set the offset. If the size of the data is not greater than
+          four, the offset is written into the offset field as an
+          unsigned long using the byte order given to encode it.
+        */
+        void setOffset(uint32 offset, ByteOrder byteOrder);
+        //! Set the status 
+        void setStatus(Status status) { status_ = status; }
+
+    private:
+        /*!
+          @brief True:  requires memory allocation and deallocation,<BR>
+          False: no memory management needed.
+        */
+        bool alloc_;
+        Status status_;      // Status of this entry
+        IfdId ifdId_;        // Redundant IFD id (it is also at the IFD)
+        int ifdIdx_;         // Position in the IFD
+        uint16 tag_;         // Tag
+        uint16 type_;        // Type
+        uint32 count_;       // Number of components
+        uint32 offset_;      // Offset from the start of the IFD,
+        // 0 if size <=4, i.e., if there is no offset
+        char offsetData_[4]; // Data from the offset field if size <= 4
+        long size_;          // Size of the data in bytes
+        char* data_;         // Pointer to the data buffer
+    }; // class Entry
+
+    //! Container type to hold all IFD directory entries
+    typedef std::vector<Entry> Entries;
+
 
     /*!
       @brief Models an IFD (Image File Directory)
@@ -597,143 +741,7 @@ namespace Exif {
           @brief Constructor. Allows to set the IFD identifier and choose
                  whether or not memory management is required for the Entries.
          */
-        explicit Ifd(IfdId ifdId =ifdIdNotSet, bool alloc =true);
-
-        //! Simple structure for 'raw' IFD directory entries (without the data)
-        struct RawEntry {
-            //! Default constructor
-            RawEntry();
-            //! The IFD id 
-            IfdId ifdId_;
-            //! Position in the IFD
-            int ifdIdx_;
-            //! Tag
-            uint16 tag_;
-            //! Type
-            uint16 type_;
-            //! Number of components
-            uint32 count_;
-            //! Offset, unprocessed
-            uint32 offset_;
-            //! Data from the IFD offset field if size is less or equal to four
-            char offsetData_[4];
-            //! Size of the data in bytes
-            long size_;
-        }; // struct RawEntry
-
-        //! Container type to hold 'raw' IFD directory entries
-        typedef std::vector<RawEntry> RawEntries;
-
-        /*!
-          @brief Data structure for one IFD directory entry. See the description
-                 of class Ifd for an explanation of the supported modes for 
-                 memory allocation.
-         */
-        class Entry {
-        public:
-            /*! 
-              @brief The status of an Entry for entries without memory management.
-
-              <TABLE BORDER=0>
-              <TR><TD>valid:</TD>
-              <TD>The entry is valid, including in particular, the data 
-                  pointed to is valid and up to date.</TD></TR>
-              <TR><TD>invalid:</TD>
-              <TD>The entry is not valid, it has been invalidated by a 
-                  modification of the corresponding metadata, which did not 
-                  fit into the original data buffer.</TD></TR>
-              <TR><TD>erased:</TD>
-              <TD>The entry has been deleted.</TD></TR>
-              </TABLE>
-             */
-            enum Status { valid, invalid, erased };
-
-            /*!
-              @brief Default constructor. The entry allocates memory for its 
-                     data if alloc is true (the default), otherwise it remembers
-                     just the pointers into a read and writeable data buffer which
-                     it doesn't allocate or delete.
-             */ 
-            explicit Entry(bool alloc =true);
-            /*!
-              @brief Constructor to create an %Entry from a raw entry structure
-                     and a data buffer. 
-
-              @param e 'Raw' entry structure filled with the relevant data. The 
-                     offset_ field will only be used if size_ is greater than four.
-              @param buf Character buffer with the data of the tag. If size_ is 
-                     less or equal four, the data from the original IFD offset 
-                     field must be available in the field offsetData_. The buf is
-                     not needed in this case and can be 0.
-              @param alloc Determines if memory management is required. If alloc
-                     is true, a data buffer will be allocated to store data
-                     of more than four bytes, else only the pointer will be 
-                     stored. Data less or equal than four bytes is stored
-                     locally in the %Entry.
-             */
-            Entry(const RawEntry& e, char* buf, bool alloc =true);
-            //! Destructor
-            ~Entry();
-            //! Copy constructor
-            Entry(const Entry& rhs);
-            //! Assignment operator
-            Entry& operator=(const Entry& rhs);
-
-            //! @name Accessors
-            //@{
-            //! Return the status
-            Status status() const { return status_; }
-            //! Return the IFD id
-            IfdId ifdId() const { return ifdId_; }
-            //! Return the index in the IFD
-            int ifdIdx() const { return ifdIdx_; }
-            //! Return the tag
-            uint16 tag() const { return tag_; }
-            //! Return the type id.
-            uint16 type() const { return type_; }
-            //! Return the number of components in the value
-            uint32 count() const { return count_; }
-            //! Return the offset from the start of the IFD
-            uint32 offset() const { return offset_; }
-            //! Return the size of the value in bytes
-            long size() const { return size_; }
-            /*!
-              @brief Return a pointer to the data area. Do not attempt to write
-                     to this pointer.
-             */
-            const char* data() const;
-            //@}
-
-            //! Set the status 
-            void setStatus(Status status) { status_ = status; }
-            //! Return the size in bytes of one element of this type
-            long typeSize() const
-                { return ExifTags::typeSize(TypeId(type_)); }
-            //! Return the name of the type
-            const char* typeName() const 
-                { return ExifTags::typeName(TypeId(type_)); }
-
-        private:
-            /*!
-              @brief True:  requires memory allocation and deallocation,<BR>
-                     False: no memory management needed.
-             */
-            bool alloc_;
-            Status status_;      // Status of this entry
-            IfdId ifdId_;        // Redundant IFD id (it is also at the IFD)
-            int ifdIdx_;         // Position in the IFD
-            uint16 tag_;         // Tag
-            uint16 type_;        // Type
-            uint32 count_;       // Number of components
-            uint32 offset_;      // Offset from the start of the IFD,
-                                 // 0 if size <=4, i.e., if there is no offset
-            char offsetData_[4]; // Data from the offset field if size <= 4
-            long size_;          // Size of the data in bytes
-            char* data_;         // Pointer to the data buffer
-        }; // class Entry
-
-        //! Container type to hold all IFD directory entries
-        typedef std::vector<Entry> Entries;
+        explicit Ifd(IfdId ifdId =ifdIdNotSet, uint32 offset =0, bool alloc =true);
 
         //! Entries const iterator type
         typedef Entries::const_iterator const_iterator;
@@ -758,6 +766,17 @@ namespace Exif {
         //! Delete the directory entry at iterator position pos
         void erase(iterator pos);
         /*!
+          @brief Set the offset of the entry identified by tag. If no entry with
+                 this tag exists, an entry of type unsigned long with one
+                 component is created. If the size of the data is greater than
+                 four, the offset of the entry is set to the value provided in
+                 offset, else it is written to the offset field of the entry as
+                 an unsigned long, encoded according to the byte order.
+         */
+        void setOffset(uint16 tag, uint32 offset, ByteOrder byteOrder);
+        //! Set the offset of the next IFD
+        void setNext(uint32 next) { next_ = next; }
+        /*!
           @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
@@ -784,7 +803,7 @@ namespace Exif {
               @brief Returns true if the tag of the argument entry is equal
               to that of the object.
             */
-            bool operator()(const Ifd::Entry& entry) const
+            bool operator()(const Entry& entry) const
                 { return tag_ == entry.tag(); }
         private:
             uint16 tag_;
@@ -795,7 +814,7 @@ 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 (unlike the readSubIfd() method).
+                 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
                  header, if known. If not given, the offset will be guessed
@@ -805,7 +824,7 @@ namespace Exif {
 
           @return 0 if successful
          */
-        int read(char* buf, ByteOrder byteOrder, long offset =0);
+        int read(const char* buf, ByteOrder byteOrder, long offset =0);
         /*!
           @brief Read a sub-IFD from the location pointed to by the directory entry 
                  with the given tag.
@@ -822,18 +841,28 @@ namespace Exif {
             Ifd& dest, char* buf, ByteOrder byteOrder, uint16 tag
         ) const;
         /*!
-          @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.
+          @brief Copy the IFD to a data array, return the number of bytes
+                 written. 
+
+                 First the number of IFD entries is written (2 bytes), followed
+                 by all directory entries: tag (2), type (2), number of data
+                 components (4) and offset to the data or the data, if it
+                 occupies not more than four bytes (4). The directory entries
+                 are followed by the offset of the next IFD (4). All these
+                 fields are encoded according to the byte order argument. Data
+                 that doesn't fit into the offset fields follows immediately
+                 after the IFD entries. The offsets in the IFD are set to
+                 correctly point to the data fields, using the offset parameter
+                 or the offset of the IFD.
+
+          @param buf Pointer to the data buffer. The user must ensure that the
+                 buffer has enough memory. Otherwise the call results in
+                 undefined behaviour.
           @param byteOrder Applicable byte order (little or big endian).
           @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, i.e., the offset 
-                        of the IFD will be used.
+                 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, 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;
@@ -847,7 +876,7 @@ namespace Exif {
         long next() const { return next_; }
         //@}
         //! Get the size of this IFD in bytes (IFD only, without data)
-        long size() const { return 2 + 12 * entries_.size() + 4; }
+        long size() const;
         /*!
           @brief Return the total size of the data of this IFD in bytes,
                  sums the size of all directory entries where size is greater
@@ -897,14 +926,55 @@ namespace Exif {
                  ByteOrder byteOrder =littleEndian);
         //! Write thumbnail to file path, return 0 if successful
         int write(const std::string& path) const;
+        /*!
+          @brief Copy the thumbnail image data (without the IFD, if any) to the
+                 data buffer buf. The user must ensure that the buffer has
+                 enough memory. Otherwise the call results in undefined
+                 behaviour. Return the number of characters written.
+         */
+        long copy(char* buf) const;
+        /*!
+          @brief Update the %Exif data according to the actual thumbnail image.
+          
+          If the type of the thumbnail image is JPEG, JPEGInterchangeFormat is
+          set to 0. If the type is TIFF, StripOffsets are set to the offsets of
+          the IFD of the thumbnail image itself.
+         */
+        void update(ExifData& exifData) const;
+        /*!
+          @brief Update the thumbnail data offsets in IFD1 assuming the
+                 thumbnail data follows immediately after IFD1.  
+
+          If the type of the thumbnail image is JPEG, JPEGInterchangeFormat is
+          set to point directly behind the data area of IFD1. If the type is
+          TIFF, StripOffsets from the thumbnail image are adjusted to point to
+          the strips, which have to follow immediately after IFD1. Use copy() to
+          write the thumbnail image data. The offset of IFD1 must be set
+          correctly. Changing the size of IFD1 invalidates the thumbnail data
+          offsets set by this method.
+         */
+        void setOffsets(Ifd& ifd1, ByteOrder byteOrder) const;
 
     private:
+
         //! 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);
+        //! Update the Exif data according to the actual JPEG thumbnail image
+        void updateJpegImage(ExifData& exifData) const;
+        //! Update the Exif data according to the actual TIFF thumbnail image
+        void updateTiffImage(ExifData& exifData) const;
+        //! Copy the JPEG thumbnail image data to the data buffer buf
+        long copyJpegImage(char* buf) const;
+        //! Copy the TIFF thumbnail image data to the data buffer buf
+        long copyTiffImage(char* buf) const;
+        //! Update the offsets to the JPEG thumbnail image in the IFD
+        void setJpegImageOffsets(Ifd& ifd1, ByteOrder byteOrder) const;
+        //! Update the offsets to the TIFF thumbnail image in the IFD
+        void setTiffImageOffsets(Ifd& ifd1, ByteOrder byteOrder) const;
 
         std::string image_;
         Type type_;
@@ -948,15 +1018,19 @@ namespace Exif {
           @return 0 if successful
          */
         int read(const char* buf, long len);
-        //! Write %Exif data to a data buffer, return number of bytes written
-        long copy(char* buf) const;
+        /*!
+          @brief Write %Exif data to a data buffer, return number of bytes 
+                 written. Updates %Exif data with the metadata from the actual
+                 thumbnail image (overriding existing metadata).
+         */ 
+        long copy(char* buf);
         //! Returns the size of all %Exif data (TIFF header plus metadata)
         long size() const;
         //! Returns the byte order as specified in the TIFF header
         ByteOrder byteOrder() const { return tiffHeader_.byteOrder(); }
         /*!
           @brief Add all IFD entries in the range from iterator position begin
-                 to iterator position end to the Exif metadata. Checks for
+                 to iterator position end to the %Exif metadata. Checks for
                  duplicates: if a metadatum already exists, its value is
                  overwritten.
          */
@@ -971,7 +1045,7 @@ namespace Exif {
          */
         void add(const std::string& key, Value* value);
         /*! 
-          @brief Add a copy of the metadatum to the Exif metadata. If a
+          @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.
          */
@@ -1080,12 +1154,12 @@ namespace Exif {
              else false. By definition, entries without an offset are greater
              than those with an offset.
      */
-    bool cmpOffset(const Ifd::RawEntry& lhs, const Ifd::RawEntry& rhs);        
+    bool cmpOffset(const RawEntry& lhs, const RawEntry& 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);
+    bool cmpTag(const Entry& lhs, const Entry& rhs);
 
 // *****************************************************************************
 // template and inline definitions
diff --git a/src/exiftest.cpp b/src/exiftest.cpp
index 35100ff..d5eb1ff 100644
--- a/src/exiftest.cpp
+++ b/src/exiftest.cpp
@@ -3,11 +3,11 @@
   Abstract : This is playground code, do what you want with it.
 
   Author(s): Andreas Huggel (ahu) <ahuggel at gmx.net>
-  Version  : $Name:  $ $Revision: 1.11 $
+  Version  : $Name:  $ $Revision: 1.12 $
  */
 // *****************************************************************************
 #include "rcsid.hpp"
-EXIV2_RCSID("@(#) $Name:  $ $Revision: 1.11 $ $RCSfile: exiftest.cpp,v $")
+EXIV2_RCSID("@(#) $Name:  $ $Revision: 1.12 $ $RCSfile: exiftest.cpp,v $")
 
 // *****************************************************************************
 // included header files
@@ -64,9 +64,20 @@ try {
     }
 
     exifPrint(exifData);
-    
     exifData.writeThumbnail("thumb");
 
+    char* buf = new char[1024*128];
+    long siz = exifData.copy(buf);
+
+    std::cout << siz << " Bytes written.
" 
+              << "=======================
";
+
+    ExifData e2;
+    e2.read(buf, siz);
+    
+    exifPrint(e2);
+    e2.writeThumbnail("t2");
+
     return rc;
 }
 catch (Error& e) {

-- 
exiv2 packaging



More information about the pkg-kde-commits mailing list