feat: improve lens recognition of canon makernote

If multiple choices are possible they are now all reported. This
behaviour is now the same as it is in exiftool.

All lenses are tested in the new test_canon_lenses.py test
main
Christoph Hasse 4 years ago
parent 907fe2369e
commit bdd8a386b5

@ -25,6 +25,7 @@
*/ */
// ***************************************************************************** // *****************************************************************************
// included header files // included header files
#include "error.hpp"
#include "types.hpp" #include "types.hpp"
#include "makernote_int.hpp" #include "makernote_int.hpp"
#include "canonmn_int.hpp" #include "canonmn_int.hpp"
@ -34,6 +35,7 @@
#include "i18n.h" // NLS support. #include "i18n.h" // NLS support.
// + standard includes // + standard includes
#include <regex>
#include <string> #include <string>
#include <sstream> #include <sstream>
#include <iomanip> #include <iomanip>
@ -54,18 +56,8 @@ namespace Exiv2 {
{ 1, N_("On") } { 1, N_("On") }
}; };
//! Special treatment pretty-print function for non-unique lens ids. std::ostream& printCsLensTypeByMetadata(std::ostream& os, const Value& value, const ExifData* metadata);
std::ostream& printCsLensByFocalLengthAndMaxAperture(std::ostream& os,
const Value& value,
const ExifData* metadata);
//! Special treatment pretty-print function for non-unique lens ids.
std::ostream& printCsLensByFocalLength(std::ostream& os,
const Value& value,
const ExifData* metadata);
//! Special treatment pretty-print function for non-unique lens ids.
std::ostream& printCsLensByFocalLengthTC(std::ostream& os,
const Value& value,
const ExifData* metadata);
//! Special treatment pretty-print function for non-unique lens ids. //! Special treatment pretty-print function for non-unique lens ids.
std::ostream& printCsLensFFFF(std::ostream& os, std::ostream& printCsLensFFFF(std::ostream& os,
const Value& value, const Value& value,
@ -1972,10 +1964,9 @@ namespace Exiv2 {
{ 368, "Sigma 150-600mm f/5-6.3 DG OS HSM | S" }, // 6 { 368, "Sigma 150-600mm f/5-6.3 DG OS HSM | S" }, // 6
{ 368, "Sigma 85mm f/1.4 DG HSM | A" }, // 7 { 368, "Sigma 85mm f/1.4 DG HSM | A" }, // 7
{ 368, "Sigma 105mm f/1.4 DG HSM" }, // 8 { 368, "Sigma 105mm f/1.4 DG HSM" }, // 8
{ 368, "Sigma 14-24mm f/2.8 DG HSM" }, // 9 { 368, "Sigma 70mm f/2.8 DG Macro" }, // 9
{ 368, "Sigma 70mm f/2.8 DG Macro" }, // 10 { 368, "Sigma 18-35mm f/1.8 DC HSM | A" }, // 10
{ 368, "Sigma 18-35mm f/1.8 DC HSM | A" }, // 11 { 368, "Sigma 35mm f/1.4 DG HSM | A" }, // 11
{ 368, "Sigma 35mm f/1.4 DG HSM | A" }, // 12
{ 488, "Canon EF-S 15-85mm f/3.5-5.6 IS USM" }, { 488, "Canon EF-S 15-85mm f/3.5-5.6 IS USM" },
{ 489, "Canon EF 70-300mm f/4-5.6L IS USM" }, { 489, "Canon EF 70-300mm f/4-5.6L IS USM" },
{ 490, "Canon EF 8-15mm f/4L Fisheye USM" }, { 490, "Canon EF 8-15mm f/4L Fisheye USM" },
@ -2078,70 +2069,6 @@ namespace Exiv2 {
{65535, "n/a" } {65535, "n/a" }
}; };
//! A lens id and a pretty-print function for special treatment of the id.
struct LensIdFct {
long id_; //!< Lens id
PrintFct fct_; //!< Pretty-print function
//! Comparison operator for find template
bool operator==(long id) const { return id_ == id; }
};
//! List of lens ids which require special treatment with the medicine
const LensIdFct lensIdFct[] = {
{ 4, printCsLensByFocalLength }, // not tested
{ 6, printCsLensByFocalLength },
{ 8, printCsLensByFocalLength },
{ 9, printCsLensByFocalLength },
{ 10, printCsLensByFocalLengthAndMaxAperture }, // works partly
{ 22, printCsLensByFocalLength },
{ 26, printCsLensByFocalLengthAndMaxAperture }, // works partly
{ 28, printCsLensByFocalLength },
{ 31, printCsLensByFocalLength },
{ 32, printCsLensByFocalLength },
{ 33, printCsLensByFocalLengthAndMaxAperture }, // works partly
{ 37, printCsLensByFocalLength },
{ 42, printCsLensByFocalLength },
{ 47, printCsLensByFocalLength }, // not tested
{ 131, printCsLensByFocalLength },
{ 136, printCsLensByFocalLength },
{ 137, printCsLensByFocalLength }, // not tested
{ 143, printCsLensByFocalLength },
{ 150, printCsLensByFocalLength },
{ 152, printCsLensByFocalLength },
{ 153, printCsLensByFocalLength },
{ 154, printCsLensByFocalLength }, // not tested
{ 155, printCsLensByFocalLength },
{ 156, printCsLensByFocalLengthAndMaxAperture },
{ 160, printCsLensByFocalLength },
{ 161, printCsLensByFocalLength },
{ 168, printCsLensByFocalLength },
{ 169, printCsLensByFocalLengthAndMaxAperture },
{ 172, printCsLensByFocalLengthTC }, // not tested
{ 173, printCsLensByFocalLengthTC }, // works partly
{ 174, printCsLensByFocalLength }, // not tested
{ 197, printCsLensByFocalLength },
{ 180, printCsLensByFocalLength },
{ 181, printCsLensByFocalLengthTC }, // not tested
{ 182, printCsLensByFocalLengthTC }, // not tested
{ 183, printCsLensByFocalLength }, // not tested
{ 198, printCsLensByFocalLength }, // not tested
{ 213, printCsLensByFocalLength }, // not tested
{ 234, printCsLensByFocalLength }, // not tested
{ 248, printCsLensByFocalLength }, // not tested
{ 250, printCsLensByFocalLength }, // not tested
{ 254, printCsLensByFocalLength },
{ 255, printCsLensByFocalLength }, // not tested
{ 368, printCsLensByFocalLengthAndMaxAperture },
{ 491, printCsLensByFocalLength },
{ 493, printCsLensByFocalLength }, // not tested
{ 624, printCsLensByFocalLengthTC },
{ 747, printCsLensByFocalLength }, // not tested
{ 4143,printCsLensByFocalLength }, // not tested
{ 4154,printCsLensByFocalLength }, // not tested
{61182,printCsLensByFocalLength },
{0xffff,printCsLensFFFF }
};
//! FlashActivity, tag 0x001c //! FlashActivity, tag 0x001c
constexpr TagDetails canonCsFlashActivity[] = { constexpr TagDetails canonCsFlashActivity[] = {
{ 0, N_("Did not fire") }, { 0, N_("Did not fire") },
@ -2805,152 +2732,97 @@ namespace Exiv2 {
return EXV_PRINT_TAG(canonCsLensType)(os, value, metadata); return EXV_PRINT_TAG(canonCsLensType)(os, value, metadata);
} }
//! Helper structure std::ostream& printCsLensTypeByMetadata(std::ostream& os, const Value& value, const ExifData* metadata)
struct LensTypeAndFocalLengthAndMaxAperture {
long lensType_; //!< Lens type
float focalLengthMin_; //!< Mininum focal length
float focalLengthMax_; //!< Maximum focal length
std::string focalLength_; //!< Focal length as a string
std::string maxAperture_; //!< Aperture
};
//! Compare tag details with a lens entry
bool operator==(const TagDetails& td, const LensTypeAndFocalLengthAndMaxAperture& ltfl) {
return ( td.val_ == ltfl.lensType_
&& std::string(td.label_).find(ltfl.focalLength_) != std::string::npos
&& std::string(td.label_).find(ltfl.maxAperture_) != std::string::npos);
}
//! extractLensFocalLength from metadata
void extractLensFocalLength(LensTypeAndFocalLengthAndMaxAperture& ltfl,
const ExifData* metadata)
{ {
ExifKey key("Exif.CanonCs.Lens"); if (!metadata || value.typeId() != unsignedShort || value.count() == 0)
auto pos = metadata->findKey(key);
ltfl.focalLengthMin_ = 0.0F;
ltfl.focalLengthMax_ = 0.0F;
if (pos != metadata->end()) {
const Value &value = pos->value();
if ( value.count() >= 3
&& value.typeId() == unsignedShort) {
float fu = value.toFloat(2);
if (fu != 0.0F) {
ltfl.focalLengthMin_ = value.toLong(1) / fu;
ltfl.focalLengthMax_ = value.toLong(0) / fu;
}
}
}
}
//! convertFocalLength to a human readable string
void convertFocalLength(LensTypeAndFocalLengthAndMaxAperture& ltfl, float divisor)
{
std::ostringstream oss;
oss << std::fixed << std::setprecision(0);
if (ltfl.focalLengthMin_ == ltfl.focalLengthMax_) {
oss << " " << (ltfl.focalLengthMin_ / divisor) << "mm";
} else {
oss << " " << (ltfl.focalLengthMin_ / divisor) << "-" << (ltfl.focalLengthMax_ / divisor) << "mm";
}
ltfl.focalLength_ = oss.str();
}
//! printCsLensByFocalLengthAndMaxAperture to human readable string
std::ostream& printCsLensByFocalLengthAndMaxAperture(std::ostream& os,
const Value& value,
const ExifData* metadata)
{
if ( !metadata || value.typeId() != unsignedShort
|| value.count() == 0) return os << value;
LensTypeAndFocalLengthAndMaxAperture ltfl;
ltfl.lensType_ = value.toLong();
extractLensFocalLength(ltfl, metadata);
if (ltfl.focalLengthMax_ == 0.0F)
return os << value; return os << value;
convertFocalLength(ltfl, 1.0F);
ExifKey key("Exif.CanonCs.MaxAperture"); auto const lensType = value.toLong();
auto pos = metadata->findKey(key);
if ( pos != metadata->end()
&& pos->value().count() == 1
&& pos->value().typeId() == unsignedShort) {
long val = static_cast<int16_t>(pos->value().toLong(0)); if (lensType == 0xffff){
if (val > 0) return printCsLensFFFF(os, value, metadata);
{
std::ostringstream oss;
oss << std::setprecision(2);
oss << fnumber(canonEv(val));
ltfl.maxAperture_ = oss.str();
}
} }
if (ltfl.maxAperture_.empty()) return os << value;
const TagDetails* td = find(canonCsLensType, ltfl);
if (!td) return os << value;
return os << td->label_;
}
//! printCsLensByFocalLength to human readable string // get the values we need from the metadata container
std::ostream& printCsLensByFocalLength(std::ostream& os, ExifKey lensKey("Exif.CanonCs.Lens");
const Value& value, auto pos = metadata->findKey(lensKey);
const ExifData* metadata) // catch possible error cases
{ if (pos == metadata->end() or pos->value().count() < 3 or pos->value().typeId() != unsignedShort or
if ( !metadata || value.typeId() != unsignedShort pos->value().toFloat(2) == 0.0F) {
|| value.count() == 0) return os << value; os << "Unknown Lens (" << lensType << ")";
}
LensTypeAndFocalLengthAndMaxAperture ltfl;
ltfl.lensType_ = value.toLong();
extractLensFocalLength(ltfl, metadata); int const exifFlMin = pos->value().toLong(1) / pos->value().toFloat(2);
if (ltfl.focalLengthMax_ == 0.0F) int const exifFlMax = pos->value().toLong(0) / pos->value().toFloat(2);
return os << value;
convertFocalLength(ltfl, 1.0F);
if (ltfl.focalLength_.empty()) return os << value; ExifKey aperKey("Exif.CanonCs.MaxAperture");
pos = metadata->findKey(aperKey);
if (pos == metadata->end() or pos->value().count() != 1 or pos->value().typeId() != unsignedShort) {
os << "Unknown Lens (" << lensType << ")";
}
const TagDetails* td = find(canonCsLensType, ltfl); auto exifAperMax = fnumber(canonEv(static_cast<int16_t>(pos->value().toLong(0))));
if (!td) return os << value;
return os << td->label_; // regex to extract short and tele focal length, max aperture at short and tele position
} // and the teleconverter factor from the lens label
std::regex const lens_regex(
// anything at the start
".*?"
// maybe min focal length and hyphen, surely max focal length e.g.: 24-70mm
"(?:([0-9]+)-)?([0-9]+)mm"
// anything in-between
".*?"
// maybe short focal length max aperture and hyphen, surely at least single max aperture e.g.: f/4.5-5.6
// short and tele indicate apertures at the short (focal_length_min) and tele (focal_length_max)
// position of the lens
"(?:(?:f\\/)|T)(?:([0-9]+(?:\\.[0-9]+)?)-)?([0-9]+(?:\\.[0-9])?)"
// check if there is a teleconverter pattern e.g. + 1.4x
"(?:.*?\\+.*?([0-9.]+)x)?"
);
bool unmatched = true;
// we loop over all our lenses to print out all matching lenses
// if we have multiple possibilities, they are concatenated by "*OR*"
for (auto const& lens : canonCsLensType) {
if (lens.val_ != lensType) {
continue;
}
//! printCsLensByFocalLengthTC to human readable string std::cmatch base_match;
std::ostream& printCsLensByFocalLengthTC(std::ostream& os, if (not std::regex_search(lens.label_, base_match, lens_regex)) {
const Value& value, // this should never happen, as it would indicate the lens is specified incorrectly
const ExifData* metadata) // in the CanonCsLensType array
{ throw Error(kerErrorMessage, std::string("Lens regex didn't match for: ") + std::string(lens.label_));
if ( !metadata || value.typeId() != unsignedShort }
|| value.count() == 0) return os << value;
LensTypeAndFocalLengthAndMaxAperture ltfl; auto tc = base_match[5].length() > 0 ? std::stof(base_match[5].str()) : 1.f;
ltfl.lensType_ = value.toLong();
extractLensFocalLength(ltfl, metadata); int flMax = std::stoi(base_match[2].str()) * tc;
int flMin = base_match[1].length() > 0 ? std::stoi(base_match[1].str()) * tc : flMax;
if (ltfl.focalLengthMax_ == 0.0) return os << value; auto aperMaxTele = std::stof(base_match[4].str()) * tc;
auto aperMaxShort = base_match[3].length() > 0 ? std::stof(base_match[3].str()) * tc : aperMaxTele;
const TagDetails* td; if (flMin != exifFlMin or flMax != exifFlMax or exifAperMax < (aperMaxShort - .1) or
const double factors[] = {1.0, 1.4, 2.0}; exifAperMax > (aperMaxTele + .1)) {
for (const double &factor : factors) continue;
{ }
convertFocalLength(ltfl, factor);
std::ostringstream oss; if (unmatched) {
oss << std::setprecision(2); unmatched = false;
oss << factor << "x"; os << lens.label_;
continue;
}
ltfl.maxAperture_ = oss.str(); os << " *OR* " << lens.label_;
td = find(canonCsLensType, ltfl); }
if (td) break;
ltfl.maxAperture_ = ""; // if the entire for loop left us with unmatched==false
td = find(canonCsLensType, ltfl); // we weren't able to find a single matching lens :(
if (td) break; if (unmatched) {
os << "Unknown Lens (" << lensType << ")";
} }
if (!td) return os << value; return os;
return os << td->label_;
} }
//! printCsLensType by searching the config file if necessary //! printCsLensType by searching the config file if necessary
@ -2968,14 +2840,9 @@ namespace Exiv2 {
return os << Internal::readExiv2Config(section,value.toString(),undefined); return os << Internal::readExiv2Config(section,value.toString(),undefined);
} }
const LensIdFct* lif = find(lensIdFct, value.toLong()); // try our best to determine the lens based on metadata
if (!lif) { // sometimes the result will be a set of multiple choices
return EXV_PRINT_TAG(canonCsLensType)(os, value, metadata); return printCsLensTypeByMetadata(os, value, metadata);
}
if (metadata && lif->fct_) {
return lif->fct_(os, value, metadata);
}
return os << value;
} }
std::ostream& CanonMakerNote::printCsLens(std::ostream& os, std::ostream& CanonMakerNote::printCsLens(std::ostream& os,

@ -1,10 +1,15 @@
# -*- coding: utf-8 -*- # -*- coding: utf-8 -*-
import re import re
import os import os
import system_tests import system_tests
import math from lens_tests.utils import extract_lenses_from_cpp, make_test_cases, aperture_to_raw_exif
from lens_tests.utils import extract_lenses_from_cpp, make_test_cases
# NOTE
# Normally the canon maker note holds the max aperture of the lens at the focal length
# the picture was taken at. Thus for a f/4-6.3 lens, this value could be anywhere in that range.
# For the below tests we only test the scenario where the lens was used at it's shortest focal length.
# Thus we always pick the 'aperture_max_short' of a lens as the value to write into the
# Exif.CanonCs.MaxAperture field.
# get directory of the current file # get directory of the current file
file_dir = os.path.dirname(os.path.realpath(__file__)) file_dir = os.path.dirname(os.path.realpath(__file__))
@ -17,31 +22,6 @@ lenses = extract_lenses_from_cpp(canon_lens_file, startpattern)
# use utils function to define test case data # use utils function to define test case data
test_cases = make_test_cases(lenses) test_cases = make_test_cases(lenses)
# see https://github.com/exiftool/exiftool/blob/master/lib/Image/ExifTool/Canon.pm#L9678
def aperture_to_raw_exif(aperture):
# for apertures < 1 the below is negative
num = math.log(aperture) * 2 / math.log(2)
# temporarily make the number positive
if num < 0:
num = -num
sign = -1
else:
sign = 1
val = int(num)
frac = num - val
if abs(frac - 0.33) < 0.05:
frac = 0x0C
elif abs(frac - 0.67) < 0.05:
frac = 0x14
else:
frac = int(frac * 0x20 + 0.5)
return sign * (val * 0x20 + frac)
for lens_tc in test_cases: for lens_tc in test_cases:
testname = lens_tc["id"] + "_" + lens_tc["desc"] testname = lens_tc["id"] + "_" + lens_tc["desc"]
@ -59,7 +39,7 @@ for lens_tc in test_cases:
"retval": [0], "retval": [0],
"lens_id": lens_tc["id"], "lens_id": lens_tc["id"],
"lens_description": lens_tc["target"], "lens_description": lens_tc["target"],
"aperture_max": aperture_to_raw_exif(lens_tc["aperture_max_short"]), "aperture_max": aperture_to_raw_exif(lens_tc["aperture_max_short"] * lens_tc["tc"]),
"focal_length_min": int(lens_tc["focal_length_min"] * lens_tc["tc"]), "focal_length_min": int(lens_tc["focal_length_min"] * lens_tc["tc"]),
"focal_length_max": int(lens_tc["focal_length_max"] * lens_tc["tc"]), "focal_length_max": int(lens_tc["focal_length_max"] * lens_tc["tc"]),
}, },

@ -1,6 +1,7 @@
import re import re
import os import os
import logging import logging
import math
from itertools import groupby from itertools import groupby
log = logging.getLogger(__name__) log = logging.getLogger(__name__)
@ -12,11 +13,11 @@ LENS_META_DEFAULT_RE = re.compile(
( (
# anything at the start # anything at the start
".*?" ".*?"
# maybe min focal length and hyhpen, surely max focal length e.g.: 24-70mm # maybe min focal length and hyphen, surely max focal length e.g.: 24-70mm
"(?:(?P<focal_length_min>[0-9]+)-)?(?P<focal_length_max>[0-9]+)mm" "(?:(?P<focal_length_min>[0-9]+)-)?(?P<focal_length_max>[0-9]+)mm"
# anything inbetween # anything in-between
".*?" ".*?"
# maybe short focal length max aperture and hyhpen, surely at least single max aperture e.g.: f/4.5-5.6 # maybe short focal length max aperture and hyphen, surely at least single max aperture e.g.: f/4.5-5.6
# short and tele indicate apertures at the short (focal_length_min) and tele (focal_length_max) position of the lens # short and tele indicate apertures at the short (focal_length_min) and tele (focal_length_max) position of the lens
"(?:(?:f\/)|T)(?:(?P<aperture_max_short>[0-9]+(?:\.[0-9]+)?)-)?(?P<aperture_max_tele>[0-9]+(?:\.[0-9])?)" "(?:(?:f\/)|T)(?:(?P<aperture_max_short>[0-9]+(?:\.[0-9]+)?)-)?(?P<aperture_max_tele>[0-9]+(?:\.[0-9])?)"
# check if there is a teleconverter pattern e.g. + 1.4x # check if there is a teleconverter pattern e.g. + 1.4x
@ -25,9 +26,58 @@ LENS_META_DEFAULT_RE = re.compile(
) )
def aperture_to_raw_exif(aperture):
# see https://github.com/exiftool/exiftool/blob/master/lib/Image/ExifTool/Canon.pm#L9678
"""Transform aperture value to Canon maker note style hex format."""
# for apertures < 1 the below is negative
num = math.log(aperture) * 2 / math.log(2)
# temporarily make the number positive
if num < 0:
num = -num
sign = -1
else:
sign = 1
val = int(num)
frac = num - val
if abs(frac - 0.33) < 0.05:
frac = 0x0C
elif abs(frac - 0.67) < 0.05:
frac = 0x14
else:
frac = int(frac * 0x20 + 0.5)
return sign * (val * 0x20 + frac)
def raw_exif_to_aperture(raw):
"""The inverse operation of aperture_to_raw_exif"""
val = raw
if val < 0:
val = -val
sign = -1
else:
sign = 1
frac = val & 0x1F
val -= frac
# Convert 1/3 and 2/3 codes
if frac == 0x0C:
frac = 0x20 / 3
elif frac == 0x14:
frac = 0x40 / 3
ev = sign * (val + frac) / 0x20
return math.exp(ev * math.log(2) / 2)
def parse_lens_entry(text, pattern=LENS_ENTRY_DEFAULT_RE): def parse_lens_entry(text, pattern=LENS_ENTRY_DEFAULT_RE):
"""get the ID, and description from a lens entry field """
Expexted input format: get the ID, and description from a lens entry field
Expected input format:
{ 748, "Canon EF 100-400mm f/4.5-5.6L IS II USM + 1.4x" } { 748, "Canon EF 100-400mm f/4.5-5.6L IS II USM + 1.4x" }
We return a dict of: We return a dict of:
lens_id = 748 lens_id = 748
@ -40,6 +90,7 @@ def parse_lens_entry(text, pattern=LENS_ENTRY_DEFAULT_RE):
def extract_meta(text, pattern=LENS_META_DEFAULT_RE): def extract_meta(text, pattern=LENS_META_DEFAULT_RE):
""" """
Extract metadata from lens description. Extract metadata from lens description.
Input expected in the form of e.g. "Canon EF 100-400mm f/4.5-5.6L IS II USM + 1.4x" Input expected in the form of e.g. "Canon EF 100-400mm f/4.5-5.6L IS II USM + 1.4x"
We return a dict of: We return a dict of:
focal_length_min = 100 focal_length_min = 100
@ -64,16 +115,27 @@ def extract_meta(text, pattern=LENS_META_DEFAULT_RE):
return ret return ret
# FIXME explain somwhere that lens_is_match(l1,l2) does not imply lens_is_match(l2,l1)
# becuse we don't have short and tele aperture values in exif
def lens_is_match(l1, l2): def lens_is_match(l1, l2):
""" """
Test if lens l2 is compatible with lens l1, Test if lens l2 is compatible with lens l1
assuming we write l1's metadata and apeture_max_short into exif
This assumes we write l1's metadata and pick its 'aperture_max_short' value
as the maximum aperture value to write into exif.
Normally the canon maker note holds the max aperture of the lens at the focal length
the picture was taken at. Thus for a f/4-6.3 lens, this value could be anywhere in that range.
""" """
return ( # the problem is that the round trip transformation isn't exact
all([l1[k] == l2[k] for k in ["tc", "focal_length_min", "focal_length_max"]]) # so we need to account for this here as well to not define a target
and l2["aperture_max_short"] <= l1["aperture_max_short"] <= l2["aperture_max_tele"] # which isn't achievable for exiv2
reconstructed_aperture = raw_exif_to_aperture(aperture_to_raw_exif(l1["aperture_max_short"] * l1["tc"]))
return all(
[
l1["focal_length_min"] * l1["tc"] == l2["focal_length_min"] * l2["tc"],
l1["focal_length_max"] * l1["tc"] == l2["focal_length_max"] * l2["tc"],
(l2["aperture_max_short"] * l2["tc"]) - 0.1
<= reconstructed_aperture
<= (l2["aperture_max_tele"] * l2["tc"]) + 0.1,
]
) )
@ -100,7 +162,7 @@ def make_test_cases(lenses):
def extract_lenses_from_cpp(filename, start_pattern): def extract_lenses_from_cpp(filename, start_pattern):
""" """
Extract lens information from the lens descritpions array in a maker note cpp file Extract lens information from the lens descriptions array in a maker note cpp file
filename: path to cpp file filename: path to cpp file
start_pattern: start_pattern == line.strip() should return True for start_pattern: start_pattern == line.strip() should return True for
the starting line of the array containing the lenses. the starting line of the array containing the lenses.
@ -134,7 +196,7 @@ def extract_lenses_from_cpp(filename, start_pattern):
meta = extract_meta(lens_entry[1]) meta = extract_meta(lens_entry[1])
if not meta: if not meta:
log.error(f"Failure extracing metadata from lens description: {lens_entry[0]}: {lens_entry[1]}.") log.error(f"Failure extracting metadata from lens description: {lens_entry[0]}: {lens_entry[1]}.")
continue continue
lenses.append({"id": lens_entry[0], "desc": lens_entry[1], "meta": meta}) lenses.append({"id": lens_entry[0], "desc": lens_entry[1], "meta": meta})

Loading…
Cancel
Save