void add_exif_coordinate( Exiv2::ExifData &data, const std::string &attribute, double value)
{
    Exiv2::URationalValue::AutoPtr rational(new Exiv2::URationalValue);

    // Add more elements through the extended interface of rational value
    double frac = 0.0;
    double intpart = 0.0;
    frac = std::modf( value, &intpart);
    rational->value_.push_back(std::make_pair( (unsigned int)intpart, (unsigned int)1));

    // intpart = minutes * 10000
    frac = std::modf( frac * 600000, &intpart);
    rational->value_.push_back(std::make_pair( (unsigned int)intpart, (unsigned int)10000));

    rational->value_.push_back(std::make_pair(0,1));

    // Add the key and value pair to the Exif data
    Exiv2::ExifKey key = Exiv2::ExifKey( attribute);
    data.add(key, rational.get());
}
Exemple #2
0
// *****************************************************************************
// Main
int main(int argc, char* const argv[])
try {

    if (argc != 2) {
        std::cout << "Usage: " << argv[0] << " file\n";
        return 1;
    }

    Exiv2::ExifData exifData;
    int rc = exifData.read(argv[1]);
    if (rc) {
        std::string error = Exiv2::ExifData::strError(rc, argv[1]);
        throw Exiv2::Error(error);
    }

    /*
      There are two pitfalls that we need to consider when setting the Exif user
      comment (Exif.Photo.UserComment) of an image:

      First, the type of the Exif user comment tag is "undefined" (and not
      ASCII) according to the Exif standard. This means that in Exiv2, we have
      to deal with a DataValue (and not an AsciiValue). DataValue has the usual
      two read methods, however, the one taking a const std::string& buf expects
      the string to contain a series of integers (e.g., "0 1 2") and not a text
      string. Thus, we need to use the read function that reads the value from a
      character buffer of a given length.

      Second, the Exif comment field starts with an eight character area that
      identifies the used character set. For ASCII, these eight characters are
      "ASCII\0\0\0". The actual comment follows after this code.

      Note: There is a more simple Exif tag for the title of an image. It is a
      20 byte string (type ASCII) and does not store two-byte characters.
      (Image.OtherTags.ImageDescription)
     */

    // Initialise a data value with the character set and comment
    std::string charset("ASCII\0\0\0", 8);
    std::string comment("A comment added to the Exif metadata through Exiv2");
    Exiv2::DataValue value;
    value.read(reinterpret_cast<const Exiv2::byte*>((charset + comment).data()), 
                8 + static_cast<long>(comment.size()));

    // Set the Exif comment
    Exiv2::ExifKey key("Exif.Photo.UserComment");
    Exiv2::ExifData::iterator pos = exifData.findKey(key);
    if (pos != exifData.end()) {
        // Use the existing Exif UserComment metadatum if there is one
        pos->setValue(&value);
    }
    else {
        // Otherwise add a new UserComment metadatum
        exifData.add(key, &value);
        pos = exifData.findKey(key);
    }

    // Now we should have a valid iterator in any case. We use the metadatum
    // output operator to print the formatted value
    std::cout << "Writing user comment '" << *pos << "' back to the image\n";

    rc = exifData.write(argv[1]);
    if (rc) {
        std::string error = Exiv2::ExifData::strError(rc, argv[1]);
        throw Exiv2::Error(error);
    }

   return rc;
}
catch (Exiv2::Error& e) {
    std::cout << "Caught Exiv2 exception '" << e << "'\n";
    return -1;
}
bool ptImageHelper::WriteExif(const QString              &AFileName,
                              const std::vector<uint8_t> &AExifBuffer,
                              Exiv2::IptcData            &AIptcData,
                              Exiv2::XmpData             &AXmpData) {
  try {
#if EXIV2_TEST_VERSION(0,17,91)   /* Exiv2 0.18-pre1 */

    Exiv2::ExifData hInExifData;

    Exiv2::ExifParser::decode(hInExifData,
                              AExifBuffer.data() + CExifHeader.size(),
                              AExifBuffer.size() - CExifHeader.size());

    // Reset orientation
    Exiv2::ExifData::iterator pos = hInExifData.begin();
    if ((pos = hInExifData.findKey(Exiv2::ExifKey("Exif.Image.Orientation"))) != hInExifData.end()) {
      pos->setValue("1"); // Normal orientation
    }

    // Adapted from UFRaw, necessary for Tiff files
    QStringList ExifKeys;
    ExifKeys  << "Exif.Image.ImageWidth"
              << "Exif.Image.ImageLength"
              << "Exif.Image.BitsPerSample"
              << "Exif.Image.Compression"
              << "Exif.Image.PhotometricInterpretation"
              << "Exif.Image.FillOrder"
              << "Exif.Image.SamplesPerPixel"
              << "Exif.Image.StripOffsets"
              << "Exif.Image.RowsPerStrip"
              << "Exif.Image.StripByteCounts"
              << "Exif.Image.XResolution"
              << "Exif.Image.YResolution"
              << "Exif.Image.PlanarConfiguration"
              << "Exif.Image.ResolutionUnit";

    for (short i = 0; i < ExifKeys.count(); i++) {
      if ((pos = hInExifData.findKey(Exiv2::ExifKey(ExifKeys.at(i).toLocal8Bit().data()))) != hInExifData.end())
        hInExifData.erase(pos);
    }

    if (Settings->GetInt("EraseExifThumbnail")) {
      Exiv2::ExifThumb Thumb(hInExifData);
      Thumb.erase();
    }

    QStringList JpegExtensions;
    JpegExtensions << "jpg" << "JPG" << "Jpg" << "jpeg" << "Jpeg" << "JPEG";
    bool deleteDNGdata = false;
    for (short i = 0; i < JpegExtensions.count(); i++) {
      if (!AFileName.endsWith(JpegExtensions.at(i))) deleteDNGdata = true;
    }

    Exiv2::Image::AutoPtr Exiv2Image = Exiv2::ImageFactory::open(AFileName.toLocal8Bit().data());

    Exiv2Image->readMetadata();
    Exiv2::ExifData outExifData = Exiv2Image->exifData();

    for (auto hPos = hInExifData.begin(); hPos != hInExifData.end(); hPos++) {
      if (!deleteDNGdata || (*hPos).key() != "Exif.Image.DNGPrivateData") {
        outExifData.add(*hPos);
      }
    }

    // IPTC data

    QStringList Tags        = Settings->GetStringList("TagsList");
    QStringList DigikamTags = Settings->GetStringList("DigikamTagsList");

    Exiv2::StringValue StringValue;
    for (int i = 0; i < Tags.size(); i++) {
      StringValue.read(Tags.at(i).toStdString());
      AIptcData.add(Exiv2::IptcKey("Iptc.Application2.Keywords"), &StringValue);
    }


    // XMP data

    for (int i = 0; i < Tags.size(); i++) {
      AXmpData["Xmp.dc.subject"] = Tags.at(i).toStdString();
    }
    for (int i = 0; i < DigikamTags.size(); i++) {
      AXmpData["Xmp.digiKam.TagsList"] = DigikamTags.at(i).toStdString();
    }

    // Image rating
    outExifData["Exif.Image.Rating"] = Settings->GetInt("ImageRating");
    AXmpData["Xmp.xmp.Rating"]       = Settings->GetInt("ImageRating");

    // Program name
    outExifData["Exif.Image.ProcessingSoftware"]  = ProgramName;
    outExifData["Exif.Image.Software"]            = ProgramName;
    AIptcData["Iptc.Application2.Program"]        = ProgramName;
    AIptcData["Iptc.Application2.ProgramVersion"] = "idle";
    AXmpData["Xmp.xmp.CreatorTool"]               = ProgramName;
    AXmpData["Xmp.tiff.Software"]                 = ProgramName;

    // Title
    QString TitleWorking = Settings->GetString("ImageTitle");
    StringClean(TitleWorking);
    if (TitleWorking != "") {
      outExifData["Exif.Photo.UserComment"]  = TitleWorking.toStdString();
      AIptcData["Iptc.Application2.Caption"] = TitleWorking.toStdString();
      AXmpData["Xmp.dc.description"]         = TitleWorking.toStdString();
      AXmpData["Xmp.exif.UserComment"]       = TitleWorking.toStdString();
      AXmpData["Xmp.tiff.ImageDescription"]  = TitleWorking.toStdString();
    }

    // Copyright
    QString CopyrightWorking = Settings->GetString("Copyright");
    StringClean(CopyrightWorking);
    if (CopyrightWorking != "") {
      outExifData["Exif.Image.Copyright"]      = CopyrightWorking.toStdString();
      AIptcData["Iptc.Application2.Copyright"] = CopyrightWorking.toStdString();
      AXmpData["Xmp.tiff.Copyright"]           = CopyrightWorking.toStdString();
    }

    Exiv2Image->setExifData(outExifData);
    Exiv2Image->setIptcData(AIptcData);
    Exiv2Image->setXmpData(AXmpData);
    Exiv2Image->writeMetadata();
    return true;
#endif
  } catch (Exiv2::AnyError& Error) {
    if (Settings->GetInt("JobMode") == 0) {
      ptMessageBox::warning(0 ,"Exiv2 Error","No exif data written!\nCaught Exiv2 exception '" + QString(Error.what()) + "'\n");
    } else {
      std::cout << "Caught Exiv2 exception '" << Error << "'\n";
    }
  }
  return false;
}
Exemple #4
0
// *****************************************************************************
// Main
int main()
try {
    // Container for all metadata
    Exiv2::ExifData exifData;

    // *************************************************************************
    // Add to the Exif data

    // Create a ASCII string value (note the use of create)
    Exiv2::Value* v = Exiv2::Value::create(Exiv2::asciiString);
    // Set the value to a string
    v->read("1999:12:31 23:59:59");
    // Add the value together with its key to the Exif data container
    Exiv2::ExifKey key("Exif.Photo.DateTimeOriginal");
    exifData.add(key, v);

    std::cout << "Added key \"" << key << "\", value \"" << *v << "\"\n";
    // Delete the memory allocated by Value::create
    delete v;

    // Now create a more interesting value (without using the create method)
    Exiv2::URationalValue* rv = new Exiv2::URationalValue;
    // Set two rational components from a string
    rv->read("1/2 1/3");
    // Add more elements through the extended interface of rational value 
    rv->value_.push_back(std::make_pair(2,3));
    rv->value_.push_back(std::make_pair(3,4));
    // Add the key and value pair to the Exif data
    key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
    exifData.add(key, rv);

    std::cout << "Added key \"" << key << "\", value \"" << *rv << "\"\n";
    // Delete memory allocated on the heap
    delete rv;

    // *************************************************************************
    // Modify Exif data

    // Find the timestamp metadatum by its key
    key = Exiv2::ExifKey("Exif.Photo.DateTimeOriginal");
    Exiv2::ExifData::iterator pos = exifData.findKey(key);
    if (pos == exifData.end()) throw Exiv2::Error("Key not found");
    // Modify the value
    std::string date = pos->toString();
    date.replace(0,4,"2000");
    pos->setValue(date); 
    std::cout << "Modified key \"" << key 
              << "\", new value \"" << pos->value() << "\"\n";

    // Find the other key
    key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
    pos = exifData.findKey(key);
    if (pos == exifData.end()) throw Exiv2::Error("Key not found");
    // Get a pointer to a copy of the value
    v = pos->getValue();
    // Downcast the Value pointer to its actual type
    rv = dynamic_cast<Exiv2::URationalValue*>(v);
    if (rv == 0) throw Exiv2::Error("Downcast failed");
    // Modify the value directly through the interface of URationalValue
    rv->value_[2] = std::make_pair(88,77);
    // Copy the modified value back to the metadatum
    pos->setValue(rv);
    // Delete the memory allocated by getValue
    delete v;
    std::cout << "Modified key \"" << key 
              << "\", new value \"" << pos->value() << "\"\n";

    // *************************************************************************
    // Delete metadata from the Exif data container

    // Delete the metadatum at iterator position pos
    key = Exiv2::ExifKey("Exif.Image.PrimaryChromaticities");
    pos = exifData.findKey(key);
    if (pos == exifData.end()) throw Exiv2::Error("Key not found");
    exifData.erase(pos);
    std::cout << "Deleted key \"" << key << "\"\n";

    // *************************************************************************
    // Finally, write the remaining Exif data to an image file
    int rc = exifData.write("img_2158.jpg");
    if (rc) {
        std::string error = Exiv2::ExifData::strError(rc, "img_2158.jpg");
        throw Exiv2::Error(error);
    }

    return 0;
}
catch (Exiv2::Error& e) {
    std::cout << "Caught Exiv2 exception '" << e << "'\n";
    return -1;
}
bool KisExifIO::saveTo(KisMetaData::Store* store, QIODevice* ioDevice, HeaderType headerType) const
{
    ioDevice->open(QIODevice::WriteOnly);
    Exiv2::ExifData exifData;
    if (headerType == KisMetaData::IOBackend::JpegHeader) {
        QByteArray header(6, 0);
        header[0] = 0x45;
        header[1] = 0x78;
        header[2] = 0x69;
        header[3] = 0x66;
        header[4] = 0x00;
        header[5] = 0x00;
        ioDevice->write(header);
    }

    for (QHash<QString, KisMetaData::Entry>::const_iterator it = store->begin();
            it != store->end(); ++it) {
        try {
            const KisMetaData::Entry& entry = *it;
            dbgFile << "Trying to save: " << entry.name() << " of " << entry.schema()->prefix() << ":" << entry.schema()->uri();
            QString exivKey;
            if (entry.schema()->uri() == KisMetaData::Schema::TIFFSchemaUri) {
                exivKey = "Exif.Image." + entry.name();
            } else if (entry.schema()->uri() == KisMetaData::Schema::EXIFSchemaUri) { // Distinguish between exif and gps
                if (entry.name().left(3) == "GPS") {
                    exivKey = "Exif.GPS." + entry.name();
                } else {
                    exivKey = "Exif.Photo." + entry.name();
                }
            } else if (entry.schema()->uri() == KisMetaData::Schema::DublinCoreSchemaUri) {
                if (entry.name() == "description") {
                    exivKey = "Exif.Image.ImageDescription";
                } else if (entry.name() == "creator") {
                    exivKey = "Exif.Image.Artist";
                } else if (entry.name() == "rights") {
                    exivKey = "Exif.Image.Copyright";
                }
            } else if (entry.schema()->uri() == KisMetaData::Schema::XMPSchemaUri) {
                if (entry.name() == "ModifyDate") {
                    exivKey = "Exif.Image.DateTime";
                } else if (entry.name() == "CreatorTool") {
                    exivKey = "Exif.Image.Software";
                }
            } else if (entry.schema()->uri() == KisMetaData::Schema::MakerNoteSchemaUri) {
                if (entry.name() == "RawData") {
                    exivKey = "Exif.Photo.MakerNote";
                }
            }
            dbgFile << "Saving " << entry.name() << " to " << exivKey;
            if (exivKey.isEmpty()) {
                dbgFile << entry.qualifiedName() << " is unsavable to EXIF";
            } else {
                Exiv2::ExifKey exifKey(qPrintable(exivKey));
                Exiv2::Value* v = 0;
                if (exivKey == "Exif.Photo.ExifVersion" || exivKey == "Exif.Photo.FlashpixVersion") {
                    v = kmdValueToExifVersion(entry.value());
                } else if (exivKey == "Exif.Photo.FileSource") {
                    char s[] = { 0x03 };
                    v = new Exiv2::DataValue((const Exiv2::byte*)s, 1);
                } else if (exivKey == "Exif.Photo.SceneType") {
                    char s[] = { 0x01 };
                    v = new Exiv2::DataValue((const Exiv2::byte*)s, 1);
                } else if (exivKey == "Exif.Photo.ComponentsConfiguration") {
                    v = kmdIntOrderedArrayToExifArray(entry.value());
                } else if (exivKey == "Exif.Image.Artist") { // load as dc:creator
                    KisMetaData::Value creator = entry.value().asArray()[0];
#if EXIV2_MAJOR_VERSION == 0 && EXIV2_MINOR_VERSION <= 20
                    v = kmdValueToExivValue(creator, Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId()));
#else
                    v = kmdValueToExivValue(creator, exifKey.defaultTypeId());
#endif
                } else if (exivKey == "Exif.Photo.OECF") {
                    v = kmdOECFStructureToExifOECF(entry.value());
                } else if (exivKey == "Exif.Photo.DeviceSettingDescription") {
                    v = deviceSettingDescriptionKMDToExif(entry.value());
                } else if (exivKey == "Exif.Photo.CFAPattern") {
                    v = cfaPatternKMDToExif(entry.value());
                } else if (exivKey == "Exif.Photo.Flash") {
                    v = flashKMDToExif(entry.value());
                } else if (exivKey == "Exif.Photo.UserComment") {
                    Q_ASSERT(entry.value().type() == KisMetaData::Value::LangArray);
                    QMap<QString, KisMetaData::Value> langArr = entry.value().asLangArray();
                    if (langArr.contains("x-default")) {
#if EXIV2_MAJOR_VERSION == 0 && EXIV2_MINOR_VERSION <= 20
                        v = kmdValueToExivValue(langArr.value("x-default"), Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId()));
#else
                        v = kmdValueToExivValue(langArr.value("x-default"), exifKey.defaultTypeId());
#endif
                    } else if (langArr.size() > 0) {
#if EXIV2_MAJOR_VERSION == 0 && EXIV2_MINOR_VERSION <= 20
                        v = kmdValueToExivValue(langArr.begin().value(), Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId()));
#else
                        v = kmdValueToExivValue(langArr.begin().value(), exifKey.defaultTypeId());
#endif
                    }
                } else {
                    dbgFile << exifKey.tag();
#if EXIV2_MAJOR_VERSION == 0 && EXIV2_MINOR_VERSION <= 20
                    v = kmdValueToExivValue(entry.value(), Exiv2::ExifTags::tagType(exifKey.tag(), exifKey.ifdId()));
#else
                    v = kmdValueToExivValue(entry.value(), exifKey.defaultTypeId());
#endif
                }
                if (v && v->typeId() != Exiv2::invalidTypeId) {
                    dbgFile << "Saving key" << exivKey << " of KMD value" << entry.value();
                    exifData.add(exifKey, v);
                } else {
                    dbgFile << "No exif value was created for" << entry.qualifiedName() << " as" << exivKey;// << " of KMD value" << entry.value();
                }
            }
        } catch (Exiv2::AnyError& e) {
            dbgFile << "exiv error " << e.what();
        }
    }
#if EXIV2_MAJOR_VERSION == 0 && EXIV2_MINOR_VERSION <= 17
    Exiv2::DataBuf rawData = exifData.copy();
    ioDevice->write((const char*) rawData.pData_, rawData.size_);
#else
    Exiv2::Blob rawData;
    Exiv2::ExifParser::encode(rawData, Exiv2::littleEndian, exifData);
    ioDevice->write((const char*) &*rawData.begin(), rawData.size());
#endif
    ioDevice->close();
    return true;
}