Added Image::AutoPtr and related updates

Changed some local buffers to DataBuf
v0.27.3
Andreas Huggel 21 years ago
parent 61171b5857
commit f40fba88bf

@ -3,7 +3,7 @@ Library Features:
+ add ExifData::erase(tag)
+ Thumbnail support: set (re-calculate)
+ operator>> for Value, since we already have read()?
+ Use auto_ptr where applicable
+ Use auto_ptr and DataBuf where applicable
+ Use size_t where appropriate
+ Support TIFF type ids
+ Support for broken IFD makernotes (which have corrupted IFD offsets)
@ -13,9 +13,7 @@ Library Features:
+ Write an example using low level IFD classes to print summary Exif info
+ Implement proper error handling
+ Complete support to create Exif data from scratch:
+ set makernote, write makernote tags
+ set thumbnail, write thumbnail tags
+ read and write unknown tags
+ Make it possible to force write from metadata (just an optional arg to write?)
+ Get rid of Image::detach and make Image open files on-demand

@ -20,13 +20,13 @@
*/
/*
File: actions.cpp
Version: $Name: $ $Revision: 1.37 $
Version: $Name: $ $Revision: 1.38 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 08-Dec-03, ahu: created
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.37 $ $RCSfile: actions.cpp,v $");
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.38 $ $RCSfile: actions.cpp,v $");
// *****************************************************************************
// included header files
@ -559,14 +559,14 @@ namespace Action {
<< ": Failed to open the file\n";
return -1;
}
Exiv2::Image* pImage = Exiv2::ImageFactory::instance().open(path_);
if (!pImage) {
Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::instance().open(path_);
if (image.get() == 0) {
std::cerr << path_
<< ": The file contains data of an unknown image type\n";
return -2;
}
int rc = pImage->readMetadata();
pImage->detach();
int rc = image->readMetadata();
image->detach();
if (rc) {
std::cerr << path_
<< ": Could not read metadata\n";
@ -575,8 +575,7 @@ namespace Action {
if (Params::instance().verbose_) {
std::cout << "Jpeg comment: ";
}
std::cout << pImage->comment() << "\n";
delete pImage;
std::cout << image->comment() << "\n";
return 0;
} // Print::printComment
@ -968,61 +967,62 @@ namespace {
<< ": Failed to open the file\n";
return -1;
}
Exiv2::Image* pSource = Exiv2::ImageFactory::instance().open(source);
if (!pSource) {
Exiv2::Image::AutoPtr sourceImage
= Exiv2::ImageFactory::instance().open(source);
if (sourceImage.get() == 0) {
std::cerr << source
<< ": The file contains data of an unknown image type\n";
return -2;
}
int rc = pSource->readMetadata();
pSource->detach();
int rc = sourceImage->readMetadata();
sourceImage->detach();
if (rc) {
std::cerr << source
<< ": Could not read metadata\n";
return 1;
}
Exiv2::Image* pTarget = Exiv2::ImageFactory::instance().open(target);
if (!pTarget) {
pTarget = Exiv2::ImageFactory::instance().create(Exiv2::Image::exv,
target);
Exiv2::Image::AutoPtr targetImage
= Exiv2::ImageFactory::instance().open(target);
if (targetImage.get() == 0) {
targetImage
= Exiv2::ImageFactory::instance().create(Exiv2::Image::exv, target);
}
if (!pTarget) {
if (targetImage.get() == 0) {
std::cerr << target
<< ": Could not open nor create the file\n";
return 2;
}
if ( Params::instance().target_ & Params::ctExif
&& pSource->sizeExifData() > 0) {
&& sourceImage->sizeExifData() > 0) {
if (Params::instance().verbose_) {
std::cout << "Writing Exif data from " << source
<< " to " << target << "\n";
}
pTarget->setExifData(pSource->exifData(), pSource->sizeExifData());
targetImage->setExifData(sourceImage->exifData(),
sourceImage->sizeExifData());
}
if ( Params::instance().target_ & Params::ctIptc
&& pSource->sizeIptcData() > 0) {
&& sourceImage->sizeIptcData() > 0) {
if (Params::instance().verbose_) {
std::cout << "Writing Iptc data from " << source
<< " to " << target << "\n";
}
pTarget->setIptcData(pSource->iptcData(), pSource->sizeIptcData());
targetImage->setIptcData(sourceImage->iptcData(),
sourceImage->sizeIptcData());
}
if ( Params::instance().target_ & Params::ctComment
&& !pSource->comment().empty()) {
&& !sourceImage->comment().empty()) {
if (Params::instance().verbose_) {
std::cout << "Writing Jpeg comment from " << source
<< " to " << target << "\n";
}
pTarget->setComment(pSource->comment());
targetImage->setComment(sourceImage->comment());
}
rc = pTarget->writeMetadata();
rc = targetImage->writeMetadata();
if (rc) {
std::cerr << target <<
": Could not write metadata to file, rc = " << rc << "\n";
}
delete pSource;
delete pTarget;
return rc;
} // metacopy
}

@ -20,14 +20,14 @@
*/
/*
File: exif.cpp
Version: $Name: $ $Revision: 1.63 $
Version: $Name: $ $Revision: 1.64 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 26-Jan-04, ahu: created
11-Feb-04, ahu: isolated as a component
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.63 $ $RCSfile: exif.cpp,v $");
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.64 $ $RCSfile: exif.cpp,v $");
// Define DEBUG_MAKERNOTE to output debug information to std::cerr
#undef DEBUG_MAKERNOTE
@ -160,19 +160,19 @@ namespace Exiv2 {
TiffThumbnail& TiffThumbnail::operator=(const TiffThumbnail& rhs)
{
byte* pNewImage = 0;
DataBuf newImage;
if (rhs.pImage_ && rhs.size_ > 0) {
pNewImage = new byte[rhs.size_];
memcpy(pNewImage, rhs.pImage_, rhs.size_);
newImage.alloc(rhs.size_);
memcpy(newImage.pData_, rhs.pImage_, rhs.size_);
tiffHeader_.read(rhs.pImage_);
ifd_.read(pNewImage + tiffHeader_.offset(),
ifd_.read(newImage.pData_ + tiffHeader_.offset(),
rhs.size_ - tiffHeader_.offset(),
tiffHeader_.byteOrder(), tiffHeader_.offset());
}
offset_ = rhs.offset_;
size_ = rhs.size_;
delete[] pImage_;
pImage_ = pNewImage;
pImage_ = newImage.release();
return *this;
}
@ -385,15 +385,15 @@ namespace Exiv2 {
JpegThumbnail& JpegThumbnail::operator=(const JpegThumbnail& rhs)
{
byte* pNewImage = 0;
DataBuf newImage;
if (rhs.pImage_ && rhs.size_ > 0) {
pNewImage = new byte[rhs.size_];
memcpy(pNewImage, rhs.pImage_, rhs.size_);
newImage.alloc(rhs.size_);
memcpy(newImage.pData_, rhs.pImage_, rhs.size_);
}
offset_ = rhs.offset_;
size_ = rhs.size_;
delete[] pImage_;
pImage_ = pNewImage;
pImage_ = newImage.release();
return *this;
}
@ -511,22 +511,22 @@ namespace Exiv2 {
int ExifData::read(const std::string& path)
{
if (!fileExists(path, true)) return -1;
Image* pImage = ImageFactory::instance().open(path);
if (pImage) {
int rc = pImage->readMetadata();
if (rc == 0) {
if (pImage->sizeExifData() > 0) {
rc = read(pImage->exifData(), pImage->sizeExifData());
}
else {
rc = 3;
}
Image::AutoPtr image = ImageFactory::instance().open(path);
if (image.get() == 0) {
// We don't know this type of file
return -2;
}
int rc = image->readMetadata();
if (rc == 0) {
if (image->sizeExifData() > 0) {
rc = read(image->exifData(), image->sizeExifData());
}
else {
rc = 3;
}
delete pImage;
return rc;
}
// We don't know this type of file
return -2;
return rc;
}
int ExifData::read(const byte* buf, long len)
@ -633,16 +633,15 @@ namespace Exiv2 {
int ExifData::erase(const std::string& path) const
{
if (!fileExists(path, true)) return -1;
Image* pImage = ImageFactory::instance().open(path);
if (pImage == 0) return -2;
Image::AutoPtr image = ImageFactory::instance().open(path);
if (image.get() == 0) return -2;
// Read all metadata then erase only Exif data
int rc = pImage->readMetadata();
int rc = image->readMetadata();
if (rc == 0) {
pImage->clearExifData();
rc = pImage->writeMetadata();
image->clearExifData();
rc = image->writeMetadata();
}
delete pImage;
return rc;
} // ExifData::erase
@ -652,20 +651,19 @@ namespace Exiv2 {
if (count() == 0 && !pThumbnail_) return erase(path);
if (!fileExists(path, true)) return -1;
Image* pImage = ImageFactory::instance().open(path);
if (pImage == 0) return -2;
Image::AutoPtr image = ImageFactory::instance().open(path);
if (image.get() == 0) return -2;
DataBuf buf(size());
long actualSize = copy(buf.pData_);
assert(actualSize <= buf.size_);
// Read all metadata to preserve non-Exif data
int rc = pImage->readMetadata();
int rc = image->readMetadata();
if (rc == 0) {
pImage->setExifData(buf.pData_, actualSize);
rc = pImage->writeMetadata();
image->setExifData(buf.pData_, actualSize);
rc = image->writeMetadata();
}
delete pImage;
return rc;
} // ExifData::write

@ -20,7 +20,7 @@
*/
/*
File: image.cpp
Version: $Name: $ $Revision: 1.26 $
Version: $Name: $ $Revision: 1.27 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
Brad Schick (brad) <schick@robotbattle.com>
History: 26-Jan-04, ahu: created
@ -29,7 +29,7 @@
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.26 $ $RCSfile: image.cpp,v $");
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.27 $ $RCSfile: image.cpp,v $");
// *****************************************************************************
// included header files
@ -71,14 +71,14 @@ namespace Exiv2 {
@brief Create a new ExvImage instance and return a pointer to it. Caller
is responsible to delete the object when it is no longer needed.
*/
Image* newExvInstance(const std::string& path, FILE* fp);
Image::AutoPtr newExvInstance(const std::string& path, FILE* fp);
//! Check if the file ifp is an EXV file.
bool isExvType(FILE* ifp, bool advance);
/*!
@brief Create a new JpegImage instance and return a pointer to it. Caller
is responsible to delete the object when it is no longer needed.
@brief Create a new JpegImage instance and return an auto-pointer to it.
Caller owns the returned object.
*/
Image* newJpegInstance(const std::string& path, FILE* fp);
Image::AutoPtr newJpegInstance(const std::string& path, FILE* fp);
//! Check if the file ifp is a JPEG image.
bool isJpegType(FILE* ifp, bool advance);
@ -125,31 +125,33 @@ namespace Exiv2 {
return type;
} // ImageFactory::getType
Image* ImageFactory::open(const std::string& path) const
Image::AutoPtr ImageFactory::open(const std::string& path) const
{
Image::AutoPtr image;
FILE* ifp = fopen(path.c_str(), "rb");
if (!ifp) return 0;
if (!ifp) return image;
Image* pImage = 0;
Registry::const_iterator b = registry_.begin();
Registry::const_iterator e = registry_.end();
for (Registry::const_iterator i = b; i != e; ++i)
{
if (i->second.isThisType(ifp, false)) {
pImage = i->second.newInstance(path, ifp);
image = Image::AutoPtr(i->second.newInstance(path, ifp));
break;
}
}
return pImage;
return image;
} // ImageFactory::open
Image* ImageFactory::create(Image::Type type, const std::string& path) const
Image::AutoPtr ImageFactory::create(Image::Type type,
const std::string& path) const
{
Registry::const_iterator i = registry_.find(type);
if (i != registry_.end()) {
return i->second.newInstance(path, 0);
}
return 0;
Image::AutoPtr p;
return p;
} // ImageFactory::create
@ -709,20 +711,17 @@ namespace Exiv2 {
return isJpegType(ifp, advance);
}
Image* newJpegInstance(const std::string& path, FILE* fp)
Image::AutoPtr newJpegInstance(const std::string& path, FILE* fp)
{
Image* pImage = 0;
Image::AutoPtr image;
if (fp == 0) {
pImage = new JpegImage(path, true);
if (!pImage->good()) {
delete pImage;
pImage = 0;
}
image = Image::AutoPtr(new JpegImage(path, true));
if (!image->good()) delete image.release();
}
else {
pImage = new JpegImage(path, fp);
image = Image::AutoPtr(new JpegImage(path, fp));
}
return pImage;
return image;
}
bool isJpegType(FILE* ifp, bool advance)
@ -765,20 +764,17 @@ namespace Exiv2 {
return isExvType(ifp, advance);
}
Image* newExvInstance(const std::string& path, FILE* fp)
Image::AutoPtr newExvInstance(const std::string& path, FILE* fp)
{
Image* pImage = 0;
Image::AutoPtr image;
if (fp == 0) {
pImage = new ExvImage(path, true);
if (!pImage->good()) {
delete pImage;
pImage = 0;
}
image = Image::AutoPtr(new ExvImage(path, true));
if (!image->good()) delete image.release();
}
else {
pImage = new ExvImage(path, fp);
image = Image::AutoPtr(new ExvImage(path, fp));
}
return pImage;
return image;
}
bool isExvType(FILE* ifp, bool advance)

@ -21,7 +21,7 @@
/*!
@file image.hpp
@brief Class JpegImage to access JPEG images
@version $Name: $ $Revision: 1.20 $
@version $Name: $ $Revision: 1.21 $
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@author Brad Schick (brad)
@ -40,19 +40,12 @@
// + standard includes
#include <string>
#include <map>
#include <memory>
// *****************************************************************************
// namespace extensions
namespace Exiv2 {
//! Type for function pointer that creates new Image instances
typedef class Image* (*NewInstanceFct)(const std::string& path, FILE* ifp);
//! Type for function pointer that checks image types
typedef bool (*IsThisTypeFct)(FILE* ifp, bool advance);
// *****************************************************************************
// class definitions
@ -61,6 +54,9 @@ namespace Exiv2 {
*/
class Image {
public:
//! Image auto_ptr type
typedef std::auto_ptr<Image> AutoPtr;
//! Supported image formats
enum Type { none, jpeg, exv };
@ -181,6 +177,12 @@ namespace Exiv2 {
}; // class Image
//! Type for function pointer that creates new Image instances
typedef Image::AutoPtr (*NewInstanceFct)(const std::string& path,
FILE* ifp);
//! Type for function pointer that checks image types
typedef bool (*IsThisTypeFct)(FILE* ifp, bool advance);
/*!
@brief Image factory.
@ -218,21 +220,19 @@ namespace Exiv2 {
@param path %Image file. The contents of the file are tested to
determine the image type to open. File extension is ignored.
@return A pointer that owns an %Image of the type derived from the
file. Caller must delete the returned object. If no image type
could be determined, the pointer is 0.
file. If no image type could be determined, the pointer is 0.
*/
Image* open(const std::string& path) const;
Image::AutoPtr open(const std::string& path) const;
/*!
@brief Create an %Image of the requested type by creating a new
file. If the file already exists, it will be overwritten.
@param type Type of the image to be created.
@param path %Image file. The contents of the file are tested to
determine the image type to open. File extension is ignored.
@return A pointer that owns an %Image of the requested type. Caller
must delete the returned object. If the image type is not
supported, the pointer is 0.
@return An auto-pointer that owns an %Image of the requested type.
If the image type is not supported, the pointer is 0.
*/
Image* create(Image::Type type, const std::string& path) const;
Image::AutoPtr create(Image::Type type, const std::string& path) const;
/*!
@brief Returns the image type of the provided file.
@param path %Image file. The contents of the file are tested to
@ -481,7 +481,7 @@ namespace Exiv2 {
@brief Helper class to access JPEG images
*/
class JpegImage : public JpegBase {
friend Image* newJpegInstance(const std::string& path, FILE* fp);
friend Image::AutoPtr newJpegInstance(const std::string& path, FILE* fp);
friend bool isJpegType(FILE* ifp, bool advance);
public:
//! @name Creators
@ -550,7 +550,7 @@ namespace Exiv2 {
//! Helper class to access %Exiv2 files
class ExvImage : public JpegBase {
friend Image* newExvInstance(const std::string& path, FILE* fp);
friend Image::AutoPtr newExvInstance(const std::string& path, FILE* fp);
friend bool isExvType(FILE* ifp, bool advance);
public:
//! @name Creators

@ -20,13 +20,13 @@
*/
/*
File: iptc.cpp
Version: $Name: $ $Revision: 1.6 $
Version: $Name: $ $Revision: 1.7 $
Author(s): Brad Schick (brad) <schick@robotbattle.com>
History: 31-July-04, brad: created
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.6 $ $RCSfile: iptc.cpp,v $");
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.7 $ $RCSfile: iptc.cpp,v $");
// Define DEBUG_MAKERNOTE to output debug information to std::cerr
#undef DEBUG_MAKERNOTE
@ -114,22 +114,22 @@ namespace Exiv2 {
int IptcData::read(const std::string& path)
{
if (!fileExists(path, true)) return -1;
Image* pImage = ImageFactory::instance().open(path);
if (pImage) {
int rc = pImage->readMetadata();
if (rc == 0) {
if (pImage->sizeIptcData() > 0) {
rc = read(pImage->iptcData(), pImage->sizeIptcData());
}
else {
rc = 3;
}
Image::AutoPtr image = ImageFactory::instance().open(path);
if (image.get() == 0) {
// We don't know this type of file
return -2;
}
int rc = image->readMetadata();
if (rc == 0) {
if (image->sizeIptcData() > 0) {
rc = read(image->iptcData(), image->sizeIptcData());
}
else {
rc = 3;
}
delete pImage;
return rc;
}
// We don't know this type of file
return -2;
return rc;
}
int IptcData::read(const byte* buf, long len)
@ -204,16 +204,15 @@ namespace Exiv2 {
int IptcData::erase(const std::string& path) const
{
if (!fileExists(path, true)) return -1;
Image* pImage = ImageFactory::instance().open(path);
if (pImage == 0) return -2;
Image::AutoPtr image = ImageFactory::instance().open(path);
if (image.get() == 0) return -2;
// Read all metadata then erase only Iptc data
int rc = pImage->readMetadata();
if( rc == 0 ) {
pImage->clearIptcData();
rc = pImage->writeMetadata();
int rc = image->readMetadata();
if (rc == 0) {
image->clearIptcData();
rc = image->writeMetadata();
}
delete pImage;
return rc;
} // IptcData::erase
@ -223,18 +222,17 @@ namespace Exiv2 {
if (count() == 0) return erase(path);
if (!fileExists(path, true)) return -1;
Image* pImage = ImageFactory::instance().open(path);
if (pImage == 0) return -2;
Image::AutoPtr image = ImageFactory::instance().open(path);
if (image.get() == 0) return -2;
updateBuffer();
// Read all metadata to preserve non-Iptc data
int rc = pImage->readMetadata();
if( rc == 0 ) {
pImage->setIptcData(pData_, size_);
rc = pImage->writeMetadata();
int rc = image->readMetadata();
if (rc == 0) {
image->setIptcData(pData_, size_);
rc = image->writeMetadata();
}
delete pImage;
return rc;
} // IptcData::write

@ -22,7 +22,7 @@
Abstract : Tester application for image file handling
File : metacopy.cpp
Version : $Name: $ $Revision: 1.1 $
Version : $Name: $ $Revision: 1.2 $
Author(s): Brad Schick (brad) <schick@robotbattle.com>
History : 13-Jul-04, brad: created
*/
@ -50,8 +50,9 @@ try {
return 2;
}
Exiv2::Image* readImg = Exiv2::ImageFactory::instance().open(params.read_);
if (!readImg) {
Exiv2::Image::AutoPtr readImg
= Exiv2::ImageFactory::instance().open(params.read_);
if (readImg.get() == 0) {
std::cerr << params.progname() <<
": Could not read file (" << params.read_ << ")\n";
return 4;
@ -63,8 +64,9 @@ try {
}
readImg->detach();
Exiv2::Image* writeImg = Exiv2::ImageFactory::instance().open(params.write_);
if (!writeImg) {
Exiv2::Image::AutoPtr writeImg
= Exiv2::ImageFactory::instance().open(params.write_);
if (writeImg.get() == 0) {
std::cerr << params.progname() <<
": Could not read file (" << params.write_ << ")\n";
return 6;
@ -93,8 +95,6 @@ try {
return 8;
}
delete readImg;
delete writeImg;
return 0;
}
catch (Exiv2::Error& e) {

@ -20,14 +20,14 @@
*/
/*
File: types.cpp
Version: $Name: $ $Revision: 1.13 $
Version: $Name: $ $Revision: 1.14 $
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
History: 26-Jan-04, ahu: created
11-Feb-04, ahu: isolated as a component
*/
// *****************************************************************************
#include "rcsid.hpp"
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.13 $ $RCSfile: types.cpp,v $");
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.14 $ $RCSfile: types.cpp,v $");
// *****************************************************************************
// included header files
@ -76,6 +76,23 @@ namespace Exiv2 {
{
return typeInfoTable_[ typeId < lastTypeId ? typeId : 0 ].size_;
}
void DataBuf::alloc(long size)
{
if (size > size_) {
delete[] pData_;
size_ = size;
pData_ = new byte[size];
}
}
byte* DataBuf::release()
{
byte* p = pData_;
pData_ = 0;
size_ = 0;
return p;
}
// *************************************************************************
// free functions

@ -21,7 +21,7 @@
/*!
@file types.hpp
@brief Type definitions for %Exiv2 and related functionality
@version $Name: $ $Revision: 1.21 $
@version $Name: $ $Revision: 1.22 $
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 09-Jan-04, ahu: created<BR>
@ -123,7 +123,7 @@ namespace Exiv2 {
care of memory allocation and deletion. Its primary use is meant to
be as a stack variable in functions that need a temporary data
buffer. Todo: this should be some sort of smart pointer,
essentially an std:auto_ptr for a character array. But it isn't.
essentially an std::auto_ptr for a character array. But it isn't...
*/
class DataBuf {
// Not implemented
@ -139,8 +139,12 @@ namespace Exiv2 {
//! Destructor, deletes the allocated buffer
~DataBuf() { delete[] pData_; }
//! Allocate a data buffer of the given size
void alloc(long size)
{ if( size > size_ ){delete[] pData_; size_ = size; pData_ = new byte[size];} }
void alloc(long size);
/*!
@brief Release ownership of the buffer to the caller. Returns pointer
value, resets pData_ and size_ to 0.
*/
byte* release();
//! The current size of the buffer
long size_;
//! Pointer to the buffer, 0 if none has been allocated

Loading…
Cancel
Save