r1108 Recursively dump an image (exiv2 -pR file...)
This commit is contained in:
parent
b7607c34db
commit
fd5e983746
@ -113,7 +113,7 @@ namespace Exiv2 {
|
||||
not valid (does not look like data of the specific image type).
|
||||
@caution This function is not thread safe and intended for exiv2 -pS for debugging.
|
||||
*/
|
||||
virtual void printStructure(std::ostream& out, PrintStructureOption option =kpsNone);
|
||||
virtual void printStructure(std::ostream& out, PrintStructureOption option =kpsNone, int depth=0);
|
||||
/*!
|
||||
@brief Read all metadata supported by a specific image format from the
|
||||
image. Before this method is called, the image metadata will be
|
||||
|
||||
@ -159,7 +159,7 @@ namespace Exiv2 {
|
||||
not valid (does not look like data of the specific image type).
|
||||
@caution This function is not thread safe and intended for exiv2 -pS for debugging.
|
||||
*/
|
||||
void printStructure(std::ostream& out, PrintStructureOption option);
|
||||
void printStructure(std::ostream& out, PrintStructureOption option,int depth);
|
||||
//@}
|
||||
|
||||
protected:
|
||||
|
||||
@ -93,7 +93,7 @@ namespace Exiv2
|
||||
not valid (does not look like data of the specific image type).
|
||||
@caution This function is not thread safe and intended for exiv2 -pS for debugging.
|
||||
*/
|
||||
void printStructure(std::ostream& out, PrintStructureOption option);
|
||||
void printStructure(std::ostream& out, PrintStructureOption option,int depth);
|
||||
//@}
|
||||
|
||||
//! @name Accessors
|
||||
|
||||
@ -91,9 +91,23 @@ namespace Exiv2 {
|
||||
@brief Print out the structure of image file.
|
||||
@throw Error if reading of the file fails or the image data is
|
||||
not valid (does not look like data of the specific image type).
|
||||
@caution This function is not thread safe and intended for exiv2 -pS for debugging.
|
||||
@caution This function is not thread safe and intended for exiv2 -p{S|R} as a file debugging aid
|
||||
*/
|
||||
void printStructure(std::ostream& out, PrintStructureOption option);
|
||||
void printStructure(std::ostream& out, PrintStructureOption option,int depth=-1);
|
||||
|
||||
/*!
|
||||
@brief Print out the structure of image file.
|
||||
@throw Error if reading of the file fails or the image data is
|
||||
not valid (does not look like data of the specific image type).
|
||||
@caution This function is not thread safe. See TiffImage::printStructure for more details
|
||||
*/
|
||||
static void printTiffStructure(BasicIo& io,std::ostream& out, PrintStructureOption option,int depth);
|
||||
|
||||
/*!
|
||||
@brief Print out the structure of a TIFF IFD
|
||||
@caution This function is not thread safe. See TiffImage::printStructure for more details
|
||||
*/
|
||||
static void printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,size_t start,bool bSwap,char c,int depth);
|
||||
|
||||
/*!
|
||||
@brief Not supported. TIFF format does not contain a comment.
|
||||
|
||||
14
src/exiv2.1
14
src/exiv2.1
@ -3,7 +3,7 @@
|
||||
.\" First parameter, NAME, should be all caps
|
||||
.\" Second parameter, SECTION, should be 1-8, maybe w/ subsection
|
||||
.\" other parameters are allowed: see man(7), man(1)
|
||||
.TH EXIV2 1 "Dec 29, 2015"
|
||||
.TH EXIV2 1 "Jan 5, 2016"
|
||||
.\" Please adjust this date whenever revising the manpage.
|
||||
.\"
|
||||
.\" Some roff macros, for reference:
|
||||
@ -175,9 +175,9 @@ fmt Default format is %Y%m%d_%H%M%S.
|
||||
lvl d | i | i | w | e
|
||||
debug, info, warning, error
|
||||
|
||||
mod s | a | t | v | h | i | x | c | p | i | S | X :
|
||||
mod s | a | t | v | h | i | x | c | p | i | C | R | S | X :
|
||||
summary, add, translated, vanilla, hex ...
|
||||
iptc ,xmp, comment, preview, Structure,XMP raw
|
||||
iptc ,xmp, comment, preview, ICC, Recursive, Structure, raw XMP
|
||||
|
||||
tgt a | c | e | i | t | x
|
||||
all, comment, exif, iptc, thumb, xmp
|
||||
@ -315,9 +315,13 @@ c : JPEG comment
|
||||
.br
|
||||
p : list available image previews, sorted by preview image size in pixels
|
||||
.br
|
||||
S : print image structure information (jpg, png and tiff only)
|
||||
C : print image ICC Profile (jpg only)
|
||||
.br
|
||||
X : print "raw" XMP (jpg, png and tiff only)
|
||||
R : print image structure recursively (jpg, tiff only)
|
||||
.br
|
||||
S : print image structure information (jpg, png, tiff only)
|
||||
.br
|
||||
X : print "raw" XMP (jpg, png, tiff only)
|
||||
.TP
|
||||
.B \-P \fIflgs\fP
|
||||
Print flags for fine control of the tag list ('print' action). Allows
|
||||
|
||||
@ -169,7 +169,7 @@ namespace Exiv2 {
|
||||
{
|
||||
}
|
||||
|
||||
void Image::printStructure(std::ostream&, PrintStructureOption)
|
||||
void Image::printStructure(std::ostream&, PrintStructureOption,int /*depth*/)
|
||||
{
|
||||
throw Error(13, io_->path());
|
||||
}
|
||||
|
||||
@ -35,6 +35,7 @@ EXIV2_RCSID("@(#) $Id$")
|
||||
#include "config.h"
|
||||
|
||||
#include "jpgimage.hpp"
|
||||
#include "tiffimage.hpp"
|
||||
#include "image_int.hpp"
|
||||
#include "error.hpp"
|
||||
#include "futils.hpp"
|
||||
@ -516,9 +517,9 @@ namespace Exiv2 {
|
||||
return true ;
|
||||
}
|
||||
|
||||
#define REPORT_MARKER if ( option == kpsBasic ) out << Internal::stringFormat("%8ld | %#02x %-5s",io_->tell(), marker,nm[marker].c_str())
|
||||
#define REPORT_MARKER if ( (option == kpsBasic||option == kpsRecursive) ) out << Internal::stringFormat("%8ld | %#02x %-5s",io_->tell(), marker,nm[marker].c_str())
|
||||
|
||||
void JpegBase::printStructure(std::ostream& out, PrintStructureOption option)
|
||||
void JpegBase::printStructure(std::ostream& out, PrintStructureOption option,int depth)
|
||||
{
|
||||
if (io_->open() != 0) throw Error(9, io_->path(), strError());
|
||||
// Ensure that this is the correct image type
|
||||
@ -570,7 +571,8 @@ namespace Exiv2 {
|
||||
out << " address | marker | length | data" << std::endl ;
|
||||
REPORT_MARKER;
|
||||
}
|
||||
first = false;
|
||||
first = false;
|
||||
bool bLF = option == kpsBasic||option == kpsRecursive;
|
||||
|
||||
// Read size and signature
|
||||
std::memset(buf.pData_, 0x0, buf.size_);
|
||||
@ -590,7 +592,7 @@ namespace Exiv2 {
|
||||
){
|
||||
size = getUShort(buf.pData_, bigEndian);
|
||||
}
|
||||
if ( option == kpsBasic ) out << Internal::stringFormat(" | %7d ", size);
|
||||
if ( option == kpsBasic||option==kpsRecursive ) out << Internal::stringFormat(" | %7d ", size);
|
||||
|
||||
// only print the signature for appn
|
||||
if (marker >= app0_ && marker <= (app0_ | 0x0F)) {
|
||||
@ -637,15 +639,43 @@ namespace Exiv2 {
|
||||
bufRead = size;
|
||||
delete [] icc;
|
||||
}
|
||||
} else if ( option == kpsBasic ) {
|
||||
out << "| " << Internal::binaryToString(buf,32,size>0?2:0);
|
||||
} else if ( option == kpsBasic||option==kpsRecursive ) {
|
||||
out << "| " << Internal::binaryToString(buf,size>32?32:size,size>0?2:0);
|
||||
}
|
||||
|
||||
// for MPF: http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/MPF.html
|
||||
if( (option == kpsRecursive && marker == (app0_+1) && std::strcmp(http,"Exif")==0 )
|
||||
|| (option == kpsRecursive && marker == (app0_+2) && std::strcmp(http,"MPF" )==0 )
|
||||
) {
|
||||
// extract Exif data block which is tiff formatted
|
||||
if ( size > 0 ) {
|
||||
out << std::endl;
|
||||
|
||||
// allocate storage and current file position
|
||||
byte* exif = new byte[size];
|
||||
size_t restore = io_->tell();
|
||||
|
||||
// copy the data to memory
|
||||
io_->seek(-bufRead , BasicIo::cur);
|
||||
io_->read(exif,size);
|
||||
std::size_t start = std::strcmp(http,"Exif")==0 ? 8 : 6;
|
||||
|
||||
// create a copy on write memio object with the data, then print the structure
|
||||
BasicIo::AutoPtr p = BasicIo::AutoPtr(new MemIo(exif+start,size-start));
|
||||
TiffImage::printTiffStructure(*p,out,option,depth);
|
||||
|
||||
// restore and clean up
|
||||
io_->seek(restore,Exiv2::BasicIo::beg);
|
||||
delete [] exif;
|
||||
bLF = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Skip the segment if the size is known
|
||||
if (io_->seek(size - bufRead, BasicIo::cur)) throw Error(14);
|
||||
|
||||
if ( option == kpsBasic ) out << std::endl;
|
||||
if ( bLF ) out << std::endl;
|
||||
|
||||
if (marker == sos_)
|
||||
// sos_ is immediately followed by entropy-coded data & eoi_
|
||||
|
||||
@ -48,6 +48,8 @@ EXIV2_RCSID("@(#) $Id$")
|
||||
#include <iostream>
|
||||
#include <cassert>
|
||||
|
||||
#include <zlib.h> // To uncompress IccProfiles
|
||||
|
||||
// Signature from front of PNG file
|
||||
const unsigned char pngSignature[8] = { 0x89, 0x50, 0x4E, 0x47, 0x0D, 0x0A, 0x1A, 0x0A };
|
||||
|
||||
@ -92,7 +94,47 @@ namespace Exiv2 {
|
||||
return "image/png";
|
||||
}
|
||||
|
||||
void PngImage::printStructure(std::ostream& out, PrintStructureOption option)
|
||||
static void zlibUncompress(const byte* compressedText,
|
||||
unsigned int compressedTextSize,
|
||||
DataBuf& arr)
|
||||
{
|
||||
uLongf uncompressedLen = compressedTextSize * 2; // just a starting point
|
||||
int zlibResult;
|
||||
int dos = 0;
|
||||
|
||||
do {
|
||||
arr.alloc(uncompressedLen);
|
||||
zlibResult = uncompress((Bytef*)arr.pData_,
|
||||
&uncompressedLen,
|
||||
compressedText,
|
||||
compressedTextSize);
|
||||
if (zlibResult == Z_OK) {
|
||||
assert((uLongf)arr.size_ >= uncompressedLen);
|
||||
arr.size_ = uncompressedLen;
|
||||
}
|
||||
else if (zlibResult == Z_BUF_ERROR) {
|
||||
// the uncompressedArray needs to be larger
|
||||
uncompressedLen *= 2;
|
||||
// DoS protection. can't be bigger than 64k
|
||||
if (uncompressedLen > 131072) {
|
||||
if (++dos > 1) break;
|
||||
uncompressedLen = 131072;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// something bad happened
|
||||
throw Error(14);
|
||||
}
|
||||
}
|
||||
while (zlibResult == Z_BUF_ERROR);
|
||||
|
||||
if (zlibResult != Z_OK) {
|
||||
throw Error(14);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
void PngImage::printStructure(std::ostream& out, PrintStructureOption option, int /*depth*/)
|
||||
{
|
||||
if (io_->open() != 0) {
|
||||
throw Error(9, io_->path(), strError());
|
||||
@ -104,7 +146,7 @@ namespace Exiv2 {
|
||||
throw Error(3, "PNG");
|
||||
}
|
||||
|
||||
if ( option == kpsIccProfile || option == kpsRecursive ) {
|
||||
if ( option == kpsRecursive || option == kpsIccProfile ) { // disable kpsIccProfile because decompress isn't working!
|
||||
throw Error(13, io_->path());
|
||||
}
|
||||
|
||||
@ -112,7 +154,7 @@ namespace Exiv2 {
|
||||
chType[0]=0;
|
||||
chType[4]=0;
|
||||
|
||||
if ( option == kpsBasic || option == kpsXMP ) {
|
||||
if ( option == kpsBasic || option == kpsXMP || option == kpsIccProfile ) {
|
||||
|
||||
if ( option == kpsBasic ) {
|
||||
out << "STRUCTURE OF PNG FILE: " << io_->path() << std::endl;
|
||||
@ -154,24 +196,38 @@ namespace Exiv2 {
|
||||
}
|
||||
|
||||
if ( option == kpsBasic ) out << Internal::stringFormat("%8d | %5d | %10s |%8d | ",(uint32_t)address, index++,chType,dOff) << dataString << std::endl;
|
||||
// for XMP, back up and read the whole block
|
||||
|
||||
// for XMP and ICC, back up and read the whole block
|
||||
const char* key = "XML:com.adobe.xmp" ;
|
||||
size_t start = ::strlen(key);
|
||||
|
||||
if ( option == kpsXMP && dataString.find(key)==0 ) {
|
||||
if( (option == kpsXMP && dataString.find(key)==0)
|
||||
|| (option == kpsIccProfile && std::strcmp(chType,"iCCP")==0)
|
||||
){
|
||||
#if defined(_MSC_VER)
|
||||
io_->seek(-static_cast<int64_t>(blen) , BasicIo::cur);
|
||||
#else
|
||||
io_->seek(-static_cast<long>(blen) , BasicIo::cur);
|
||||
#endif
|
||||
dataOffset = dOff ;
|
||||
byte* xmp = new byte[dataOffset+5];
|
||||
io_->read(xmp,dataOffset+4);
|
||||
xmp[dataOffset]=0;
|
||||
while ( xmp[start] == 0 ) start++; // crawl over the '\0' bytes between XML:....\0\0<xml stuff
|
||||
out << xmp+start; // output the xml
|
||||
delete [] xmp;
|
||||
dataOffset = 0;
|
||||
if ( option == kpsXMP ) {
|
||||
byte* xmp = new byte[dataOffset+5];
|
||||
io_->read(xmp,dataOffset+4);
|
||||
xmp[dataOffset]=0;
|
||||
while ( xmp[start] == 0 ) start++; // crawl over the '\0' bytes between XML:....\0\0<xml stuff
|
||||
out << xmp+start; // output the xml
|
||||
delete [] xmp;
|
||||
dataOffset = 0; // we've read the data, so don't seek past the block
|
||||
} else if ( option == kpsIccProfile ) {
|
||||
byte* icc = new byte[dataOffset];
|
||||
io_->read(icc,dataOffset);
|
||||
DataBuf decompressed;
|
||||
size_t name_l = std::strlen((const char*)icc)+1; // length of profile name
|
||||
zlibUncompress(icc+name_l,dataOffset-name_l,decompressed);
|
||||
out.write((const char*)decompressed.pData_,decompressed.size_);
|
||||
delete [] icc;
|
||||
dataOffset = 0;
|
||||
}
|
||||
}
|
||||
|
||||
if ( dataOffset ) io_->seek(dataOffset + 4 , BasicIo::cur);
|
||||
|
||||
71
src/tags.cpp
71
src/tags.cpp
@ -85,6 +85,7 @@ namespace Exiv2 {
|
||||
{ exifId, "Exif", "Photo", exifTagList },
|
||||
{ gpsId, "GPSInfo", "GPSInfo", gpsTagList },
|
||||
{ iopId, "Iop", "Iop", iopTagList },
|
||||
{ mpfId, "MPF", "MPF", mpfTagList },
|
||||
{ subImage1Id, "SubImage1", "SubImage1", ifdTagList },
|
||||
{ subImage2Id, "SubImage2", "SubImage2", ifdTagList },
|
||||
{ subImage3Id, "SubImage3", "SubImage3", ifdTagList },
|
||||
@ -2118,11 +2119,81 @@ namespace Exiv2 {
|
||||
iopId, iopTags, asciiString, -1, printValue)
|
||||
};
|
||||
|
||||
// MPF Tags http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/MPF.html
|
||||
static const TagInfo mpfTagInfo[] = {
|
||||
TagInfo(0xb000, "MPFVersion", N_("MPFVersion"),
|
||||
N_("MPF Version"),
|
||||
mpfId, iopTags, asciiString, 0, printValue),
|
||||
TagInfo(0xb001, "MPFNumberOfImages", N_("MPFNumberOfImages"),
|
||||
N_("MPF Number of Images"),
|
||||
mpfId, iopTags, undefined, -1, printExifVersion),
|
||||
TagInfo(0xb002, "MPFImageList", N_("MPFImageList"),
|
||||
N_("MPF Image List"),
|
||||
mpfId, iopTags, asciiString, 0, printValue),
|
||||
TagInfo(0xb003, "MPFImageUIDList", N_("MPFImageUIDList "),
|
||||
N_("MPF Image UID List"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb004, "MPFTotalFrames", N_("MPFTotalFrames"),
|
||||
N_("MPF Total Frames"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb101, "MPFIndividualNum", N_("MPFIndividualNum"),
|
||||
N_("MPF Individual Num"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb201, "MPFPanOrientation", N_("MPFPanOrientation"),
|
||||
N_("MPFPanOrientation"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb202, "MPFPanOverlapH", N_("MPFPanOverlapH"),
|
||||
N_("MPF Pan Overlap Horizonal"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb203, "MPFPanOverlapV", N_("MPFPanOverlapV"),
|
||||
N_("MPF Pan Overlap Vertical"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb204, "MPFBaseViewpointNum", N_("MPFBaseViewpointNum"),
|
||||
N_("MPF Base Viewpoint Number"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb205, "MPFConvergenceAngle", N_("MPFConvergenceAngle"),
|
||||
N_("MPF Convergence Angle"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb206, "MPFBaselineLength", N_("MPFBaselineLength"),
|
||||
N_("MPF Baseline Length"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb207, "MPFVerticalDivergence", N_("MPFVerticalDivergence"),
|
||||
N_("MPF Vertical Divergence"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb208, "MPFAxisDistanceX", N_("MPFAxisDistanceX"),
|
||||
N_("MPF Axis Distance X"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb209, "MPFAxisDistanceY", N_("MPFAxisDistanceY"),
|
||||
N_("MPF Axis Distance Y"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb20a, "MPFAxisDistanceZ", N_("MPFAxisDistanceZ"),
|
||||
N_("MPF Axis Distance Z"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb20b, "MPFYawAngle", N_("MPFYawAngle"),
|
||||
N_("MPF Yaw Angle"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb20c, "MPFPitchAngle", N_("MPFPitchAngle"),
|
||||
N_("MPF Pitch Angle"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb20d, "MPFRollAngle", N_("MPFRollAngle"),
|
||||
N_("MPF Roll Angle"),
|
||||
mpfId, iopTags, unsignedLong, 1, printValue),
|
||||
// End of list marker
|
||||
TagInfo(0xffff, "(UnknownIopTag)", N_("Unknown MPF tag"),
|
||||
N_("Unknown MPF tag"),
|
||||
mpfId, iopTags, asciiString, -1, printValue)
|
||||
};
|
||||
|
||||
const TagInfo* iopTagList()
|
||||
{
|
||||
return iopTagInfo;
|
||||
}
|
||||
|
||||
const TagInfo* mpfTagList()
|
||||
{
|
||||
return mpfTagInfo;
|
||||
}
|
||||
|
||||
// Synthesized Exiv2 Makernote info Tags (read-only)
|
||||
static const TagInfo mnTagInfo[] = {
|
||||
TagInfo(0x0001, "Offset", N_("Offset"),
|
||||
|
||||
@ -62,6 +62,7 @@ namespace Exiv2 {
|
||||
exifId,
|
||||
gpsId,
|
||||
iopId,
|
||||
mpfId,
|
||||
subImage1Id,
|
||||
subImage2Id,
|
||||
subImage3Id,
|
||||
@ -304,6 +305,8 @@ namespace Exiv2 {
|
||||
const TagInfo* gpsTagList();
|
||||
//! Return read-only list of built-in Exiv2 Makernote info tags
|
||||
const TagInfo* mnTagList();
|
||||
//! Return read-only list of built-in mfp Tags http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/MPF.html
|
||||
const TagInfo* mpfTagList();
|
||||
|
||||
//! Return the group id for a group name
|
||||
IfdId groupId(const std::string& groupName);
|
||||
|
||||
@ -393,6 +393,7 @@ namespace Exiv2 {
|
||||
for (ti = Exiv2:: gpsTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Exiv2:: ifdTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Exiv2::exifTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
for (ti = Exiv2:: mpfTagList(), idx = 0; ti[idx].tag_ != 0xffff; ++idx) tags[ti[idx].tag_] = ti[idx].name_;
|
||||
}
|
||||
init = false;
|
||||
|
||||
@ -446,7 +447,14 @@ namespace Exiv2 {
|
||||
|
||||
#define MIN(a,b) ((a)<(b))?(b):(a)
|
||||
|
||||
void TiffImage::printStructure(std::ostream& out, Exiv2::PrintStructureOption option)
|
||||
static std::string indent(int depth)
|
||||
{
|
||||
std::string result;
|
||||
while ( depth -- ) result += " ";
|
||||
return result;
|
||||
}
|
||||
|
||||
void TiffImage::printStructure(std::ostream& out, Exiv2::PrintStructureOption option,int depth)
|
||||
{
|
||||
if (io_->open() != 0) throw Error(9, io_->path(), strError());
|
||||
// Ensure that this is the correct image type
|
||||
@ -455,113 +463,138 @@ namespace Exiv2 {
|
||||
throw Error(15);
|
||||
}
|
||||
|
||||
if ( option == kpsIccProfile || option == kpsRecursive ) {
|
||||
throw Error(13, io_->path());
|
||||
if ( option == kpsIccProfile ) {
|
||||
throw Error(13, io_->path());
|
||||
}
|
||||
io_->seek(0,BasicIo::beg);
|
||||
|
||||
printTiffStructure(io(),out,option,depth-1);
|
||||
}
|
||||
|
||||
void TiffImage::printIFDStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,size_t start,bool bSwap,char c,int depth)
|
||||
{
|
||||
depth++;
|
||||
if ( option == kpsBasic || option == kpsRecursive ) {
|
||||
out << indent(depth) << Internal::stringFormat("STRUCTURE OF TIFF FILE (%c%c): ",c,c) << io.path() << std::endl;
|
||||
out << indent(depth) << " address | tag | type | count | offset | value\n";
|
||||
}
|
||||
|
||||
// buffer
|
||||
const size_t dirSize = 32;
|
||||
DataBuf dir(dirSize);
|
||||
while ( start ) {
|
||||
// if ( option == kpsBasic ) out << Internal::stringFormat("bSwap, start = %d %u\n",bSwap,offset);
|
||||
|
||||
if ( option == kpsBasic || option == kpsXMP ) {
|
||||
io_->seek(0,BasicIo::beg);
|
||||
// Read top of directory
|
||||
io.seek(start,BasicIo::beg);
|
||||
io.read(dir.pData_, 2);
|
||||
uint16_t dirLength = byteSwap2(dir,0,bSwap);
|
||||
|
||||
// Read the dictionary
|
||||
for ( int i = 0 ; i < dirLength ; i ++ ) {
|
||||
io.read(dir.pData_, 12);
|
||||
uint16_t tag = byteSwap2(dir,0,bSwap);
|
||||
uint16_t type = byteSwap2(dir,2,bSwap);
|
||||
uint32_t count = byteSwap4(dir,4,bSwap);
|
||||
uint32_t offset = byteSwap4(dir,8,bSwap);
|
||||
|
||||
std::string sp = "" ; // output spacer
|
||||
|
||||
//prepare to print the value
|
||||
uint16_t kount = isPrintXMP(tag,option) ? count // restrict long arrays
|
||||
: isStringType(type) ? (count > 32 ? 32 : count)
|
||||
: count > 5 ? 5
|
||||
: count
|
||||
;
|
||||
uint32_t pad = isStringType(type) ? 1 : 0;
|
||||
uint32_t size = isStringType(type) ? 1
|
||||
: is2ByteType(type) ? 2
|
||||
: is4ByteType(type) ? 4
|
||||
: 1
|
||||
;
|
||||
uint32_t Offset = 0 ; // used by ExifTag == 0x8769 && MakerNote == 0x927c to locate an FID
|
||||
|
||||
// if ( offset > io.size() ) offset = 0;
|
||||
DataBuf buf(MIN(size*kount + pad,48)); // allocate a buffer
|
||||
if ( isStringType(type) || count*size > 4 ) { // data is in the directory => read into buffer
|
||||
size_t restore = io.tell(); // save
|
||||
io.seek(offset,BasicIo::beg); // position
|
||||
io.read(buf.pData_,kount*size);// read
|
||||
io.seek(restore,BasicIo::beg); // restore
|
||||
} else { // move data from directory to the buffer
|
||||
std::memcpy(buf.pData_,dir.pData_+8,12);
|
||||
}
|
||||
|
||||
if ( option == kpsBasic || option == kpsRecursive ) {
|
||||
uint32_t address = start + 2 + i*12 ;
|
||||
out << indent(depth) << Internal::stringFormat("%8u | %#06x %-25s |%10s |%9u |%9u | ",address,tag,tagName(tag,25),typeName(type),count,offset);
|
||||
|
||||
if ( isShortType(type) ){
|
||||
for ( uint16_t k = 0 ; k < kount ; k++ ) {
|
||||
out << sp << byteSwap2(buf,k*size,bSwap);
|
||||
sp = " ";
|
||||
}
|
||||
} else if ( isLongType(type) ){
|
||||
for ( uint16_t k = 0 ; k < kount ; k++ ) {
|
||||
out << sp << byteSwap4(buf,k*size,bSwap);
|
||||
if ( k == 0 ) Offset = byteSwap4(buf,k*size,bSwap) ;
|
||||
sp = " ";
|
||||
}
|
||||
} else if ( isRationalType(type) ){
|
||||
for ( uint16_t k = 0 ; k < kount ; k++ ) {
|
||||
uint16_t a = byteSwap2(buf,k*size+0,bSwap);
|
||||
uint16_t b = byteSwap2(buf,k*size+2,bSwap);
|
||||
if ( isLittleEndian() ) {
|
||||
if ( bSwap ) out << sp << b << "/" << a;
|
||||
else out << sp << a << "/" << b;
|
||||
} else {
|
||||
if ( bSwap ) out << sp << a << "/" << b;
|
||||
else out << sp << b << "/" << a;
|
||||
}
|
||||
sp = " ";
|
||||
}
|
||||
} else if ( isStringType(type) ) {
|
||||
out << sp << Internal::binaryToString(buf, kount);
|
||||
}
|
||||
sp = kount == count ? "" : " ...";
|
||||
out << sp << std::endl;
|
||||
if ( option == kpsRecursive
|
||||
&& (tag == 0x8769 /* ExifTag */ || tag == 0x927c /* MakerNote */)
|
||||
){
|
||||
size_t restore = io.tell();
|
||||
printIFDStructure(io,out,option,Offset,bSwap,c,depth);
|
||||
io.seek(restore,BasicIo::beg);
|
||||
}
|
||||
}
|
||||
|
||||
if ( isPrintXMP(tag,option) ) {
|
||||
buf.pData_[count]=0;
|
||||
out << (char*) buf.pData_;
|
||||
}
|
||||
}
|
||||
io.read(dir.pData_, 4);
|
||||
start = byteSwap4(dir,0,bSwap);
|
||||
out.flush();
|
||||
} // while start
|
||||
depth--;
|
||||
}
|
||||
|
||||
void TiffImage::printTiffStructure(BasicIo& io, std::ostream& out, Exiv2::PrintStructureOption option,int depth)
|
||||
{
|
||||
if ( option == kpsBasic || option == kpsXMP || option == kpsRecursive ) {
|
||||
// buffer
|
||||
const size_t dirSize = 32;
|
||||
DataBuf dir(dirSize);
|
||||
|
||||
// read header (we already know for certain that we have a Tiff file)
|
||||
io_->read(dir.pData_, 8);
|
||||
io.read(dir.pData_, 8);
|
||||
char c = (char) dir.pData_[0] ;
|
||||
bool bSwap = ( c == 'M' && isLittleEndian() )
|
||||
|| ( c == 'I' && isBigEndian() )
|
||||
;
|
||||
|
||||
if ( option == kpsBasic ) {
|
||||
out << Internal::stringFormat("STRUCTURE OF TIFF FILE (%c%c): ",c,c) << io_->path() << std::endl;
|
||||
out << " address | tag | type | count | offset | value\n";
|
||||
}
|
||||
|
||||
uint32_t start = byteSwap4(dir,4,bSwap);
|
||||
while ( start ) {
|
||||
// if ( option == kpsBasic ) out << Internal::stringFormat("bSwap, start = %d %u\n",bSwap,offset);
|
||||
|
||||
// Read top of directory
|
||||
io_->seek(start,BasicIo::beg);
|
||||
io_->read(dir.pData_, 2);
|
||||
uint16_t dirLength = byteSwap2(dir,0,bSwap);
|
||||
|
||||
// Read the dictionary
|
||||
for ( int i = 0 ; i < dirLength ; i ++ ) {
|
||||
io_->read(dir.pData_, 12);
|
||||
uint16_t tag = byteSwap2(dir,0,bSwap);
|
||||
uint16_t type = byteSwap2(dir,2,bSwap);
|
||||
uint32_t count = byteSwap4(dir,4,bSwap);
|
||||
uint32_t offset = byteSwap4(dir,8,bSwap);
|
||||
|
||||
std::string sp = "" ; // output spacer
|
||||
|
||||
//prepare to print the value
|
||||
uint16_t kount = isPrintXMP(tag,option) ? count // restrict long arrays
|
||||
: isStringType(type) ? (count > 32 ? 32 : count)
|
||||
: count > 5 ? 5
|
||||
: count
|
||||
;
|
||||
uint32_t pad = isStringType(type) ? 1 : 0;
|
||||
uint32_t size = isStringType(type) ? 1
|
||||
: is2ByteType(type) ? 2
|
||||
: is4ByteType(type) ? 4
|
||||
: 1
|
||||
;
|
||||
|
||||
DataBuf buf(MIN(size*kount + pad,48)); // allocate a buffer
|
||||
if ( isStringType(type) || count*size > 4 ) { // data is in the directory => read into buffer
|
||||
size_t restore = io_->tell(); // save
|
||||
io_->seek(offset,BasicIo::beg); // position
|
||||
io_->read(buf.pData_,kount*size);// read
|
||||
io_->seek(restore,BasicIo::beg); // restore
|
||||
} else { // move data from directory to the buffer
|
||||
std::memcpy(buf.pData_,dir.pData_+8,12);
|
||||
}
|
||||
|
||||
if ( option == kpsBasic ) {
|
||||
uint32_t address = start + 2 + i*12 ;
|
||||
out << Internal::stringFormat("%8u | %#06x %-25s |%10s |%9u |%9u | ",address,tag,tagName(tag,25),typeName(type),count,offset);
|
||||
|
||||
if ( isShortType(type) ){
|
||||
for ( uint16_t k = 0 ; k < kount ; k++ ) {
|
||||
out << sp << byteSwap2(buf,k*size,bSwap);
|
||||
sp = " ";
|
||||
}
|
||||
} else if ( isLongType(type) ){
|
||||
for ( uint16_t k = 0 ; k < kount ; k++ ) {
|
||||
out << sp << byteSwap4(buf,k*size,bSwap);
|
||||
sp = " ";
|
||||
}
|
||||
} else if ( isRationalType(type) ){
|
||||
for ( uint16_t k = 0 ; k < kount ; k++ ) {
|
||||
uint16_t a = byteSwap2(buf,k*size+0,bSwap);
|
||||
uint16_t b = byteSwap2(buf,k*size+2,bSwap);
|
||||
if ( isLittleEndian() ) {
|
||||
if ( bSwap ) out << sp << b << "/" << a;
|
||||
else out << sp << a << "/" << b;
|
||||
} else {
|
||||
if ( bSwap ) out << sp << a << "/" << b;
|
||||
else out << sp << b << "/" << a;
|
||||
}
|
||||
sp = " ";
|
||||
}
|
||||
} else if ( isStringType(type) ) {
|
||||
out << sp << Internal::binaryToString(buf, kount);
|
||||
}
|
||||
sp = kount == count ? "" : " ...";
|
||||
out << sp << std::endl;
|
||||
}
|
||||
|
||||
if ( isPrintXMP(tag,option) ) {
|
||||
buf.pData_[count]=0;
|
||||
out << (char*) buf.pData_;
|
||||
}
|
||||
}
|
||||
io_->read(dir.pData_, 4);
|
||||
start = byteSwap4(dir,0,bSwap);
|
||||
} // while offset
|
||||
printIFDStructure(io,out,option,start,bSwap,c,depth);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Loading…
Reference in New Issue
Block a user