Blame src/exif.cpp

Packit 01d647
// ***************************************************************** -*- C++ -*-
Packit 01d647
/*
Packit 01d647
 * Copyright (C) 2004-2018 Exiv2 authors
Packit 01d647
 * This program is part of the Exiv2 distribution.
Packit 01d647
 *
Packit 01d647
 * This program is free software; you can redistribute it and/or
Packit 01d647
 * modify it under the terms of the GNU General Public License
Packit 01d647
 * as published by the Free Software Foundation; either version 2
Packit 01d647
 * of the License, or (at your option) any later version.
Packit 01d647
 *
Packit 01d647
 * This program is distributed in the hope that it will be useful,
Packit 01d647
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 01d647
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 01d647
 * GNU General Public License for more details.
Packit 01d647
 *
Packit 01d647
 * You should have received a copy of the GNU General Public License
Packit 01d647
 * along with this program; if not, write to the Free Software
Packit 01d647
 * Foundation, Inc., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA.
Packit 01d647
 */
Packit 01d647
/*
Packit 01d647
  File:      exif.cpp
Packit 01d647
  Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
Packit 01d647
  History:   26-Jan-04, ahu: created
Packit 01d647
             11-Feb-04, ahu: isolated as a component
Packit 01d647
 */
Packit 01d647
// *****************************************************************************
Packit 01d647
// included header files
Packit 01d647
#include "config.h"
Packit 01d647
Packit 01d647
#include "exif.hpp"
Packit 01d647
#include "metadatum.hpp"
Packit 01d647
#include "tags.hpp"
Packit 01d647
#include "tags_int.hpp"
Packit 01d647
#include "value.hpp"
Packit 01d647
#include "types.hpp"
Packit 01d647
#include "error.hpp"
Packit 01d647
#include "basicio.hpp"
Packit 01d647
#include "tiffimage.hpp"
Packit 01d647
#include "tiffimage_int.hpp"
Packit 01d647
#include "tiffcomposite_int.hpp" // for Tag::root
Packit 01d647
Packit 01d647
// + standard includes
Packit 01d647
#include <iostream>
Packit 01d647
#include <sstream>
Packit 01d647
#include <utility>
Packit 01d647
#include <algorithm>
Packit 01d647
#include <cstring>
Packit 01d647
#include <cassert>
Packit 01d647
#include <cstdio>
Packit 01d647
Packit 01d647
// *****************************************************************************
Packit 01d647
namespace {
Packit 01d647
Packit 01d647
    //! Unary predicate that matches a Exifdatum with a given key
Packit 01d647
    class FindExifdatumByKey {
Packit 01d647
    public:
Packit 01d647
        //! Constructor, initializes the object with the key to look for
Packit 01d647
        FindExifdatumByKey(const std::string& key) : key_(key) {}
Packit 01d647
        /*!
Packit 01d647
          @brief Returns true if the key of \em exifdatum is equal
Packit 01d647
                 to that of the object.
Packit 01d647
        */
Packit 01d647
        bool operator()(const Exiv2::Exifdatum& exifdatum) const
Packit 01d647
        {
Packit 01d647
            return key_ == exifdatum.key();
Packit 01d647
        }
Packit 01d647
Packit 01d647
    private:
Packit 01d647
        const std::string& key_;
Packit 01d647
Packit 01d647
    }; // class FindExifdatumByKey
Packit 01d647
Packit 01d647
    /*!
Packit 01d647
      @brief Exif %Thumbnail image. This abstract base class provides the
Packit 01d647
             interface for the thumbnail image that is optionally embedded in
Packit 01d647
             the Exif data. This class is used internally by ExifData, it is
Packit 01d647
             probably not useful for a client as a standalone class.  Instead,
Packit 01d647
             use an instance of ExifData to access the Exif thumbnail image.
Packit 01d647
     */
Packit 01d647
    class Thumbnail {
Packit 01d647
    public:
Packit 01d647
        //! Shortcut for a %Thumbnail auto pointer.
Packit 01d647
        typedef std::auto_ptr<Thumbnail> AutoPtr;
Packit 01d647
Packit 01d647
        //! @name Creators
Packit 01d647
        //@{
Packit 01d647
        //! Virtual destructor
Packit 01d647
        virtual ~Thumbnail() {}
Packit 01d647
        //@}
Packit 01d647
Packit 01d647
        //! Factory function to create a thumbnail for the Exif metadata provided.
Packit 01d647
        static AutoPtr create(const Exiv2::ExifData& exifData);
Packit 01d647
Packit 01d647
        //! @name Accessors
Packit 01d647
        //@{
Packit 01d647
        /*!
Packit 01d647
          @brief Return the thumbnail image in a %DataBuf. The caller owns the
Packit 01d647
                 data buffer and %DataBuf ensures that it will be deleted.
Packit 01d647
         */
Packit 01d647
        virtual Exiv2::DataBuf copy(const Exiv2::ExifData& exifData) const =0;
Packit 01d647
        /*!
Packit 01d647
          @brief Return the MIME type of the thumbnail ("image/tiff" or
Packit 01d647
                 "image/jpeg").
Packit 01d647
         */
Packit 01d647
        virtual const char* mimeType() const =0;
Packit 01d647
        /*!
Packit 01d647
          @brief Return the file extension for the format of the thumbnail
Packit 01d647
                 (".tif", ".jpg").
Packit 01d647
         */
Packit 01d647
        virtual const char* extension() const =0;
Packit 01d647
#ifdef EXV_UNICODE_PATH
Packit 01d647
        /*!
Packit 01d647
          @brief Like extension() but returns the extension in a wchar_t.
Packit 01d647
          @note This function is only available on Windows.
Packit 01d647
         */
Packit 01d647
        virtual const wchar_t* wextension() const =0;
Packit 01d647
#endif
Packit 01d647
        //@}
Packit 01d647
Packit 01d647
    }; // class Thumbnail
Packit 01d647
Packit 01d647
    //! Exif thumbnail image in TIFF format
Packit 01d647
    class TiffThumbnail : public Thumbnail {
Packit 01d647
    public:
Packit 01d647
        //! Shortcut for a %TiffThumbnail auto pointer.
Packit 01d647
        typedef std::auto_ptr<TiffThumbnail> AutoPtr;
Packit 01d647
Packit 01d647
        //! @name Manipulators
Packit 01d647
        //@{
Packit 01d647
        //! Assignment operator.
Packit 01d647
        TiffThumbnail& operator=(const TiffThumbnail& rhs);
Packit 01d647
        //@}
Packit 01d647
Packit 01d647
        //! @name Accessors
Packit 01d647
        //@{
Packit 01d647
        Exiv2::DataBuf copy(const Exiv2::ExifData& exifData) const;
Packit 01d647
        const char* mimeType() const;
Packit 01d647
        const char* extension() const;
Packit 01d647
#ifdef EXV_UNICODE_PATH
Packit 01d647
        const wchar_t* wextension() const;
Packit 01d647
#endif
Packit 01d647
        //@}
Packit 01d647
Packit 01d647
    }; // class TiffThumbnail
Packit 01d647
Packit 01d647
    //! Exif thumbnail image in JPEG format
Packit 01d647
    class JpegThumbnail : public Thumbnail {
Packit 01d647
    public:
Packit 01d647
        //! Shortcut for a %JpegThumbnail auto pointer.
Packit 01d647
        typedef std::auto_ptr<JpegThumbnail> AutoPtr;
Packit 01d647
Packit 01d647
        //! @name Manipulators
Packit 01d647
        //@{
Packit 01d647
        //! Assignment operator.
Packit 01d647
        JpegThumbnail& operator=(const JpegThumbnail& rhs);
Packit 01d647
        //@}
Packit 01d647
Packit 01d647
        //! @name Accessors
Packit 01d647
        //@{
Packit 01d647
        Exiv2::DataBuf copy(const Exiv2::ExifData& exifData) const;
Packit 01d647
        const char* mimeType() const;
Packit 01d647
        const char* extension() const;
Packit 01d647
#ifdef EXV_UNICODE_PATH
Packit 01d647
        const wchar_t* wextension() const;
Packit 01d647
#endif
Packit 01d647
        //@}
Packit 01d647
Packit 01d647
    }; // class JpegThumbnail
Packit 01d647
Packit 01d647
    //! Helper function to sum all components of the value of a metadatum
Packit 01d647
    long sumToLong(const Exiv2::Exifdatum& md);
Packit 01d647
Packit 01d647
    //! Helper function to delete all tags of a specific IFD from the metadata.
Packit 01d647
    void eraseIfd(Exiv2::ExifData& ed, Exiv2::Internal::IfdId ifdId);
Packit 01d647
Packit 01d647
}
Packit 01d647
Packit 01d647
// *****************************************************************************
Packit 01d647
// class member definitions
Packit 01d647
namespace Exiv2 {
Packit 01d647
Packit 01d647
    using namespace Internal;
Packit 01d647
Packit 01d647
    /*!
Packit 01d647
      @brief Set the value of \em exifDatum to \em value. If the object already
Packit 01d647
             has a value, it is replaced. Otherwise a new ValueType\<T\> value
Packit 01d647
             is created and set to \em value.
Packit 01d647
Packit 01d647
      This is a helper function, called from Exifdatum members. It is meant to
Packit 01d647
      be used with T = (u)int16_t, (u)int32_t or (U)Rational. Do not use directly.
Packit 01d647
    */
Packit 01d647
    template<typename T>
Packit 01d647
    Exiv2::Exifdatum& setValue(Exiv2::Exifdatum& exifDatum, const T& value)
Packit 01d647
    {
Packit 01d647
        std::auto_ptr<Exiv2::ValueType<T> > v
Packit 01d647
            = std::auto_ptr<Exiv2::ValueType<T> >(new Exiv2::ValueType<T>);
Packit 01d647
        v->value_.push_back(value);
Packit 01d647
        exifDatum.value_ = v;
Packit 01d647
        return exifDatum;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum::Exifdatum(const ExifKey& key, const Value* pValue)
Packit 01d647
        : key_(key.clone())
Packit 01d647
    {
Packit 01d647
        if (pValue) value_ = pValue->clone();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum::~Exifdatum()
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum::Exifdatum(const Exifdatum& rhs)
Packit 01d647
        : Metadatum(rhs)
Packit 01d647
    {
Packit 01d647
        if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy
Packit 01d647
        if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::ostream& Exifdatum::write(std::ostream& os, const ExifData* pMetadata) const
Packit 01d647
    {
Packit 01d647
        if (value().count() == 0) return os;
Packit Service fb147c
Packit Service fb147c
        PrintFct       fct = printValue;
Packit Service fb147c
        const TagInfo* ti  = Internal::tagInfo(tag(), static_cast<IfdId>(ifdId()));
Packit Service fb147c
        // be careful with comments (User.Photo.UserComment, GPSAreaInfo etc).
Packit Service fb147c
        if ( ti ) {
Packit Service fb147c
            fct = ti->printFct_;
Packit Service fb147c
            if ( ti->typeId_ == comment ) {
Packit Service fb147c
              os << value().toString();
Packit Service fb147c
              fct=NULL;
Packit Service fb147c
            }
Packit Service fb147c
        }
Packit Service fb147c
        if ( fct ) fct(os, value(), pMetadata);
Packit Service fb147c
        return os;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const Value& Exifdatum::value() const
Packit 01d647
    {
Packit 01d647
        if (value_.get() == 0) throw Error(kerValueNotSet);
Packit 01d647
        return *value_;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum& Exifdatum::operator=(const Exifdatum& rhs)
Packit 01d647
    {
Packit 01d647
        if (this == &rhs) return *this;
Packit 01d647
        Metadatum::operator=(rhs);
Packit 01d647
Packit 01d647
        key_.reset();
Packit 01d647
        if (rhs.key_.get() != 0) key_ = rhs.key_->clone(); // deep copy
Packit 01d647
Packit 01d647
        value_.reset();
Packit 01d647
        if (rhs.value_.get() != 0) value_ = rhs.value_->clone(); // deep copy
Packit 01d647
Packit 01d647
        return *this;
Packit 01d647
    } // Exifdatum::operator=
Packit 01d647
Packit 01d647
    Exifdatum& Exifdatum::operator=(const std::string& value)
Packit 01d647
    {
Packit 01d647
        setValue(value);
Packit 01d647
        return *this;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum& Exifdatum::operator=(const uint16_t& value)
Packit 01d647
    {
Packit 01d647
        return Exiv2::setValue(*this, value);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum& Exifdatum::operator=(const uint32_t& value)
Packit 01d647
    {
Packit 01d647
        return Exiv2::setValue(*this, value);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum& Exifdatum::operator=(const URational& value)
Packit 01d647
    {
Packit 01d647
        return Exiv2::setValue(*this, value);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum& Exifdatum::operator=(const int16_t& value)
Packit 01d647
    {
Packit 01d647
        return Exiv2::setValue(*this, value);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum& Exifdatum::operator=(const int32_t& value)
Packit 01d647
    {
Packit 01d647
        return Exiv2::setValue(*this, value);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum& Exifdatum::operator=(const Rational& value)
Packit 01d647
    {
Packit 01d647
        return Exiv2::setValue(*this, value);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum& Exifdatum::operator=(const Value& value)
Packit 01d647
    {
Packit 01d647
        setValue(&value);
Packit 01d647
        return *this;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void Exifdatum::setValue(const Value* pValue)
Packit 01d647
    {
Packit 01d647
        value_.reset();
Packit 01d647
        if (pValue) value_ = pValue->clone();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int Exifdatum::setValue(const std::string& value)
Packit 01d647
    {
Packit 01d647
        if (value_.get() == 0) {
Packit 01d647
            TypeId type = key_->defaultTypeId();
Packit 01d647
            value_ = Value::create(type);
Packit 01d647
        }
Packit 01d647
        return value_->read(value);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int Exifdatum::setDataArea(const byte* buf, long len)
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? -1 : value_->setDataArea(buf, len);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string Exifdatum::key() const
Packit 01d647
    {
Packit 01d647
        return key_.get() == 0 ? "" : key_->key();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const char* Exifdatum::familyName() const
Packit 01d647
    {
Packit 01d647
        return key_.get() == 0 ? "" : key_->familyName();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string Exifdatum::groupName() const
Packit 01d647
    {
Packit 01d647
        return key_.get() == 0 ? "" : key_->groupName();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string Exifdatum::tagName() const
Packit 01d647
    {
Packit 01d647
        return key_.get() == 0 ? "" : key_->tagName();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string Exifdatum::tagLabel() const
Packit 01d647
    {
Packit 01d647
        return key_.get() == 0 ? "" : key_->tagLabel();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    uint16_t Exifdatum::tag() const
Packit 01d647
    {
Packit 01d647
        return key_.get() == 0 ? 0xffff : key_->tag();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int Exifdatum::ifdId() const
Packit 01d647
    {
Packit 01d647
        return key_.get() == 0 ? ifdIdNotSet : key_->ifdId();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const char* Exifdatum::ifdName() const
Packit 01d647
    {
Packit 01d647
        return key_.get() == 0 ? "" : Internal::ifdName(static_cast<Internal::IfdId>(key_->ifdId()));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    int Exifdatum::idx() const
Packit 01d647
    {
Packit 01d647
        return key_.get() == 0 ? 0 : key_->idx();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long Exifdatum::copy(byte* buf, ByteOrder byteOrder) const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? 0 : value_->copy(buf, byteOrder);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    TypeId Exifdatum::typeId() const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? invalidTypeId : value_->typeId();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const char* Exifdatum::typeName() const
Packit 01d647
    {
Packit 01d647
        return TypeInfo::typeName(typeId());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long Exifdatum::typeSize() const
Packit 01d647
    {
Packit 01d647
        return TypeInfo::typeSize(typeId());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long Exifdatum::count() const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? 0 : value_->count();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long Exifdatum::size() const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? 0 : value_->size();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string Exifdatum::toString() const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? "" : value_->toString();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    std::string Exifdatum::toString(long n) const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? "" : value_->toString(n);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long Exifdatum::toLong(long n) const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? -1 : value_->toLong(n);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    float Exifdatum::toFloat(long n) const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? -1 : value_->toFloat(n);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Rational Exifdatum::toRational(long n) const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? Rational(-1, 1) : value_->toRational(n);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Value::AutoPtr Exifdatum::getValue() const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? Value::AutoPtr(0) : value_->clone();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long Exifdatum::sizeDataArea() const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? 0 : value_->sizeDataArea();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DataBuf Exifdatum::dataArea() const
Packit 01d647
    {
Packit 01d647
        return value_.get() == 0 ? DataBuf(0, 0) : value_->dataArea();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    ExifThumbC::ExifThumbC(const ExifData& exifData)
Packit 01d647
        : exifData_(exifData)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    DataBuf ExifThumbC::copy() const
Packit 01d647
    {
Packit 01d647
        Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_);
Packit 01d647
        if (thumbnail.get() == 0) return DataBuf();
Packit 01d647
        return thumbnail->copy(exifData_);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long ExifThumbC::writeFile(const std::string& path) const
Packit 01d647
    {
Packit 01d647
        Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_);
Packit 01d647
        if (thumbnail.get() == 0) return 0;
Packit 01d647
        std::string name = path + thumbnail->extension();
Packit 01d647
        DataBuf buf(thumbnail->copy(exifData_));
Packit 01d647
        if (buf.size_ == 0) return 0;
Packit 01d647
        return Exiv2::writeFile(buf, name);
Packit 01d647
    }
Packit 01d647
Packit 01d647
#ifdef EXV_UNICODE_PATH
Packit 01d647
    long ExifThumbC::writeFile(const std::wstring& wpath) const
Packit 01d647
    {
Packit 01d647
        Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_);
Packit 01d647
        if (thumbnail.get() == 0) return 0;
Packit 01d647
        std::wstring name = wpath + thumbnail->wextension();
Packit 01d647
        DataBuf buf(thumbnail->copy(exifData_));
Packit 01d647
        if (buf.size_ == 0) return 0;
Packit 01d647
        return Exiv2::writeFile(buf, name);
Packit 01d647
    }
Packit 01d647
Packit 01d647
#endif
Packit 01d647
    const char* ExifThumbC::mimeType() const
Packit 01d647
    {
Packit 01d647
        Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_);
Packit 01d647
        if (thumbnail.get() == 0) return "";
Packit 01d647
        return thumbnail->mimeType();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const char* ExifThumbC::extension() const
Packit 01d647
    {
Packit 01d647
        Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_);
Packit 01d647
        if (thumbnail.get() == 0) return "";
Packit 01d647
        return thumbnail->extension();
Packit 01d647
    }
Packit 01d647
Packit 01d647
#ifdef EXV_UNICODE_PATH
Packit 01d647
    const wchar_t* ExifThumbC::wextension() const
Packit 01d647
    {
Packit 01d647
        Thumbnail::AutoPtr thumbnail = Thumbnail::create(exifData_);
Packit 01d647
        if (thumbnail.get() == 0) return EXV_WIDEN("");
Packit 01d647
        return thumbnail->wextension();
Packit 01d647
    }
Packit 01d647
Packit 01d647
#endif
Packit 01d647
    ExifThumb::ExifThumb(ExifData& exifData)
Packit 01d647
        : ExifThumbC(exifData), exifData_(exifData)
Packit 01d647
    {
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void ExifThumb::setJpegThumbnail(
Packit 01d647
        const std::string& path,
Packit 01d647
              URational    xres,
Packit 01d647
              URational    yres,
Packit 01d647
              uint16_t     unit
Packit 01d647
    )
Packit 01d647
    {
Packit 01d647
        DataBuf thumb = readFile(path); // may throw
Packit 01d647
        setJpegThumbnail(thumb.pData_, thumb.size_, xres, yres, unit);
Packit 01d647
    }
Packit 01d647
Packit 01d647
#ifdef EXV_UNICODE_PATH
Packit 01d647
    void ExifThumb::setJpegThumbnail(
Packit 01d647
        const std::wstring& wpath,
Packit 01d647
              URational     xres,
Packit 01d647
              URational     yres,
Packit 01d647
              uint16_t      unit
Packit 01d647
    )
Packit 01d647
    {
Packit 01d647
        DataBuf thumb = readFile(wpath); // may throw
Packit 01d647
        setJpegThumbnail(thumb.pData_, thumb.size_, xres, yres, unit);
Packit 01d647
    }
Packit 01d647
Packit 01d647
#endif
Packit 01d647
    void ExifThumb::setJpegThumbnail(
Packit 01d647
        const byte*     buf,
Packit 01d647
              long      size,
Packit 01d647
              URational xres,
Packit 01d647
              URational yres,
Packit 01d647
              uint16_t  unit
Packit 01d647
    )
Packit 01d647
    {
Packit 01d647
        setJpegThumbnail(buf, size);
Packit 01d647
        exifData_["Exif.Thumbnail.XResolution"] = xres;
Packit 01d647
        exifData_["Exif.Thumbnail.YResolution"] = yres;
Packit 01d647
        exifData_["Exif.Thumbnail.ResolutionUnit"] = unit;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void ExifThumb::setJpegThumbnail(const std::string& path)
Packit 01d647
    {
Packit 01d647
        DataBuf thumb = readFile(path); // may throw
Packit 01d647
        setJpegThumbnail(thumb.pData_, thumb.size_);
Packit 01d647
    }
Packit 01d647
Packit 01d647
#ifdef EXV_UNICODE_PATH
Packit 01d647
    void ExifThumb::setJpegThumbnail(const std::wstring& wpath)
Packit 01d647
    {
Packit 01d647
        DataBuf thumb = readFile(wpath); // may throw
Packit 01d647
        setJpegThumbnail(thumb.pData_, thumb.size_);
Packit 01d647
    }
Packit 01d647
Packit 01d647
#endif
Packit 01d647
    void ExifThumb::setJpegThumbnail(const byte* buf, long size)
Packit 01d647
    {
Packit 01d647
        exifData_["Exif.Thumbnail.Compression"] = uint16_t(6);
Packit 01d647
        Exifdatum& format = exifData_["Exif.Thumbnail.JPEGInterchangeFormat"];
Packit 01d647
        format = uint32_t(0);
Packit 01d647
        format.setDataArea(buf, size);
Packit 01d647
        exifData_["Exif.Thumbnail.JPEGInterchangeFormatLength"] = uint32_t(size);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void ExifThumb::erase()
Packit 01d647
    {
Packit 01d647
        eraseIfd(exifData_, ifd1Id);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    Exifdatum& ExifData::operator[](const std::string& key)
Packit 01d647
    {
Packit 01d647
        ExifKey exifKey(key);
Packit 01d647
        iterator pos = findKey(exifKey);
Packit 01d647
        if (pos == end()) {
Packit 01d647
            add(Exifdatum(exifKey));
Packit 01d647
            pos = findKey(exifKey);
Packit 01d647
        }
Packit 01d647
        return *pos;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void ExifData::add(const ExifKey& key, const Value* pValue)
Packit 01d647
    {
Packit 01d647
        add(Exifdatum(key, pValue));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void ExifData::add(const Exifdatum& exifdatum)
Packit 01d647
    {
Packit 01d647
        // allow duplicates
Packit 01d647
        exifMetadata_.push_back(exifdatum);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    ExifData::const_iterator ExifData::findKey(const ExifKey& key) const
Packit 01d647
    {
Packit 01d647
        return std::find_if(exifMetadata_.begin(), exifMetadata_.end(),
Packit 01d647
                            FindExifdatumByKey(key.key()));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    ExifData::iterator ExifData::findKey(const ExifKey& key)
Packit 01d647
    {
Packit 01d647
        return std::find_if(exifMetadata_.begin(), exifMetadata_.end(),
Packit 01d647
                            FindExifdatumByKey(key.key()));
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void ExifData::clear()
Packit 01d647
    {
Packit 01d647
        exifMetadata_.clear();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void ExifData::sortByKey()
Packit 01d647
    {
Packit 01d647
        exifMetadata_.sort(cmpMetadataByKey);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void ExifData::sortByTag()
Packit 01d647
    {
Packit 01d647
        exifMetadata_.sort(cmpMetadataByTag);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    ExifData::iterator ExifData::erase(ExifData::iterator beg, ExifData::iterator end)
Packit 01d647
    {
Packit 01d647
        return exifMetadata_.erase(beg, end);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    ExifData::iterator ExifData::erase(ExifData::iterator pos)
Packit 01d647
    {
Packit 01d647
        return exifMetadata_.erase(pos);
Packit 01d647
    }
Packit 01d647
Packit 01d647
    ByteOrder ExifParser::decode(
Packit 01d647
              ExifData& exifData,
Packit 01d647
        const byte*     pData,
Packit 01d647
              uint32_t  size
Packit 01d647
    )
Packit 01d647
    {
Packit 01d647
        IptcData iptcData;
Packit 01d647
        XmpData  xmpData;
Packit 01d647
        ByteOrder bo = TiffParser::decode(exifData,
Packit 01d647
                                          iptcData,
Packit 01d647
                                          xmpData,
Packit 01d647
                                          pData,
Packit 01d647
                                          size);
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
        if (!iptcData.empty()) {
Packit 01d647
            EXV_WARNING << "Ignoring IPTC information encoded in the Exif data.\n";
Packit 01d647
        }
Packit 01d647
        if (!xmpData.empty()) {
Packit 01d647
            EXV_WARNING << "Ignoring XMP information encoded in the Exif data.\n";
Packit 01d647
        }
Packit 01d647
#endif
Packit 01d647
        return bo;
Packit 01d647
    } // ExifParser::decode
Packit 01d647
Packit 01d647
    //! @cond IGNORE
Packit 01d647
    enum Ptt { pttLen, pttTag, pttIfd };
Packit 01d647
    struct PreviewTags {
Packit 01d647
        Ptt ptt_;
Packit 01d647
        const char* key_;
Packit 01d647
    };
Packit 01d647
    //! @endcond
Packit 01d647
Packit 01d647
    WriteMethod ExifParser::encode(
Packit 01d647
              Blob&     blob,
Packit 01d647
        const byte*     pData,
Packit 01d647
              uint32_t  size,
Packit 01d647
              ByteOrder byteOrder,
Packit 01d647
        const ExifData& exifData
Packit 01d647
    )
Packit 01d647
    {
Packit 01d647
        ExifData ed = exifData;
Packit 01d647
Packit 01d647
        // Delete IFD0 tags that are "not recorded" in compressed images
Packit 01d647
        // Reference: Exif 2.2 specs, 4.6.8 Tag Support Levels, section A
Packit 01d647
        static const char* filteredIfd0Tags[] = {
Packit 01d647
            "Exif.Image.PhotometricInterpretation",
Packit 01d647
            "Exif.Image.StripOffsets",
Packit 01d647
            "Exif.Image.RowsPerStrip",
Packit 01d647
            "Exif.Image.StripByteCounts",
Packit 01d647
            "Exif.Image.JPEGInterchangeFormat",
Packit 01d647
            "Exif.Image.JPEGInterchangeFormatLength",
Packit Service fb147c
            "Exif.Image.SubIFDs",
Packit Service fb147c
            // Issue 981.  Never allow manufactured data to be written
Packit Service fb147c
            "Exif.Canon.AFInfoSize",
Packit Service fb147c
            "Exif.Canon.AFAreaMode",
Packit Service fb147c
            "Exif.Canon.AFNumPoints",
Packit Service fb147c
            "Exif.Canon.AFValidPoints",
Packit Service fb147c
            "Exif.Canon.AFCanonImageWidth",
Packit Service fb147c
            "Exif.Canon.AFCanonImageHeight",
Packit Service fb147c
            "Exif.Canon.AFImageWidth",
Packit Service fb147c
            "Exif.Canon.AFImageHeight",
Packit Service fb147c
            "Exif.Canon.AFAreaWidths",
Packit Service fb147c
            "Exif.Canon.AFAreaHeights",
Packit Service fb147c
            "Exif.Canon.AFXPositions",
Packit Service fb147c
            "Exif.Canon.AFYPositions",
Packit Service fb147c
            "Exif.Canon.AFPointsInFocus",
Packit Service fb147c
            "Exif.Canon.AFPointsSelected",
Packit Service fb147c
            "Exif.Canon.AFPointsUnusable",
Packit 01d647
        };
Packit 01d647
        for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfd0Tags); ++i) {
Packit 01d647
            ExifData::iterator pos = ed.findKey(ExifKey(filteredIfd0Tags[i]));
Packit 01d647
            if (pos != ed.end()) {
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
                std::cerr << "Warning: Exif tag " << pos->key() << " not encoded\n";
Packit 01d647
#endif
Packit 01d647
                ed.erase(pos);
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
Packit 01d647
        // Delete IFDs which do not occur in JPEGs
Packit 01d647
        static const IfdId filteredIfds[] = {
Packit 01d647
            subImage1Id,
Packit 01d647
            subImage2Id,
Packit 01d647
            subImage3Id,
Packit 01d647
            subImage4Id,
Packit 01d647
            subImage5Id,
Packit 01d647
            subImage6Id,
Packit 01d647
            subImage7Id,
Packit 01d647
            subImage8Id,
Packit 01d647
            subImage9Id,
Packit 01d647
            subThumb1Id,
Packit 01d647
            panaRawId,
Packit 01d647
            ifd2Id,
Packit 01d647
            ifd3Id
Packit 01d647
        };
Packit 01d647
        for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfds); ++i) {
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
            std::cerr << "Warning: Exif IFD " << filteredIfds[i] << " not encoded\n";
Packit 01d647
#endif
Packit 01d647
            eraseIfd(ed, filteredIfds[i]);
Packit 01d647
        }
Packit 01d647
Packit 01d647
        // IPTC and XMP are stored elsewhere, not in the Exif APP1 segment.
Packit 01d647
        IptcData emptyIptc;
Packit 01d647
        XmpData  emptyXmp;
Packit 01d647
Packit 01d647
        // Encode and check if the result fits into a JPEG Exif APP1 segment
Packit 01d647
        MemIo mio1;
Packit 01d647
        std::auto_ptr<TiffHeaderBase> header(new TiffHeader(byteOrder, 0x00000008, false));
Packit 01d647
        WriteMethod wm = TiffParserWorker::encode(mio1,
Packit 01d647
                                                  pData,
Packit 01d647
                                                  size,
Packit 01d647
                                                  ed,
Packit 01d647
                                                  emptyIptc,
Packit 01d647
                                                  emptyXmp,
Packit 01d647
                                                  Tag::root,
Packit 01d647
                                                  TiffMapping::findEncoder,
Packit 01d647
                                                  header.get(),
Packit 01d647
                                                  0);
Packit 01d647
        if (mio1.size() <= 65527) {
Packit 01d647
            append(blob, mio1.mmap(), (uint32_t) mio1.size());
Packit 01d647
            return wm;
Packit 01d647
        }
Packit 01d647
Packit 01d647
        // If it doesn't fit, remove additional tags
Packit 01d647
Packit 01d647
        // Delete preview tags if the preview is larger than 32kB.
Packit 01d647
        // Todo: Enhance preview classes to be able to write and delete previews and use that instead.
Packit 01d647
        // Table must be sorted by preview, the first tag in each group is the size
Packit 01d647
        static const PreviewTags filteredPvTags[] = {
Packit 01d647
            { pttLen, "Exif.Minolta.ThumbnailLength"                  },
Packit 01d647
            { pttTag, "Exif.Minolta.ThumbnailOffset"                  },
Packit 01d647
            { pttLen, "Exif.Minolta.Thumbnail"                        },
Packit 01d647
            { pttLen, "Exif.NikonPreview.JPEGInterchangeFormatLength" },
Packit 01d647
            { pttIfd, "NikonPreview"                                  },
Packit 01d647
            { pttLen, "Exif.Olympus.ThumbnailLength"                  },
Packit 01d647
            { pttTag, "Exif.Olympus.ThumbnailOffset"                  },
Packit 01d647
            { pttLen, "Exif.Olympus.ThumbnailImage"                   },
Packit 01d647
            { pttLen, "Exif.Olympus.Thumbnail"                        },
Packit 01d647
            { pttLen, "Exif.Olympus2.ThumbnailLength"                 },
Packit 01d647
            { pttTag, "Exif.Olympus2.ThumbnailOffset"                 },
Packit 01d647
            { pttLen, "Exif.Olympus2.ThumbnailImage"                  },
Packit 01d647
            { pttLen, "Exif.Olympus2.Thumbnail"                       },
Packit 01d647
            { pttLen, "Exif.OlympusCs.PreviewImageLength"             },
Packit 01d647
            { pttTag, "Exif.OlympusCs.PreviewImageStart"              },
Packit 01d647
            { pttTag, "Exif.OlympusCs.PreviewImageValid"              },
Packit 01d647
            { pttLen, "Exif.Pentax.PreviewLength"                     },
Packit 01d647
            { pttTag, "Exif.Pentax.PreviewOffset"                     },
Packit 01d647
            { pttTag, "Exif.Pentax.PreviewResolution"                 },
Packit 01d647
            { pttLen, "Exif.PentaxDng.PreviewLength"                  },
Packit 01d647
            { pttTag, "Exif.PentaxDng.PreviewOffset"                  },
Packit 01d647
            { pttTag, "Exif.PentaxDng.PreviewResolution"              },
Packit 01d647
            { pttLen, "Exif.SamsungPreview.JPEGInterchangeFormatLength" },
Packit 01d647
            { pttIfd, "SamsungPreview"                                },
Packit 01d647
            { pttLen, "Exif.Thumbnail.StripByteCounts"                },
Packit 01d647
            { pttIfd, "Thumbnail"                                     },
Packit 01d647
            { pttLen, "Exif.Thumbnail.JPEGInterchangeFormatLength"    },
Packit 01d647
            { pttIfd, "Thumbnail"                                     }
Packit 01d647
        };
Packit 01d647
        bool delTags = false;
Packit 01d647
        ExifData::iterator pos;
Packit 01d647
        for (unsigned int i = 0; i < EXV_COUNTOF(filteredPvTags); ++i) {
Packit 01d647
            switch (filteredPvTags[i].ptt_) {
Packit 01d647
            case pttLen:
Packit 01d647
                delTags = false;
Packit 01d647
                pos = ed.findKey(ExifKey(filteredPvTags[i].key_));
Packit 01d647
                if (pos != ed.end() && sumToLong(*pos) > 32768) {
Packit 01d647
                    delTags = true;
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
                    EXV_WARNING << "Exif tag " << pos->key() << " not encoded\n";
Packit 01d647
#endif
Packit 01d647
                    ed.erase(pos);
Packit 01d647
                }
Packit 01d647
                break;
Packit 01d647
            case pttTag:
Packit 01d647
                if (delTags) {
Packit 01d647
                    pos = ed.findKey(ExifKey(filteredPvTags[i].key_));
Packit 01d647
                    if (pos != ed.end()) {
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
                        EXV_WARNING << "Exif tag " << pos->key() << " not encoded\n";
Packit 01d647
#endif
Packit 01d647
                        ed.erase(pos);
Packit 01d647
                    }
Packit 01d647
                }
Packit 01d647
                break;
Packit 01d647
            case pttIfd:
Packit 01d647
                if (delTags) {
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
                    EXV_WARNING << "Exif IFD " << filteredPvTags[i].key_ << " not encoded\n";
Packit 01d647
#endif
Packit 01d647
                    eraseIfd(ed, Internal::groupId(filteredPvTags[i].key_));
Packit 01d647
                }
Packit 01d647
                break;
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
Packit 01d647
        // Delete unknown tags larger than 4kB and known tags larger than 20kB.
Packit 01d647
        for (ExifData::iterator tag_iter = ed.begin(); tag_iter != ed.end(); ) {
Packit 01d647
            if ( (tag_iter->size() > 4096 && tag_iter->tagName().substr(0, 2) == "0x") ||
Packit 01d647
                  tag_iter->size() > 20480) {
Packit 01d647
#ifndef SUPPRESS_WARNINGS
Packit 01d647
                EXV_WARNING << "Exif tag " << tag_iter->key() << " not encoded\n";
Packit 01d647
#endif
Packit 01d647
                tag_iter = ed.erase(tag_iter);
Packit 01d647
            }
Packit 01d647
            else {
Packit 01d647
                ++tag_iter;
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
Packit 01d647
        // Encode the remaining Exif tags again, don't care if it fits this time
Packit 01d647
        MemIo mio2;
Packit 01d647
        wm = TiffParserWorker::encode(mio2,
Packit 01d647
                                      pData,
Packit 01d647
                                      size,
Packit 01d647
                                      ed,
Packit 01d647
                                      emptyIptc,
Packit 01d647
                                      emptyXmp,
Packit 01d647
                                      Tag::root,
Packit 01d647
                                      TiffMapping::findEncoder,
Packit 01d647
                                      header.get(),
Packit 01d647
                                      0);
Packit 01d647
        append(blob, mio2.mmap(), (uint32_t) mio2.size());
Packit 01d647
#ifdef EXIV2_DEBUG_MESSAGES
Packit 01d647
        if (wm == wmIntrusive) {
Packit 01d647
            std::cerr << "SIZE OF EXIF DATA IS " << std::dec << mio2.size() << " BYTES\n";
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            std::cerr << "SIZE DOESN'T MATTER, NON-INTRUSIVE WRITING USED\n";
Packit 01d647
        }
Packit 01d647
#endif
Packit 01d647
        return wm;
Packit 01d647
Packit 01d647
    } // ExifParser::encode
Packit 01d647
Packit 01d647
}                                       // namespace Exiv2
Packit 01d647
Packit 01d647
// *****************************************************************************
Packit 01d647
// local definitions
Packit 01d647
namespace {
Packit 01d647
Packit 01d647
    //! @cond IGNORE
Packit 01d647
    Thumbnail::AutoPtr Thumbnail::create(const Exiv2::ExifData& exifData)
Packit 01d647
    {
Packit 01d647
        Thumbnail::AutoPtr thumbnail;
Packit 01d647
        const Exiv2::ExifKey k1("Exif.Thumbnail.Compression");
Packit 01d647
        Exiv2::ExifData::const_iterator pos = exifData.findKey(k1);
Packit 01d647
        if (pos != exifData.end()) {
Packit 01d647
            if (pos->count() == 0) return thumbnail;
Packit 01d647
            long compression = pos->toLong();
Packit 01d647
            if (compression == 6) {
Packit 01d647
                thumbnail = Thumbnail::AutoPtr(new JpegThumbnail);
Packit 01d647
            }
Packit 01d647
            else {
Packit 01d647
                thumbnail = Thumbnail::AutoPtr(new TiffThumbnail);
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        else {
Packit 01d647
            const Exiv2::ExifKey k2("Exif.Thumbnail.JPEGInterchangeFormat");
Packit 01d647
            pos = exifData.findKey(k2);
Packit 01d647
            if (pos != exifData.end()) {
Packit 01d647
                thumbnail = Thumbnail::AutoPtr(new JpegThumbnail);
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
        return thumbnail;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const char* TiffThumbnail::mimeType() const
Packit 01d647
    {
Packit 01d647
        return "image/tiff";
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const char* TiffThumbnail::extension() const
Packit 01d647
    {
Packit 01d647
        return ".tif";
Packit 01d647
    }
Packit 01d647
Packit 01d647
#ifdef EXV_UNICODE_PATH
Packit 01d647
    const wchar_t* TiffThumbnail::wextension() const
Packit 01d647
    {
Packit 01d647
        return EXV_WIDEN(".tif");
Packit 01d647
    }
Packit 01d647
Packit 01d647
#endif
Packit 01d647
    Exiv2::DataBuf TiffThumbnail::copy(const Exiv2::ExifData& exifData) const
Packit 01d647
    {
Packit 01d647
        Exiv2::ExifData thumb;
Packit 01d647
        // Copy all Thumbnail (IFD1) tags from exifData to Image (IFD0) tags in thumb
Packit 01d647
        for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != exifData.end(); ++i) {
Packit 01d647
            if (i->groupName() == "Thumbnail") {
Packit 01d647
                std::string key = "Exif.Image." + i->tagName();
Packit 01d647
                thumb.add(Exiv2::ExifKey(key), &i->value());
Packit 01d647
            }
Packit 01d647
        }
Packit 01d647
Packit 01d647
        Exiv2::MemIo io;
Packit 01d647
        Exiv2::IptcData emptyIptc;
Packit 01d647
        Exiv2::XmpData  emptyXmp;
Packit 01d647
        Exiv2::TiffParser::encode(io, 0, 0, Exiv2::littleEndian, thumb, emptyIptc, emptyXmp);
Packit 01d647
        return io.read((long) io.size());
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const char* JpegThumbnail::mimeType() const
Packit 01d647
    {
Packit 01d647
        return "image/jpeg";
Packit 01d647
    }
Packit 01d647
Packit 01d647
    const char* JpegThumbnail::extension() const
Packit 01d647
    {
Packit 01d647
        return ".jpg";
Packit 01d647
    }
Packit 01d647
Packit 01d647
#ifdef EXV_UNICODE_PATH
Packit 01d647
    const wchar_t* JpegThumbnail::wextension() const
Packit 01d647
    {
Packit 01d647
        return EXV_WIDEN(".jpg");
Packit 01d647
    }
Packit 01d647
Packit 01d647
#endif
Packit 01d647
    Exiv2::DataBuf JpegThumbnail::copy(const Exiv2::ExifData& exifData) const
Packit 01d647
    {
Packit 01d647
        Exiv2::ExifKey key("Exif.Thumbnail.JPEGInterchangeFormat");
Packit 01d647
        Exiv2::ExifData::const_iterator format = exifData.findKey(key);
Packit 01d647
        if (format == exifData.end()) return Exiv2::DataBuf();
Packit 01d647
        return format->dataArea();
Packit 01d647
    }
Packit 01d647
Packit 01d647
    long sumToLong(const Exiv2::Exifdatum& md)
Packit 01d647
    {
Packit 01d647
        long sum = 0;
Packit 01d647
        for (int i = 0; i < md.count(); ++i) {
Packit 01d647
            sum += md.toLong(i);
Packit 01d647
        }
Packit 01d647
        return sum;
Packit 01d647
    }
Packit 01d647
Packit 01d647
    void eraseIfd(Exiv2::ExifData& ed, Exiv2::IfdId ifdId)
Packit 01d647
    {
Packit 01d647
        ed.erase(std::remove_if(ed.begin(),
Packit 01d647
                                ed.end(),
Packit 01d647
                                Exiv2::FindExifdatum(ifdId)),
Packit 01d647
                 ed.end());
Packit 01d647
    }
Packit 01d647
    //! @endcond
Packit 01d647
}