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; }
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; }
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; }
WriteMethod Cr2Parser::encode( BasicIo& io, const byte* pData, uint32_t size, ByteOrder byteOrder, const ExifData& exifData, const IptcData& iptcData, const XmpData& xmpData ) { // Copy to be able to modify the Exif data ExifData ed = exifData; // Delete IFDs which do not occur in TIFF images static const IfdId filteredIfds[] = { panaRawId }; for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfds); ++i) { #ifdef DEBUG std::cerr << "Warning: Exif IFD " << filteredIfds[i] << " not encoded\n"; #endif ed.erase(std::remove_if(ed.begin(), ed.end(), FindExifdatum(filteredIfds[i])), ed.end()); } std::auto_ptr<TiffHeaderBase> header(new Cr2Header(byteOrder)); OffsetWriter offsetWriter; offsetWriter.setOrigin(OffsetWriter::cr2RawIfdOffset, Cr2Header::offset2addr(), byteOrder); return TiffParserWorker::encode(io, pData, size, ed, iptcData, xmpData, Tag::root, TiffMapping::findEncoder, header.get(), &offsetWriter); }
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 print(const ExifData& exifData) { if (exifData.empty()) { std::string error("No Exif data found in the file"); throw Exiv2::Error(1, error); } Exiv2::ExifData::const_iterator end = exifData.end(); for (Exiv2::ExifData::const_iterator i = exifData.begin(); i != 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 exiv2_dump_tags(const ExifData& exif) { cout << "exiv2_dump_tags: " << endl; Exiv2::ExifData::const_iterator end = exif.end(); for (Exiv2::ExifData::const_iterator i = exif.begin(); i != 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"; } }
WriteMethod ExifParser::encode( Blob& blob, const byte* pData, uint32_t size, ByteOrder byteOrder, const ExifData& exifData ) { ExifData ed = exifData; // Delete IFD0 tags that are "not recorded" in compressed images // Reference: Exif 2.2 specs, 4.6.8 Tag Support Levels, section A static const char* filteredIfd0Tags[] = { "Exif.Image.PhotometricInterpretation", "Exif.Image.StripOffsets", "Exif.Image.RowsPerStrip", "Exif.Image.StripByteCounts", "Exif.Image.JPEGInterchangeFormat", "Exif.Image.JPEGInterchangeFormatLength", "Exif.Image.SubIFDs" }; for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfd0Tags); ++i) { ExifData::iterator pos = ed.findKey(ExifKey(filteredIfd0Tags[i])); if (pos != ed.end()) { #ifdef DEBUG std::cerr << "Warning: Exif tag " << pos->key() << " not encoded\n"; #endif ed.erase(pos); } } // Delete IFDs which do not occur in JPEGs static const IfdId filteredIfds[] = { subImage1Id, subImage2Id, subImage3Id, subImage4Id, subImage5Id, subImage6Id, subImage7Id, subImage8Id, subImage9Id, subThumb1Id, panaRawId, ifd2Id, ifd3Id }; for (unsigned int i = 0; i < EXV_COUNTOF(filteredIfds); ++i) { #ifdef DEBUG std::cerr << "Warning: Exif IFD " << filteredIfds[i] << " not encoded\n"; #endif eraseIfd(ed, filteredIfds[i]); } // IPTC and XMP are stored elsewhere, not in the Exif APP1 segment. IptcData emptyIptc; XmpData emptyXmp; // Encode and check if the result fits into a JPEG Exif APP1 segment MemIo mio1; std::auto_ptr<TiffHeaderBase> header(new TiffHeader(byteOrder, 0x00000008, false)); WriteMethod wm = TiffParserWorker::encode(mio1, pData, size, ed, emptyIptc, emptyXmp, Tag::root, TiffMapping::findEncoder, header.get(), 0); if (mio1.size() <= 65527) { append(blob, mio1.mmap(), mio1.size()); return wm; } // If it doesn't fit, remove additional tags // Delete preview tags if the preview is larger than 32kB. // Todo: Enhance preview classes to be able to write and delete previews and use that instead. // Table must be sorted by preview, the first tag in each group is the size static const PreviewTags filteredPvTags[] = { { pttLen, "Exif.Minolta.ThumbnailLength" }, { pttTag, "Exif.Minolta.ThumbnailOffset" }, { pttLen, "Exif.Minolta.Thumbnail" }, { pttLen, "Exif.NikonPreview.JPEGInterchangeFormatLength" }, { pttIfd, "NikonPreview" }, { pttLen, "Exif.Olympus.ThumbnailLength" }, { pttTag, "Exif.Olympus.ThumbnailOffset" }, { pttLen, "Exif.Olympus.ThumbnailImage" }, { pttLen, "Exif.Olympus.Thumbnail" }, { pttLen, "Exif.Olympus2.ThumbnailLength" }, { pttTag, "Exif.Olympus2.ThumbnailOffset" }, { pttLen, "Exif.Olympus2.ThumbnailImage" }, { pttLen, "Exif.Olympus2.Thumbnail" }, { pttLen, "Exif.OlympusCs.PreviewImageLength" }, { pttTag, "Exif.OlympusCs.PreviewImageStart" }, { pttTag, "Exif.OlympusCs.PreviewImageValid" }, { pttLen, "Exif.Pentax.PreviewLength" }, { pttTag, "Exif.Pentax.PreviewOffset" }, { pttTag, "Exif.Pentax.PreviewResolution" }, { pttLen, "Exif.PentaxDng.PreviewLength" }, { pttTag, "Exif.PentaxDng.PreviewOffset" }, { pttTag, "Exif.PentaxDng.PreviewResolution" }, { pttLen, "Exif.SamsungPreview.JPEGInterchangeFormatLength" }, { pttIfd, "SamsungPreview" }, { pttLen, "Exif.Thumbnail.StripByteCounts" }, { pttIfd, "Thumbnail" }, { pttLen, "Exif.Thumbnail.JPEGInterchangeFormatLength" }, { pttIfd, "Thumbnail" } }; bool delTags = false; ExifData::iterator pos; for (unsigned int i = 0; i < EXV_COUNTOF(filteredPvTags); ++i) { switch (filteredPvTags[i].ptt_) { case pttLen: delTags = false; pos = ed.findKey(ExifKey(filteredPvTags[i].key_)); if (pos != ed.end() && sumToLong(*pos) > 32768) { delTags = true; #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Exif tag " << pos->key() << " not encoded\n"; #endif ed.erase(pos); } break; case pttTag: if (delTags) { pos = ed.findKey(ExifKey(filteredPvTags[i].key_)); if (pos != ed.end()) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Exif tag " << pos->key() << " not encoded\n"; #endif ed.erase(pos); } } break; case pttIfd: if (delTags) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Exif IFD " << filteredPvTags[i].key_ << " not encoded\n"; #endif eraseIfd(ed, Internal::groupId(filteredPvTags[i].key_)); } break; } } // Delete unknown tags larger than 4kB and known tags larger than 40kB. for (ExifData::iterator pos = ed.begin(); pos != ed.end(); ) { if ( (pos->size() > 4096 && pos->tagName().substr(0, 2) == "0x") || pos->size() > 40960) { #ifndef SUPPRESS_WARNINGS EXV_WARNING << "Exif tag " << pos->key() << " not encoded\n"; #endif pos = ed.erase(pos); } else { ++pos; } } // Encode the remaining Exif tags again, don't care if it fits this time MemIo mio2; wm = TiffParserWorker::encode(mio2, pData, size, ed, emptyIptc, emptyXmp, Tag::root, TiffMapping::findEncoder, header.get(), 0); append(blob, mio2.mmap(), mio2.size()); #ifdef DEBUG if (wm == wmIntrusive) { std::cerr << "SIZE OF EXIF DATA IS " << std::dec << mio2.size() << " BYTES\n"; } else { std::cerr << "SIZE DOESN'T MATTER, NON-INTRUSIVE WRITING USED\n"; } #endif return wm; } // ExifParser::encode
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; } }