[SCM] exiv2 packaging branch, master, updated. debian/0.25-3.1-3734-gdcbc29a
Maximiliano Curia
maxy at moszumanska.debian.org
Thu Jul 13 17:39:38 UTC 2017
Gitweb-URL: http://git.debian.org/?p=pkg-kde/kde-extras/exiv2.git;a=commitdiff;h=3fe5ebb
The following commit has been merged in the master branch:
commit 3fe5ebb8ca702635ef5cbdb91ff75d4fa1085fa7
Author: HumanDynamo <caulier.gilles at gmail.com>
Date: Sun Jul 27 09:23:08 2008 +0000
PNG file format parser.
- Refactoring code: main loop to parse PNG chunk contents go to pngimage class. pngchunk only play with chunk contents
- Implement PNG writting mode : all metadata are supported:
* UTF8 comment as "Description" iTXt chunk (compressed)
* XMP data as iTXt chunk (uncompressed as XMP spec instruction)
* IPTC data as zTXt chunk (compressed and encoded as ImageMagick method)
* EXIF data as zTXt chunk (compressed and encoded as ImageMagick method)
Note: writting mode resample metadata chunk to follow list given behind. There are several ways where other programs writte metadata in other place.
For ex : digiKam 0.9.x or ImageMagick 5.x writte Exif and Iptc to an tEXt chunk (uncompressed)
ImageMagick 5.x writte Xmp to an uncompressed tEXt chunk
ImageMagick 6.x writte Xmp to a compressed zTXt chunk.
---
src/pngchunk.cpp | 639 +++++++++++++++++++++++++++++++------------------------
src/pngchunk.hpp | 151 +++++++++----
src/pngimage.cpp | 312 +++++++++++++++++++++++----
src/pngimage.hpp | 38 ++--
4 files changed, 759 insertions(+), 381 deletions(-)
diff --git a/src/pngchunk.cpp b/src/pngchunk.cpp
index bcf0e66..a785612 100644
--- a/src/pngchunk.cpp
+++ b/src/pngchunk.cpp
@@ -39,12 +39,7 @@ EXIV2_RCSID("@(#) $Id: pngchunk.cpp 823 2006-06-23 07:35:00Z cgilles $")
//#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
+// To uncompress or compress text chunk
#include <zlib.h>
#include "pngchunk.hpp"
@@ -64,200 +59,144 @@ EXIV2_RCSID("@(#) $Id: pngchunk.cpp 823 2006-06-23 07:35:00Z cgilles $")
URLs to find informations about PNG chunks :
-tEXt and zTXt chuncks : http://www.vias.org/pngguide/chapter11_04.html
-iTXt chunck : http://www.vias.org/pngguide/chapter11_05.html
-PNG tags : http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData
+tEXt and zTXt chunks : http://www.vias.org/pngguide/chapter11_04.html
+iTXt chunk : http://www.vias.org/pngguide/chapter11_05.html
+PNG tags : http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/PNG.html#TextualData
*/
// *****************************************************************************
-// local declarations
-namespace {
- // Return the checked length of a PNG chunk
- long chunkLength(const Exiv2::byte* pData, long index);
-}
-
-// *****************************************************************************
// class member definitions
-namespace Exiv2 {
-
- void PngChunk::decode(Image* pImage,
- const byte* pData,
- long size,
- int* outWidth,
- int* outHeight)
+namespace Exiv2
+{
+ void PngChunk::decodeIHDRChunk(const DataBuf& data,
+ int* outWidth,
+ int* outHeight)
{
- assert(pImage != 0);
- assert(pData != 0);
- assert(outWidth != 0);
- assert(outHeight != 0);
-
- 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);
- }
+ // Extract image width and height from IHDR chunk.
- // look for a tEXt chunk
- index += chunkLength(pData, index) + 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) &&
- strncmp((char*)PNG_CHUNK_TYPE(pData, index), "iTXt", 4))
- {
- if (!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "IEND", 4))
- throw Error(14);
-
- index += chunkLength(pData, index) + PNG_CHUNK_HEADER_SIZE;
- }
-
- if (index < size-PNG_CHUNK_HEADER_SIZE)
- {
- // we found a tEXt, zTXt, or iTXt field
+ *outWidth = getLong((const byte*)data.pData_, bigEndian);
+ *outHeight = getLong((const byte*)data.pData_ + 4, bigEndian);
- // get the key, it's a null terminated string at the chunk start
- const byte *key = &PNG_CHUNK_DATA(pData, index, 0);
+ } // PngChunk::decodeIHDRChunk
- 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);
- }
+ void PngChunk::decodeTXTChunk(Image* pImage,
+ const DataBuf& data,
+ TxtChunkType type)
+ {
+ DataBuf key = keyTXTChunk(data);
- DataBuf arr = parsePngChunk(pData, size, index, keysize);
+#ifdef DEBUG
+ std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk key: "
+ << std::string((const char*)key.pData_) << "
";
+#endif
+ DataBuf arr = parseTXTChunk(data, key.size_, type);
#ifdef DEBUG
- std::cerr << "Exiv2::PngChunk::decode: Found PNG chunk: "
- << std::string((const char*)key) << " :: "
- << std::string((const char*)arr.pData_, 32) << "
";
+ std::cout << "Exiv2::PngChunk::decodeTXTChunk: TXT chunk data: "
+ << std::string((const char*)arr.pData_, 32) << "
";
#endif
+ parseChunkContent(pImage, key.pData_, arr);
- parseChunkContent(pImage, key, arr);
+ } // PngChunk::decodeTXTChunk
- index += chunkLength(pData, index) + PNG_CHUNK_HEADER_SIZE;
- }
+ DataBuf PngChunk::keyTXTChunk(const DataBuf& data, bool stripHeader)
+ {
+ // From a tEXt, zTXt, or iTXt chunk,
+ // we get the key, it's a null terminated string at the chunk start
+
+ const byte *key = data.pData_ + (stripHeader ? 8 : 0);
+
+ // Find null string at end of key.
+ int keysize=0;
+ for ( ; key[keysize] != 0 ; keysize++)
+ {
+ // look if keysize is valid.
+ if (keysize >= data.size_)
+ throw Error(14);
}
- } // PngChunk::decode
+ return DataBuf(key, keysize);
- DataBuf PngChunk::parsePngChunk(const byte* pData, long size, long& index, int keysize)
+ } // PngChunk::keyTXTChunk
+
+ DataBuf PngChunk::parseTXTChunk(const DataBuf& data,
+ int keysize,
+ TxtChunkType type)
{
DataBuf arr;
- if(!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "zTXt", 4))
+ if(type == zTXt_Chunk)
{
// Extract a deflate compressed Latin-1 text chunk
-#ifdef DEBUG
- std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a zTXt field
";
-#endif
// we get the compression method after the key
- const byte* compressionMethod = &PNG_CHUNK_DATA(pData, index, keysize+1);
+ const byte* compressionMethod = data.pData_ + keysize + 1;
if ( *compressionMethod != 0x00 )
{
// then it isn't zlib compressed and we are sunk
#ifdef DEBUG
- std::cerr << "Exiv2::PngChunk::parsePngChunk: Non-standard zTXt compression method.
";
+ std::cerr << "Exiv2::PngChunk::parseTXTChunk: Non-standard zTXt compression method.
";
#endif
throw Error(14);
}
// compressed string after the compression technique spec
- const byte* compressedText = &PNG_CHUNK_DATA(pData, index, keysize+2);
- unsigned int 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);
+ const byte* compressedText = data.pData_ + keysize + 2;
+ unsigned int compressedTextSize = data.size_ - keysize - 2;
zlibUncompress(compressedText, compressedTextSize, arr);
}
- else if (!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "tEXt", 4))
+ else if(type == tEXt_Chunk)
{
// Extract a non-compressed Latin-1 text chunk
-#ifdef DEBUG
- std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a tEXt field
";
-#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);
+ // the text comes after the key, but isn't null terminated
+ const byte* text = data.pData_ + keysize + 1;
+ long textsize = data.size_ - keysize - 1;
arr.alloc(textsize);
arr = DataBuf(text, textsize);
}
- else if(!strncmp((char*)PNG_CHUNK_TYPE(pData, index), "iTXt", 4))
+ else if(type == iTXt_Chunk)
{
// Extract a deflate compressed or uncompressed UTF-8 text chunk
// we get the compression flag after the key
- const byte* compressionFlag = &PNG_CHUNK_DATA(pData, index, keysize+1);
+ const byte* compressionFlag = data.pData_ + keysize + 1;
// we get the compression method after the compression flag
- const byte* compressionMethod = &PNG_CHUNK_DATA(pData, index, keysize+1);
+ const byte* compressionMethod = data.pData_ + keysize + 2;
// language description string after the compression technique spec
- const byte* languageText = &PNG_CHUNK_DATA(pData, index, keysize+1);
- unsigned int languageTextSize = getLong(&pData[index], bigEndian)-keysize-1;
+ std::string languageText((const char*)(data.pData_ + keysize + 3));
+ unsigned int languageTextSize = languageText.size();
// translated keyword string after the language description
- const byte* translatedKeyText = &PNG_CHUNK_DATA(pData, index, keysize+1);
- unsigned int translatedKeyTextSize = getLong(&pData[index], bigEndian)-keysize-1;
+ std::string translatedKeyText((const char*)(data.pData_ + keysize + 3 + languageTextSize));
+ unsigned int translatedKeyTextSize = translatedKeyText.size();
- if ( *compressionFlag == 0x00 )
+ if ( compressionFlag[0] == 0x00 )
{
// then it's an uncompressed iTXt chunk
#ifdef DEBUG
- std::cerr << "Exiv2::PngChunk::parsePngChunk: We found an uncompressed iTXt field
";
+ std::cout << "Exiv2::PngChunk::parseTXTChunk: We found an uncompressed iTXt field
";
#endif
// the text comes after the translated keyword, 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);
+ const byte* text = data.pData_ + keysize + 3 + languageTextSize + translatedKeyTextSize;
+ long textsize = data.size_ - (keysize + 3 + languageTextSize + translatedKeyTextSize);
arr.alloc(textsize);
arr = DataBuf(text, textsize);
}
- else if ( *compressionMethod == 0x00 )
+ else if ( compressionFlag[0] == 0x01 && compressionMethod[0] == 0x00 )
{
// then it's a zlib compressed iTXt chunk
#ifdef DEBUG
- std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a zlib compressed iTXt field
";
+ std::cout << "Exiv2::PngChunk::parseTXTChunk: We found a zlib compressed iTXt field
";
#endif
// the compressed text comes after the translated keyword, but isn't null terminated
- const byte* compressedText = &PNG_CHUNK_DATA(pData, index, keysize+1);
- long compressedTextSize = 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)(compressedText - pData);
- long onePastLastIndex = firstIndex + compressedTextSize;
- if ( onePastLastIndex > size || onePastLastIndex <= firstIndex)
- throw Error(14);
+ const byte* compressedText = data.pData_ + keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1;
+ long compressedTextSize = data.size_ - (keysize + 3 + languageTextSize + 1 + translatedKeyTextSize + 1);
zlibUncompress(compressedText, compressedTextSize, arr);
}
@@ -265,7 +204,7 @@ namespace Exiv2 {
{
// then it isn't zlib compressed and we are sunk
#ifdef DEBUG
- std::cerr << "Exiv2::PngChunk::parsePngChunk: Non-standard iTXt compression method.
";
+ std::cerr << "Exiv2::PngChunk::parseTXTChunk: Non-standard iTXt compression method.
";
#endif
throw Error(14);
}
@@ -273,12 +212,12 @@ namespace Exiv2 {
else
{
#ifdef DEBUG
- std::cerr << "Exiv2::PngChunk::parsePngChunk: We found a field, not expected though
";
+ std::cerr << "Exiv2::PngChunk::parseTXTChunk: We found a field, not expected though
";
#endif
throw Error(14);
}
- return arr;
+ return arr;
} // PngChunk::parsePngChunk
@@ -314,7 +253,7 @@ namespace Exiv2 {
if (pos !=-1)
{
#ifdef DEBUG
- std::cerr << "Exiv2::PngChunk::decode: Exif header found at position " << pos << "
";
+ std::cout << "Exiv2::PngChunk::decode: Exif header found at position " << pos << "
";
#endif
pos = pos + sizeof(exifHeader);
ByteOrder bo = TiffParser::decode(pImage->exifData(),
@@ -360,7 +299,7 @@ namespace Exiv2 {
#endif
xmpPacket = xmpPacket.substr(idx);
}
- if (XmpParser::decode(pImage->xmpData(), xmpPacket))
+ if (XmpParser::decode(pImage->xmpData(), xmpPacket))
{
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Failed to decode XMP metadata.
";
@@ -387,7 +326,7 @@ namespace Exiv2 {
#endif
xmpPacket = xmpPacket.substr(idx);
}
- if (XmpParser::decode(pImage->xmpData(), xmpPacket))
+ if (XmpParser::decode(pImage->xmpData(), xmpPacket))
{
#ifndef SUPPRESS_WARNINGS
std::cerr << "Warning: Failed to decode XMP metadata.
";
@@ -407,6 +346,254 @@ namespace Exiv2 {
} // PngChunk::parseChunkContent
+ DataBuf PngChunk::makeMetadataChunk(const DataBuf& metadata, MetadataType type, bool compress)
+ {
+ if (type == comment_Data)
+ {
+ DataBuf key(11);
+ memcpy(key.pData_, "Description", 11);
+ DataBuf rawData = makeUtf8TxtChunk(key, metadata, compress);
+ return rawData;
+ }
+ else if (type == exif_Data)
+ {
+ DataBuf tmp(4);
+ memcpy(tmp.pData_, "exif", 4);
+ DataBuf rawProfile = writeRawProfile(metadata, tmp);
+ DataBuf key(17 + tmp.size_);
+ memcpy(key.pData_, "Raw profile type ", 17);
+ memcpy(key.pData_ + 17, tmp.pData_, tmp.size_);
+ DataBuf rawData = makeAsciiTxtChunk(key, rawProfile, compress);
+ return rawData;
+ }
+ else if (type == iptc_Data)
+ {
+ DataBuf tmp(4);
+ memcpy(tmp.pData_, "iptc", 4);
+ DataBuf rawProfile = writeRawProfile(metadata, tmp);
+ DataBuf key(17 + tmp.size_);
+ memcpy(key.pData_, "Raw profile type ", 17);
+ memcpy(key.pData_ + 17, tmp.pData_, tmp.size_);
+ DataBuf rawData = makeAsciiTxtChunk(key, rawProfile, compress);
+ return rawData;
+ }
+ else if (type == xmp_Data)
+ {
+ DataBuf key(17);
+ memcpy(key.pData_, "XML:com.adobe.xmp", 17);
+ DataBuf rawData = makeUtf8TxtChunk(key, metadata, compress);
+ return rawData;
+ }
+
+ return DataBuf();
+
+ } // PngChunk::makeMetadataChunk
+
+ void PngChunk::zlibUncompress(const byte* compressedText,
+ unsigned int compressedTextSize,
+ DataBuf& arr)
+ {
+ uLongf uncompressedLen = compressedTextSize * 2; // just a starting point
+ int zlibResult;
+
+ do
+ {
+ arr.alloc(uncompressedLen);
+ zlibResult = uncompress((Bytef*)arr.pData_, &uncompressedLen,
+ compressedText, compressedTextSize);
+
+ if (zlibResult == Z_OK)
+ {
+ // then it is all OK
+ arr.alloc(uncompressedLen);
+ }
+ else if (zlibResult == Z_BUF_ERROR)
+ {
+ // the uncompressedArray needs to be larger
+#ifdef DEBUG
+ std::cout << "Exiv2::PngChunk::parsePngChunk: doubling size for decompression.
";
+#endif
+ uncompressedLen *= 2;
+
+ // DoS protection. can't be bigger than 64k
+ if ( uncompressedLen > 131072 )
+ break;
+ }
+ else
+ {
+ // something bad happened
+ throw Error(14);
+ }
+ }
+ while (zlibResult == Z_BUF_ERROR);
+
+ if (zlibResult != Z_OK)
+ throw Error(14);
+
+ } // PngChunk::zlibUncompress
+
+ void PngChunk::zlibCompress(const byte* text,
+ unsigned int textSize,
+ DataBuf& arr)
+ {
+ uLongf compressedLen = textSize * 2; // just a starting point
+ int zlibResult;
+
+ do
+ {
+ arr.alloc(compressedLen);
+ zlibResult = compress2((Bytef*)arr.pData_, &compressedLen,
+ text, textSize, Z_BEST_COMPRESSION);
+
+ if (zlibResult == Z_OK)
+ {
+ // then it is all OK
+ arr.alloc(compressedLen);
+ }
+ else if (zlibResult == Z_BUF_ERROR)
+ {
+ // the compressedArray needs to be larger
+#ifdef DEBUG
+ std::cout << "Exiv2::PngChunk::parsePngChunk: doubling size for compression.
";
+#endif
+ compressedLen *= 2;
+
+ // DoS protection. can't be bigger than 64k
+ if ( compressedLen > 131072 )
+ break;
+ }
+ else
+ {
+ // something bad happened
+ throw Error(14);
+ }
+ }
+ while (zlibResult == Z_BUF_ERROR);
+
+ if (zlibResult != Z_OK)
+ throw Error(14);
+
+ } // PngChunk::zlibCompress
+
+ DataBuf PngChunk::makeAsciiTxtChunk(const DataBuf& key, const DataBuf& data, bool compress)
+ {
+ DataBuf type(4);
+ DataBuf data4crc;
+ DataBuf chunkData;
+ byte chunkDataSize[4];
+ byte chunkCRC[4];
+
+ if (compress)
+ {
+ // Compressed text chunk using ZLib.
+ // Data format : key ("zTXt") + 0x00 + compression type (0x00) + compressed data
+ // Chunk structure: data lenght (4 bytes) + chunk type (4 bytes) + compressed data + CRC (4 bytes)
+
+ memcpy(type.pData_, "zTXt", 4);
+
+ DataBuf compressedData;
+ zlibCompress(data.pData_, data.size_, compressedData);
+
+ data4crc.alloc(key.size_ + 1 + 1 + compressedData.size_);
+ memcpy(data4crc.pData_, key.pData_, key.size_);
+ memcpy(data4crc.pData_ + key.size_, "
--
exiv2 packaging
More information about the pkg-kde-commits
mailing list