int set_date(const ExifData& exif, char date[]) { const ExifData::const_iterator end = exif.end(); ExifData::const_iterator value = exif.findKey(ExifDateTimeCreated); if(value == end) value = exif.findKey(ExifDateTimeDigitized); if(value == end) return 1; const std::string dateTime = value->value().toString(); if(!dateTime.empty()) { //*date = (char*)realloc(*date, (dateTime.length() + 1) * sizeof(char)); strcpy(date, const_cast<char*>(dateTime.c_str())); // format gets returned as 'YYYY:MM:DD HH:MM:SS' when it // needs to be 'YYYY-MM-DDTHH:MM:SS' so fix separators char* dateStr = date; if(dateTime.length() > 4 && dateStr[4] != '-') dateStr[4] = '-'; if(dateTime.length() > 6 && dateStr[7] != '-') dateStr[7] = '-'; if(dateTime.length() > 10 && dateStr[10] != 'T') dateStr[10] = 'T'; } return 0; }
int MrwImage::pixelHeight() const { ExifData::const_iterator imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageLength")); if (imageHeight != exifData_.end() && imageHeight->count() > 0) { return imageHeight->toLong(); } return 0; }
int MrwImage::pixelWidth() const { ExifData::const_iterator imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Image.ImageWidth")); if (imageWidth != exifData_.end() && imageWidth->count() > 0) { return imageWidth->toLong(); } return 0; }
int Cr2Image::pixelHeight() const { ExifData::const_iterator imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelYDimension")); if (imageHeight != exifData_.end() && imageHeight->count() > 0) { return imageHeight->toLong(); } return 0; }
int Cr2Image::pixelWidth() const { ExifData::const_iterator imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.Photo.PixelXDimension")); if (imageWidth != exifData_.end() && imageWidth->count() > 0) { return imageWidth->toLong(); } return 0; }
int main(int argc, char* const argv[]) try { if (argc != 2) { std::cout << "Usage: " << argv[0] << " file\n"; return 1; } const char* path=argv[1]; Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(path); assert(image.get() != 0); image->readMetadata(); Jzon::Object root; const char* FS="FS"; Jzon::Object fs ; root.Add (FS,fs) ; fileSystemPush(path,root.Get(FS)); Exiv2::ExifData &exifData = image->exifData(); for ( ExifData::const_iterator i = exifData.begin(); i != exifData.end() ; ++i ) { std::string key ; push(objectForKey(i->key(),key,root),key,i); } Exiv2::IptcData &iptcData = image->iptcData(); for (Exiv2::IptcData::const_iterator i = iptcData.begin(); i != iptcData.end(); ++i) { std::string key ; push(objectForKey(i->key(),key,root),key,i); } Exiv2::XmpData &xmpData = image->xmpData(); for (Exiv2::XmpData::const_iterator i = xmpData.begin(); i != xmpData.end(); ++i) { std::string key ; push(objectForKey(i->key(),key,root),key,i); } /* This is only for testing long paths { ExifData::const_iterator i = exifData.begin(); std::string key; push(objectForKey("This.Is.A.Rather.Long.Path.Key",key,root),key,i); } */ Jzon::Writer writer(root,Jzon::StandardFormat); writer.Write(); std::cout << writer.GetResult() << std::endl; return 0; } //catch (std::exception& e) { //catch (Exiv2::AnyError& e) { catch (Exiv2::Error& e) { std::cout << "Caught Exiv2 exception '" << e.what() << "'\n"; return -1; }
int Rw2Image::pixelHeight() const { ExifData::const_iterator imageHeight = exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorHeight")); if (imageHeight != exifData_.end() && imageHeight->count() > 0) { return imageHeight->toLong(); } return 0; }
int Rw2Image::pixelWidth() const { ExifData::const_iterator imageWidth = exifData_.findKey(Exiv2::ExifKey("Exif.PanasonicRaw.SensorWidth")); if (imageWidth != exifData_.end() && imageWidth->count() > 0) { return imageWidth->toLong(); } return 0; }
int set_long_value(const ExifData& exif, const ExifKey& key, unsigned int& field) { const ExifData::const_iterator end = exif.end(); const ExifData::const_iterator value = exif.findKey(key); if(value == end) return -1; field = value->value().toLong(); return 0; }
ExifData::const_iterator isoSpeed(const ExifData& ed) { static const char* keys[] = { "Exif.Photo.ISOSpeedRatings", "Exif.Image.ISOSpeedRatings", "Exif.CanonSi.ISOSpeed", "Exif.CanonCs.ISOSpeed", "Exif.Nikon1.ISOSpeed", "Exif.Nikon2.ISOSpeed", "Exif.Nikon3.ISOSpeed", "Exif.NikonIi.ISO", "Exif.NikonIi.ISO2", "Exif.MinoltaCsNew.ISOSetting", "Exif.MinoltaCsOld.ISOSetting", "Exif.MinoltaCs5D.ISOSpeed", "Exif.MinoltaCs7D.ISOSpeed", "Exif.Sony1Cs.ISOSetting", "Exif.Sony2Cs.ISOSetting", "Exif.Sony1Cs2.ISOSetting", "Exif.Sony2Cs2.ISOSetting", "Exif.Sony1MltCsA100.ISOSetting", "Exif.Pentax.ISO", "Exif.PentaxDng.ISO", "Exif.Olympus.ISOSpeed", "Exif.Samsung2.ISO", "Exif.Casio.ISO", "Exif.Casio2.ISO", "Exif.Casio2.ISOSpeed" }; // Find the first ISO value which is not "0" const int cnt = EXV_COUNTOF(keys); ExifData::const_iterator md = ed.end(); for (int idx = 0; idx < cnt; ) { md = findMetadatum(ed, keys + idx, cnt - idx); if (md == ed.end()) break; std::ostringstream os; md->write(os, &ed); bool ok = false; long v = parseLong(os.str(), ok); if (ok && v != 0) break; while (strcmp(keys[idx++], md->key().c_str()) != 0 && idx < cnt) {} md = ed.end(); } return md; }
void exifPrint(const ExifData& exifData) { ExifData::const_iterator i = exifData.begin(); for (; i != exifData.end(); ++i) { std::cout << std::setw(44) << std::setfill(' ') << std::left << i->key() << " " << "0x" << std::setw(4) << std::setfill('0') << std::right << std::hex << i->tag() << " " << std::setw(9) << std::setfill(' ') << std::left << i->typeName() << " " << std::dec << std::setw(3) << std::setfill(' ') << std::right << i->count() << " " << std::dec << i->value() << "\n"; } }
void Rw2Image::readMetadata() { #ifdef DEBUG std::cerr << "Reading RW2 file " << io_->path() << "\n"; #endif if (io_->open() != 0) { throw Error(9, io_->path(), strError()); } IoCloser closer(*io_); // Ensure that this is the correct image type if (!isRw2Type(*io_, false)) { if (io_->error() || io_->eof()) throw Error(14); throw Error(3, "RW2"); } clearMetadata(); std::ofstream devnull; printStructure(devnull, kpsRecursive, 0); ByteOrder bo = Rw2Parser::decode(exifData_, iptcData_, xmpData_, io_->mmap(), io_->size()); setByteOrder(bo); // A lot more metadata is hidden in the embedded preview image // Todo: This should go into the Rw2Parser, but for that it needs the Image PreviewManager loader(*this); PreviewPropertiesList list = loader.getPreviewProperties(); // Todo: What if there are more preview images? if (list.size() > 1) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "RW2 image contains more than one preview. None used.\n"; #endif } if (list.size() != 1) return; ExifData exifData; PreviewImage preview = loader.getPreviewImage(*list.begin()); Image::AutoPtr image = ImageFactory::open(preview.pData(), preview.size()); if (image.get() == 0) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Failed to open RW2 preview image.\n"; #endif return; } image->readMetadata(); ExifData& prevData = image->exifData(); if (!prevData.empty()) { // Filter duplicate tags for (ExifData::const_iterator pos = exifData_.begin(); pos != exifData_.end(); ++pos) { if (pos->ifdId() == panaRawId) continue; ExifData::iterator dup = prevData.findKey(ExifKey(pos->key())); if (dup != prevData.end()) { #ifdef DEBUG std::cerr << "Filtering duplicate tag " << pos->key() << " (values '" << pos->value() << "' and '" << dup->value() << "')\n"; #endif prevData.erase(dup); } } } // Remove tags not applicable for raw images static const char* filteredTags[] = { "Exif.Photo.ComponentsConfiguration", "Exif.Photo.CompressedBitsPerPixel", "Exif.Panasonic.ColorEffect", "Exif.Panasonic.Contrast", "Exif.Panasonic.NoiseReduction", "Exif.Panasonic.ColorMode", "Exif.Panasonic.OpticalZoomMode", "Exif.Panasonic.Contrast", "Exif.Panasonic.Saturation", "Exif.Panasonic.Sharpness", "Exif.Panasonic.FilmMode", "Exif.Panasonic.SceneMode", "Exif.Panasonic.WBRedLevel", "Exif.Panasonic.WBGreenLevel", "Exif.Panasonic.WBBlueLevel", "Exif.Photo.ColorSpace", "Exif.Photo.PixelXDimension", "Exif.Photo.PixelYDimension", "Exif.Photo.SceneType", "Exif.Photo.CustomRendered", "Exif.Photo.DigitalZoomRatio", "Exif.Photo.SceneCaptureType", "Exif.Photo.GainControl", "Exif.Photo.Contrast", "Exif.Photo.Saturation", "Exif.Photo.Sharpness", "Exif.Image.PrintImageMatching", "Exif.Image.YCbCrPositioning" }; for (unsigned int i = 0; i < EXV_COUNTOF(filteredTags); ++i) { ExifData::iterator pos = prevData.findKey(ExifKey(filteredTags[i])); if (pos != prevData.end()) { #ifdef DEBUG std::cerr << "Exif tag " << pos->key() << " removed\n"; #endif prevData.erase(pos); } } // Add the remaining tags for (ExifData::const_iterator pos = prevData.begin(); pos != prevData.end(); ++pos) { exifData_.add(*pos); } } // Rw2Image::readMetadata
QImage Exiv2Lib::getPreview() { PreviewManager loader(*mImageFile); PreviewPropertiesList list = loader.getPreviewProperties(); if (list.empty()) { qDebug() << "Image contains no thumbnail"; return QImage(); } PreviewProperties selected; // Take the last image in the list. // For Canon raw pictures, the 2nd preview has no white balance applied. // see http://lclevy.free.fr/cr2/ // section 2.6 IFD #2 selected = list.back(); // FIXME: crash hapened here when reading the QImage. // not quite sure what caused it // load the thumbnail PreviewImage thumbnail = loader.getPreviewImage(selected); const unsigned char* tmp = thumbnail.pData(); size_t size = thumbnail.size(); QImage thumb; thumb.loadFromData(tmp, size); // Read the EXIF orientation flag and rotate the image accordingly. ExifData& data = mImageFile->exifData(); ExifData::const_iterator pos; pos = data.findKey(ExifKey("Exif.Image.Orientation")); // TODO: should flip/rotate after resize if (pos != data.end()) { qDebug() << "rotation" << pos->toLong(); QTransform rotate; switch (pos->toLong()) { case 1: // no rotation needed break; case 2: // flip over y thumb = thumb.mirrored(true, false); break; case 3: // rotate 180 (or flip x flip y) thumb = thumb.mirrored(true, true); break; case 4: // flip over x thumb = thumb.mirrored(false, true); break; case 5: // rotate 90 CW & flip over y rotate.rotate(90); rotate.rotate(180, Qt::YAxis); thumb = thumb.transformed(rotate); break; case 6: // rotate 90 CW rotate.rotate(90); thumb = thumb.transformed(rotate); break; case 7: // rotate 90 CCW flip over y rotate.rotate(-90); rotate.rotate(180, Qt::YAxis); thumb = thumb.transformed(rotate); break; case 8: // rotate 90 CCW rotate.rotate(-90); thumb = thumb.transformed(rotate); break; } } return thumb; }
void Exiv2Lib::setWhiteBalanceCoeffsCanon(ExifData& data, float wb[3]) { ExifData::const_iterator pos; if (*mExifInfo.model == "Canon EOS 300D DIGITAL" || *mExifInfo.model == "Canon EOS DIGITAL REBEL") { pos = data.findKey(ExifKey("Exif.Canon.WhiteBalanceTable")); if (pos != data.end()) { qDebug() << "Reading EOS 300D tags"; uint16_t* cdata = new uint16_t[pos->size() / 2]; pos->copy((unsigned char*)cdata, littleEndian); wb[0] = cdata[1]; wb[1] = (cdata[2] + cdata[3]) / 2; wb[2] = cdata[4]; float mx = max3(wb[0], wb[1], wb[2]); wb[0] /= mx; wb[1] /= mx; wb[2] /= mx; delete [] cdata; return; } } pos = data.findKey(ExifKey("Exif.Canon.ColorData")); if (pos != data.end()) { uint8_t* cdata = new uint8_t[pos->size()]; struct Canon_ColorData* colorData; pos->copy(cdata, littleEndian); colorData = (struct Canon_ColorData*)cdata; if (*mExifInfo.model == "Canon EOS 350D DIGITAL") // || EOS 20D { // optimize with bitshifts later // wb[0] = colorData->V1.WhiteBalanceTable[WB_AsShot].RGGB[2]; // wb[1] = ((colorData->V1.WhiteBalanceTable[WB_AsShot].RGGB[1]+colorData->V1.WhiteBalanceTable[WB_AsShot].RGGB[3])/2); // wb[2] = colorData->V1.WhiteBalanceTable[WB_AsShot].RGGB[0]; wb[0] = colorData->V1.WhiteBalanceTable[WB_AsShot].RGGB[0]; wb[1] = ((colorData->V1.WhiteBalanceTable[WB_AsShot].RGGB[1] + colorData->V1.WhiteBalanceTable[WB_AsShot].RGGB[2]) / 2); wb[2] = colorData->V1.WhiteBalanceTable[WB_AsShot].RGGB[3]; qDebug() << "WB EOS 350D DIGITAL RGGB" << wb[0] << "," << wb[1] << "," << wb[2]; } else if (*mExifInfo.model == "Canon EOS 1D Mark II") // || 1Ds Mark II { qDebug() << "Whitebalance info unavailable"; } else if (*mExifInfo.model == "Canon G10") { qDebug() << "Whitebalance info unavailable"; } else if (*mExifInfo.model == "Canon PowerShot S30") { wb[0] = colorData->V5.WhiteBalanceTable[WB_AsShot].GRBG[1]; wb[1] = (colorData->V5.WhiteBalanceTable[WB_AsShot].GRBG[0] + colorData->V5.WhiteBalanceTable[WB_AsShot].GRBG[3]) / 2; wb[2] = colorData->V5.WhiteBalanceTable[WB_AsShot].GRBG[2]; } else if (*mExifInfo.model == "Canon PowerShot S110") { wb[0] = colorData->V3.WhiteBalanceTable[WB_AsShot].RGGB[0]; wb[1] = (colorData->V3.WhiteBalanceTable[WB_AsShot].RGGB[1] + colorData->V3.WhiteBalanceTable[WB_AsShot].RGGB[2]) / 2; wb[2] = colorData->V3.WhiteBalanceTable[WB_AsShot].RGGB[3]; } else // attempt to read at the default position at V4 { qDebug() << "Model unknown, Parsing whitebalance using canon default format"; qDebug() << "Color data version: " << colorData->V7.version; // optimize with bitshifs later wb[0] = colorData->V7.WhiteBalanceTable[WB_AsShot].RGGB[0]; wb[1] = (colorData->V7.WhiteBalanceTable[WB_AsShot].RGGB[1] + colorData->V7.WhiteBalanceTable[WB_AsShot].RGGB[2]) / 2; wb[2] = colorData->V7.WhiteBalanceTable[WB_AsShot].RGGB[3]; } float mx = max3(wb[0], wb[1], wb[2]); wb[0] /= mx; wb[1] /= mx; wb[2] /= mx; delete [] cdata; } else { //qDebug() << "no such exif key"; wb[0] = 1.0; wb[1] = 1.0; wb[2] = 1.0; } // qDebug() << "WB RGGB Multipliers" <<wb[0] <<","<<wb[1]<<","<<wb[2]; }
void Exiv2Lib::setWhiteBalanceCoeffsNikon(ExifData& data, float wb[3]) { ExifData::const_iterator pos; /* * This seems to be unnecessary as the multipliers are also * available as rational numbers in the WB_RBLevels tag */ /* pos = data.findKey(ExifKey("Exif.Nikon3.Version")); int makerNoteVersion = -1; if (pos != data.end()) { char* buf = new char[pos->size()]; pos->copy((unsigned char*)buf, littleEndian); QString val(buf); qDebug() << val; delete [] buf; makerNoteVersion = val.toInt(); } qDebug() << "Nikon makenote version:" << makerNoteVersion; if (makerNoteVersion >= 200) { qDebug() << "Decrypt Nikon Color Balance"; } */ pos = data.findKey(ExifKey("Exif.Nikon3.WB_RBLevels")); if (pos != data.end()) { if (*mExifInfo.model == "NIKON D300") { wb[0] = 1.0f; wb[1] = 1.0f; wb[2] = 1.0f; // wb[0] = colorData->V3.WhiteBalanceTable[WB_AsShot].RGGB[0]; // wb[1] = // ((colorData->V1.WhiteBalanceTable[WB_AsShot].RGGB[1] + // colorData->V1.WhiteBalanceTable[WB_AsShot].RGGB[2]) / 2); // wb[2] = colorData->V1.WhiteBalanceTable[WB_AsShot].RGGB[3]; qDebug() << "White balance for model Nikon D300"; if (pos != data.end()) { wb[0] = pos->toFloat(0); wb[1] = 1.0f; wb[2] = pos->toFloat(1); qDebug() << "Nikon: RGB" << wb[0] << "," << wb[1] << "," << wb[2]; } } float mx = max3(wb[0], wb[1], wb[2]); wb[0] /= mx; wb[1] /= mx; wb[2] /= mx; } else { qDebug () << "Nikon: Color balance data not available"; wb[0] = 1.0f; wb[1] = 1.0f; wb[2] = 1.0f; } }
gboolean exiv2_load_meta_interface(const gchar *service, RAWFILE *rawfile, guint offset, RSMetadata *meta) { try { Image::AutoPtr img = ImageFactory::open((byte*)raw_get_map(rawfile), raw_get_filesize(rawfile)); img->readMetadata(); ExifData &exifData = img->exifData(); #if EXIV2_TEST_VERSION(0,17,0) /* We perfer XMP data, so copy it to EXIF */ XmpData &xmpData = img->xmpData(); if (!xmpData.empty()) copyXmpToExif(xmpData, exifData); #endif /* Parse Exif Data */ if (!exifData.empty()) { ExifData::const_iterator i; i = exifData.findKey(ExifKey("Exif.Image.Make")); if (i != exifData.end()) set_metadata_maker(i->toString(), meta); i = exifData.findKey(ExifKey("Exif.Image.Model")); if (i != exifData.end()) meta->model_ascii = g_strdup(i->toString().c_str()); #if EXIV2_TEST_VERSION(0,19,0) i = orientation(exifData); if (i != exifData.end()) { std::auto_ptr<Exiv2::Value> val = i->getValue(); if (val->count()) { switch (val->toLong()) { case 6: meta->orientation = 90; break; case 8: meta->orientation = 270; break; } } } #endif i = exifData.findKey(ExifKey("Exif.Image.DateTimeOriginal")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.Image.DateTime")); if (i != exifData.end()) { meta->time_ascii = g_strdup(i->toString().c_str()); meta->timestamp = rs_exiftime_to_unixtime(meta->time_ascii); } i = exifData.findKey(ExifKey("Exif.Image.ExposureTime")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.Photo.ExposureTime")); if (i != exifData.end()) meta->shutterspeed = 1.0 / i->getValue()->toFloat(); else { i = exifData.findKey(ExifKey("Exif.Image.ShutterSpeedValue")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.Photo.ShutterSpeedValue")); if (i != exifData.end()) meta->shutterspeed = 1.0 / i->toFloat(); } i = exifData.findKey(ExifKey("Exif.Image.FNumber")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.Photo.FNumber")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.Image.ApertureValue")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.Photo.ApertureValue")); if (i != exifData.end()) meta->aperture = i->toFloat(); i = exifData.findKey(ExifKey("Exif.Image.FocalLength")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.Photo.FocalLength")); if (i != exifData.end()) meta->focallength = i->toFloat()-0.01; #if EXIV2_TEST_VERSION(0,19,0) i = isoSpeed(exifData); if (i != exifData.end()) meta->iso = i->toLong(); /* Text based Lens Identifier */ i = lensName(exifData); if (i != exifData.end()) { TypeId type = i->typeId(); if (type == unsignedShort || type == unsignedLong || type == signedShort || type == signedLong || type == unsignedByte || type == signedByte) meta->lens_id = i->toLong(); else if (type == asciiString || type == string) meta->fixed_lens_identifier = g_strdup(i->toString().c_str()); } #endif /* Canon*/ i = exifData.findKey(ExifKey("Exif.CanonCs.Lens")); if (i != exifData.end() && i->value().count() >= 3 && i->value().typeId() == unsignedShort) { float fu = i->value().toFloat(2); if (fu != 0.0) { meta->lens_min_focal = i->toFloat(0) / fu; meta->lens_max_focal = i->toFloat(1) /fu; } } i = exifData.findKey(ExifKey("Exif.CanonCs.MinAperture")); if (i != exifData.end()) meta->lens_min_aperture = (gfloat) exp(CanonEv(i->toFloat())*log(2)/2); i = exifData.findKey(ExifKey("Exif.CanonCs.MaxAperture")); if (i != exifData.end()) meta->lens_max_aperture = (gfloat) exp(CanonEv(i->toFloat())*log(2)/2); /* Olympus */ i = exifData.findKey(ExifKey("Exif.OlympusEq.MinFocalLength")); if (i != exifData.end()) meta->lens_min_focal = i->toFloat(); i = exifData.findKey(ExifKey("Exif.OlympusEq.MaxFocalLength")); if (i != exifData.end()) meta->lens_max_focal = i->toFloat(); /* Nikon */ i = exifData.findKey(ExifKey("Exif.NikonLd1.MinFocalLength")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.NikonLd2.MinFocalLength")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.NikonLd3.MinFocalLength")); if (i != exifData.end()) meta->lens_min_focal = 5.0 * pow(2.0, i->toLong()/24.0); i = exifData.findKey(ExifKey("Exif.NikonLd1.MaxFocalLength")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.NikonLd2.MaxFocalLength")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.NikonLd3.MaxFocalLength")); if (i != exifData.end()) meta->lens_max_focal = 5.0 * pow(2.0, i->toLong()/24.0); i = exifData.findKey(ExifKey("Exif.NikonLd1.MaxApertureAtMinFocal")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.NikonLd2.MaxApertureAtMinFocal")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.NikonLd3.MaxApertureAtMinFocal")); if (i != exifData.end()) meta->lens_min_aperture = i->toLong()/12.0; i = exifData.findKey(ExifKey("Exif.NikonLd1.MaxApertureAtMaxFocal")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.NikonLd2.MaxApertureAtMaxFocal")); if (i == exifData.end()) i = exifData.findKey(ExifKey("Exif.NikonLd3.MaxApertureAtMaxFocal")); if (i != exifData.end()) meta->lens_max_aperture = i->toLong()/12.0; /* Fuji */ i = exifData.findKey(ExifKey("Exif.Fujifilm.MinFocalLength")); if (i != exifData.end()) meta->lens_min_focal = i->toFloat(); i = exifData.findKey(ExifKey("Exif.Fujifilm.MaxFocalLength")); if (i != exifData.end()) meta->lens_max_focal = i->toFloat(); return TRUE; } } catch (Exiv2::Error& e) { g_debug("Exiv2 Metadata Loader:'%s'", e.what()); } return FALSE; }