// convert from KisMetaData value to ExifVersion and FlashpixVersion Exiv2::Value* kmdValueToExifVersion(const KisMetaData::Value& value) { Exiv2::DataValue* dvalue = new Exiv2::DataValue; QString ver = value.asVariant().toString(); dvalue->read((const Exiv2::byte*)ver.toLatin1().constData(), ver.size()); return dvalue; }
bool KExiv2::setImagePreview(const QImage& preview, bool setProgramName) const { if (!setProgramId(setProgramName)) return false; if (preview.isNull()) { removeIptcTag("Iptc.Application2.Preview"); removeIptcTag("Iptc.Application2.PreviewFormat"); removeIptcTag("Iptc.Application2.PreviewVersion"); return true; } try { QByteArray data; QBuffer buffer(&data); buffer.open(QIODevice::WriteOnly); // A little bit compressed preview jpeg image to limit IPTC size. preview.save(&buffer, "JPEG"); kDebug() << "JPEG image preview size: (" << preview.width() << " x " << preview.height() << ") pixels - " << data.size() << " bytes"; Exiv2::DataValue val; val.read((Exiv2::byte *)data.data(), data.size()); d->iptcMetadata()["Iptc.Application2.Preview"] = val; // See http://www.iptc.org/std/IIM/4.1/specification/IIMV4.1.pdf Appendix A for details. d->iptcMetadata()["Iptc.Application2.PreviewFormat"] = 11; // JPEG d->iptcMetadata()["Iptc.Application2.PreviewVersion"] = 1; return true; } catch( Exiv2::Error& e ) { d->printExiv2ExceptionError("Cannot get image preview using Exiv2 ", e); } catch(...) { kError() << "Default exception from Exiv2"; } return false; }
int main(int argc, char* const argv[]) try { if (argc != 3) { std::cout << "Usage: " << argv[0] << " image datafile\n"; return 1; } std::string file(argv[1]); std::string data(argv[2]); // Read data file into data buffer Exiv2::FileIo io(data); if (io.open() != 0) { throw Exiv2::Error(Exiv2::kerDataSourceOpenFailed, io.path(), Exiv2::strError()); } Exiv2::DataBuf buf((long)io.size()); std::cout << "Reading " << buf.size_ << " bytes from " << data << "\n"; io.read(buf.pData_, buf.size_); if (io.error() || !io.eof()) throw Exiv2::Error(Exiv2::kerFailedToReadImageData); // Read metadata from file Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file); assert(image.get() != 0); image->readMetadata(); // Set Preview field to the content of the data file Exiv2::DataValue value; value.read(buf.pData_, buf.size_); Exiv2::IptcData& iptcData = image->iptcData(); std::cout << "IPTC fields: " << iptcData.size() << "\n"; iptcData["Iptc.Application2.Preview"] = value; std::cout << "IPTC fields: " << iptcData.size() << "\n"; // Set IRB, compare with IPTC raw data Exiv2::DataBuf irb = Exiv2::Photoshop::setIptcIrb(0, 0, iptcData); std::cout << "IRB buffer : " << irb.size_ << "\n"; const Exiv2::byte* record; uint32_t sizeHdr; uint32_t sizeData; Exiv2::Photoshop::locateIptcIrb(irb.pData_, irb.size_, &record, &sizeHdr, &sizeData); Exiv2::DataBuf rawIptc = Exiv2::IptcParser::encode(iptcData); std::cout << "Comparing IPTC and IRB size... "; if (static_cast<uint32_t>(rawIptc.size_) != sizeData) { std::cout << "not "; } std::cout << "ok\n"; std::cout << "Comparing IPTC and IRB data... "; if (0 != memcmp(rawIptc.pData_, record + sizeHdr, sizeData)) { std::cout << "not "; } std::cout << "ok\n"; // Set Iptc data and write it to the file image->writeMetadata(); return 0; } catch (Exiv2::AnyError& e) { std::cout << "Caught Exiv2 exception '" << e << "'\n"; return -1; }
// ***************************************************************************** // 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; }