diff --git a/src/pngimage.cpp b/src/pngimage.cpp index 594df90867..599fd61df0 100644 --- a/src/pngimage.cpp +++ b/src/pngimage.cpp @@ -304,6 +304,7 @@ namespace Exiv2 { bool zTXt = std::strcmp(chType,"zTXt")== 0; bool iCCP = std::strcmp(chType,"iCCP")== 0; bool iTXt = std::strcmp(chType,"iTXt")== 0; + bool eXIf = std::strcmp(chType,"eXIf")== 0; // for XMP, ICC etc: read and format data bool bXMP = option == kpsXMP && findi(dataString,xmpKey)==0; @@ -313,7 +314,7 @@ namespace Exiv2 { bool bSoft = option == kpsRecursive && findi(dataString,softKey)==0; 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 ; + bool bDump = bXMP || bICC || bExif || bIptc || bSoft || bComm || bDesc || eXIf ; if( bDump ) { DataBuf dataBuf; @@ -339,6 +340,9 @@ namespace Exiv2 { if ( iTXt ) { bGood = (start+3) < dataOffset ; // good if not a nul chunk } + if ( eXIf ) { + bGood = true ;// eXIf requires no pre-processing) + } // format is content dependent if ( bGood ) { @@ -383,6 +387,11 @@ namespace Exiv2 { out.write((const char*)decoded.pData_,decoded.size_); bLF = true; } + if ( eXIf && option == kpsRecursive ) { + // create memio object with the data, then print the structure + BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(data,dataOffset)); + printTiffStructure(*p,out,option,depth); + } if ( bLF ) out << std::endl; } @@ -448,8 +457,11 @@ namespace Exiv2 { /// \todo analyse remaining chunks of the standard // Perform a chunk triage for item that we need. - if (chunkType == "IEND" || chunkType == "IHDR" || chunkType == "tEXt" || chunkType == "zTXt" || - chunkType == "iTXt" || chunkType == "iCCP") { + if(chunkType == "IEND" || chunkType == "IHDR" + || chunkType == "tEXt" || chunkType == "zTXt" + || chunkType == "eXIf" + || chunkType == "iTXt" || chunkType == "iCCP" + ){ DataBuf chunkData(chunkLength); readChunk(chunkData, *io_); // Extract chunk data. @@ -463,6 +475,13 @@ namespace Exiv2 { PngChunk::decodeTXTChunk(this, chunkData, PngChunk::zTXt_Chunk); } else if (chunkType == "iTXt") { PngChunk::decodeTXTChunk(this, chunkData, PngChunk::iTXt_Chunk); + } else if (chunkType == "eXIf") { + ByteOrder bo = TiffParser::decode(exifData(), + iptcData(), + xmpData(), + chunkData.pData_, + chunkData.size_); + setByteOrder(bo); } else if (chunkType == "iCCP") { // The ICC profile name can vary from 1-79 characters. uint32_t iccOffset = 0; @@ -540,9 +559,9 @@ namespace Exiv2 { // Read chunk header. std::memset(cheaderBuf.pData_, 0x00, cheaderBuf.size_); - long bufRead = io_->read(cheaderBuf.pData_, cheaderBuf.size_); + long bufRead = io_->read(cheaderBuf.pData_, 8); if (io_->error()) throw Error(kerFailedToReadImageData); - if (bufRead != cheaderBuf.size_) throw Error(kerInputDataReadFailed); + if (bufRead != 8) throw Error(kerInputDataReadFailed); // Decode chunk data length. @@ -551,7 +570,7 @@ namespace Exiv2 { // Read whole chunk : Chunk header + Chunk data (not fixed size - can be null) + CRC (4 bytes). - DataBuf chunkBuf(8 + dataOffset + 4); // Chunk header (8 bytes) + Chunk data + CRC (4 bytes). + DataBuf chunkBuf(8 + dataOffset + 4); // Chunk header (8 bytes) + Chunk data + CRC (4 bytes). memcpy(chunkBuf.pData_, cheaderBuf.pData_, 8); // Copy header. bufRead = io_->read(chunkBuf.pData_ + 8, dataOffset + 4); // Extract chunk data + CRC if (io_->error()) throw Error(kerFailedToReadImageData); @@ -561,16 +580,21 @@ namespace Exiv2 { memcpy(szChunk,cheaderBuf.pData_ + 4,4); szChunk[4] = 0; - if (!memcmp(cheaderBuf.pData_ + 4, "IEND", 4)) + if ( !strcmp(szChunk,"IEND") ) { // Last chunk found: we write it and done. #ifdef EXIV2_DEBUG_MESSAGES std::cout << "Exiv2::PngImage::doWriteMetadata: Write IEND chunk (length: " << dataOffset << ")\n"; #endif - if (outIo.write(chunkBuf.pData_, chunkBuf.size_) != chunkBuf.size_) throw Error(kerImageWriteFailed); + if (outIo.write(chunkBuf.pData_, chunkBuf.size_) != chunkBuf.size_) + throw Error(kerImageWriteFailed); return; } - else if (!memcmp(cheaderBuf.pData_ + 4, "IHDR", 4)) + else if ( !strcmp(szChunk, "eXIf") ) { + ; // do nothing Exif metdata is written following IHDR + ; // as zTXt chunk with signature Raw profile type exif__ + } + else if ( !strcmp(szChunk, "IHDR") ) { #ifdef EXIV2_DEBUG_MESSAGES std::cout << "Exiv2::PngImage::doWriteMetadata: Write IHDR chunk (length: " << dataOffset << ")\n"; @@ -672,10 +696,10 @@ namespace Exiv2 { } } } - else if (!memcmp(cheaderBuf.pData_ + 4, "tEXt", 4) || - !memcmp(cheaderBuf.pData_ + 4, "zTXt", 4) || - !memcmp(cheaderBuf.pData_ + 4, "iTXt", 4) || - !memcmp(cheaderBuf.pData_ + 4, "iCCP", 4)) + else if (!strcmp(szChunk, "tEXt") || + !strcmp(szChunk, "zTXt") || + !strcmp(szChunk, "iTXt") || + !strcmp(szChunk, "iCCP")) { DataBuf key = PngChunk::keyTXTChunk(chunkBuf, true); if (compare("Raw profile type exif", key, 21) || diff --git a/test/Makefile b/test/Makefile index b5a745c572..64997e65be 100644 --- a/test/Makefile +++ b/test/Makefile @@ -85,6 +85,7 @@ TESTS = addmoddel.sh \ iso65k-test.sh \ modify-test.sh \ path-test.sh \ + png-test.sh \ preview-test.sh \ stdin-test.sh \ stringto-test.sh \ @@ -102,6 +103,7 @@ icc-test \ iso65k-test \ modify-test \ path-test \ +png-test \ stringto-test \ webp-test \ write2-test \ diff --git a/test/data/1343_comment.png b/test/data/1343_comment.png new file mode 100644 index 0000000000..29a34d1e57 Binary files /dev/null and b/test/data/1343_comment.png differ diff --git a/test/data/1343_empty.png b/test/data/1343_empty.png new file mode 100644 index 0000000000..65c1c446f5 Binary files /dev/null and b/test/data/1343_empty.png differ diff --git a/test/data/1343_exif.png b/test/data/1343_exif.png new file mode 100644 index 0000000000..3f920b990c Binary files /dev/null and b/test/data/1343_exif.png differ diff --git a/test/data/png-test.out b/test/data/png-test.out new file mode 100644 index 0000000000..ced4cd3f22 --- /dev/null +++ b/test/data/png-test.out @@ -0,0 +1,71 @@ +STRUCTURE OF PNG FILE: 1343_empty.png + address | chunk | length | data | checksum + 8 | IHDR | 13 | .......d.... | 0x4ce4e85c + 33 | sRGB | 1 | | 0xaece1ce9 + 46 | gAMA | 4 | .... | 0x0bfc6105 + 62 | pHYs | 9 | ......... | 0xc76fa864 + 83 | IDAT | 257 | x^..1..0......t.....h......z.. | 0x64465429 + 352 | IEND | 0 | | 0xae426082 + +STRUCTURE OF PNG FILE: 1343_empty.png + address | chunk | length | data | checksum + 8 | IHDR | 13 | .......d.... | 0x4ce4e85c + 33 | iTXt | 39 | Description.....x.K.H.KOMQH... | 0xe0a1c8ce + 84 | sRGB | 1 | | 0xaece1ce9 + 97 | gAMA | 4 | .... | 0x0bfc6105 + 113 | pHYs | 9 | ......... | 0xc76fa864 + 134 | IDAT | 257 | x^..1..0......t.....h......z.. | 0x64465429 + 403 | IEND | 0 | | 0xae426082 +changed comment +STRUCTURE OF PNG FILE: 1343_comment.png + address | chunk | length | data | checksum + 8 | IHDR | 13 | .......d.... | 0x4ce4e85c + 33 | sRGB | 1 | | 0xaece1ce9 + 46 | gAMA | 4 | .... | 0x0bfc6105 + 62 | pHYs | 9 | ......... | 0xc76fa864 + 83 | IDAT | 257 | x^..1..0......t.....h......z.. | 0x64465429 + 352 | tEXt | 24 | Comment.Can you read me? | 0x83cad5fa + 388 | IEND | 0 | | 0xae426082 + +STRUCTURE OF PNG FILE: 1343_comment.png + address | chunk | length | data | checksum + 8 | IHDR | 13 | .......d.... | 0x4ce4e85c + 33 | iTXt | 39 | Description.....x.K.H.KOMQH... | 0xe0a1c8ce + 84 | sRGB | 1 | | 0xaece1ce9 + 97 | gAMA | 4 | .... | 0x0bfc6105 + 113 | pHYs | 9 | ......... | 0xc76fa864 + 134 | IDAT | 257 | x^..1..0......t.....h......z.. | 0x64465429 + 403 | tEXt | 24 | Comment.Can you read me? | 0x83cad5fa + 439 | IEND | 0 | | 0xae426082 +changed comment +STRUCTURE OF PNG FILE: 1343_exif.png + address | chunk | length | data | checksum + 8 | IHDR | 13 | .......d.... | 0x4ce4e85c + 33 | sRGB | 1 | | 0xaece1ce9 + 46 | gAMA | 4 | .... | 0x0bfc6105 + 62 | pHYs | 9 | ......... | 0xc76fa864 + 83 | IDAT | 257 | x^..1..0......t.....h......z.. | 0x64465429 + 352 | eXIf | 108 | MM.*.................J........ | 0x764e86e1 + 472 | IEND | 0 | | 0xae426082 + +Exif.Image.ImageDescription Ascii 17 Can you read me? +Exif.Image.XResolution Rational 1 72 +Exif.Image.YResolution Rational 1 72 +Exif.Image.ResolutionUnit Short 1 inch +Exif.Image.YCbCrPositioning Short 1 Centered +STRUCTURE OF PNG FILE: 1343_exif.png + address | chunk | length | data | checksum + 8 | IHDR | 13 | .......d.... | 0x4ce4e85c + 33 | iTXt | 39 | Description.....x.K.H.KOMQH... | 0xe0a1c8ce + 84 | zTXt | 145 | Raw profile type exif..x.U.... | 0x2f6d89e8 + 241 | sRGB | 1 | | 0xaece1ce9 + 254 | gAMA | 4 | .... | 0x0bfc6105 + 270 | pHYs | 9 | ......... | 0xc76fa864 + 291 | IDAT | 257 | x^..1..0......t.....h......z.. | 0x64465429 + 560 | IEND | 0 | | 0xae426082 +changed comment +Exif.Image.ImageDescription Ascii 17 Can you read me? +Exif.Image.XResolution Rational 1 72 +Exif.Image.YResolution Rational 1 72 +Exif.Image.ResolutionUnit Short 1 inch +Exif.Image.YCbCrPositioning Short 1 Centered diff --git a/test/png-test.sh b/test/png-test.sh new file mode 100755 index 0000000000..8044c00e38 --- /dev/null +++ b/test/png-test.sh @@ -0,0 +1,23 @@ +#!/usr/bin/env bash +# Test PNG support (-pS, -pc, -pa -c ) + +source ./functions.source + +( cd "$testdir" + + files="1343_empty.png 1343_comment.png 1343_exif.png" + copyTestFiles $files + for file in $files ; do + for i in 1 2 ; do + runTest exiv2 -pS $file + runTest exiv2 -pc $file + runTest exiv2 -pa $file + runTest exiv2 -c 'changed comment' $file + done + done +) > $results 2>&1 + +reportTest + +# That's all Folks! +## diff --git a/tests/bash_tests/testcases.py b/tests/bash_tests/testcases.py index 90b03821f5..3ad0df2b7f 100644 --- a/tests/bash_tests/testcases.py +++ b/tests/bash_tests/testcases.py @@ -868,6 +868,38 @@ def path_test(self): # print(out) + def png_test(self): + # Test PNG support (-pS, -pc, -c, -pa) +# files="1343_empty.png 1343_comment.png 1343_exif.png" +# copyTestFiles $files +# runTest exiv2 -c 'comment in Reagan to hide non UTF-8 bytes' +# for file in $files ; do +# for i in 1 2 ; do +# runTest exiv2 -pS $file +# runTest exiv2 -pc $file +# runTest exiv2 -pa $file +# runTest exiv2 -c 'changed comment' $file +# done +# done + + out = BT.Output() + files = ['1343_empty.png' + ,'1343_comment.png' + ,'1343_exif.png' + ] + for file in files: + BT.copyTestFile(file) + for i in [1,2]: + out += BT.Executer('exiv2 -pS {file}', vars()) + out += BT.Executer('exiv2 -pc {file}', vars()) + if i ==1: + out+= '' + out += BT.Executer('exiv2 -pa {file}', vars()) + out += BT.Executer('exiv2 -c "changed comment" {file}', vars()) + + BT.reportTest('png-test', out) # skip! blank lines from -pc are in the wrong order! + + def preview_test(self): # Test driver for previews images = [