Added class ExvFile, fixed JpegImage::writeExifData

This commit is contained in:
Andreas Huggel
2004-04-02 09:56:20 +00:00
parent bfd5a4d974
commit ab9ee9da21
2 changed files with 258 additions and 26 deletions
+169 -16
View File
@@ -20,14 +20,14 @@
*/
/*
File: image.cpp
Version: $Name: $ $Revision: 1.9 $
Version: $Name: $ $Revision: 1.10 $
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.9 $ $RCSfile: image.cpp,v $")
EXIV2_RCSID("@(#) $Name: $ $Revision: 1.10 $ $RCSfile: image.cpp,v $")
// *****************************************************************************
// included header files
@@ -225,7 +225,7 @@ namespace Exif {
return 2;
}
// Read and check section marker and size
char tmpbuf[10];
char tmpbuf[11];
is.read(tmpbuf, 10);
if (!is.good()) return 1;
uint16 marker = getUShort(tmpbuf, bigEndian);
@@ -325,28 +325,68 @@ namespace Exif {
}
// Read and check section marker and size
char tmpbuf[12];
char tmpbuf[10];
is.read(tmpbuf, 10);
if (!is.good()) return 1;
uint16 marker = getUShort(tmpbuf, bigEndian);
uint16 size = getUShort(tmpbuf + 2, bigEndian);
if (size < 8) return 3;
if (!( (marker == app0_ && memcmp(tmpbuf + 4, jfifId_, 5) == 0)
|| (marker == app1_ && memcmp(tmpbuf + 4, exifId_, 6) == 0))) {
return 3;
}
// Write SOI and APP1 markers, size of APP1 field, Exif id and Exif data
bool validFile = false;
long sizeJfifData = 0;
char* pJfifData = 0; // Todo: Memory Leak! Use an auto pointer
if (marker == app0_ && memcmp(tmpbuf + 4, jfifId_, 5) == 0) {
// Read the remainder of the JFIF APP0 segment
is.seekg(-1, std::ios::cur);
sizeJfifData = size - 7;
pJfifData = new char[sizeJfifData];
is.read(pJfifData, sizeJfifData);
if (!is.good()) {
delete[] pJfifData;
pJfifData = 0;
return 1;
}
// Read the beginning of the next segment
is.read(tmpbuf, 10);
if (!is.good()) return 1;
marker = getUShort(tmpbuf, bigEndian);
size = getUShort(tmpbuf + 2, bigEndian);
validFile = true;
}
if (marker == app1_ && memcmp(tmpbuf + 4, exifId_, 6) == 0) {
// Skip the rest of the Exif APP1 segment
is.seekg(size - 8, std::ios::cur);
if (!is.good()) return 1;
validFile = true;
}
else {
is.seekg(-10, std::ios::cur);
}
if (!validFile) return 3;
// Write SOI marker
us2Data(tmpbuf, soi_, bigEndian);
us2Data(tmpbuf + 2, app1_, bigEndian);
us2Data(tmpbuf + 4, sizeExifData_ + 8, bigEndian);
memcpy(tmpbuf + 6, exifId_, 6);
os.write(tmpbuf, 12);
os.write(tmpbuf, 2);
if (!os.good()) return 4;
if (pJfifData) {
// Write APP0 marker, size of APP0 field and JFIF data
us2Data(tmpbuf, app0_, bigEndian);
us2Data(tmpbuf + 2, 7 + sizeJfifData, bigEndian);
memcpy(tmpbuf + 4, jfifId_, 5);
os.write(tmpbuf, 9);
os.write(pJfifData, sizeJfifData);
if (!os.good()) return 4;
delete pJfifData;
pJfifData = 0;
}
// Write APP1 marker, size of APP1 field, Exif id and Exif data
us2Data(tmpbuf, app1_, bigEndian);
us2Data(tmpbuf + 2, sizeExifData_ + 8, bigEndian);
memcpy(tmpbuf + 4, exifId_, 6);
os.write(tmpbuf, 10);
os.write(pExifData_, sizeExifData_);
if (!os.good()) return 4;
// Copy rest of the stream
is.ignore(size - 8);
if (!is.good()) return 1;
os.flush();
is >> os.rdbuf();
if (!os.good()) return 4;
@@ -425,6 +465,119 @@ namespace Exif {
us2Data(buf+2, 0x002a, byteOrder_);
ul2Data(buf+4, 0x00000008, byteOrder_);
return size();
}
} // TiffHeader::copy
const uint16 ExvFile::app1_ = 0xffe1;
const char ExvFile::exifId_[] = "Exif\0\0";
ExvFile::ExvFile()
: sizeExifData_(0), pExifData_(0)
{
} // ExvFile default constructor
ExvFile::ExvFile(const ExvFile& rhs)
: sizeExifData_(0), pExifData_(0)
{
char* newExifData = 0;
if (rhs.sizeExifData_ > 0) {
char* newExifData = new char[rhs.sizeExifData_];
memcpy(newExifData, rhs.pExifData_, rhs.sizeExifData_);
}
pExifData_ = newExifData;
sizeExifData_ = rhs.sizeExifData_;
} // ExvFile copy constructor
ExvFile& ExvFile::operator=(const ExvFile& rhs)
{
if (this == &rhs) return *this;
char* newExifData = 0;
if (rhs.sizeExifData_ > 0) {
char* newExifData = new char[rhs.sizeExifData_];
memcpy(newExifData, rhs.pExifData_, rhs.sizeExifData_);
}
pExifData_ = newExifData;
sizeExifData_ = rhs.sizeExifData_;
return *this;
} // ExvFile::operator=
ExvFile::~ExvFile()
{
delete[] pExifData_;
} // ExvFile destructor
int ExvFile::readExifData(const std::string& path)
{
std::ifstream file(path.c_str(), std::ios::binary);
if (!file) return -1;
return readExifData(file);
} // ExvFile::readExifData
int ExvFile::readExifData(std::istream& is)
{
// Check if this is an Exiv2 file in the first place
if (!isThisType(is, false)) {
if (!is.good()) return 1;
return 2;
}
// Read the first ten bytes and extract the size
char tmpbuf[10];
is.read(tmpbuf, 10);
if (!is.good()) return 1;
uint16 size = getUShort(tmpbuf + 2, bigEndian);
if (size < 8) return 3;
// Read the rest of the APP1 field (Exif data)
long sizeExifData = size - 8;
char* pExifData = new char[sizeExifData];
is.read(pExifData, sizeExifData);
if (!is.good()) {
delete[] pExifData;
return 1;
}
sizeExifData_ = sizeExifData;
pExifData_ = pExifData;
return 0;
} // ExvFile::readExifData
void ExvFile::setExifData(const char* buf, long size)
{
sizeExifData_ = size;
delete[] pExifData_;
pExifData_ = new char[size];
memcpy(pExifData_, buf, size);
} // ExvFile::setExifData
bool ExvFile::isThisType(std::istream& is, bool advance)
{
// Read and check section marker and size
char tmpbuf[10];
is.read(tmpbuf, 10);
if (!is.good()) return false;
bool rc = true;
uint16 marker = getUShort(tmpbuf, bigEndian);
uint16 size = getUShort(tmpbuf + 2, bigEndian);
if (size < 8) rc = false;
if (!(marker == app1_ && memcmp(tmpbuf + 4, exifId_, 6) == 0)) {
rc = false;
}
if (!advance) is.seekg(-10, std::ios::cur);
return rc;
} // ExvFile::isThisType
int ExvFile::writeExifData(const std::string& path) const
{
std::ofstream os(path.c_str(), std::ios::binary);
if (!os) return -1;
// Write APP1 marker, size of APP1 field, Exif id and Exif data
char tmpbuf[10];
us2Data(tmpbuf, app1_, bigEndian);
us2Data(tmpbuf + 2, sizeExifData_ + 8, bigEndian);
memcpy(tmpbuf + 4, exifId_, 6);
os.write(tmpbuf, 10);
os.write(pExifData_, sizeExifData_);
if (!os.good()) return 4;
return 0;
} // ExvFile::writeExifData
} // namespace Exif
+89 -10
View File
@@ -21,7 +21,7 @@
/*!
@file image.hpp
@brief Class JpegImage to access JPEG images
@version $Name: $ $Revision: 1.9 $
@version $Name: $ $Revision: 1.10 $
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@date 09-Jan-04, ahu: created
@@ -52,7 +52,7 @@ namespace Exif {
class Image {
public:
//! Supported image formats
enum Type { none, jpeg, exiv2 };
enum Type { none, jpeg };
//! @name Creators
//@{
@@ -126,8 +126,6 @@ namespace Exif {
*/
virtual int eraseExifData(const std::string& path,
std::istream& is) const =0;
/*!
@brief Read from the image input stream is, erase %Exif data from the
image, if there is any, and write the resulting image to the
@@ -138,8 +136,6 @@ namespace Exif {
@return 0 if successful.
*/
virtual int eraseExifData(std::ostream& os, std::istream& is) const =0;
/*!
@brief Write the %Exif data to file path.
@param path Path to the file.
@@ -353,8 +349,6 @@ namespace Exif {
-4 if renaming the temporary file fails.
*/
int eraseExifData(const std::string& path, std::istream& is) const;
/*!
@brief Erase %Exif data from the JPEG image is, write the resulting
image to the output stream os. If an %Exif APP1 section exists
@@ -372,8 +366,6 @@ namespace Exif {
state for more information).
*/
int eraseExifData(std::ostream& os, std::istream& is) const;
/*!
@brief Write the %Exif data to file path, which must contain a JPEG
image. If an %Exif APP1 section exists in the file, it is
@@ -491,6 +483,93 @@ namespace Exif {
uint32 offset_;
}; // class TiffHeader
//! Helper class to access Exiv2 files
class ExvFile {
public:
//! @name Creators
//@{
//! Default Constructor
ExvFile();
//! Destructor
~ExvFile();
//! Copy constructor
ExvFile(const ExvFile& rhs);
//@}
//! @name Manipulators
//@{
//! Assignment operator
ExvFile& operator=(const ExvFile& rhs);
/*!
@brief Read the %Exif data from the file path into the internal
data buffer.
@param path Path to the file.
@return 0 if successful.
*/
int readExifData(const std::string& path);
/*!
@brief Read the %Exif data from the stream is into the internal
data buffer.
@param is Input stream to read from.
@return 0 if successful.
*/
int readExifData(std::istream& is);
/*!
@brief Read the %Exif data from the buffer buf which has size bytes.
@param buf Pointer to the data buffer.
@param size Number of characters in the data buffer.
*/
void setExifData(const char* buf, long size);
//@}
//! @name Accessors
//@{
/*!
@brief Write the %Exif data to file path.
@param path Path to the file.
@return 0 if successful.
*/
int writeExifData(const std::string& path) const;
//! Return the size of the %Exif data in bytes.
long sizeExifData() const { return sizeExifData_; }
/*!
@brief Return a read-only pointer to an %Exif data buffer. Do not
attempt to write to this buffer.
*/
const char* exifData() const { return pExifData_; }
//@}
/*!
@brief Determine if the content of the stream is of the type of this
class.
The advance flag determines if the read position in the stream is
moved (see below). This applies only if the type matches and the
function returns true. If the type does not match, the stream
position is not changed. However, if reading from the stream fails,
the stream position is undefined. Consult the stream state to obtain
more information in this case.
@param is Input stream.
@param advance Flag indicating whether the read position in the stream
should be advanced by the number of characters read to
analyse the stream (true) or left at its original
position (false). This applies only if the type matches.
@return true if the stream data matches the type of this class;<BR>
false if the stream data does not match.
*/
static bool isThisType(std::istream& is, bool advance =false);
private:
// DATA
static const uint16 app1_; // APP1 marker
static const char exifId_[]; // Exif identifier
long sizeExifData_; // Size of the Exif data buffer
char* pExifData_; // Exif data buffer
}; // class ExvFile
} // namespace Exif