Add support for Exif.Canon.AF tags to be read from images
This PR (and fix981_canonAutoFocus2) use a decoder listed in TiffMappingInfo to decode Exif.Canon.AFInfo. The decoding function "manufactures" Exif tags such as Exif.Canon.AFNumPoints from the data in Exif.Canon.AFInfo. These tags must never be written to file and are removed from the metadata in exif.cpp/ExifParser::encode(). Three of the tags created (AFPointsInFocus,AFPointsSelected, AFPrimaryPoint) are bitmasks. As the camera can have up to 64 focus points, the tags are a 64 bit mask to say which points are active. The function printBitmask() reports data such as 1,2,3 or (none). This decoding function decodeCanonAFInfo() added to TiffMappingInfo manufactures the new tags. Normally, tags are processed by the binary tag decoder and that approach was taken in branch fix981_canonAf. However, the binary tag decoder cannot deal with AFInfo because the size of some metadata arrays cannot be determined at compile time.
This commit is contained in:
@@ -406,6 +406,23 @@ namespace Exiv2 {
|
||||
{ 2, N_("Adobe RGB") }
|
||||
};
|
||||
|
||||
extern const TagDetails canonAFAreaMode[] = {
|
||||
{ 0, N_("Off (Manual Focus)") },
|
||||
{ 1, N_("AF Point Expansion (surround)")},
|
||||
{ 2, N_("Single-point AF") },
|
||||
{ 4, N_("Multi-point AF") },
|
||||
{ 5, N_("Face Detect AF") },
|
||||
{ 6, N_("Face + Tracking") },
|
||||
{ 7, N_("Zone AF") },
|
||||
{ 8, N_("AF Point Expansion (4 point)") },
|
||||
{ 9, N_("Spot AF") },
|
||||
{ 10, N_("AF Point Expansion (8 point)") },
|
||||
{ 11, N_("Flexizone Multi (49 point)") },
|
||||
{ 12, N_("Flexizone Multi (9 point)") },
|
||||
{ 13, N_("Flexizone Single") },
|
||||
{ 14, N_("Large Zone AF") },
|
||||
};
|
||||
|
||||
// Canon MakerNote Tag Info
|
||||
const TagInfo CanonMakerNote::tagInfo_[] = {
|
||||
TagInfo(0x0000, "0x0000", "0x0000", N_("Unknown"), canonId, makerTags, unsignedShort, -1, printValue),
|
||||
@@ -442,6 +459,21 @@ namespace Exiv2 {
|
||||
TagInfo(0x00c1, "0x00c1", "0x00c1", N_("Unknown"), canonId, makerTags, unsignedShort, -1, printValue),
|
||||
TagInfo(0x00d0, "VRDOffset", N_("VRD Offset"), N_("VRD offset"), canonId, makerTags, unsignedLong, -1, printValue),
|
||||
TagInfo(0x00e0, "SensorInfo", N_("Sensor Info"), N_("Sensor info"), canonId, makerTags, unsignedShort, -1, printValue),
|
||||
TagInfo(0x2600, "AFInfoSize", N_("AF InfoSize"), N_("AF InfoSize"), canonId, makerTags, signedShort, -1, printValue),
|
||||
TagInfo(0x2601, "AFAreaMode", N_("AF Area Mode"), N_("AF Area Mode"), canonId, makerTags, signedShort, -1, EXV_PRINT_TAG(canonAFAreaMode)),
|
||||
TagInfo(0x2602, "AFNumPoints", N_("AF NumPoints"), N_("AF NumPoints"), canonId, makerTags, signedShort, -1, printValue),
|
||||
TagInfo(0x2603, "AFValidPoints", N_("AF ValidPoints"), N_("AF ValidPoints"), canonId, makerTags, signedShort, -1, printValue),
|
||||
TagInfo(0x2604, "AFCanonImageWidth", N_("AF ImageWidth"), N_("AF ImageWidth"), canonId, makerTags, signedShort, -1, printValue),
|
||||
TagInfo(0x2605, "AFCanonImageHeight", N_("AF ImageHeight"), N_("AF ImageHeight"), canonId, makerTags, signedShort, -1, printValue),
|
||||
TagInfo(0x2606, "AFImageWidth", N_("AF Width"), N_("AF Width"), canonId, makerTags, signedShort, -1, printValue),
|
||||
TagInfo(0x2607, "AFImageHeight", N_("AF Height"), N_("AF Height"), canonId, makerTags, signedShort, -1, printValue),
|
||||
TagInfo(0x2608, "AFAreaWidths", N_("AF Area Widths"), N_("AF Area Widths"), canonId, makerTags, signedShort, -1, printValue),
|
||||
TagInfo(0x2609, "AFAreaHeights", N_("AF Area Heights"), N_("AF Area Heights"), canonId, makerTags, signedShort, -1, printValue),
|
||||
TagInfo(0x260a, "AFXPositions", N_("AF X Positions"), N_("AF X Positions"), canonId, makerTags, signedShort, -1, printValue),
|
||||
TagInfo(0x260b, "AFYPositions", N_("AF Y Positions"), N_("AF Y Positions"), canonId, makerTags, signedShort, -1, printValue),
|
||||
TagInfo(0x260c, "AFPointsInFocus", N_("AF Points in Focus"), N_("AF Points in Focus"), canonId, makerTags, signedShort, -1,printBitmask),
|
||||
TagInfo(0x260d, "AFPointsSelected", N_("AF Points Selected"), N_("AF Points Selected"), canonId, makerTags, signedShort, -1, printBitmask),
|
||||
TagInfo(0x260e, "AFPrimaryPoint", N_("AF Primary Point"), N_("AF Primary Point"), canonId, makerTags, signedShort, -1, printBitmask),
|
||||
TagInfo(0x4001, "ColorData", N_("Color Data"), N_("Color data"), canonId, makerTags, unsignedShort, -1, printValue),
|
||||
// End of list marker
|
||||
TagInfo(0xffff, "(UnknownCanonMakerNoteTag)", "(UnknownCanonMakerNoteTag)", N_("Unknown CanonMakerNote tag"), canonId, makerTags, asciiString, -1, printValue)
|
||||
|
||||
+17
-1
@@ -660,7 +660,23 @@ namespace Exiv2 {
|
||||
"Exif.Image.StripByteCounts",
|
||||
"Exif.Image.JPEGInterchangeFormat",
|
||||
"Exif.Image.JPEGInterchangeFormatLength",
|
||||
"Exif.Image.SubIFDs"
|
||||
"Exif.Image.SubIFDs",
|
||||
// Issue 981. Never allow manufactured data to be written
|
||||
"Exif.Canon.AFInfoSize",
|
||||
"Exif.Canon.AFAreaMode",
|
||||
"Exif.Canon.AFNumPoints",
|
||||
"Exif.Canon.AFValidPoints",
|
||||
"Exif.Canon.AFCanonImageWidth",
|
||||
"Exif.Canon.AFCanonImageHeight",
|
||||
"Exif.Canon.AFImageWidth",
|
||||
"Exif.Canon.AFImageHeight",
|
||||
"Exif.Canon.AFAreaWidths",
|
||||
"Exif.Canon.AFAreaHeights",
|
||||
"Exif.Canon.AFXPositions",
|
||||
"Exif.Canon.AFYPositions",
|
||||
"Exif.Canon.AFPointsInFocus",
|
||||
"Exif.Canon.AFPointsSelected",
|
||||
"Exif.Canon.AFPrimaryPoint",
|
||||
};
|
||||
for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfd0Tags); ++i) {
|
||||
ExifData::iterator pos = ed.findKey(ExifKey(filteredIfd0Tags[i]));
|
||||
|
||||
+27
-1
@@ -1944,7 +1944,7 @@ namespace Exiv2 {
|
||||
TagInfo(0xb002, "MPFImageList", N_("MPFImageList"),
|
||||
N_("MPF Image List"),
|
||||
mpfId, mpfTags, asciiString, 0, printValue),
|
||||
TagInfo(0xb003, "MPFImageUIDList", N_("MPFImageUIDList "),
|
||||
TagInfo(0xb003, "MPFImageUIDList", N_("MPFImageUIDList "),
|
||||
N_("MPF Image UID List"),
|
||||
mpfId, mpfTags, unsignedLong, 1, printValue),
|
||||
TagInfo(0xb004, "MPFTotalFrames", N_("MPFTotalFrames"),
|
||||
@@ -2164,6 +2164,32 @@ namespace Exiv2 {
|
||||
return os << value;
|
||||
}
|
||||
|
||||
std::ostream& printBitmask(std::ostream& os, const Value& value, const ExifData* metadata)
|
||||
{
|
||||
if (value.typeId() == Exiv2::unsignedShort || value.typeId() == Exiv2::signedShort)
|
||||
{
|
||||
uint16_t bit = 0;
|
||||
uint16_t comma = 0;
|
||||
for (uint16_t i = 0; i < value.count(); i++ ) { // for each element in value array
|
||||
uint16_t bits = static_cast<uint16_t>(value.toLong(i));
|
||||
for (uint16_t b = 0; b < 16; ++b) { // for every bit
|
||||
if (bits & (1 << b)) {
|
||||
if ( comma++ ) {
|
||||
os << ",";
|
||||
}
|
||||
os << bit;
|
||||
}
|
||||
bit++ ;
|
||||
}
|
||||
}
|
||||
// if no bits are set, print "(none)"
|
||||
if ( !comma ) os << N_("(none)");
|
||||
} else {
|
||||
printValue(os,value,metadata);
|
||||
}
|
||||
return os;
|
||||
}
|
||||
|
||||
float fnumber(float apertureValue)
|
||||
{
|
||||
return std::exp(std::log(2.0f) * apertureValue / 2.f);
|
||||
|
||||
@@ -441,6 +441,8 @@ namespace Exiv2 {
|
||||
std::ostream& printXmpVersion(std::ostream& os, const Value& value, const ExifData*);
|
||||
//! Print a date following the format YYYY-MM-DDTHH:MM:SSZ
|
||||
std::ostream& printXmpDate(std::ostream& os, const Value& value, const ExifData*);
|
||||
//! Print a bitmask as (none) | n | n,m... where: (none) = no bits set | n = bit n from left (0=left-most) | n,m.. = multiple bits "
|
||||
std::ostream& printBitmask(std::ostream& os, const Value& value, const ExifData*);
|
||||
//@}
|
||||
|
||||
//! Calculate F number from an APEX aperture value
|
||||
|
||||
@@ -1514,7 +1514,8 @@ namespace Exiv2 {
|
||||
{ "*", Tag::all, ignoreId, 0, 0 }, // Do not decode tags with group == ignoreId
|
||||
{ "*", 0x02bc, ifd0Id, &TiffDecoder::decodeXmp, 0 /*done before the tree is traversed*/ },
|
||||
{ "*", 0x83bb, ifd0Id, &TiffDecoder::decodeIptc, 0 /*done before the tree is traversed*/ },
|
||||
{ "*", 0x8649, ifd0Id, &TiffDecoder::decodeIptc, 0 /*done before the tree is traversed*/ }
|
||||
{ "*", 0x8649, ifd0Id, &TiffDecoder::decodeIptc, 0 /*done before the tree is traversed*/ },
|
||||
{ "*", 0x0026, canonId, &TiffDecoder::decodeCanonAFInfo, 0 /* Exiv2.Canon.AFInfo is read-only */ },
|
||||
};
|
||||
|
||||
DecoderFct TiffMapping::findDecoder(const std::string& make,
|
||||
|
||||
@@ -45,6 +45,7 @@
|
||||
#include <iomanip>
|
||||
#include <cassert>
|
||||
#include <limits>
|
||||
#include <ostream>
|
||||
|
||||
// *****************************************************************************
|
||||
namespace {
|
||||
@@ -462,6 +463,78 @@ namespace Exiv2 {
|
||||
}
|
||||
} // TiffMetadataDecoder::decodeIptc
|
||||
|
||||
static const TagInfo* findTag(const TagInfo* pList,uint16_t tag)
|
||||
{
|
||||
while ( pList->tag_ != 0xffff && pList->tag_ != tag ) pList++;
|
||||
return pList->tag_ != 0xffff ? pList : NULL;
|
||||
}
|
||||
|
||||
void TiffDecoder::decodeCanonAFInfo(const TiffEntryBase* object) {
|
||||
// report Exif.Canon.AFInfo as usual
|
||||
TiffDecoder::decodeStdTiffEntry(object);
|
||||
if ( object->pValue()->count() < 3 || object->pValue()->typeId() != unsignedShort ) return; // insufficient data
|
||||
|
||||
// create vector of signedShorts from unsignedShorts in Exif.Canon.AFInfo
|
||||
std::vector<int16_t> ints;
|
||||
std::vector<uint16_t> uint;
|
||||
for (int i = 0; i < object->pValue()->count(); i++) {
|
||||
ints.push_back((int16_t) object->pValue()->toLong(i));
|
||||
uint.push_back((uint16_t) object->pValue()->toLong(i));
|
||||
}
|
||||
// Check this is AFInfo2 (ints[0] = bytes in object)
|
||||
if ( ints[0] != object->pValue()->count()*2 ) return ;
|
||||
|
||||
std::string familyGroup(std::string("Exif.") + groupName(object->group()) + ".");
|
||||
|
||||
const uint16_t nPoints = uint.at(2);
|
||||
const uint16_t nMasks = (nPoints+15)/(sizeof(uint16_t) * 8);
|
||||
int nStart = 0;
|
||||
|
||||
struct {
|
||||
uint16_t tag ;
|
||||
uint16_t size ;
|
||||
bool bSigned;
|
||||
} records[] = {
|
||||
{ 0x2600 , 1 , true }, // AFInfoSize
|
||||
{ 0x2601 , 1 , true }, // AFAreaMode
|
||||
{ 0x2602 , 1 , true }, // AFNumPoints
|
||||
{ 0x2603 , 1 , true }, // AFValidPoints
|
||||
{ 0x2604 , 1 , true }, // AFCanonImageWidth
|
||||
{ 0x2605 , 1 , true }, // AFCanonImageHeight
|
||||
{ 0x2606 , 1 , true }, // AFImageWidth"
|
||||
{ 0x2607 , 1 , true }, // AFImageHeight
|
||||
{ 0x2608 , nPoints , true }, // AFAreaWidths
|
||||
{ 0x2609 , nPoints , true }, // AFAreaHeights
|
||||
{ 0x260a , nPoints , true }, // AFXPositions
|
||||
{ 0x260b , nPoints , true }, // AFYPositions
|
||||
{ 0x260c , nMasks , false }, // AFPointsInFocus
|
||||
{ 0x260d , nMasks , false }, // AFPointsSelected
|
||||
{ 0x260e , nMasks , false }, // AFPrimaryPoint
|
||||
{ 0xffff , 0 , true } // end marker
|
||||
};
|
||||
// check we have enough data!
|
||||
uint16_t count = 0;
|
||||
for ( uint16_t i = 0; records[i].tag != 0xffff ; i++) count += records[i].size ;
|
||||
if ( count > ints.size() ) return ;
|
||||
|
||||
for ( uint16_t i = 0; records[i].tag != 0xffff ; i++) {
|
||||
const TagInfo* pTags = ExifTags::tagList("Canon") ;
|
||||
const TagInfo* pTag = findTag(pTags,records[i].tag);
|
||||
if ( pTag ) {
|
||||
Exiv2::Value::AutoPtr v = Exiv2::Value::create(records[i].bSigned?Exiv2::signedShort:Exiv2::unsignedShort);
|
||||
std::ostringstream s;
|
||||
if ( records[i].bSigned ) {
|
||||
for ( int16_t k = 0 ; k < records[i].size ; k++ ) s << " " << ints.at(nStart++);
|
||||
} else {
|
||||
for ( int16_t k = 0 ; k < records[i].size ; k++ ) s << " " << uint.at(nStart++);
|
||||
}
|
||||
|
||||
v->read(s.str());
|
||||
exifData_[familyGroup + pTag->name_] = *v;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void TiffDecoder::decodeTiffEntry(const TiffEntryBase* object)
|
||||
{
|
||||
assert(object != 0);
|
||||
|
||||
@@ -332,6 +332,8 @@ namespace Exiv2 {
|
||||
void decodeIptc(const TiffEntryBase* object);
|
||||
//! Decode XMP packet from an XMLPacket tag
|
||||
void decodeXmp(const TiffEntryBase* object);
|
||||
//! Decode Exif.Canon.AFInfo
|
||||
void decodeCanonAFInfo(const TiffEntryBase* object);
|
||||
//@}
|
||||
|
||||
private:
|
||||
|
||||
Binary file not shown.
Binary file not shown.
Binary file not shown.
Binary file not shown.
@@ -0,0 +1,65 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from system_tests import CaseMeta, path
|
||||
|
||||
class CanonAfInfoTest(metaclass=CaseMeta):
|
||||
|
||||
filenameA = path("$data_path/test_issue_981a.exv")
|
||||
filenameB = path("$data_path/test_issue_981b.exv")
|
||||
filenameC = path("$data_path/test_issue_981c.exv")
|
||||
filenameC = path("$data_path/test_issue_981c.exv")
|
||||
filenameD = path("$data_path/test_issue_981d.exv")
|
||||
commands = ["$exiv2 -pa --grep Canon.AF $filenameA",
|
||||
"$exiv2 -pa --grep Canon.AF $filenameB",
|
||||
"$exiv2 -pv --grep Points $filenameC",
|
||||
"$exiv2 -pt --grep Points $filenameC",
|
||||
"$exiv2 -pv --grep Primary $filenameD",
|
||||
"$exiv2 -pt --grep Primary $filenameD",
|
||||
]
|
||||
|
||||
stdout = ["""Exif.Canon.AFInfo Short 48 96 2 9 9 4752 3168 4272 2848 115 115 115 162 200 162 115 115 115 153 153 153 105 199 105 153 153 153 64409 64862 64862 0 0 0 674 674 1127 0 321 65215 603 0 64933 321 65215 0 16 256 0 65535
|
||||
Exif.Canon.AFInfoSize SShort 1 96
|
||||
Exif.Canon.AFAreaMode SShort 1 Single-point AF
|
||||
Exif.Canon.AFNumPoints SShort 1 9
|
||||
Exif.Canon.AFValidPoints SShort 1 9
|
||||
Exif.Canon.AFCanonImageWidth SShort 1 4752
|
||||
Exif.Canon.AFCanonImageHeight SShort 1 3168
|
||||
Exif.Canon.AFImageWidth SShort 1 4272
|
||||
Exif.Canon.AFImageHeight SShort 1 2848
|
||||
Exif.Canon.AFAreaWidths SShort 9 115 115 115 162 200 162 115 115 115
|
||||
Exif.Canon.AFAreaHeights SShort 9 153 153 153 105 199 105 153 153 153
|
||||
Exif.Canon.AFXPositions SShort 9 -1127 -674 -674 0 0 0 674 674 1127
|
||||
Exif.Canon.AFYPositions SShort 9 0 321 -321 603 0 -603 321 -321 0
|
||||
Exif.Canon.AFPointsInFocus Short 1 4
|
||||
Exif.Canon.AFPointsSelected Short 1 8
|
||||
Exif.Canon.AFPrimaryPoint Short 1 (none)
|
||||
""" , """Exif.Canon.AFInfo Short 273 546 2 63 61 6720 4480 6720 4480 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 0 0 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 0 0 65200 64790 64435 64099 63764 336 0 65200 64099 63764 1772 1437 1101 746 336 0 1437 1101 746 336 0 65200 64790 64435 336 0 65200 64790 64435 64099 63764 1772 64790 64435 64099 63764 1772 1437 1101 746 63764 1772 1437 1101 746 336 0 65200 1101 746 336 0 65200 64790 64435 64099 336 0 65200 1772 1437 0 0 547 625 625 625 625 821 821 821 308 308 625 625 625 625 547 547 308 308 308 274 274 274 308 308 0 0 0 0 0 0 0 308 65228 65228 65228 65228 0 0 0 0 64911 65228 65228 65228 65228 65262 65262 65262 64911 64911 64989 64989 64989 64911 64911 64911 64715 64715 64715 64911 64911 0 0 0 512 0 0 0 512 0 0 0 0 0 0 65535
|
||||
Exif.Canon.AFInfoSize SShort 1 546
|
||||
Exif.Canon.AFAreaMode SShort 1 Single-point AF
|
||||
Exif.Canon.AFNumPoints SShort 1 63
|
||||
Exif.Canon.AFValidPoints SShort 1 61
|
||||
Exif.Canon.AFCanonImageWidth SShort 1 6720
|
||||
Exif.Canon.AFCanonImageHeight SShort 1 4480
|
||||
Exif.Canon.AFImageWidth SShort 1 6720
|
||||
Exif.Canon.AFImageHeight SShort 1 4480
|
||||
Exif.Canon.AFAreaWidths SShort 63 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 0 0
|
||||
Exif.Canon.AFAreaHeights SShort 63 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 218 0 0
|
||||
Exif.Canon.AFXPositions SShort 63 -336 -746 -1101 -1437 -1772 336 0 -336 -1437 -1772 1772 1437 1101 746 336 0 1437 1101 746 336 0 -336 -746 -1101 336 0 -336 -746 -1101 -1437 -1772 1772 -746 -1101 -1437 -1772 1772 1437 1101 746 -1772 1772 1437 1101 746 336 0 -336 1101 746 336 0 -336 -746 -1101 -1437 336 0 -336 1772 1437 0 0
|
||||
Exif.Canon.AFYPositions SShort 63 547 625 625 625 625 821 821 821 308 308 625 625 625 625 547 547 308 308 308 274 274 274 308 308 0 0 0 0 0 0 0 308 -308 -308 -308 -308 0 0 0 0 -625 -308 -308 -308 -308 -274 -274 -274 -625 -625 -547 -547 -547 -625 -625 -625 -821 -821 -821 -625 -625 0 0
|
||||
Exif.Canon.AFPointsInFocus Short 4 25
|
||||
Exif.Canon.AFPointsSelected Short 4 25
|
||||
Exif.Canon.AFPrimaryPoint Short 4 (none)
|
||||
""","""0x2602 Canon AFNumPoints SShort 1 63
|
||||
0x2603 Canon AFValidPoints SShort 1 61
|
||||
0x260c Canon AFPointsInFocus Short 4 0 560 57344 0
|
||||
0x260d Canon AFPointsSelected Short 4 0 1848 57344 0
|
||||
""","""Exif.Canon.AFNumPoints SShort 1 63
|
||||
Exif.Canon.AFValidPoints SShort 1 61
|
||||
Exif.Canon.AFPointsInFocus Short 4 20,21,25,45,46,47
|
||||
Exif.Canon.AFPointsSelected Short 4 19,20,21,24,25,26,45,46,47
|
||||
""","""0x260e Canon AFPrimaryPoint Short 4 3608 49152 792 6272
|
||||
""","""Exif.Canon.AFPrimaryPoint Short 4 3,4,9,10,11,30,31,35,36,40,41,55,59,60
|
||||
"""
|
||||
]
|
||||
stderr = [""]*len(commands)
|
||||
retval = [ 0]*len(commands)
|
||||
Reference in New Issue
Block a user