diff --git a/src/Makefile b/src/Makefile index fa6d928d..2caa7f5c 100644 --- a/src/Makefile +++ b/src/Makefile @@ -68,6 +68,7 @@ CCHDR = exv_conf.h \ # Add library C++ source files to this list CCSRC = basicio.cpp \ + bmpimage.cpp \ canonmn.cpp \ convert.cpp \ cr2image.cpp \ @@ -77,9 +78,11 @@ CCSRC = basicio.cpp \ exif.cpp \ futils.cpp \ fujimn.cpp \ + gifimage.cpp \ ifd.cpp \ image.cpp \ iptc.cpp \ + jp2image.cpp \ jpgimage.cpp \ makernote.cpp \ makernote2.cpp \ @@ -94,11 +97,13 @@ ifdef HAVE_LIBZ CCSRC += pngimage.cpp \ pngchunk.cpp endif -CCSRC += rafimage.cpp \ +CCSRC += psdimage.cpp \ + rafimage.cpp \ sigmamn.cpp \ pentaxmn.cpp \ sonymn.cpp \ tags.cpp \ + tgaimage.cpp \ tiffcomposite.cpp \ tiffimage.cpp \ tiffparser.cpp \ diff --git a/src/actions.cpp b/src/actions.cpp index 46ef427e..f9b9407c 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -241,11 +241,6 @@ namespace Action { assert(image.get() != 0); image->readMetadata(); Exiv2::ExifData& exifData = image->exifData(); - if (exifData.empty()) { - std::cerr << path_ << ": " - << _("No Exif data found in the file\n"); - return -3; - } align_ = 16; // Filename @@ -259,6 +254,20 @@ namespace Action { std::cout << buf.st_size << " " << _("Bytes") << std::endl; } + // MIME type + printLabel(_("MIME type")); + std::cout << image->mimeType() << "\n"; + + // Image size + printLabel(_("Image size")); + std::cout << image->pixelWidth() << " x " << image->pixelHeight() << "\n"; + + if (exifData.empty()) { + std::cerr << path_ << ": " + << _("No Exif data found in the file\n"); + return -3; + } + // Camera make printTag(exifData, "Exif.Image.Make", _("Camera make")); diff --git a/src/bmpimage.cpp b/src/bmpimage.cpp new file mode 100644 index 00000000..db9bf965 --- /dev/null +++ b/src/bmpimage.cpp @@ -0,0 +1,160 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 Andreas Huggel + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/* + File: bmpimage.cpp + Version: $Rev$ + Author(s): Marco Piovanelli, Ovolabs (marco) + History: 05-Mar-2007, marco: created + */ +// ***************************************************************************** +#include "rcsid.hpp" +EXIV2_RCSID("@(#) $Id$") + +//#define DEBUG 1 + +// ***************************************************************************** +// included header files +#ifdef _MSC_VER +# include "exv_msvc.h" +#else +# include "exv_conf.h" +#endif +#include "bmpimage.hpp" +#include "image.hpp" +#include "basicio.hpp" +#include "error.hpp" +#include "futils.hpp" + +// + standard includes +#include +#include +#include + +// ***************************************************************************** +// class member definitions +namespace Exiv2 { + + BmpImage::BmpImage(BasicIo::AutoPtr io) + : Image(ImageType::bmp, mdNone, io) + { + } // BmpImage::BmpImage + + void BmpImage::setExifData(const ExifData& /*exifData*/) + { + // Todo: implement me! + throw(Error(32, "Exif metadata", "BMP")); + } + + void BmpImage::setIptcData(const IptcData& /*iptcData*/) + { + // Todo: implement me! + throw(Error(32, "IPTC metadata", "BMP")); + } + + void BmpImage::setComment(const std::string& /*comment*/) + { + // not supported + throw(Error(32, "Image comment", "BMP")); + } + + void BmpImage::readMetadata() + { +#ifdef DEBUG + std::cerr << "Exiv2::BmpImage::readMetadata: Reading Windows bitmap file " << io_->path() << "\n"; +#endif + if (io_->open() != 0) + { + throw Error(9, io_->path(), strError()); + } + IoCloser closer(*io_); + // Ensure that this is the correct image type + if (!isBmpType(*io_, false)) + { + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "BMP"); + } + clearMetadata(); + + /* + The Windows bitmap header goes as follows -- all numbers are in little-endian byte order: + + offset length name description + ====== ======= ===================== ======= + 0 2 bytes signature always 'BM' + 2 4 bytes bitmap size + 6 4 bytes reserved + 10 4 bytes bitmap offset + 14 4 bytes header size + 18 4 bytes bitmap width + 22 4 bytes bitmap height + 26 2 bytes plane count + 28 2 bytes depth + 30 4 bytes compression 0 = none; 1 = RLE, 8 bits/pixel; 2 = RLE, 4 bits/pixel; 3 = bitfield; 4 = JPEG; 5 = PNG + 34 4 bytes image size size of the raw bitmap data, in bytes + 38 4 bytes horizontal resolution (in pixels per meter) + 42 4 bytes vertical resolution (in pixels per meter) + 46 4 bytes color count + 50 4 bytes important colors number of "important" colors + */ + byte buf[54]; + if (io_->read(buf, sizeof(buf)) == sizeof(buf)) + { + pixelWidth_ = getLong(buf + 18, littleEndian); + pixelHeight_ = getLong(buf + 22, littleEndian); + } + } // BmpImage::readMetadata + + void BmpImage::writeMetadata() + { + // Todo: implement me! + throw(Error(31, "BMP")); + } // BmpImage::writeMetadata + + // ************************************************************************* + // free functions + Image::AutoPtr newBmpInstance(BasicIo::AutoPtr io, bool /*create*/) + { + Image::AutoPtr image(new BmpImage(io)); + if (!image->good()) + { + image.reset(); + } + return image; + } + + bool isBmpType(BasicIo& iIo, bool advance) + { + const int32_t len = 2; + const unsigned char BmpImageId[2] = { 'B', 'M' }; + byte buf[len]; + iIo.read(buf, len); + if (iIo.error() || iIo.eof()) + { + return false; + } + bool matched = (memcmp(buf, BmpImageId, len) == 0); + if (!advance || !matched) + { + iIo.seek(-len, BasicIo::cur); + } + return matched; + } +} // namespace Exiv2 diff --git a/src/bmpimage.hpp b/src/bmpimage.hpp new file mode 100644 index 00000000..1af39d84 --- /dev/null +++ b/src/bmpimage.hpp @@ -0,0 +1,133 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 Andreas Huggel + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/*! + @file bmpimage.hpp + @brief Windows Bitmap (BMP) image + @version $Rev$ + @author Marco Piovanelli, Ovolabs (marco) + marco.piovanelli@pobox.com + @date 05-Mar-2007, marco: created + */ +#ifndef BMPIMAGE_HPP_ +#define BMPIMAGE_HPP_ + +// ***************************************************************************** +// included header files +#include "exif.hpp" +#include "iptc.hpp" +#include "image.hpp" + +// + standard includes +#include + +// ***************************************************************************** +// namespace extensions +namespace Exiv2 { + +// ***************************************************************************** +// class definitions + + // Add Windows Bitmap (BMP) to the supported image formats + namespace ImageType { + const int bmp = 14; //!< Windows bitmap (bmp) image type (see class BmpImage) + } + + /*! + @brief Class to access Windows bitmaps. This is just a stub - we only + read width and height. + */ + class BmpImage : public Image { + //! @name NOT Implemented + //@{ + //! Copy constructor + BmpImage(const BmpImage& rhs); + //! Assignment operator + BmpImage& operator=(const BmpImage& rhs); + //@} + + public: + //! @name Creators + //@{ + /*! + @brief Constructor to open a Windows bitmap image. Since the + constructor can not return a result, callers should check the + good() method after object construction to determine success + or failure. + @param io An auto-pointer that owns a BasicIo instance used for + reading and writing image metadata. \b Important: The constructor + takes ownership of the passed in BasicIo instance through the + auto-pointer. Callers should not continue to use the BasicIo + instance after it is passed to this method. Use the Image::io() + method to get a temporary reference. + */ + BmpImage(BasicIo::AutoPtr io); + //@} + + //! @name Manipulators + //@{ + void readMetadata(); + /*! + @brief Todo: Write metadata back to the image. This method is not + yet(?) implemented. Calling it will throw an Error(31). + */ + void writeMetadata(); + /*! + @brief Todo: Not supported yet(?). Calling this function will throw + an instance of Error(32). + */ + void setExifData(const ExifData& exifData); + /*! + @brief Todo: Not supported yet(?). Calling this function will throw + an instance of Error(32). + */ + void setIptcData(const IptcData& iptcData); + /*! + @brief Not supported. Calling this function will throw an instance + of Error(32). + */ + void setComment(const std::string& comment); + //@} + + //! @name Accessors + //@{ + std::string mimeType() const { return "image/x-ms-bmp"; } + //@} + + }; // class BmpImage + +// ***************************************************************************** +// template, inline and free functions + + // These could be static private functions on Image subclasses but then + // ImageFactory needs to be made a friend. + /*! + @brief Create a new BmpImage instance and return an auto-pointer to it. + Caller owns the returned object and the auto-pointer ensures that + it will be deleted. + */ + Image::AutoPtr newBmpInstance(BasicIo::AutoPtr io, bool create); + + //! Check if the file iIo is a Windows Bitmap image. + bool isBmpType(BasicIo& iIo, bool advance); + +} // namespace Exiv2 + +#endif // #ifndef BMPIMAGE_HPP_ diff --git a/src/cr2image.cpp b/src/cr2image.cpp index 2189fcdd..40e34b3e 100644 --- a/src/cr2image.cpp +++ b/src/cr2image.cpp @@ -93,6 +93,18 @@ namespace Exiv2 { { } // Cr2Image::Cr2Image + int Cr2Image::pixelWidth() const + { + Exiv2::ExifData::const_iterator widthIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); + return (widthIter == exifData_.end()) ? 0 : widthIter->toLong(); + } + + int Cr2Image::pixelHeight() const + { + Exiv2::ExifData::const_iterator heightIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); + return (heightIter == exifData_.end()) ? 0 : heightIter->toLong(); + } + void Cr2Image::setExifData(const ExifData& /*exifData*/) { // Todo: implement me! diff --git a/src/cr2image.hpp b/src/cr2image.hpp index 9492d270..e22d88d8 100644 --- a/src/cr2image.hpp +++ b/src/cr2image.hpp @@ -106,6 +106,8 @@ namespace Exiv2 { //! @name Accessors //@{ std::string mimeType() const { return "image/x-canon-cr2"; } + int pixelWidth() const; + int pixelHeight() const; //@} private: diff --git a/src/crwimage.cpp b/src/crwimage.cpp index 8808756b..6016d300 100644 --- a/src/crwimage.cpp +++ b/src/crwimage.cpp @@ -170,6 +170,18 @@ namespace Exiv2 { { } // CrwImage::CrwImage + int CrwImage::pixelWidth() const + { + Exiv2::ExifData::const_iterator widthIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); + return (widthIter == exifData_.end()) ? 0 : widthIter->toLong(); + } + + int CrwImage::pixelHeight() const + { + Exiv2::ExifData::const_iterator heightIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); + return (heightIter == exifData_.end()) ? 0 : heightIter->toLong(); + } + void CrwImage::setIptcData(const IptcData& /*iptcData*/) { // not supported diff --git a/src/crwimage.hpp b/src/crwimage.hpp index 3e690f8b..356a3f35 100644 --- a/src/crwimage.hpp +++ b/src/crwimage.hpp @@ -121,6 +121,8 @@ namespace Exiv2 { //! @name Accessors //@{ std::string mimeType() const { return "image/x-canon-crw"; } + int pixelWidth() const; + int pixelHeight() const; //@} private: diff --git a/src/exiv2.cpp b/src/exiv2.cpp index 1ea76e5e..3884037f 100644 --- a/src/exiv2.cpp +++ b/src/exiv2.cpp @@ -147,7 +147,7 @@ int main(int argc, char* const argv[]) for (Params::Files::const_iterator i = params.files_.begin(); i != params.files_.end(); ++i) { if (params.verbose_) { - std::cout << _("File") << " " << std::setw(w) << n++ << "/" << s << ": " + std::cout << _("File") << " " << std::setw(w) << std::right << n++ << "/" << s << ": " << *i << std::endl; } int ret = task->run(*i); diff --git a/src/gifimage.cpp b/src/gifimage.cpp new file mode 100644 index 00000000..9f97742a --- /dev/null +++ b/src/gifimage.cpp @@ -0,0 +1,141 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 Andreas Huggel + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/* + File: gifimage.cpp + Version: $Rev$ + Author(s): Marco Piovanelli, Ovolabs (marco) + History: 26-Feb-2007, marco: created + */ +// ***************************************************************************** +#include "rcsid.hpp" +EXIV2_RCSID("@(#) $Id$") + +//#define DEBUG 1 + +// ***************************************************************************** +// included header files +#ifdef _MSC_VER +# include "exv_msvc.h" +#else +# include "exv_conf.h" +#endif +#include "gifimage.hpp" +#include "image.hpp" +#include "basicio.hpp" +#include "error.hpp" +#include "futils.hpp" + +// + standard includes +#include +#include +#include + +// ***************************************************************************** +// class member definitions +namespace Exiv2 { + + GifImage::GifImage(BasicIo::AutoPtr io) + : Image(ImageType::gif, mdNone, io) + { + } // GifImage::GifImage + + void GifImage::setExifData(const ExifData& /*exifData*/) + { + // Todo: implement me! + throw(Error(32, "Exif metadata", "GIF")); + } + + void GifImage::setIptcData(const IptcData& /*iptcData*/) + { + // Todo: implement me! + throw(Error(32, "IPTC metadata", "GIF")); + } + + void GifImage::setComment(const std::string& /*comment*/) + { + // not supported + throw(Error(32, "Image comment", "GIF")); + } + + void GifImage::readMetadata() + { +#ifdef DEBUG + std::cerr << "Exiv2::GifImage::readMetadata: Reading GIF file " << io_->path() << "\n"; +#endif + if (io_->open() != 0) + { + throw Error(9, io_->path(), strError()); + } + IoCloser closer(*io_); + // Ensure that this is the correct image type + if (!isGifType(*io_, true)) + { + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "GIF"); + } + clearMetadata(); + + byte buf[4]; + if (io_->read(buf, sizeof(buf)) == sizeof(buf)) + { + pixelWidth_ = getShort(buf, littleEndian); + pixelHeight_ = getShort(buf + 2, littleEndian); + } + } // GifImage::readMetadata + + void GifImage::writeMetadata() + { + // Todo: implement me! + throw(Error(31, "GIF")); + } // GifImage::writeMetadata + + // ************************************************************************* + // free functions + Image::AutoPtr newGifInstance(BasicIo::AutoPtr io, bool /*create*/) + { + Image::AutoPtr image(new GifImage(io)); + if (!image->good()) + { + image.reset(); + } + return image; + } + + bool isGifType(BasicIo& iIo, bool advance) + { + const int32_t len = 6; + const unsigned char Gif87aId[8] = { 'G', 'I', 'F', '8', '7', 'a' }; + const unsigned char Gif89aId[8] = { 'G', 'I', 'F', '8', '9', 'a' }; + byte buf[len]; + iIo.read(buf, len); + if (iIo.error() || iIo.eof()) + { + return false; + } + bool matched = (memcmp(buf, Gif87aId, len) == 0) + || (memcmp(buf, Gif89aId, len) == 0); + if (!advance || !matched) + { + iIo.seek(-len, BasicIo::cur); + } + return matched; + } +} // namespace Exiv2 diff --git a/src/gifimage.hpp b/src/gifimage.hpp new file mode 100644 index 00000000..a3ed3fd4 --- /dev/null +++ b/src/gifimage.hpp @@ -0,0 +1,134 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 Andreas Huggel + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/*! + @file gifimage.hpp + @brief GIF image, implemented using the following references: + GIF89 specification by W3C
+ @version $Rev$ + @author Marco Piovanelli, Ovolabs (marco) + marco.piovanelli@pobox.com + @date 26-Feb-2007, marco: created + */ +#ifndef GIFIMAGE_HPP_ +#define GIFIMAGE_HPP_ + +// ***************************************************************************** +// included header files +#include "exif.hpp" +#include "iptc.hpp" +#include "image.hpp" + +// + standard includes +#include + +// ***************************************************************************** +// namespace extensions +namespace Exiv2 { + +// ***************************************************************************** +// class definitions + + // Add GIF to the supported image formats + namespace ImageType { + const int gif = 11; //!< GIF image type (see class GifImage) + } + + /*! + @brief Class to access raw GIF images. Exif/IPTC metadata are supported + directly. + */ + class GifImage : public Image { + //! @name NOT Implemented + //@{ + //! Copy constructor + GifImage(const GifImage& rhs); + //! Assignment operator + GifImage& operator=(const GifImage& rhs); + //@} + + public: + //! @name Creators + //@{ + /*! + @brief Constructor to open a GIF image. Since the + constructor can not return a result, callers should check the + good() method after object construction to determine success + or failure. + @param io An auto-pointer that owns a BasicIo instance used for + reading and writing image metadata. \b Important: The constructor + takes ownership of the passed in BasicIo instance through the + auto-pointer. Callers should not continue to use the BasicIo + instance after it is passed to this method. Use the Image::io() + method to get a temporary reference. + */ + GifImage(BasicIo::AutoPtr io); + //@} + + //! @name Manipulators + //@{ + void readMetadata(); + /*! + @brief Todo: Write metadata back to the image. This method is not + yet(?) implemented. Calling it will throw an Error(31). + */ + void writeMetadata(); + /*! + @brief Todo: Not supported yet(?). Calling this function will throw + an instance of Error(32). + */ + void setExifData(const ExifData& exifData); + /*! + @brief Todo: Not supported yet(?). Calling this function will throw + an instance of Error(32). + */ + void setIptcData(const IptcData& iptcData); + /*! + @brief Not supported. Calling this function will throw an instance + of Error(32). + */ + void setComment(const std::string& comment); + //@} + + //! @name Accessors + //@{ + std::string mimeType() const { return "image/gif"; } + //@} + + }; // class GifImage + +// ***************************************************************************** +// template, inline and free functions + + // These could be static private functions on Image subclasses but then + // ImageFactory needs to be made a friend. + /*! + @brief Create a new GifImage instance and return an auto-pointer to it. + Caller owns the returned object and the auto-pointer ensures that + it will be deleted. + */ + Image::AutoPtr newGifInstance(BasicIo::AutoPtr io, bool create); + + //! Check if the file iIo is a GIF image. + bool isGifType(BasicIo& iIo, bool advance); + +} // namespace Exiv2 + +#endif // #ifndef GIFIMAGE_HPP_ diff --git a/src/image.cpp b/src/image.cpp index 61bd8c14..93b5b555 100644 --- a/src/image.cpp +++ b/src/image.cpp @@ -54,6 +54,11 @@ EXIV2_RCSID("@(#) $Id$") #include "rafimage.hpp" #include "tiffimage.hpp" #include "orfimage.hpp" +#include "gifimage.hpp" +#include "psdimage.hpp" +#include "tgaimage.hpp" +#include "bmpimage.hpp" +#include "jp2image.hpp" #include "xmpsidecar.hpp" // + standard includes @@ -84,12 +89,17 @@ namespace Exiv2 { { ImageType::mrw, newMrwInstance, isMrwType, amRead, amRead, amRead, amNone }, { ImageType::tiff, newTiffInstance, isTiffType, amRead, amRead, amRead, amNone }, { ImageType::orf, newOrfInstance, isOrfType, amRead, amRead, amRead, amNone }, -#ifdef EXV_HAVE_LIBZ + #ifdef EXV_HAVE_LIBZ { ImageType::png, newPngInstance, isPngType, amRead, amRead, amRead, amNone }, -#endif // EXV_HAVE_LIBZ + #endif // EXV_HAVE_LIBZ { ImageType::raf, newRafInstance, isRafType, amRead, amRead, amRead, amNone }, { ImageType::xmp, newXmpInstance, isXmpType, amNone, amNone, amReadWrite, amNone }, - // End of list marker + { ImageType::gif, newGifInstance, isGifType, amNone, amNone, amNone, amNone }, + { ImageType::psd, newPsdInstance, isPsdType, amRead, amRead, amRead, amNone }, + { ImageType::tga, newTgaInstance, isTgaType, amNone, amNone, amNone, amNone }, + { ImageType::bmp, newBmpInstance, isBmpType, amNone, amNone, amNone, amNone }, + { ImageType::jp2, newJp2Instance, isJp2Type, amRead, amRead, amRead, amNone }, + // End of list marker { ImageType::none, 0, 0, amNone, amNone, amNone, amNone } }; @@ -102,6 +112,8 @@ namespace Exiv2 { uint16_t supportedMetadata, BasicIo::AutoPtr io) : io_(io), + pixelWidth_(0), + pixelHeight_(0), imageType_(imageType), supportedMetadata_(supportedMetadata), #ifdef EXV_HAVE_XMP_TOOLKIT @@ -214,6 +226,8 @@ namespace Exiv2 { if (!r) throw Error(13, type); AccessMode am = amNone; switch (metadataId) { + case mdNone: + break; case mdExif: am = r->exifSupport_; break; diff --git a/src/image.hpp b/src/image.hpp index 5f578dd3..aad28085 100644 --- a/src/image.hpp +++ b/src/image.hpp @@ -295,6 +295,14 @@ namespace Exiv2 { specific MIME type may exist (e.g., "image/x-nikon-nef"). */ virtual std::string mimeType() const =0; + /*! + @brief Return the pixel width of the image. + */ + virtual int pixelWidth() const { return pixelWidth_; } + /*! + @brief Return the pixel height of the image. + */ + virtual int pixelHeight() const { return pixelHeight_; } /*! @brief Returns an ExifData instance containing currently buffered Exif data. @@ -378,6 +386,8 @@ namespace Exiv2 { XmpData xmpData_; //!< XMP data container std::string comment_; //!< User comment std::string xmpPacket_; //!< XMP packet + int pixelWidth_; //!< image pixel width + int pixelHeight_; //!< image pixel height private: //! @name NOT implemented diff --git a/src/jp2image.cpp b/src/jp2image.cpp new file mode 100644 index 00000000..b9f1d3d7 --- /dev/null +++ b/src/jp2image.cpp @@ -0,0 +1,266 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 Andreas Huggel + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/* + File: jp2image.cpp + Version: $Rev$ + Author(s): Marco Piovanelli, Ovolabs (marco) + History: 12-Mar-2007, marco: created + */ +// ***************************************************************************** +#include "rcsid.hpp" +EXIV2_RCSID("@(#) $Id$") + +//#define DEBUG 1 + +// ***************************************************************************** +// included header files +#ifdef _MSC_VER +# include "exv_msvc.h" +#else +# include "exv_conf.h" +#endif +#include "jp2image.hpp" +#include "image.hpp" +#include "basicio.hpp" +#include "error.hpp" +#include "futils.hpp" + +// + standard includes +#include +#include +#include + +// JPEG-2000 box types +const uint32_t kJp2BoxTypeJp2Header = 0x6a703268; // 'jp2h' +const uint32_t kJp2BoxTypeImageHeader = 0x69686472; // 'ihdr' +const uint32_t kJp2BoxTypeUuid = 0x75756964; // 'uuid' + +// JPEG-2000 UUIDs for embedded metadata +// +// See http://www.jpeg.org/public/wg1n2600.doc for information about embedding IPTC-NAA data in JPEG-2000 files +// See http://www.adobe.com/devnet/xmp/pdfs/xmp_specification.pdf for information about embedding XMP data in JPEG-2000 files +const char* const kJp2UuidExif = "JpgTiffExif->JP2"; +const char* const kJp2UuidIptc = "\x33\xc7\xa4\xd2\xb8\x1d\x47\x23\xa0\xba\xf1\xa3\xe0\x97\xad\x38"; +const char* const kJp2UuidXmp = "\xbe\x7a\xcf\xcb\x97\xa9\x42\xe8\x9c\x71\x99\x94\x91\xe3\xaf\xac"; + +//! @cond IGNORE +struct Jp2BoxHeader { + uint32_t boxLength; + uint32_t boxType; +}; + +struct Jp2ImageHeaderBox { + uint32_t imageHeight; + uint32_t imageWidth; + uint16_t componentCount; + uint8_t bitsPerComponent; + uint8_t compressionType; + uint8_t colorspaceIsUnknown; + uint8_t intellectualPropertyFlag; + uint16_t compressionTypeProfile; +}; + +struct Jp2UuidBox { + uint8_t uuid[16]; +}; +//! @endcond + +// ***************************************************************************** +// class member definitions +namespace Exiv2 { + + Jp2Image::Jp2Image(BasicIo::AutoPtr io) + : Image(ImageType::jp2, mdExif | mdIptc | mdXmp, io) + { + } // Jp2Image::Jp2Image + + void Jp2Image::setExifData(const ExifData& /*exifData*/) + { + // Todo: implement me! + throw(Error(32, "Exif metadata", "JP2")); + } + + void Jp2Image::setIptcData(const IptcData& /*iptcData*/) + { + // Todo: implement me! + throw(Error(32, "IPTC metadata", "JP2")); + } + + void Jp2Image::setComment(const std::string& /*comment*/) + { + // Todo: implement me! + throw(Error(32, "Image comment", "JP2")); + } + + void Jp2Image::readMetadata() + { +#ifdef DEBUG + std::cerr << "Exiv2::Jp2Image::readMetadata: Reading JPEG-2000 file " << io_->path() << "\n"; +#endif + if (io_->open() != 0) + { + throw Error(9, io_->path(), strError()); + } + IoCloser closer(*io_); + // Ensure that this is the correct image type + if (!isJp2Type(*io_, true)) + { + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "JPEG-2000"); + } + + Jp2BoxHeader box = {0,0}; + Jp2BoxHeader subBox = {0,0}; + Jp2ImageHeaderBox ihdr = {0,0,0,0,0,0,0,0}; + Jp2UuidBox uuid = {{0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}}; + long curOffset = io_->tell(); + + while (io_->read((byte*)&box, sizeof(box)) == sizeof(box)) + { + box.boxLength = getLong((byte*)&box.boxLength, bigEndian); + box.boxType = getLong((byte*)&box.boxType, bigEndian); + + if (box.boxLength == 0) + { + break; + } + + switch(box.boxType) + { + case kJp2BoxTypeJp2Header: + { + if (io_->read((byte*)&subBox, sizeof(subBox)) == sizeof(subBox)) + { + subBox.boxLength = getLong((byte*)&subBox.boxLength, bigEndian); + subBox.boxType = getLong((byte*)&subBox.boxType, bigEndian); + + if((subBox.boxType == kJp2BoxTypeImageHeader) && (io_->read((byte*)&ihdr, sizeof(ihdr)) == sizeof(ihdr))) + { + ihdr.imageHeight = getLong((byte*)&ihdr.imageHeight, bigEndian); + ihdr.imageWidth = getLong((byte*)&ihdr.imageWidth, bigEndian); + ihdr.componentCount = getShort((byte*)&ihdr.componentCount, bigEndian); + ihdr.compressionTypeProfile = getShort((byte*)&ihdr.compressionTypeProfile, bigEndian); + + pixelWidth_ = ihdr.imageWidth; + pixelHeight_ = ihdr.imageHeight; + } + } + break; + } + + case kJp2BoxTypeUuid: + { + if (io_->read((byte*)&uuid, sizeof(uuid)) == sizeof(uuid)) + { + if(memcmp(uuid.uuid, kJp2UuidExif, sizeof(uuid)) == 0) + { + // we've hit an embedded Exif block + DataBuf rawExif(box.boxLength - (sizeof(box) + sizeof(uuid))); + io_->read(rawExif.pData_, rawExif.size_); + if (io_->error() || io_->eof()) throw Error(14); + if (exifData_.load(rawExif.pData_, rawExif.size_)) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: Failed to decode Exif metadata.\n"; +#endif + exifData_.clear(); + } + } + else if(memcmp(uuid.uuid, kJp2UuidIptc, sizeof(uuid)) == 0) + { + // we've hit an embedded IPTC block + DataBuf rawIPTC(box.boxLength - (sizeof(box) + sizeof(uuid))); + io_->read(rawIPTC.pData_, rawIPTC.size_); + if (io_->error() || io_->eof()) throw Error(14); + if (iptcData_.load(rawIPTC.pData_, rawIPTC.size_)) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: Failed to decode IPTC metadata.\n"; +#endif + iptcData_.clear(); + } + } + else if(memcmp(uuid.uuid, kJp2UuidXmp, sizeof(uuid)) == 0) + { + // we've hit an embedded XMP block + DataBuf xmpPacket(box.boxLength - (sizeof(box) + sizeof(uuid))); + io_->read(xmpPacket.pData_, xmpPacket.size_); + if (io_->error() || io_->eof()) throw Error(14); + xmpPacket_.assign(reinterpret_cast(xmpPacket.pData_), xmpPacket.size_); + if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: Failed to decode XMP metadata.\n"; +#endif + } + } + } + break; + } + + default: + { + break; + } + } + + curOffset += box.boxLength; + if(io_->seek(curOffset, BasicIo::beg) != 0) + { + break; // Todo: should throw an error here + } + } + } // Jp2Image::readMetadata + + void Jp2Image::writeMetadata() + { + // Todo: implement me! + throw(Error(31, "JP2")); + } // Jp2Image::writeMetadata + + // ************************************************************************* + // free functions + Image::AutoPtr newJp2Instance(BasicIo::AutoPtr io, bool /*create*/) + { + Image::AutoPtr image(new Jp2Image(io)); + if (!image->good()) + { + image.reset(); + } + return image; + } + + bool isJp2Type(BasicIo& iIo, bool advance) + { + // see section B.1.1 (JPEG 2000 Signature box) of JPEG-2000 specification + const int32_t len = 12; + const unsigned char Jp2Header[len] = { 0x00, 0x00, 0x00, 0x0c, 0x6a, 0x50, 0x20, 0x20, 0x0d, 0x0a, 0x87, 0x0a }; + byte buf[len]; + iIo.read(buf, len); + if (iIo.error() || iIo.eof()) + { + return false; + } + bool matched = (memcmp(buf, Jp2Header, len) == 0); + if (!advance || !matched) + { + iIo.seek(-len, BasicIo::cur); + } + return matched; + } +} // namespace Exiv2 diff --git a/src/jp2image.hpp b/src/jp2image.hpp new file mode 100644 index 00000000..216ba5af --- /dev/null +++ b/src/jp2image.hpp @@ -0,0 +1,133 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 Andreas Huggel + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/*! + @file jp2image.hpp + @brief JPEG-2000 image, implemented using the following references: + ISO/IEC JTC 1/SC 29/WG1 N2401: JPEG 2000 Part 6 FCD 15444-6
+ @version $Rev$ + @author Marco Piovanelli, Ovolabs (marco) + marco.piovanelli@pobox.com + @date 12-Mar-2007, marco: created + */ +#ifndef JP2IMAGE_HPP_ +#define JP2IMAGE_HPP_ + +// ***************************************************************************** +// included header files +#include "exif.hpp" +#include "iptc.hpp" +#include "image.hpp" + +// + standard includes +#include + +// ***************************************************************************** +// namespace extensions +namespace Exiv2 { + +// ***************************************************************************** +// class definitions + + // Add JPEG-2000 to the supported image formats + namespace ImageType { + const int jp2 = 15; //!< JPEG-2000 image type + } + + /*! + @brief Class to access JPEG-2000 images. + */ + class Jp2Image : public Image { + //! @name NOT Implemented + //@{ + //! Copy constructor + Jp2Image(const Jp2Image& rhs); + //! Assignment operator + Jp2Image& operator=(const Jp2Image& rhs); + //@} + + public: + //! @name Creators + //@{ + /*! + @brief Constructor to open a JPEG-2000 image. Since the + constructor can not return a result, callers should check the + good() method after object construction to determine success + or failure. + @param io An auto-pointer that owns a BasicIo instance used for + reading and writing image metadata. \b Important: The constructor + takes ownership of the passed in BasicIo instance through the + auto-pointer. Callers should not continue to use the BasicIo + instance after it is passed to this method. Use the Image::io() + method to get a temporary reference. + */ + Jp2Image(BasicIo::AutoPtr io); + //@} + + //! @name Manipulators + //@{ + void readMetadata(); + /*! + @brief Todo: Write metadata back to the image. This method is not + yet implemented. Calling it will throw an Error(31). + */ + void writeMetadata(); + /*! + @brief Todo: Not supported yet. Calling this function will throw + an instance of Error(32). + */ + void setExifData(const ExifData& exifData); + /*! + @brief Todo: Not supported yet. Calling this function will throw + an instance of Error(32). + */ + void setIptcData(const IptcData& iptcData); + /*! + @brief Todo: Not supported yet(?). Calling this function will throw + an instance of Error(32). + */ + void setComment(const std::string& comment); + //@} + + //! @name Accessors + //@{ + std::string mimeType() const { return "image/jp2"; } + //@} + + }; // class Jp2Image + +// ***************************************************************************** +// template, inline and free functions + + // These could be static private functions on Image subclasses but then + // ImageFactory needs to be made a friend. + /*! + @brief Create a new Jp2Image instance and return an auto-pointer to it. + Caller owns the returned object and the auto-pointer ensures that + it will be deleted. + */ + Image::AutoPtr newJp2Instance(BasicIo::AutoPtr io, bool create); + + //! Check if the file iIo is a JPEG-2000 image. + bool isJp2Type(BasicIo& iIo, bool advance); + +} // namespace Exiv2 + +#endif // #ifndef JP2IMAGE_HPP_ diff --git a/src/jpgimage.cpp b/src/jpgimage.cpp index b09df6ef..73a8bf3c 100644 --- a/src/jpgimage.cpp +++ b/src/jpgimage.cpp @@ -57,6 +57,28 @@ namespace Exiv2 { const byte JpegBase::app1_ = 0xe1; const byte JpegBase::app13_ = 0xed; const byte JpegBase::com_ = 0xfe; + +// Start of Frame markers, nondifferential Huffman-coding frames + const byte JpegBase::sof0_ = 0xc0; // start of frame 0, baseline DCT + const byte JpegBase::sof1_ = 0xc1; // start of frame 1, extended sequential DCT, Huffman coding + const byte JpegBase::sof2_ = 0xc2; // start of frame 2, progressive DCT, Huffman coding + const byte JpegBase::sof3_ = 0xc3; // start of frame 3, lossless sequential, Huffman coding + +// Start of Frame markers, differential Huffman-coding frames + const byte JpegBase::sof5_ = 0xc5; // start of frame 5, differential sequential DCT, Huffman coding + const byte JpegBase::sof6_ = 0xc6; // start of frame 6, differential progressive DCT, Huffman coding + const byte JpegBase::sof7_ = 0xc7; // start of frame 7, differential lossless, Huffman coding + +// Start of Frame markers, nondifferential arithmetic-coding frames + const byte JpegBase::sof9_ = 0xc9; // start of frame 9, extended sequential DCT, arithmetic coding + const byte JpegBase::sof10_ = 0xca; // start of frame 10, progressive DCT, arithmetic coding + const byte JpegBase::sof11_ = 0xcb; // start of frame 11, lossless sequential, arithmetic coding + +// Start of Frame markers, differential arithmetic-coding frames + const byte JpegBase::sof13_ = 0xcd; // start of frame 13, differential sequential DCT, arithmetic coding + const byte JpegBase::sof14_ = 0xce; // start of frame 14, progressive DCT, arithmetic coding + const byte JpegBase::sof15_ = 0xcf; // start of frame 15, differential lossless, arithmetic coding + const char JpegBase::exifId_[] = "Exif\0\0"; const char JpegBase::jfifId_[] = "JFIF\0"; const char JpegBase::xmpId_[] = "http://ns.adobe.com/xap/1.0/\0"; @@ -255,7 +277,7 @@ namespace Exiv2 { throw Error(15); } clearMetadata(); - int search = 4; + int search = 5; const long bufMinSize = 36; long bufRead = 0; DataBuf buf(bufMinSize); @@ -377,6 +399,18 @@ namespace Exiv2 { } --search; } + else if ( pixelHeight_ == 0 + && ( marker == sof0_ || marker == sof1_ || marker == sof2_ + || marker == sof3_ || marker == sof5_ || marker == sof6_ + || marker == sof7_ || marker == sof9_ || marker == sof10_ + || marker == sof11_ || marker == sof13_ || marker == sof14_ + || marker == sof15_)) { + // we hit a SOFn (start-of-frame) marker + if (size < 8) throw Error(15); + pixelHeight_ = getUShort(buf.pData_ + 3, bigEndian); + pixelWidth_ = getUShort(buf.pData_ + 5, bigEndian); + if (pixelHeight_ != 0) --search; + } else { if (size < 2) { rc = 4; diff --git a/src/jpgimage.hpp b/src/jpgimage.hpp index 6bc21309..a383ae0d 100644 --- a/src/jpgimage.hpp +++ b/src/jpgimage.hpp @@ -189,6 +189,19 @@ namespace Exiv2 { static const byte app1_; //!< JPEG APP1 marker static const byte app13_; //!< JPEG APP13 marker static const byte com_; //!< JPEG Comment marker + static const byte sof0_; //!< JPEG Start-Of-Frame marker + static const byte sof1_; //!< JPEG Start-Of-Frame marker + static const byte sof2_; //!< JPEG Start-Of-Frame marker + static const byte sof3_; //!< JPEG Start-Of-Frame marker + static const byte sof5_; //!< JPEG Start-Of-Frame marker + static const byte sof6_; //!< JPEG Start-Of-Frame marker + static const byte sof7_; //!< JPEG Start-Of-Frame marker + static const byte sof9_; //!< JPEG Start-Of-Frame marker + static const byte sof10_; //!< JPEG Start-Of-Frame marker + static const byte sof11_; //!< JPEG Start-Of-Frame marker + static const byte sof13_; //!< JPEG Start-Of-Frame marker + static const byte sof14_; //!< JPEG Start-Of-Frame marker + static const byte sof15_; //!< JPEG Start-Of-Frame marker static const char exifId_[]; //!< Exif identifier static const char jfifId_[]; //!< JFIF identifier static const char xmpId_[]; //!< XMP packet identifier @@ -268,6 +281,7 @@ namespace Exiv2 { //@{ std::string mimeType() const { return "image/jpeg"; } //@} + protected: //! @name Accessors //@{ @@ -326,6 +340,7 @@ namespace Exiv2 { //@{ std::string mimeType() const { return "image/x-exv"; } //@} + protected: //! @name Accessors //@{ diff --git a/src/mrwimage.cpp b/src/mrwimage.cpp index 7066314f..29549b23 100644 --- a/src/mrwimage.cpp +++ b/src/mrwimage.cpp @@ -59,6 +59,26 @@ namespace Exiv2 { { } // MrwImage::MrwImage + int MrwImage::pixelWidth() const + { + ExifData::const_iterator imageWidth; + if ((imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth"))) != exifData_.end()) + { + return imageWidth->toLong(); + } + return 0; + } + + int MrwImage::pixelHeight() const + { + ExifData::const_iterator imageHeight; + if ((imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageLength"))) != exifData_.end()) + { + return imageHeight->toLong(); + } + return 0; + } + void MrwImage::setExifData(const ExifData& /*exifData*/) { // Todo: implement me! diff --git a/src/mrwimage.hpp b/src/mrwimage.hpp index 4e0c7429..e03a6cc4 100644 --- a/src/mrwimage.hpp +++ b/src/mrwimage.hpp @@ -104,6 +104,8 @@ namespace Exiv2 { //! @name Accessors //@{ std::string mimeType() const { return "image/x-minolta-mrw"; } + int pixelWidth() const; + int pixelHeight() const; //@} private: diff --git a/src/orfimage.cpp b/src/orfimage.cpp index 30e75563..eb70bd02 100644 --- a/src/orfimage.cpp +++ b/src/orfimage.cpp @@ -59,6 +59,26 @@ namespace Exiv2 { { } // OrfImage::OrfImage + int OrfImage::pixelWidth() const + { + ExifData::const_iterator imageWidth; + if ((imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth"))) != exifData_.end()) + { + return imageWidth->toLong(); + } + return 0; + } + + int OrfImage::pixelHeight() const + { + ExifData::const_iterator imageHeight; + if ((imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageLength"))) != exifData_.end()) + { + return imageHeight->toLong(); + } + return 0; + } + void OrfImage::setExifData(const ExifData& /*exifData*/) { // Todo: implement me! diff --git a/src/orfimage.hpp b/src/orfimage.hpp index 8640cd30..b9f48291 100644 --- a/src/orfimage.hpp +++ b/src/orfimage.hpp @@ -104,6 +104,8 @@ namespace Exiv2 { //! @name Accessors //@{ std::string mimeType() const { return "image/x-olympus-orf"; } + int pixelWidth() const; + int pixelHeight() const; //@} private: diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp index fb207117..f4f46bc2 100644 --- a/src/pngchunk.cpp +++ b/src/pngchunk.cpp @@ -81,15 +81,27 @@ namespace { // class member definitions namespace Exiv2 { - void PngChunk::decode(Image* pImage, - const byte* pData, - long size) + void PngChunk::decode(Image* pImage, + const byte* pData, + long size, + int* outWidth, + int* outHeight) { assert(pImage != 0); assert(pData != 0); + assert(outWidth != 0); + assert(outHeight != 0); - // look for a tEXt chunk long index = 8; + + // extract width and height from IHDR chunk, which *must* be the first chunk in the PNG file + if (strncmp((const char *)PNG_CHUNK_TYPE(pData, index), "IHDR", 4) == 0) + { + *outWidth = getLong((const byte*)&PNG_CHUNK_DATA(pData, index, 0), bigEndian); + *outHeight = getLong((const byte*)&PNG_CHUNK_DATA(pData, index, 4), bigEndian); + } + + // look for a tEXt chunk index += chunkLength(pData, index) + PNG_CHUNK_HEADER_SIZE; while(index < size-PNG_CHUNK_HEADER_SIZE) diff --git a/src/pngchunk.hpp b/src/pngchunk.hpp index bbf018df..71e9ad44 100644 --- a/src/pngchunk.hpp +++ b/src/pngchunk.hpp @@ -69,10 +69,14 @@ namespace Exiv2 { @param pData Pointer to the data buffer. Must point to PNG chunk data; no checks are performed. @param size Length of the data buffer. + @param outWidth Integer pointer to be set to the width of the image. + @param outHeight Integer pointer to be set to the height of the image. */ static void decode(Image* pImage, const byte* pData, - long size); + long size, + int* outWidth, + int* outHeight); private: //! @name Accessors diff --git a/src/pngimage.cpp b/src/pngimage.cpp index 071e9a02..208bb0a7 100644 --- a/src/pngimage.cpp +++ b/src/pngimage.cpp @@ -99,7 +99,7 @@ namespace Exiv2 { throw Error(3, "PNG"); } clearMetadata(); - PngChunk::decode(this, io_->mmap(), io_->size()); + PngChunk::decode(this, io_->mmap(), io_->size(), &pixelWidth_, &pixelHeight_); /* Todo: diff --git a/src/psdimage.cpp b/src/psdimage.cpp new file mode 100644 index 00000000..fd5145d1 --- /dev/null +++ b/src/psdimage.cpp @@ -0,0 +1,339 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 Andreas Huggel + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/* + File: psdimage.cpp + Version: $Rev$ + Author(s): Marco Piovanelli, Ovolabs (marco) + History: 05-Mar-2007, marco: created + */ +// ***************************************************************************** +#include "rcsid.hpp" +EXIV2_RCSID("@(#) $Id$") + +//#define DEBUG 1 + +// ***************************************************************************** +// included header files +#ifdef _MSC_VER +# include "exv_msvc.h" +#else +# include "exv_conf.h" +#endif +#include "psdimage.hpp" +#include "image.hpp" +#include "basicio.hpp" +#include "error.hpp" +#include "futils.hpp" + +// + standard includes +#include +#include +#include + +// Todo: Consolidate with existing code in struct Photoshop (jpgimage.hpp): +// Extend this helper to a proper class with all required functionality, +// then move it here or into a separate file? + +const uint32_t kPhotoshopResourceType = 0x3842494d; // '8BIM' + +//! @cond IGNORE +struct PhotoshopResourceBlock { + uint32_t resourceType; // always kPhotoshopResourceType + uint16_t resourceId; + unsigned char resourceName[2]; // Pascal string (length byte + characters), padded to an even size -- this assumes the empty string + uint32_t resourceDataSize; +}; +//! @endcond + +// Photoshop resource IDs (Cf. ) +enum { + kPhotoshopResourceID_Photoshop2Info = 0x03e8, // [obsolete -- Photoshop 2.0 only] General information -- contains five 2-byte values: number of channels, rows, columns, depth and mode + kPhotoshopResourceID_MacintoshClassicPrintInfo = 0x03e9, // [optional] Macintosh classic print record (120 bytes) + kPhotoshopResourceID_MacintoshCarbonPrintInfo = 0x03ea, // [optional] Macintosh carbon print info (variable-length XML format) + kPhotoshopResourceID_Photoshop2ColorTable = 0x03eb, // [obsolete -- Photoshop 2.0 only] Indexed color table + kPhotoshopResourceID_ResolutionInfo = 0x03ed, // PhotoshopResolutionInfo structure (see below) + kPhotoshopResourceID_AlphaChannelsNames = 0x03ee, // as a series of Pstrings + kPhotoshopResourceID_DisplayInfo = 0x03ef, // see appendix A in Photoshop SDK + kPhotoshopResourceID_PStringCaption = 0x03f0, // [optional] the caption, as a Pstring + kPhotoshopResourceID_BorderInformation = 0x03f1, // border width and units + kPhotoshopResourceID_BackgroundColor = 0x03f2, // see additional Adobe information + kPhotoshopResourceID_PrintFlags = 0x03f3, // labels, crop marks, colour bars, ecc... + kPhotoshopResourceID_BWHalftoningInfo = 0x03f4, // Gray-scale and multich. half-toning info + kPhotoshopResourceID_ColorHalftoningInfo = 0x03f5, // Colour half-toning information + kPhotoshopResourceID_DuotoneHalftoningInfo = 0x03f6, // Duo-tone half-toning information + kPhotoshopResourceID_BWTransferFunc = 0x03f7, // Gray-scale and multich. transfer function + kPhotoshopResourceID_ColorTransferFuncs = 0x03f8, // Colour transfer function + kPhotoshopResourceID_DuotoneTransferFuncs = 0x03f9, // Duo-tone transfer function + kPhotoshopResourceID_DuotoneImageInfo = 0x03fa, // Duo-tone image information + kPhotoshopResourceID_EffectiveBW = 0x03fb, // two bytes for the effective black and white values + kPhotoshopResourceID_ObsoletePhotoshopTag1 = 0x03fc, // [obsolete] + kPhotoshopResourceID_EPSOptions = 0x03fd, // Encapsulated Postscript options + kPhotoshopResourceID_QuickMaskInfo = 0x03fe, // Quick Mask information. 2 bytes containing Quick Mask channel ID, 1 byte boolean indicating whether the mask was initially empty. + kPhotoshopResourceID_ObsoletePhotoshopTag2 = 0x03ff, // [obsolete] + kPhotoshopResourceID_LayerStateInfo = 0x0400, // index of target layer (0 means bottom) + kPhotoshopResourceID_WorkingPathInfo = 0x0401, // should not be saved to the file + kPhotoshopResourceID_LayersGroupInfo = 0x0402, // for grouping layers together + kPhotoshopResourceID_ObsoletePhotoshopTag3 = 0x0403, // [obsolete] ?? + kPhotoshopResourceID_IPTC_NAA = 0x0404, // IPTC/NAA data + kPhotoshopResourceID_RawImageMode = 0x0405, // image mode for raw format files + kPhotoshopResourceID_JPEGQuality = 0x0406, // [private] + kPhotoshopResourceID_GridGuidesInfo = 0x0408, // see additional Adobe information + kPhotoshopResourceID_ThumbnailResource = 0x0409, // see additional Adobe information + kPhotoshopResourceID_CopyrightFlag = 0x040a, // true if image is copyrighted + kPhotoshopResourceID_URL = 0x040b, // text string with a resource locator + kPhotoshopResourceID_ThumbnailResource2 = 0x040c, // see additional Adobe information + kPhotoshopResourceID_GlobalAngle = 0x040d, // global lighting angle for effects layer + kPhotoshopResourceID_ColorSamplersResource = 0x040e, // see additional Adobe information + kPhotoshopResourceID_ICCProfile = 0x040f, // see notes from Internat. Color Consortium + kPhotoshopResourceID_Watermark = 0x0410, // one byte + kPhotoshopResourceID_ICCUntagged = 0x0411, // 1 means intentionally untagged + kPhotoshopResourceID_EffectsVisible = 0x0412, // 1 byte to show/hide all effects layers + kPhotoshopResourceID_SpotHalftone = 0x0413, // version, length and data + kPhotoshopResourceID_IDsBaseValue = 0x0414, // base value for new layers ID's + kPhotoshopResourceID_UnicodeAlphaNames = 0x0415, // length plus Unicode string + kPhotoshopResourceID_IndexedColourTableCount = 0x0416, // [Photoshop 6.0 and later] 2 bytes + kPhotoshopResourceID_TransparentIndex = 0x0417, // [Photoshop 6.0 and later] 2 bytes + kPhotoshopResourceID_GlobalAltitude = 0x0419, // [Photoshop 6.0 and later] 4 bytes + kPhotoshopResourceID_Slices = 0x041a, // [Photoshop 6.0 and later] see additional Adobe info + kPhotoshopResourceID_WorkflowURL = 0x041b, // [Photoshop 6.0 and later] 4 bytes length + Unicode string + kPhotoshopResourceID_JumpToXPEP = 0x041c, // [Photoshop 6.0 and later] see additional Adobe info + kPhotoshopResourceID_AlphaIdentifiers = 0x041d, // [Photoshop 6.0 and later] 4*(n+1) bytes + kPhotoshopResourceID_URLList = 0x041e, // [Photoshop 6.0 and later] structured Unicode URL's + kPhotoshopResourceID_VersionInfo = 0x0421, // [Photoshop 6.0 and later] see additional Adobe info + kPhotoshopResourceID_ExifInfo = 0x0422, // [Photoshop 7.0?] Exif metadata + kPhotoshopResourceID_XMPPacket = 0x0424, // [Photoshop 7.0?] XMP packet -- see http://www.adobe.com/devnet/xmp/pdfs/xmp_specification.pdf + kPhotoshopResourceID_ClippingPathName = 0x0bb7, // [Photoshop 6.0 and later] name of clipping path + kPhotoshopResourceID_MorePrintFlags = 0x2710 // [Photoshop 6.0 and later] Print flags information. 2 bytes version (=1), 1 byte center crop marks, 1 byte (=0), 4 bytes bleed width value, 2 bytes bleed width scale. +}; + +// ***************************************************************************** +// class member definitions +namespace Exiv2 { + + PsdImage::PsdImage(BasicIo::AutoPtr io) + : Image(ImageType::psd, mdExif | mdIptc | mdXmp, io) + { + } // PsdImage::PsdImage + + void PsdImage::setExifData(const ExifData& /*exifData*/) + { + // Todo: implement me! + throw(Error(32, "Exif metadata", "Photoshop")); + } + + void PsdImage::setIptcData(const IptcData& /*iptcData*/) + { + // Todo: implement me! + throw(Error(32, "IPTC metadata", "Photoshop")); + } + + void PsdImage::setComment(const std::string& /*comment*/) + { + // Todo: implement me! + throw(Error(32, "Image comment", "Photoshop")); + } + + void PsdImage::readMetadata() + { +#ifdef DEBUG + std::cerr << "Exiv2::PsdImage::readMetadata: Reading Photoshop file " << io_->path() << "\n"; +#endif + if (io_->open() != 0) + { + throw Error(9, io_->path(), strError()); + } + IoCloser closer(*io_); + // Ensure that this is the correct image type + if (!isPsdType(*io_, false)) + { + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "Photoshop"); + } + clearMetadata(); + + /* + The Photoshop header goes as follows -- all numbers are in big-endian byte order: + + offset length name description + ====== ======= ========= ========= + 0 4 bytes signature always '8BPS' + 4 2 bytes version always equal to 1 + 6 6 bytes reserved must be zero + 12 2 bytes channels number of channels in the image, including alpha channels (1 to 24) + 14 4 bytes rows the height of the image in pixels + 18 4 bytes columns the width of the image in pixels + 22 2 bytes depth the number of bits per channel + 24 2 bytes mode the color mode of the file; Supported values are: Bitmap=0; Grayscale=1; Indexed=2; RGB=3; CMYK=4; Multichannel=7; Duotone=8; Lab=9 + */ + byte buf[26]; + if (io_->read(buf, 26) != 26) + { + throw Error(3, "Photoshop"); + } + pixelWidth_ = getLong(buf + 18, bigEndian); + pixelHeight_ = getLong(buf + 14, bigEndian); + + // immediately following the image header is the color mode data section, + // the first four bytes of which specify the byte size of the whole section + if (io_->read(buf, 4) != 4) + { + throw Error(3, "Photoshop"); + } + + // skip it + uint32_t colorDataLength = getLong(buf, bigEndian); + if (io_->seek(colorDataLength, BasicIo::cur)) + { + throw Error(3, "Photoshop"); + } + + // after the color data section, comes a list of resource blocks, preceeded by the total byte size + if (io_->read(buf, 4) != 4) + { + throw Error(3, "Photoshop"); + } + uint32_t resourcesLength = getLong(buf, bigEndian); + while (resourcesLength > 0) + { + if (io_->read(buf, 8) != 8) + { + throw Error(3, "Photoshop"); + } + + // read resource type and ID + uint32_t resourceType = getLong(buf, bigEndian); + uint16_t resourceId = getShort(buf + 4, bigEndian); + + if (resourceType != kPhotoshopResourceType) + { + break; // bad resource type + } + uint32_t resourceNameLength = buf[6] & ~1; + + // skip the resource name, plus any padding + io_->seek(resourceNameLength, BasicIo::cur); + + // read resource size + if (io_->read(buf, 4) != 4) + { + throw Error(3, "Photoshop"); + } + uint32_t resourceSize = getLong(buf, bigEndian); + uint32_t curOffset = io_->tell(); + + processResourceBlock(resourceId, resourceSize); + resourceSize = (resourceSize + 1) & ~1; // pad to even + io_->seek(curOffset + resourceSize, BasicIo::beg); + resourcesLength -= (12 + resourceNameLength + resourceSize); + } + + } // PsdImage::readMetadata + + void PsdImage::processResourceBlock(uint16_t resourceId, uint32_t resourceSize) + { + switch(resourceId) + { + case kPhotoshopResourceID_IPTC_NAA: + { + DataBuf rawIPTC(resourceSize); + io_->read(rawIPTC.pData_, rawIPTC.size_); + if (io_->error() || io_->eof()) throw Error(14); + if (iptcData_.load(rawIPTC.pData_, rawIPTC.size_)) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: Failed to decode IPTC metadata.\n"; +#endif + iptcData_.clear(); + } + break; + } + + case kPhotoshopResourceID_ExifInfo: + { + DataBuf rawExif(resourceSize); + io_->read(rawExif.pData_, rawExif.size_); + if (io_->error() || io_->eof()) throw Error(14); + if (exifData_.load(rawExif.pData_, rawExif.size_)) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: Failed to decode Exif metadata.\n"; +#endif + exifData_.clear(); + } + break; + } + + case kPhotoshopResourceID_XMPPacket: + { + DataBuf xmpPacket(resourceSize); + io_->read(xmpPacket.pData_, xmpPacket.size_); + if (io_->error() || io_->eof()) throw Error(14); + xmpPacket_.assign(reinterpret_cast(xmpPacket.pData_), xmpPacket.size_); + if (xmpPacket_.size() > 0 && XmpParser::decode(xmpData_, xmpPacket_)) { +#ifndef SUPPRESS_WARNINGS + std::cerr << "Warning: Failed to decode XMP metadata.\n"; +#endif + } + break; + } + + default: + { + break; + } + } + } + + void PsdImage::writeMetadata() + { + // Todo: implement me! + throw(Error(31, "Photoshop")); + } // PsdImage::writeMetadata + + // ************************************************************************* + // free functions + Image::AutoPtr newPsdInstance(BasicIo::AutoPtr io, bool /*create*/) + { + Image::AutoPtr image(new PsdImage(io)); + if (!image->good()) + { + image.reset(); + } + return image; + } + + bool isPsdType(BasicIo& iIo, bool advance) + { + const int32_t len = 6; + const unsigned char PsdHeader[6] = { '8', 'B', 'P', 'S', 0, 1 }; + byte buf[len]; + iIo.read(buf, len); + if (iIo.error() || iIo.eof()) + { + return false; + } + bool matched = (memcmp(buf, PsdHeader, len) == 0); + if (!advance || !matched) + { + iIo.seek(-len, BasicIo::cur); + } + + return matched; + } +} // namespace Exiv2 diff --git a/src/psdimage.hpp b/src/psdimage.hpp new file mode 100644 index 00000000..fc5ec593 --- /dev/null +++ b/src/psdimage.hpp @@ -0,0 +1,150 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 Andreas Huggel + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/*! + @file psdimage.hpp + @brief Photoshop image, implemented using the following references: + Adobe Photoshop 6.0 File Format Specification by Adobe
+ @version $Rev$ + @author Marco Piovanelli, Ovolabs (marco) + marco.piovanelli@pobox.com + @date 05-Mar-2007, marco: created + */ +#ifndef PSDIMAGE_HPP_ +#define PSDIMAGE_HPP_ + +// ***************************************************************************** +// included header files +#include "exif.hpp" +#include "iptc.hpp" +#include "image.hpp" + +// + standard includes +#include + +// ***************************************************************************** +// namespace extensions +namespace Exiv2 { + +// ***************************************************************************** +// class definitions + + // Add PSD to the supported image formats + namespace ImageType { + const int psd = 12; //!< Photoshop (PSD) image type (see class PsdImage) + } + + /*! + @brief Class to access raw Photoshop images. + */ + class PsdImage : public Image { + //! @name NOT Implemented + //@{ + //! Copy constructor + PsdImage(const PsdImage& rhs); + //! Assignment operator + PsdImage& operator=(const PsdImage& rhs); + //@} + + public: + //! @name Creators + //@{ + /*! + @brief Constructor to open a Photoshop image. Since the + constructor can not return a result, callers should check the + good() method after object construction to determine success + or failure. + @param io An auto-pointer that owns a BasicIo instance used for + reading and writing image metadata. \b Important: The constructor + takes ownership of the passed in BasicIo instance through the + auto-pointer. Callers should not continue to use the BasicIo + instance after it is passed to this method. Use the Image::io() + method to get a temporary reference. + */ + PsdImage(BasicIo::AutoPtr io); + //@} + + //! @name Manipulators + //@{ + void readMetadata(); + /*! + @brief Todo: Write metadata back to the image. This method is not + yet implemented. Calling it will throw an Error(31). + */ + void writeMetadata(); + /*! + @brief Todo: Not supported yet. Calling this function will throw + an instance of Error(32). + */ + void setExifData(const ExifData& exifData); + /*! + @brief Todo: Not supported yet. Calling this function will throw + an instance of Error(32). + */ + void setIptcData(const IptcData& iptcData); + /*! + @brief Todo: Not supported yet. Calling this function will throw + an instance of Error(32). + */ + void setComment(const std::string& comment); + //@} + + //! @name Accessors + //@{ + /*! + @brief Return the MIME type of the image. + + The MIME type returned for Photoshop images is "image/x-photoshop". + + @note This should really be "image/vnd.adobe.photoshop" + (officially registered with IANA in December 2005 -- see + http://www.iana.org/assignments/media-types/image/vnd.adobe.photoshop) + but Apple, as of Tiger (10.4.8), maps this official MIME type to a + dynamic UTI, rather than "com.adobe.photoshop-image" as it should. + */ + std::string mimeType() const { return "image/x-photoshop"; } + //@} + + private: + //! @name Manipulators + //@{ + void processResourceBlock(uint16_t resourceId, uint32_t resourceSize); + //@} + + }; // class PsdImage + +// ***************************************************************************** +// template, inline and free functions + + // These could be static private functions on Image subclasses but then + // ImageFactory needs to be made a friend. + /*! + @brief Create a new PsdImage instance and return an auto-pointer to it. + Caller owns the returned object and the auto-pointer ensures that + it will be deleted. + */ + Image::AutoPtr newPsdInstance(BasicIo::AutoPtr io, bool create); + + //! Check if the file iIo is a Photoshop image. + bool isPsdType(BasicIo& iIo, bool advance); + +} // namespace Exiv2 + +#endif // #ifndef PSDIMAGE_HPP_ diff --git a/src/rafimage.cpp b/src/rafimage.cpp index a9b3ab09..622586f6 100644 --- a/src/rafimage.cpp +++ b/src/rafimage.cpp @@ -59,6 +59,18 @@ namespace Exiv2 { { } // RafImage::RafImage + int RafImage::pixelWidth() const + { + Exiv2::ExifData::const_iterator widthIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); + return (widthIter == exifData_.end()) ? 0 : widthIter->toLong(); + } + + int RafImage::pixelHeight() const + { + Exiv2::ExifData::const_iterator heightIter = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); + return (heightIter == exifData_.end()) ? 0 : heightIter->toLong(); + } + void RafImage::setExifData(const ExifData& /*exifData*/) { // Todo: implement me! diff --git a/src/rafimage.hpp b/src/rafimage.hpp index 053010a7..7b8ff45e 100644 --- a/src/rafimage.hpp +++ b/src/rafimage.hpp @@ -103,6 +103,8 @@ namespace Exiv2 { //! @name Accessors //@{ std::string mimeType() const { return "image/x-fuji-raf"; } + int pixelWidth() const; + int pixelHeight() const; //@} private: diff --git a/src/tgaimage.cpp b/src/tgaimage.cpp new file mode 100644 index 00000000..5c0f7fc7 --- /dev/null +++ b/src/tgaimage.cpp @@ -0,0 +1,170 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 Andreas Huggel + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/* + File: tgaimage.cpp + Version: $Rev$ + Author(s): Marco Piovanelli, Ovolabs (marco) + History: 05-Mar-2007, marco: created + */ +// ***************************************************************************** +#include "rcsid.hpp" +EXIV2_RCSID("@(#) $Id$") + +//#define DEBUG 1 + +// ***************************************************************************** +// included header files +#ifdef _MSC_VER +# include "exv_msvc.h" +#else +# include "exv_conf.h" +#endif +#include "tgaimage.hpp" +#include "image.hpp" +#include "basicio.hpp" +#include "error.hpp" +#include "futils.hpp" + +// + standard includes +#include +#include +#include + +// ***************************************************************************** +// class member definitions +namespace Exiv2 { + + TgaImage::TgaImage(BasicIo::AutoPtr io) + : Image(ImageType::tga, mdNone, io) + { + } // TgaImage::TgaImage + + void TgaImage::setExifData(const ExifData& /*exifData*/) + { + // Todo: implement me! + throw(Error(32, "Exif metadata", "TGA")); + } + + void TgaImage::setIptcData(const IptcData& /*iptcData*/) + { + // Todo: implement me! + throw(Error(32, "IPTC metadata", "TGA")); + } + + void TgaImage::setComment(const std::string& /*comment*/) + { + // not supported + throw(Error(32, "Image comment", "TGA")); + } + + void TgaImage::readMetadata() + { +#ifdef DEBUG + std::cerr << "Exiv2::TgaImage::readMetadata: Reading TARGA file " << io_->path() << "\n"; +#endif + if (io_->open() != 0) + { + throw Error(9, io_->path(), strError()); + } + IoCloser closer(*io_); + // Ensure that this is the correct image type + if (!isTgaType(*io_, false)) + { + if (io_->error() || io_->eof()) throw Error(14); + throw Error(3, "TGA"); + } + clearMetadata(); + + /* + The TARGA header goes as follows -- all numbers are in little-endian byte order: + + offset length name description + ====== ======= ======================= =========== + 0 1 byte ID length length of image ID (0 to 255) + 1 1 byte color map type 0 = no color map; 1 = color map included + 2 1 byte image type 0 = no image; + 1 = uncompressed color-mapped; + 2 = uncompressed true-color; + 3 = uncompressed black-and-white; + 9 = RLE-encoded color mapped; + 10 = RLE-encoded true-color; + 11 = RLE-encoded black-and-white + 3 5 bytes color map specification + 8 2 bytes x-origin of image + 10 2 bytes y-origin of image + 12 2 bytes image width + 14 2 bytes image height + 16 1 byte pixel depth + 17 1 byte image descriptor + */ + byte buf[18]; + if (io_->read(buf, sizeof(buf)) == sizeof(buf)) + { + pixelWidth_ = getShort(buf + 12, littleEndian); + pixelHeight_ = getShort(buf + 14, littleEndian); + } + } // TgaImage::readMetadata + + void TgaImage::writeMetadata() + { + // Todo: implement me! + throw(Error(31, "TGA")); + } // TgaImage::writeMetadata + + // ************************************************************************* + // free functions + Image::AutoPtr newTgaInstance(BasicIo::AutoPtr io, bool /*create*/) + { + Image::AutoPtr image(new TgaImage(io)); + if (!image->good()) + { + image.reset(); + } + return image; + } + + bool isTgaType(BasicIo& iIo, bool /*advance*/) + { + // not all TARGA files have a signature string, so first just try to match the file name extension + std::string path = iIo.path(); + if(path.rfind(".tga") != std::string::npos || path.rfind(".TGA") != std::string::npos) + { + return true; + } + + byte buf[26]; + long curPos = iIo.tell(); + iIo.seek(-26, BasicIo::end); + if (iIo.error() || iIo.eof()) + { + return false; + } + iIo.read(buf, sizeof(buf)); + if (iIo.error()) + { + return false; + } + // some TARGA files, but not all, have a signature string at the end + bool matched = (memcmp(buf + 8, "TRUEVISION-XFILE", 16) == 0); + iIo.seek(curPos, BasicIo::beg); + return matched; + } +} // namespace Exiv2 diff --git a/src/tgaimage.hpp b/src/tgaimage.hpp new file mode 100644 index 00000000..810d6a57 --- /dev/null +++ b/src/tgaimage.hpp @@ -0,0 +1,135 @@ +// ***************************************************************** -*- C++ -*- +/* + * Copyright (C) 2004-2008 Andreas Huggel + * + * 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., 51 Franklin Street, 5th Floor, Boston, MA 02110-1301 USA. + */ +/*! + @file tgaimage.hpp + @brief Truevision TARGA v2 image, implemented using the following references: + Truevision TGA page on Wikipedia
+ TGA(tm) File Format Specification + @version $Rev$ + @author Marco Piovanelli, Ovolabs (marco) + marco.piovanelli@pobox.com + @date 05-Mar-2007, marco: created + */ +#ifndef TGAIMAGE_HPP_ +#define TGAIMAGE_HPP_ + +// ***************************************************************************** +// included header files +#include "exif.hpp" +#include "iptc.hpp" +#include "image.hpp" + +// + standard includes +#include + +// ***************************************************************************** +// namespace extensions +namespace Exiv2 { + +// ***************************************************************************** +// class definitions + + // Add TARGA to the supported image formats + namespace ImageType { + const int tga = 13; //!< Truevision TARGA (tga) image type (see class TgaImage) + } + + /*! + @brief Class to access raw TARGA images. This is just a stub - we only + read width and height. + */ + class TgaImage : public Image { + //! @name NOT Implemented + //@{ + //! Copy constructor + TgaImage(const TgaImage& rhs); + //! Assignment operator + TgaImage& operator=(const TgaImage& rhs); + //@} + + public: + //! @name Creators + //@{ + /*! + @brief Constructor to open a Targa image. Since the + constructor can not return a result, callers should check the + good() method after object construction to determine success + or failure. + @param io An auto-pointer that owns a BasicIo instance used for + reading and writing image metadata. \b Important: The constructor + takes ownership of the passed in BasicIo instance through the + auto-pointer. Callers should not continue to use the BasicIo + instance after it is passed to this method. Use the Image::io() + method to get a temporary reference. + */ + TgaImage(BasicIo::AutoPtr io); + //@} + + //! @name Manipulators + //@{ + void readMetadata(); + /*! + @brief Todo: Write metadata back to the image. This method is not + yet(?) implemented. Calling it will throw an Error(31). + */ + void writeMetadata(); + /*! + @brief Todo: Not supported yet(?). Calling this function will throw + an instance of Error(32). + */ + void setExifData(const ExifData& exifData); + /*! + @brief Todo: Not supported yet(?). Calling this function will throw + an instance of Error(32). + */ + void setIptcData(const IptcData& iptcData); + /*! + @brief Not supported. Calling this function will throw an instance + of Error(32). + */ + void setComment(const std::string& comment); + //@} + + //! @name Accessors + //@{ + std::string mimeType() const { return "image/targa"; } + //@} + + }; // class TgaImage + +// ***************************************************************************** +// template, inline and free functions + + // These could be static private functions on Image subclasses but then + // ImageFactory needs to be made a friend. + /*! + @brief Create a new TgaImage instance and return an auto-pointer to it. + Caller owns the returned object and the auto-pointer ensures that + it will be deleted. + */ + Image::AutoPtr newTgaInstance(BasicIo::AutoPtr io, bool create); + + //! Check if the file iIo is a Targa v2 image. + bool isTgaType(BasicIo& iIo, bool advance); + +} // namespace Exiv2 + +#endif // #ifndef TGAIMAGE_HPP_ diff --git a/src/tiffimage.cpp b/src/tiffimage.cpp index 15964ca0..aa04a2c7 100644 --- a/src/tiffimage.cpp +++ b/src/tiffimage.cpp @@ -59,6 +59,26 @@ namespace Exiv2 { { } // TiffImage::TiffImage + int TiffImage::pixelWidth() const + { + ExifData::const_iterator imageWidth; + if ((imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth"))) != exifData_.end()) + { + return imageWidth->toLong(); + } + return 0; + } + + int TiffImage::pixelHeight() const + { + ExifData::const_iterator imageHeight; + if ((imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageLength"))) != exifData_.end()) + { + return imageHeight->toLong(); + } + return 0; + } + void TiffImage::setExifData(const ExifData& /*exifData*/) { // Todo: implement me! diff --git a/src/tiffimage.hpp b/src/tiffimage.hpp index eed2efea..bc3702f6 100644 --- a/src/tiffimage.hpp +++ b/src/tiffimage.hpp @@ -103,6 +103,8 @@ namespace Exiv2 { //! @name Accessors //@{ std::string mimeType() const { return "image/tiff"; } + int pixelWidth() const; + int pixelHeight() const; //@} private: diff --git a/src/types.hpp b/src/types.hpp index 40407f21..0731fa88 100644 --- a/src/types.hpp +++ b/src/types.hpp @@ -90,7 +90,7 @@ namespace Exiv2 { enum ByteOrder { invalidByteOrder, littleEndian, bigEndian }; //! An identifier for each type of metadata - enum MetadataId { mdExif=1, mdIptc=2, mdComment=4, mdXmp=8 }; + enum MetadataId { mdNone=0, mdExif=1, mdIptc=2, mdComment=4, mdXmp=8 }; //! An identifier for each mode of metadata support enum AccessMode { amNone=0, amRead=1, amWrite=2, amReadWrite=3 }; diff --git a/test/data/exiv2-test.out b/test/data/exiv2-test.out index 069861aa..4a4dad2b 100644 --- a/test/data/exiv2-test.out +++ b/test/data/exiv2-test.out @@ -204,10 +204,16 @@ Renaming file to ./20060127_225027.jpg Print -------------------------------------------------------------------- File 1/15: exiv2-empty.jpg +exiv2-empty.jpg File name : exiv2-empty.jpg +exiv2-empty.jpg File size : 4745 Bytes +exiv2-empty.jpg MIME type : image/jpeg +exiv2-empty.jpg Image size : 150 x 91 exiv2-empty.jpg: No Exif data found in the file File 2/15: 20031214_000043.jpg 20031214_000043.jpg File name : 20031214_000043.jpg 20031214_000043.jpg File size : 12425 Bytes +20031214_000043.jpg MIME type : image/jpeg +20031214_000043.jpg Image size : 150 x 91 20031214_000043.jpg Camera make : Canon 20031214_000043.jpg Camera model : Canon PowerShot S40 20031214_000043.jpg Image timestamp : 2003:12:14 00:00:43 @@ -230,9 +236,11 @@ File 2/15: 20031214_000043.jpg 20031214_000043.jpg Copyright : 20031214_000043.jpg Exif comment : -File 3 /15: 20000506_020544.jpg +File 3/15: 20000506_020544.jpg 20000506_020544.jpg File name : 20000506_020544.jpg 20000506_020544.jpg File size : 19152 Bytes +20000506_020544.jpg MIME type : image/jpeg +20000506_020544.jpg Image size : 150 x 91 20000506_020544.jpg Camera make : NIKON 20000506_020544.jpg Camera model : E990 20000506_020544.jpg Image timestamp : 2000:05:06 02:05:44 @@ -255,9 +263,11 @@ File 3 /15: 20000506_020544.jpg 20000506_020544.jpg Copyright : 20000506_020544.jpg Exif comment : -File 4 /15: 20040329_224245.jpg +File 4/15: 20040329_224245.jpg 20040329_224245.jpg File name : 20040329_224245.jpg 20040329_224245.jpg File size : 44129 Bytes +20040329_224245.jpg MIME type : image/jpeg +20040329_224245.jpg Image size : 150 x 91 20040329_224245.jpg Camera make : NIKON CORPORATION 20040329_224245.jpg Camera model : NIKON D70 20040329_224245.jpg Image timestamp : 2004:03:29 22:42:45 @@ -280,9 +290,11 @@ File 4 /15: 20040329_224245.jpg 20040329_224245.jpg Copyright : 20040329_224245.jpg Exif comment : -File 5 /15: 20010405_235039.jpg +File 5/15: 20010405_235039.jpg 20010405_235039.jpg File name : 20010405_235039.jpg 20010405_235039.jpg File size : 11984 Bytes +20010405_235039.jpg MIME type : image/jpeg +20010405_235039.jpg Image size : 150 x 91 20010405_235039.jpg Camera make : NIKON 20010405_235039.jpg Camera model : E950 20010405_235039.jpg Image timestamp : 2001:04:05 23:50:39 @@ -305,9 +317,11 @@ File 5 /15: 20010405_235039.jpg 20010405_235039.jpg Copyright : 20010405_235039.jpg Exif comment : -File 6 /15: 20030925_201850.jpg +File 6/15: 20030925_201850.jpg 20030925_201850.jpg File name : 20030925_201850.jpg 20030925_201850.jpg File size : 17033 Bytes +20030925_201850.jpg MIME type : image/jpeg +20030925_201850.jpg Image size : 150 x 91 20030925_201850.jpg Camera make : Canon 20030925_201850.jpg Camera model : Canon EOS 300D DIGITAL 20030925_201850.jpg Image timestamp : 2003:09:25 20:18:50 @@ -330,9 +344,11 @@ File 6 /15: 20030925_201850.jpg 20030925_201850.jpg Copyright : 20030925_201850.jpg Exif comment : -File 7 /15: 20001026_044550.jpg +File 7/15: 20001026_044550.jpg 20001026_044550.jpg File name : 20001026_044550.jpg 20001026_044550.jpg File size : 26485 Bytes +20001026_044550.jpg MIME type : image/jpeg +20001026_044550.jpg Image size : 150 x 91 20001026_044550.jpg Camera make : Eastman Kodak Company 20001026_044550.jpg Camera model : DC210 Zoom (V05.00) 20001026_044550.jpg Image timestamp : 2000:10:26 04:45:50 @@ -355,9 +371,11 @@ File 7 /15: 20001026_044550.jpg 20001026_044550.jpg Copyright : 20001026_044550.jpg Exif comment : -File 8 /15: 20030926_111535.jpg +File 8/15: 20030926_111535.jpg 20030926_111535.jpg File name : 20030926_111535.jpg 20030926_111535.jpg File size : 15537 Bytes +20030926_111535.jpg MIME type : image/jpeg +20030926_111535.jpg Image size : 150 x 91 20030926_111535.jpg Camera make : FUJIFILM 20030926_111535.jpg Camera model : FinePixS2Pro 20030926_111535.jpg Image timestamp : 2003:09:26 11:15:35 @@ -380,9 +398,11 @@ File 8 /15: 20030926_111535.jpg 20030926_111535.jpg Copyright : 20030926_111535.jpg Exif comment : -File 9 /15: 20040316_075137.jpg +File 9/15: 20040316_075137.jpg 20040316_075137.jpg File name : 20040316_075137.jpg 20040316_075137.jpg File size : 18307 Bytes +20040316_075137.jpg MIME type : image/jpeg +20040316_075137.jpg Image size : 150 x 91 20040316_075137.jpg Camera make : SIGMA 20040316_075137.jpg Camera model : SIGMA SD10 20040316_075137.jpg Image timestamp : 2004:03:16 07:51:37 @@ -408,6 +428,8 @@ File 9 /15: 20040316_075137.jpg File 10/15: 20040208_093744.jpg 20040208_093744.jpg File name : 20040208_093744.jpg 20040208_093744.jpg File size : 19152 Bytes +20040208_093744.jpg MIME type : image/jpeg +20040208_093744.jpg Image size : 150 x 91 20040208_093744.jpg Camera make : OLYMPUS CORPORATION 20040208_093744.jpg Camera model : C8080WZ 20040208_093744.jpg Image timestamp : 2004:02:08 09:37:44 @@ -433,6 +455,8 @@ File 10/15: 20040208_093744.jpg File 11/15: 20050218_212016.jpg 20050218_212016.jpg File name : 20050218_212016.jpg 20050218_212016.jpg File size : 32041 Bytes +20050218_212016.jpg MIME type : image/jpeg +20050218_212016.jpg Image size : 150 x 91 20050218_212016.jpg Camera make : Panasonic 20050218_212016.jpg Camera model : DMC-FZ5 20050218_212016.jpg Image timestamp : 2005:02:18 21:20:16 @@ -458,6 +482,8 @@ File 11/15: 20050218_212016.jpg File 12/15: 20050527_051833.jpg 20050527_051833.jpg File name : 20050527_051833.jpg 20050527_051833.jpg File size : 22844 Bytes +20050527_051833.jpg MIME type : image/jpeg +20050527_051833.jpg Image size : 150 x 91 20050527_051833.jpg Camera make : SONY 20050527_051833.jpg Camera model : DSC-W7 20050527_051833.jpg Image timestamp : 2005:05:27 05:18:33 @@ -484,6 +510,8 @@ File 13/15: 20060802_095200.jpg Warning: Makernote: Pointer to next IFD is out of bounds; ignored. 20060802_095200.jpg File name : 20060802_095200.jpg 20060802_095200.jpg File size : 20733 Bytes +20060802_095200.jpg MIME type : image/jpeg +20060802_095200.jpg Image size : 150 x 91 20060802_095200.jpg Camera make : Canon 20060802_095200.jpg Camera model : Canon EOS 20D 20060802_095200.jpg Image timestamp : 2006:08:02 09:52:00 @@ -509,6 +537,8 @@ Warning: Makernote: Pointer to next IFD is out of bounds; ignored. File 14/15: 20001004_015404.jpg 20001004_015404.jpg File name : 20001004_015404.jpg 20001004_015404.jpg File size : 20617 Bytes +20001004_015404.jpg MIME type : image/jpeg +20001004_015404.jpg Image size : 150 x 91 20001004_015404.jpg Camera make : Canon 20001004_015404.jpg Camera model : Canon EOS D30 20001004_015404.jpg Image timestamp : 2000:10:04 01:54:04 @@ -534,6 +564,8 @@ File 14/15: 20001004_015404.jpg File 15/15: 20060127_225027.jpg 20060127_225027.jpg File name : 20060127_225027.jpg 20060127_225027.jpg File size : 13449 Bytes +20060127_225027.jpg MIME type : image/jpeg +20060127_225027.jpg Image size : 150 x 91 20060127_225027.jpg Camera make : Canon 20060127_225027.jpg Camera model : Canon PowerShot A520 20060127_225027.jpg Image timestamp : 2006:01:27 22:50:27 @@ -4893,34 +4925,94 @@ Erasing Exif data from the file File 15/15: 20060127_225027.jpg Erasing Exif data from the file File 1/15: exiv2-empty.jpg +exiv2-empty.jpg File name : exiv2-empty.jpg +exiv2-empty.jpg File size : 4745 Bytes +exiv2-empty.jpg MIME type : image/jpeg +exiv2-empty.jpg Image size : 150 x 91 exiv2-empty.jpg: No Exif data found in the file File 2/15: 20031214_000043.jpg +20031214_000043.jpg File name : 20031214_000043.jpg +20031214_000043.jpg File size : 4745 Bytes +20031214_000043.jpg MIME type : image/jpeg +20031214_000043.jpg Image size : 150 x 91 20031214_000043.jpg: No Exif data found in the file File 3/15: 20000506_020544.jpg +20000506_020544.jpg File name : 20000506_020544.jpg +20000506_020544.jpg File size : 4745 Bytes +20000506_020544.jpg MIME type : image/jpeg +20000506_020544.jpg Image size : 150 x 91 20000506_020544.jpg: No Exif data found in the file File 4/15: 20040329_224245.jpg +20040329_224245.jpg File name : 20040329_224245.jpg +20040329_224245.jpg File size : 4745 Bytes +20040329_224245.jpg MIME type : image/jpeg +20040329_224245.jpg Image size : 150 x 91 20040329_224245.jpg: No Exif data found in the file File 5/15: 20010405_235039.jpg +20010405_235039.jpg File name : 20010405_235039.jpg +20010405_235039.jpg File size : 4745 Bytes +20010405_235039.jpg MIME type : image/jpeg +20010405_235039.jpg Image size : 150 x 91 20010405_235039.jpg: No Exif data found in the file File 6/15: 20030925_201850.jpg +20030925_201850.jpg File name : 20030925_201850.jpg +20030925_201850.jpg File size : 4745 Bytes +20030925_201850.jpg MIME type : image/jpeg +20030925_201850.jpg Image size : 150 x 91 20030925_201850.jpg: No Exif data found in the file File 7/15: 20001026_044550.jpg +20001026_044550.jpg File name : 20001026_044550.jpg +20001026_044550.jpg File size : 4745 Bytes +20001026_044550.jpg MIME type : image/jpeg +20001026_044550.jpg Image size : 150 x 91 20001026_044550.jpg: No Exif data found in the file File 8/15: 20030926_111535.jpg +20030926_111535.jpg File name : 20030926_111535.jpg +20030926_111535.jpg File size : 4745 Bytes +20030926_111535.jpg MIME type : image/jpeg +20030926_111535.jpg Image size : 150 x 91 20030926_111535.jpg: No Exif data found in the file File 9/15: 20040316_075137.jpg +20040316_075137.jpg File name : 20040316_075137.jpg +20040316_075137.jpg File size : 4745 Bytes +20040316_075137.jpg MIME type : image/jpeg +20040316_075137.jpg Image size : 150 x 91 20040316_075137.jpg: No Exif data found in the file File 10/15: 20040208_093744.jpg +20040208_093744.jpg File name : 20040208_093744.jpg +20040208_093744.jpg File size : 4745 Bytes +20040208_093744.jpg MIME type : image/jpeg +20040208_093744.jpg Image size : 150 x 91 20040208_093744.jpg: No Exif data found in the file File 11/15: 20050218_212016.jpg +20050218_212016.jpg File name : 20050218_212016.jpg +20050218_212016.jpg File size : 4745 Bytes +20050218_212016.jpg MIME type : image/jpeg +20050218_212016.jpg Image size : 150 x 91 20050218_212016.jpg: No Exif data found in the file File 12/15: 20050527_051833.jpg +20050527_051833.jpg File name : 20050527_051833.jpg +20050527_051833.jpg File size : 4745 Bytes +20050527_051833.jpg MIME type : image/jpeg +20050527_051833.jpg Image size : 150 x 91 20050527_051833.jpg: No Exif data found in the file File 13/15: 20060802_095200.jpg +20060802_095200.jpg File name : 20060802_095200.jpg +20060802_095200.jpg File size : 4745 Bytes +20060802_095200.jpg MIME type : image/jpeg +20060802_095200.jpg Image size : 150 x 91 20060802_095200.jpg: No Exif data found in the file File 14/15: 20001004_015404.jpg +20001004_015404.jpg File name : 20001004_015404.jpg +20001004_015404.jpg File size : 4745 Bytes +20001004_015404.jpg MIME type : image/jpeg +20001004_015404.jpg Image size : 150 x 91 20001004_015404.jpg: No Exif data found in the file File 15/15: 20060127_225027.jpg +20060127_225027.jpg File name : 20060127_225027.jpg +20060127_225027.jpg File size : 4745 Bytes +20060127_225027.jpg MIME type : image/jpeg +20060127_225027.jpg Image size : 150 x 91 20060127_225027.jpg: No Exif data found in the file Insert Exif data ---------------------------------------------------------