New PNG image parser to extract EXIF/IPTC RAW profiles embeded in text tags by ImageMagick/GraphicsMagick during image convertion
Current implementation is read only.
TODO : Fix configure rules about zlib depency require by this implementation.
Optimize image loading.
This commit is contained in:
parent
920da80d70
commit
fa7223d103
@ -75,6 +75,8 @@ CCSRC = basicio.cpp \
|
||||
nikonmn.cpp \
|
||||
olympusmn.cpp \
|
||||
panasonicmn.cpp \
|
||||
pngimage.cpp \
|
||||
pngchunk.cpp \
|
||||
sigmamn.cpp \
|
||||
sonymn.cpp \
|
||||
tags.cpp \
|
||||
@ -193,7 +195,7 @@ endif
|
||||
# Compilation shortcuts
|
||||
COMPILE.cc = $(CXX) $(CXXFLAGS) $(CXXDEFS) $(CXXINCS) -c
|
||||
COMPILE.c = $(CC) $(CFLAGS) $(DEFS) $(INCS) -c
|
||||
LINK.cc = $(CXX) $(CXXFLAGS) $(LDLIBS) $(LDFLAGS) -rpath $(libdir)
|
||||
LINK.cc = $(CXX) $(CXXFLAGS) $(LDLIBS) $(LDFLAGS) -lz -rpath $(libdir)
|
||||
|
||||
# ******************************************************************************
|
||||
# Rules
|
||||
|
||||
@ -37,6 +37,7 @@ EXIV2_RCSID("@(#) $Id$");
|
||||
#include "crwimage.hpp"
|
||||
#include "mrwimage.hpp"
|
||||
#include "tiffimage.hpp"
|
||||
#include "pngimage.hpp"
|
||||
|
||||
// + standard includes
|
||||
|
||||
@ -50,7 +51,8 @@ namespace Exiv2 {
|
||||
// Registry(ImageType::cr2, newCr2Instance, isCr2Type),
|
||||
Registry(ImageType::crw, newCrwInstance, isCrwType),
|
||||
Registry(ImageType::mrw, newMrwInstance, isMrwType),
|
||||
Registry(ImageType::tiff, newTiffInstance, isTiffType)
|
||||
Registry(ImageType::tiff, newTiffInstance, isTiffType),
|
||||
Registry(ImageType::png, newPngInstance, isPngType)
|
||||
};
|
||||
|
||||
} // namespace Exiv2
|
||||
|
||||
334
src/pngchunk.cpp
Normal file
334
src/pngchunk.cpp
Normal file
@ -0,0 +1,334 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2006 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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: pngchunk.cpp
|
||||
Version: $Rev: 816 $
|
||||
History: 07-Jun-06, gc: submitted
|
||||
Credits: See header file
|
||||
*/
|
||||
// *****************************************************************************
|
||||
#include "rcsid.hpp"
|
||||
EXIV2_RCSID("@(#) $Id: pngchunk.cpp 816 2006-06-04 15:21:19Z ahuggel $");
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#ifdef _MSC_VER
|
||||
# include "exv_msvc.h"
|
||||
#else
|
||||
# include "exv_conf.h"
|
||||
#endif
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
// some defines to make it easier
|
||||
#define PNG_CHUNK_TYPE(data, index) &data[index+4]
|
||||
#define PNG_CHUNK_DATA(data, index, offset) data[8+index+offset]
|
||||
#define PNG_CHUNK_HEADER_SIZE 12
|
||||
|
||||
// To uncompress text chunck
|
||||
#include <zlib.h>
|
||||
|
||||
#include "pngchunk.hpp"
|
||||
#include "tiffparser.hpp"
|
||||
#include "exif.hpp"
|
||||
#include "iptc.hpp"
|
||||
#include "image.hpp"
|
||||
#include "error.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
// *****************************************************************************
|
||||
// class member definitions
|
||||
namespace Exiv2 {
|
||||
|
||||
void PngChunk::decode(Image* pImage,
|
||||
const byte* pData,
|
||||
long size)
|
||||
{
|
||||
assert(pImage != 0);
|
||||
assert(pData != 0);
|
||||
|
||||
// look for a tEXt chunk
|
||||
long index = 8;
|
||||
index += getLong(&pData[index], bigEndian) + PNG_CHUNK_HEADER_SIZE;
|
||||
|
||||
while(index < size-PNG_CHUNK_HEADER_SIZE)
|
||||
{
|
||||
while (index < size-PNG_CHUNK_HEADER_SIZE &&
|
||||
strncmp((char*)PNG_CHUNK_TYPE(pData, index), "tEXt", 4) &&
|
||||
strncmp((char*)PNG_CHUNK_TYPE(pData, index), "zTXt", 4))
|
||||
{
|
||||
if (!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "IEND", 4))
|
||||
throw Error(14);
|
||||
|
||||
index += getLong(&pData[index], bigEndian) + PNG_CHUNK_HEADER_SIZE;
|
||||
}
|
||||
|
||||
if (index < size-PNG_CHUNK_HEADER_SIZE)
|
||||
{
|
||||
// we found a tEXt or zTXt field
|
||||
|
||||
// get the key, it's a null terminated string at the chunk start
|
||||
const byte *key = &PNG_CHUNK_DATA(pData, index, 0);
|
||||
|
||||
int keysize=0;
|
||||
for ( ; key[keysize] != 0 ; keysize++)
|
||||
{
|
||||
// look if we reached the end of the file (it might be corrupted)
|
||||
if (8+index+keysize >= size)
|
||||
throw Error(14);
|
||||
}
|
||||
|
||||
DataBuf arr;
|
||||
|
||||
if(!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "zTXt", 4))
|
||||
{
|
||||
// Extract a deflate compressed Latin-1 text chunk
|
||||
|
||||
#ifdef DEBUG
|
||||
std::cerr << "Exiv2::PngChunk::decode: We found a zTXt field\n";
|
||||
#endif
|
||||
// we get the compression method after the key
|
||||
const byte* compressionMethod = &PNG_CHUNK_DATA(pData, index, keysize+1);
|
||||
if ( *compressionMethod != 0x00 )
|
||||
{
|
||||
// then it isn't zlib compressed and we are sunk
|
||||
#ifdef DEBUG
|
||||
std::cerr << "Exiv2::PngChunk::decode: Non-standard compression method.\n";
|
||||
#endif
|
||||
throw Error(14);
|
||||
}
|
||||
|
||||
// compressed string after the compression technique spec
|
||||
const byte* compressedText = &PNG_CHUNK_DATA(pData, index, keysize+2);
|
||||
uint compressedTextSize = getLong(&pData[index], bigEndian)-keysize-2;
|
||||
|
||||
// security check, also considering overflow wraparound from the addition --
|
||||
// we may endup with a /smaller/ index if we wrap all the way around
|
||||
long firstIndex = (long)(compressedText - pData);
|
||||
long onePastLastIndex = firstIndex + compressedTextSize;
|
||||
if ( onePastLastIndex > size || onePastLastIndex <= firstIndex)
|
||||
throw Error(14);
|
||||
|
||||
uLongf uncompressedLen = compressedTextSize * 2; // just a starting point
|
||||
int zlibResult;
|
||||
|
||||
do
|
||||
{
|
||||
arr.alloc(uncompressedLen);
|
||||
zlibResult = uncompress((Bytef*)arr.pData_, &uncompressedLen,
|
||||
compressedText, compressedTextSize);
|
||||
|
||||
if (Z_OK == zlibResult)
|
||||
{
|
||||
// then it is all OK
|
||||
arr.alloc(uncompressedLen);
|
||||
}
|
||||
else if (Z_BUF_ERROR == zlibResult)
|
||||
{
|
||||
// the uncompressedArray needs to be larger
|
||||
#ifdef DEBUG
|
||||
std::cerr << "Exiv2::PngChunk::decode: doubling size for decompression.\n";
|
||||
#endif
|
||||
uncompressedLen *= 2;
|
||||
|
||||
// DoS protection. can't be bigger than 64k
|
||||
if ( uncompressedLen > 131072 )
|
||||
break;
|
||||
}
|
||||
else
|
||||
{
|
||||
// something bad happened
|
||||
throw Error(14);
|
||||
}
|
||||
}
|
||||
while (Z_BUF_ERROR == zlibResult);
|
||||
|
||||
if (zlibResult != Z_OK)
|
||||
throw Error(14);
|
||||
}
|
||||
else if (!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "tEXt", 4))
|
||||
{
|
||||
// Extract a non-compressed Latin-1 text chunk
|
||||
#ifdef DEBUG
|
||||
std::cerr << "Exiv2::PngChunk::decode: We found a tEXt field\n";
|
||||
#endif
|
||||
// the text comes after the key, but isn't null terminated
|
||||
const byte* text = &PNG_CHUNK_DATA(pData, index, keysize+1);
|
||||
long textsize = getLong(&pData[index], bigEndian)-keysize-1;
|
||||
|
||||
// security check, also considering overflow wraparound from the addition --
|
||||
// we may endup with a /smaller/ index if we wrap all the way around
|
||||
long firstIndex = (long)(text - pData);
|
||||
long onePastLastIndex = firstIndex + textsize;
|
||||
|
||||
if ( onePastLastIndex > size || onePastLastIndex <= firstIndex)
|
||||
throw Error(14);
|
||||
|
||||
arr.alloc(textsize);
|
||||
arr = DataBuf(text, textsize);
|
||||
}
|
||||
else
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "Exiv2::PngChunk::decode: We found a field, not expected though\n";
|
||||
#endif
|
||||
throw Error(14);
|
||||
}
|
||||
|
||||
#ifdef DEBUG
|
||||
std::cerr << "Exiv2::PngChunk::decode: Found PNG entry " << std::string((const char*)key) << " / "
|
||||
<< std::string((const char*)arr.pData_, 64) << "\n";
|
||||
#endif
|
||||
|
||||
// We look if an EXIF raw profile exist.
|
||||
|
||||
if ( memcmp("Raw profile type exif", key, 21) == 0 ||
|
||||
memcmp("Raw profile type APP1", key, 21) == 0 )
|
||||
{
|
||||
DataBuf exifData = readRawProfile(arr);
|
||||
long length = exifData.size_;
|
||||
|
||||
if (length > 0)
|
||||
{
|
||||
// Find the position of Exif header in bytes array.
|
||||
|
||||
const byte exifHeader[] = { 0x45, 0x78, 0x69, 0x66, 0x00, 0x00 };
|
||||
long pos = -1;
|
||||
|
||||
for (long i=0 ; i < length-(long)sizeof(exifHeader) ; i++)
|
||||
{
|
||||
if (memcmp(exifHeader, &exifData.pData_[i], sizeof(exifHeader)) == 0)
|
||||
{
|
||||
pos = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// If found it, store only these data at from this place.
|
||||
|
||||
if (pos !=-1)
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "Exiv2::PngChunk::decode: Exif header found at position " << pos << "\n";
|
||||
#endif
|
||||
pos = pos + sizeof(exifHeader);
|
||||
TiffParser::decode(pImage, exifData.pData_+pos, length-pos, TiffCreator::create);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// We look if an IPTC raw profile exist.
|
||||
|
||||
if ( memcmp("Raw profile type iptc", key, 21) == 0 )
|
||||
{
|
||||
DataBuf iptcData = readRawProfile(arr);
|
||||
long length = iptcData.size_;
|
||||
|
||||
if (length > 0)
|
||||
pImage->iptcData().load(iptcData.pData_, length);
|
||||
}
|
||||
|
||||
index += getLong(&pData[index], bigEndian) + PNG_CHUNK_HEADER_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
} // PngChunk::decode
|
||||
|
||||
DataBuf PngChunk::readRawProfile(const DataBuf& text)
|
||||
{
|
||||
DataBuf info;
|
||||
register long i;
|
||||
register unsigned char *dp;
|
||||
const char *sp;
|
||||
uint nibbles;
|
||||
long length;
|
||||
unsigned char unhex[103]={0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,1, 2,3,4,5,6,7,8,9,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,0,0,0,
|
||||
0,0,0,0,0,0,0,0,0,0, 0,0,0,0,0,0,0,10,11,12,
|
||||
13,14,15};
|
||||
|
||||
sp = (char*)text.pData_+1;
|
||||
|
||||
// Look for newline
|
||||
|
||||
while (*sp != '\n')
|
||||
sp++;
|
||||
|
||||
// Look for length
|
||||
|
||||
while (*sp == '\0' || *sp == ' ' || *sp == '\n')
|
||||
sp++;
|
||||
|
||||
length = (long) atol(sp);
|
||||
|
||||
while (*sp != ' ' && *sp != '\n')
|
||||
sp++;
|
||||
|
||||
// Allocate space
|
||||
|
||||
if (length == 0)
|
||||
{
|
||||
std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: invalid profile length\n";
|
||||
return DataBuf();
|
||||
}
|
||||
|
||||
info.alloc(length);
|
||||
|
||||
if (info.size_ != length)
|
||||
{
|
||||
std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: cannot allocate memory\n";
|
||||
return DataBuf();
|
||||
}
|
||||
|
||||
// Copy profile, skipping white space and column 1 "=" signs
|
||||
|
||||
dp = (unsigned char*)info.pData_;
|
||||
nibbles = length * 2;
|
||||
|
||||
for (i = 0; i < (long) nibbles; i++)
|
||||
{
|
||||
while (*sp < '0' || (*sp > '9' && *sp < 'a') || *sp > 'f')
|
||||
{
|
||||
if (*sp == '\0')
|
||||
{
|
||||
std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: ran out of data\n";
|
||||
return DataBuf();
|
||||
}
|
||||
|
||||
sp++;
|
||||
}
|
||||
|
||||
if (i%2 == 0)
|
||||
*dp = (unsigned char) (16*unhex[(int) *sp++]);
|
||||
else
|
||||
(*dp++) += unhex[(int) *sp++];
|
||||
}
|
||||
|
||||
return info;
|
||||
} // PngChunk::readRawProfile
|
||||
} // namespace Exiv2
|
||||
88
src/pngchunk.hpp
Normal file
88
src/pngchunk.hpp
Normal file
@ -0,0 +1,88 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2006 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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 pngchunk.hpp
|
||||
@brief Class PngChunk to parse PNG chunk data.
|
||||
@version $Rev: 808 $
|
||||
@author Andreas Huggel (ahu)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@author Gilles Caulier (gc)
|
||||
<a href="mailto:caulier dot gilles at kdemail dot net">caulier dot gilles at kdemail dot net</a>
|
||||
@date 13-Jun-06, gc: submitted
|
||||
*/
|
||||
#ifndef PNGCHUNK_HPP_
|
||||
#define PNGCHUNK_HPP_
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "types.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <iosfwd>
|
||||
#include <cassert>
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
namespace Exiv2 {
|
||||
|
||||
// *****************************************************************************
|
||||
// class declarations
|
||||
|
||||
class Image;
|
||||
|
||||
// *****************************************************************************
|
||||
// class definitions
|
||||
|
||||
/*!
|
||||
@brief Stateless parser class for data in PNG chunk format. Images use this
|
||||
class to decode and encode PNG-based data.
|
||||
*/
|
||||
class PngChunk {
|
||||
public:
|
||||
/*!
|
||||
@brief Decode PNG chunk metadata from a data buffer \em pData of length
|
||||
\em size into \em pImage.
|
||||
|
||||
@param pImage Pointer to the image to hold the metadata
|
||||
@param pData Pointer to the data buffer. Must point to PNG chunk data;
|
||||
no checks are performed.
|
||||
@param size Length of the data buffer.
|
||||
*/
|
||||
static void decode(Image* pImage,
|
||||
const byte* pData,
|
||||
long size);
|
||||
|
||||
private:
|
||||
//! @name Accessors
|
||||
//@{
|
||||
|
||||
/*!
|
||||
@brief Todo: Decode ImageMagick raw text profile including encoded Exif/Iptc metadata byte array.
|
||||
*/
|
||||
static DataBuf readRawProfile(const DataBuf& text);
|
||||
|
||||
//@}
|
||||
|
||||
}; // class PngChunk
|
||||
|
||||
} // namespace Exiv2
|
||||
|
||||
#endif // #ifndef PNGCHUNK_HPP_
|
||||
187
src/pngimage.cpp
Normal file
187
src/pngimage.cpp
Normal file
@ -0,0 +1,187 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2006 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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: pngimage.cpp
|
||||
Version: $Rev: 808 $
|
||||
History: 07-Jun-06, gc: submitted
|
||||
Credits: See header file
|
||||
*/
|
||||
// *****************************************************************************
|
||||
#include "rcsid.hpp"
|
||||
EXIV2_RCSID("@(#) $Id: pngimage.cpp 808 2006-06-01 15:09:39Z ahuggel $");
|
||||
|
||||
// *****************************************************************************
|
||||
|
||||
#define DEBUG 1
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#ifdef _MSC_VER
|
||||
# include "exv_msvc.h"
|
||||
#else
|
||||
# include "exv_conf.h"
|
||||
#endif
|
||||
|
||||
#include "pngchunk.hpp"
|
||||
#include "pngimage.hpp"
|
||||
#include "image.hpp"
|
||||
#include "basicio.hpp"
|
||||
#include "error.hpp"
|
||||
#include "futils.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <string>
|
||||
#include <cstring>
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
// *****************************************************************************
|
||||
// class member definitions
|
||||
namespace Exiv2 {
|
||||
|
||||
PngImage::PngImage(BasicIo::AutoPtr io, bool create)
|
||||
: Image(mdExif | mdIptc), io_(io)
|
||||
{
|
||||
if (create)
|
||||
{
|
||||
IoCloser closer(*io_);
|
||||
io_->open();
|
||||
}
|
||||
} // PngImage::PngImage
|
||||
|
||||
bool PngImage::good() const
|
||||
{
|
||||
if (io_->open() != 0) return false;
|
||||
IoCloser closer(*io_);
|
||||
return isThisType(*io_, false);
|
||||
}
|
||||
|
||||
void PngImage::clearMetadata()
|
||||
{
|
||||
clearExifData();
|
||||
}
|
||||
|
||||
void PngImage::setMetadata(const Image& image)
|
||||
{
|
||||
setExifData(image.exifData());
|
||||
}
|
||||
|
||||
void PngImage::clearExifData()
|
||||
{
|
||||
exifData_.clear();
|
||||
}
|
||||
|
||||
void PngImage::setExifData(const ExifData& exifData)
|
||||
{
|
||||
exifData_ = exifData;
|
||||
}
|
||||
|
||||
void PngImage::clearIptcData()
|
||||
{
|
||||
iptcData_.clear();
|
||||
}
|
||||
|
||||
void PngImage::setIptcData(const IptcData& iptcData)
|
||||
{
|
||||
iptcData_ = iptcData;
|
||||
}
|
||||
|
||||
void PngImage::clearComment()
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
void PngImage::setComment(const std::string& comment)
|
||||
{
|
||||
// not supported
|
||||
}
|
||||
|
||||
void PngImage::readMetadata()
|
||||
{
|
||||
#ifdef DEBUG
|
||||
std::cerr << "Exiv2::PngImage::readMetadata: Reading PNG 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 (!isThisType(*io_, false))
|
||||
{
|
||||
if (io_->error() || io_->eof()) throw Error(14);
|
||||
throw Error(3, "PNG");
|
||||
}
|
||||
|
||||
clearMetadata();
|
||||
|
||||
DataBuf buf = io_->read(io_->size());
|
||||
if (io_->error() || io_->eof()) throw Error(14);
|
||||
|
||||
PngChunk::decode(this, buf.pData_, buf.size_);
|
||||
|
||||
} // PngImage::readMetadata
|
||||
|
||||
void PngImage::writeMetadata()
|
||||
{
|
||||
/*
|
||||
TODO: implement me!
|
||||
*/
|
||||
} // PngImage::writeMetadata
|
||||
|
||||
bool PngImage::isThisType(BasicIo& iIo, bool advance) const
|
||||
{
|
||||
return isPngType(iIo, advance);
|
||||
}
|
||||
|
||||
// *************************************************************************
|
||||
// free functions
|
||||
|
||||
Image::AutoPtr newPngInstance(BasicIo::AutoPtr io, bool create)
|
||||
{
|
||||
Image::AutoPtr image(new PngImage(io, create));
|
||||
if (!image->good())
|
||||
{
|
||||
image.reset();
|
||||
}
|
||||
return image;
|
||||
}
|
||||
|
||||
bool isPngType(BasicIo& iIo, bool advance)
|
||||
{
|
||||
const int32_t len = 8;
|
||||
const unsigned char pngID[8] = {'\211', 'P', 'N', 'G', '\r', '\n', '\032', '\n'};
|
||||
byte buf[len];
|
||||
iIo.read(buf, len);
|
||||
if (iIo.error() || iIo.eof())
|
||||
{
|
||||
return false;
|
||||
}
|
||||
int rc = memcmp(buf, pngID, 8);
|
||||
if (!advance || rc != 0)
|
||||
{
|
||||
iIo.seek(-len, BasicIo::cur);
|
||||
}
|
||||
|
||||
return rc == 0;
|
||||
}
|
||||
} // namespace Exiv2
|
||||
186
src/pngimage.hpp
Normal file
186
src/pngimage.hpp
Normal file
@ -0,0 +1,186 @@
|
||||
// ***************************************************************** -*- C++ -*-
|
||||
/*
|
||||
* Copyright (C) 2006 Andreas Huggel <ahuggel@gmx.net>
|
||||
*
|
||||
* 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 pngimage.hpp
|
||||
@brief PNG image, implemented using the following references:
|
||||
<a href="http://www.w3.org/TR/PNG/">PNG specification</a> by W3C<br>
|
||||
<a href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html">PNG tags list</a> by Phil Harvey<br>
|
||||
@version $Rev: 797 $
|
||||
@author Andreas Huggel (ahu)
|
||||
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
|
||||
@author Gilles Caulier (gc)
|
||||
<a href="mailto:caulier dot gilles at kdemail dot net">caulier dot gilles at kdemail dot net</a>
|
||||
@date 07-Jun-06, gc: submitted
|
||||
*/
|
||||
#ifndef PNGIMAGE_HPP_
|
||||
#define PNGIMAGE_HPP_
|
||||
|
||||
// *****************************************************************************
|
||||
// included header files
|
||||
#include "exif.hpp"
|
||||
#include "iptc.hpp"
|
||||
#include "image.hpp"
|
||||
|
||||
// + standard includes
|
||||
#include <string>
|
||||
|
||||
// *****************************************************************************
|
||||
// namespace extensions
|
||||
namespace Exiv2 {
|
||||
|
||||
// *****************************************************************************
|
||||
// class definitions
|
||||
|
||||
// Add PNG to the supported image formats
|
||||
namespace ImageType {
|
||||
const int png = 6; //!< PNG image type (see class PngImage)
|
||||
}
|
||||
|
||||
/*!
|
||||
@brief Class to access raw PNG images. Exif/IPTC metadata are supported
|
||||
directly.
|
||||
*/
|
||||
class PngImage : public Image {
|
||||
friend bool isPngType(BasicIo& iIo, bool advance);
|
||||
|
||||
//! @name NOT Implemented
|
||||
//@{
|
||||
//! Copy constructor
|
||||
PngImage(const PngImage& rhs);
|
||||
//! Assignment operator
|
||||
PngImage& operator=(const PngImage& rhs);
|
||||
//@}
|
||||
|
||||
public:
|
||||
//! @name Creators
|
||||
//@{
|
||||
/*!
|
||||
@brief Constructor that can either open an existing PNG image or create
|
||||
a new image from scratch. If a new image is to be created, any
|
||||
existing data is overwritten. 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.
|
||||
@param create Specifies if an existing image should be read (false)
|
||||
or if a new file should be created (true).
|
||||
*/
|
||||
PngImage(BasicIo::AutoPtr io, bool create);
|
||||
//! Destructor
|
||||
~PngImage() {}
|
||||
//@}
|
||||
|
||||
//! @name Manipulators
|
||||
//@{
|
||||
void readMetadata();
|
||||
/*!
|
||||
@brief Todo: Write metadata back to the image. This method is not
|
||||
yet implemented.
|
||||
*/
|
||||
void writeMetadata();
|
||||
void setExifData(const ExifData& exifData);
|
||||
void clearExifData();
|
||||
void setIptcData(const IptcData& iptcData);
|
||||
void clearIptcData();
|
||||
/*!
|
||||
@brief Not supported. PNG format does not contain a comment.
|
||||
Calling this function will do nothing.
|
||||
*/
|
||||
void setComment(const std::string& comment);
|
||||
/*!
|
||||
@brief Not supported. PNG format does not contain a comment.
|
||||
Calling this function will do nothing.
|
||||
*/
|
||||
void clearComment();
|
||||
void setMetadata(const Image& image);
|
||||
void clearMetadata();
|
||||
ExifData& exifData() { return exifData_; }
|
||||
IptcData& iptcData() { return iptcData_; }
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
//@{
|
||||
bool good() const;
|
||||
const ExifData& exifData() const { return exifData_; }
|
||||
const IptcData& iptcData() const { return iptcData_; }
|
||||
std::string comment() const { return comment_; }
|
||||
BasicIo& io() const { return *io_; }
|
||||
//@}
|
||||
|
||||
private:
|
||||
//! @name Accessors
|
||||
//@{
|
||||
/*!
|
||||
@brief Determine if the content of the BasicIo instance is a PNG image.
|
||||
|
||||
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 iIo BasicIo instance to read from.
|
||||
@param advance Flag indicating whether the position of the io
|
||||
should be advanced by the number of characters read to
|
||||
analyse the data (true) or left at its original
|
||||
position (false). This applies only if the type matches.
|
||||
@return true if the data matches the type of this class;<BR>
|
||||
false if the data does not match
|
||||
*/
|
||||
bool isThisType(BasicIo& iIo, bool advance) const;
|
||||
/*!
|
||||
@brief Todo: Write PNG header. Not implemented yet.
|
||||
*/
|
||||
int writeHeader(BasicIo& oIo) const;
|
||||
|
||||
//@}
|
||||
|
||||
// DATA
|
||||
BasicIo::AutoPtr io_; //!< Image data io pointer
|
||||
ExifData exifData_; //!< Exif data container
|
||||
IptcData iptcData_; //!< IPTC data container
|
||||
std::string comment_; //!< User comment
|
||||
|
||||
}; // class PngImage
|
||||
|
||||
// *****************************************************************************
|
||||
// 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 PngImage 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 newPngInstance(BasicIo::AutoPtr io, bool create);
|
||||
|
||||
//! Check if the file iIo is a PNG image.
|
||||
bool isPngType(BasicIo& iIo, bool advance);
|
||||
|
||||
} // namespace Exiv2
|
||||
|
||||
#endif // #ifndef PNGIMAGE_HPP_
|
||||
Loading…
Reference in New Issue
Block a user