#1108 Added code to dump Exif, IPTC and iTXt/zTXt comment/description blocks for PNG files.

v0.27.3
Robin Mills 9 years ago
parent e922a066be
commit 5b38d4528a

@ -21,9 +21,6 @@
/*
File: pngchunk.cpp
Version: $Rev$
Author(s): Gilles Caulier (cgilles) <caulier dot gilles at gmail dot com>
History: 12-Jun-06, gc: submitted
Credits: See header file
*/
// *****************************************************************************
#include "rcsid_int.hpp"
@ -83,11 +80,6 @@ namespace Exiv2 {
TxtChunkType type)
{
DataBuf key = keyTXTChunk(data);
#ifdef DEBUG
std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk key: "
<< std::string((const char*)key.pData_, key.size_) << "\n";
#endif
DataBuf arr = parseTXTChunk(data, key.size_, type);
#ifdef DEBUG
@ -98,6 +90,19 @@ namespace Exiv2 {
} // PngChunk::decodeTXTChunk
DataBuf PngChunk::decodeTXTChunk(const DataBuf& data,
TxtChunkType type)
{
DataBuf key = keyTXTChunk(data);
#ifdef DEBUG
std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk key: "
<< std::string((const char*)key.pData_, key.size_) << "\n";
#endif
return parseTXTChunk(data, key.size_, type);
} // PngChunk::decodeTXTChunk
DataBuf PngChunk::keyTXTChunk(const DataBuf& data, bool stripHeader)
{
// From a tEXt, zTXt, or iTXt chunk,
@ -230,7 +235,7 @@ namespace Exiv2 {
|| memcmp("Raw profile type APP1", key, 21) == 0)
&& pImage->exifData().empty())
{
DataBuf exifData = readRawProfile(arr);
DataBuf exifData = readRawProfile(arr,false);
long length = exifData.size_;
if (length > 0)
@ -279,7 +284,7 @@ namespace Exiv2 {
if ( keySize >= 21
&& memcmp("Raw profile type iptc", key, 21) == 0
&& pImage->iptcData().empty()) {
DataBuf psData = readRawProfile(arr);
DataBuf psData = readRawProfile(arr,false);
if (psData.size_ > 0) {
Blob iptcBlob;
const byte *record = 0;
@ -331,7 +336,7 @@ namespace Exiv2 {
&& memcmp("Raw profile type xmp", key, 20) == 0
&& pImage->xmpData().empty())
{
DataBuf xmpBuf = readRawProfile(arr);
DataBuf xmpBuf = readRawProfile(arr,false);
long length = xmpBuf.size_;
if (length > 0)
@ -578,7 +583,7 @@ namespace Exiv2 {
} // PngChunk::makeUtf8TxtChunk
DataBuf PngChunk::readRawProfile(const DataBuf& text)
DataBuf PngChunk::readRawProfile(const DataBuf& text,bool iTXt)
{
DataBuf info;
register long i;
@ -596,6 +601,13 @@ namespace Exiv2 {
return DataBuf();
}
if ( iTXt ) {
info.alloc(text.size_);
::memcpy(info.pData_,text.pData_,text.size_);
return info;
}
sp = (char*)text.pData_+1;
// Look for newline
@ -620,7 +632,6 @@ namespace Exiv2 {
#ifdef DEBUG
std::cerr << "Exiv2::PngChunk::readRawProfile: Unable To Copy Raw Profile: invalid profile length\n";
#endif
return DataBuf();
}
info.alloc(length);

@ -25,19 +25,20 @@
<a href="http://www.vias.org/pngguide/chapter11_04.html">PNG tTXt and zTXt chunks structures</a> from PNG definitive guide,<br>
<a href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html">PNG tags list</a> by Phil Harvey<br>
Email communication with <a href="mailto:caulier dot gilles at gmail dot com">caulier dot gilles at gmail dot com</a><br>
@version $Rev$
@author Andreas Huggel (ahu)
<a href="mailto:ahuggel@gmx.net">ahuggel@gmx.net</a>
@author Gilles Caulier (cgilles)
<a href="mailto:caulier dot gilles at gmail dot com">caulier dot gilles at gmail dot com</a>
@date 12-Jun-06, gc: submitted
*/
/*
File: pngchunk.cpp
Version: $Rev$
*/
#ifndef PNGCHUNK_INT_HPP_
#define PNGCHUNK_INT_HPP_
// *****************************************************************************
// included header files
#include "types.hpp"
#include "pngimage.hpp"
// + standard includes
#include <iosfwd>
@ -97,6 +98,17 @@ namespace Exiv2 {
const DataBuf& data,
TxtChunkType type);
/*!
@brief Decode PNG tEXt, zTXt, or iTXt chunk data from \em pImage passed by data buffer
\em data and extract Comment, Exif, Iptc, Xmp to DataBuf
@param data PNG Chunk data buffer.
@param type PNG Chunk TXT type.
*/
static DataBuf decodeTXTChunk(const DataBuf& data,
TxtChunkType type);
/*!
@brief Return PNG TXT chunk key as data buffer.
@ -180,7 +192,7 @@ namespace Exiv2 {
/*!
@brief Decode from ImageMagick raw text profile which host encoded Exif/Iptc/Xmp metadata byte array.
*/
static DataBuf readRawProfile(const DataBuf& text);
static DataBuf readRawProfile(const DataBuf& text,bool iTXt);
/*!
@brief Encode to ImageMagick raw text profile, which host encoded
@ -189,6 +201,8 @@ namespace Exiv2 {
static std::string writeRawProfile(const std::string& profileData,
const char* profileType);
friend class Exiv2::PngImage;
}; // class PngChunk
}} // namespace Internal, Exiv2

@ -216,9 +216,12 @@ namespace Exiv2 {
const std::string xmpKey = "XML:com.adobe.xmp";
const std::string exifKey = "Raw profile type exif";
const std::string app1Key = "Raw profile type APP1";
const std::string iptcKey = "Raw profile type iptc";
const std::string iccKey = "icc";
const std::string softKey = "Software";
const std::string commKey = "Comment";
const std::string descKey = "Description";
bool bPrint = option == kpsBasic || option == kpsRecursive ;
if ( bPrint ) {
@ -252,15 +255,16 @@ namespace Exiv2 {
throw Exiv2::Error(14);
}
// format output
uint32_t blen = dataOffset > 32 ? 32 : dataOffset ;
std::string dataString ;
DataBuf buff(blen);
io_->read(buff.pData_,blen);
DataBuf buff(dataOffset);
io_->read(buff.pData_,dataOffset);
io_->seek(restore, BasicIo::beg);
dataString = Internal::binaryToString(buff, blen);
while ( dataString.size() < 32 ) dataString += ' ';
dataString = dataString.substr(0,30);
// format output
const int iMax = 30 ;
uint32_t blen = dataOffset > iMax ? iMax : dataOffset ;
std::string dataString = Internal::binaryToString(buff, blen);
while ( dataString.size() < iMax ) dataString += ' ';
dataString = dataString.substr(0,iMax);
if ( bPrint ) {
io_->seek(dataOffset, BasicIo::cur);// jump to checksum
@ -285,19 +289,22 @@ namespace Exiv2 {
// for XMP, ICC etc: read and format data
bool bXMP = option == kpsXMP && findi(dataString,xmpKey)==0;
bool bICC = option == kpsIccProfile && findi(dataString,iccKey)==0;
bool bExif = option == kpsRecursive && findi(dataString,exifKey)==0;
bool bExif = option == kpsRecursive &&(findi(dataString,exifKey)==0 || findi(dataString,app1Key)==0);
bool bIptc = option == kpsRecursive && findi(dataString,iptcKey)==0;
bool bSoft = option == kpsRecursive && findi(dataString,softKey)==0;
bool bDump = bXMP || bICC || bExif || bIptc || bSoft ;
bool bComm = option == kpsRecursive && findi(dataString,commKey)==0;
bool bDesc = option == kpsRecursive && findi(dataString,descKey)==0;
bool bDump = bXMP || bICC || bExif || bIptc || bSoft || bComm || bDesc ;
if( bDump ) {
DataBuf dataBuf;
byte* data = new byte[dataOffset+1];
data[dataOffset]=0;
byte* data = new byte[dataOffset+1];
data[dataOffset] = 0;
io_->read(data,dataOffset);
io_->seek(restore, BasicIo::beg);
uint32_t name_l = (uint32_t) std::strlen((const char*)data)+1; // leading string length
uint32_t start = name_l;
uint32_t name_l = (uint32_t) std::strlen((const char*)data)+1; // leading string length
uint32_t start = name_l;
bool bLF = false;
// decode the chunk
bool bGood = false;
@ -305,26 +312,34 @@ namespace Exiv2 {
bGood = tEXtToDataBuf(data+name_l,dataOffset-name_l,dataBuf);
}
if ( zTXt || iCCP ) {
name_l++ ; // +1 = 'compressed' flag
bGood = zlibToDataBuf(data+name_l,dataOffset-name_l,dataBuf);
bGood = zlibToDataBuf(data+name_l+1,dataOffset-name_l-1,dataBuf); // +1 = 'compressed' flag
}
if ( iTXt ) {
while ( data[start] == 0 && start < dataOffset ) start++; // crawl over the '\0' bytes between XML:....\0\0<xml stuff
data[dataOffset]=0; // ensure the XML is nul terminated
bGood = (start+3) < dataOffset ; // good if not a nul chunk
}
// format is content dependent
if ( bGood ) {
if ( bXMP ) {
out << data+start; // output the xml
while ( !data[start] && start < dataOffset) start++; // skip leading nul bytes
out << data+start; // output the xmp
}
if ( bExif ) {
const char* bytes = (const char*) dataBuf.pData_;
uint32_t l = (uint32_t) std::strlen(bytes)+2;
// create a copy on write memio object with the data, then print the structure
BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(dataBuf.pData_+l,dataBuf.size_-l));
TiffImage::printTiffStructure(*p,out,option,depth);
if ( bExif || bIptc ) {
DataBuf parsedBuf = PngChunk::readRawProfile(dataBuf,tEXt);
#if DEBUG
std::cerr << Exiv2::Internal::binaryToString(parsedBuf.pData_, parsedBuf.size_>50?50:parsedBuf.size_,0) << std::endl;
#endif
if ( parsedBuf.size_ ) {
if ( bExif ) {
// create memio object with the data, then print the structure
BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(parsedBuf.pData_+6,parsedBuf.size_-6));
TiffImage::printTiffStructure(*p,out,option,depth);
}
if ( bIptc ) {
IptcData::printStructure(out,parsedBuf.pData_,parsedBuf.size_,depth);
}
}
}
if ( bSoft && dataBuf.size_ > 0) {
@ -332,16 +347,22 @@ namespace Exiv2 {
memcpy(s.pData_,dataBuf.pData_,dataBuf.size_);// copy in the dataBuf
s.pData_[dataBuf.size_] = 0 ; // nul terminate it
const char* str = (const char*) s.pData_; // give it name
out << Internal::indent(depth) << (const char*) buff.pData_ << ": " << str << std::endl;
out << Internal::indent(depth) << (const char*) buff.pData_ << ": " << str ;
bLF=true;
}
if ( bICC ) {
if ( bICC || bComm ) {
out.write((const char*) dataBuf.pData_,dataBuf.size_);
bLF = bComm ;
}
if ( bIptc ) {
IptcData::printStructure(out,dataBuf.pData_,dataBuf.size_,depth);
if ( bDesc && iTXt ) {
DataBuf decoded = PngChunk::decodeTXTChunk(buff,PngChunk::iTXt_Chunk );
out.write((const char*)decoded.pData_,decoded.size_);
bLF = true;
}
if ( bLF ) out << std::endl;
}
delete[] data;
}

Loading…
Cancel
Save