// ExifWriter.h // Copyright (c) 2009 The Foundry Visionmongers Ltd. All Rights Reserved. #include #include "DDImage/FileWriter.h" #include "DDImage/MetaData.h" class ExifWriter : public DD::Image::FileWriter { void addExifEntry(ExifData* exif, int ifd, ExifTag tag, const std::string& value); void addExifEntry(ExifData* exif, int ifd, ExifTag tag, int numer, int denom); public: ExifWriter(DD::Image::Write * iop); ExifData* makeExifData(); }; template static void StringToValue(T& val, const std::string& value) { std::istringstream iss(value); iss >> val; } template void SetRationalFromString(T& val, const std::string& value) { std::string numer = value; std::string denom = "1"; size_t slashPos = value.find('/'); if (slashPos != std::string::npos) { numer = value.substr(0, slashPos); denom = value.substr(slashPos + 1); } val.numerator = atoi(numer.c_str()); val.denominator = atoi(denom.c_str()); } static void StringToValue(ExifRational& val, const std::string& value) { SetRationalFromString(val, value); } static void StringToValue(ExifSRational& val, const std::string& value) { SetRationalFromString(val, value); } template void ExifSetByte(unsigned char* b, ExifByteOrder order, BYTETYPE byte) { if(!b) return; b[0] = byte; } #define mFnWriteData(DATATYPE, FUNCTION) \ { \ DATATYPE data; \ StringToValue(data, value); \ FUNCTION(entry->data, exif_data_get_byte_order(exif), data); \ } \ ExifWriter::ExifWriter(DD::Image::Write * iop) : DD::Image::FileWriter(iop) { } void ExifWriter::addExifEntry(ExifData* exif, int ifd, ExifTag tag, const std::string& value) { ExifContent* cont = exif->ifd[ifd]; ExifEntry* entry = exif_entry_new(); exif_content_add_entry(cont, entry); exif_entry_initialize(entry, tag); if(entry->format == EXIF_FORMAT_BYTE) mFnWriteData(ExifByte, ExifSetByte) else if(entry->format == EXIF_FORMAT_SHORT) mFnWriteData(ExifShort, exif_set_short) else if(entry->format == EXIF_FORMAT_LONG) mFnWriteData(ExifLong, exif_set_long) else if(entry->format == EXIF_FORMAT_RATIONAL) mFnWriteData(ExifRational, exif_set_rational) else if(entry->format == EXIF_FORMAT_SBYTE) mFnWriteData(ExifSByte, ExifSetByte) else if(entry->format == EXIF_FORMAT_SSHORT) mFnWriteData(ExifSShort, exif_set_sshort) else if(entry->format == EXIF_FORMAT_SLONG) mFnWriteData(ExifSLong, exif_set_slong) else if(entry->format == EXIF_FORMAT_SRATIONAL) mFnWriteData(ExifSRational, exif_set_srational) //float and double don't appear to actually be used. The comment in the libexif //exif_entry_get_value when an entry has either of these types is //What to do here? Line 1093, exif-entry.c //so for now, leave them commented out and write it out as ASCII. //else if(entry->format == EXIF_FORMAT_FLOAT) // mFnWriteData(float, exif_set_float) //else if(entry->format == EXIF_FORMAT_DOUBLE) // mFnWriteData(double, exif_set_double) else { entry->data = (unsigned char*)strdup(value.c_str()); entry->format = EXIF_FORMAT_ASCII; entry->size = unsigned(value.length() + 1); entry->components = unsigned(value.length() + 1); } exif_entry_fix(entry); exif_entry_unref(entry); } ExifData* ExifWriter::makeExifData() { using namespace DD::Image; const MetaData::Bundle& bundle = input0().fetchMetaData(nullptr); ExifData* exif = exif_data_new(); MetaData::Bundle::const_iterator it = bundle.begin(); while (it != bundle.end()) { const std::string& key = it->first; std::string value = MetaData::propertyToString(it->second); if (key.substr(0, 5) == "exif/") { int ifd = atoi(key.c_str() + 5); ExifTag tag = exif_tag_from_name(key.c_str() + 7); addExifEntry(exif, ifd, tag, value); } else if (key == MetaData::FOCAL_LENGTH) { addExifEntry(exif, EXIF_IFD_EXIF, EXIF_TAG_FOCAL_LENGTH, value); } else if (key == MetaData::FNUMBER) { addExifEntry(exif, EXIF_IFD_EXIF, EXIF_TAG_FNUMBER, value); } else if (key == MetaData::EXPOSURE) { addExifEntry(exif, EXIF_IFD_EXIF, EXIF_TAG_EXPOSURE_TIME, value); } it++; } return exif; } #undef mFnWriteData