You cannot select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
163 lines
5.2 KiB
C++
163 lines
5.2 KiB
C++
21 years ago
|
// ***************************************************************** -*- C++ -*-
|
||
|
/*
|
||
|
Abstract : Sample program showing how to set the Exif comment of an image
|
||
|
|
||
|
File: exifcomment.cpp
|
||
|
Version : $Name: $ $Revision: 1.1 $
|
||
|
Author(s): Andreas Huggel (ahu) <ahuggel@gmx.net>
|
||
|
History : 10-May-04, ahu: created
|
||
|
*/
|
||
|
// *****************************************************************************
|
||
|
// included header files
|
||
|
#include "exif.hpp"
|
||
|
#include <iostream>
|
||
|
#include <iomanip>
|
||
|
#include <cstring>
|
||
|
|
||
|
// *****************************************************************************
|
||
|
// local declarations
|
||
|
|
||
|
std::string readError(int rc, const std::string& path);
|
||
|
std::string writeError(int rc, const std::string& path);
|
||
|
|
||
|
// *****************************************************************************
|
||
|
// 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 = readError(rc, argv[1]);
|
||
|
throw Exiv2::Error(error);
|
||
|
}
|
||
|
|
||
|
/*
|
||
|
There are two pitfalls that we need to consider when setting the Exif user
|
||
|
comment (Image.UserInfo.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((charset + comment).data(), 8 + comment.size());
|
||
|
|
||
|
// Set the Exif comment
|
||
|
std::string key = "Image.UserInfo.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 = writeError(rc, argv[1]);
|
||
|
throw Exiv2::Error(error);
|
||
|
}
|
||
|
|
||
|
return rc;
|
||
|
}
|
||
|
catch (Exiv2::Error& e) {
|
||
|
std::cout << "Caught Exiv2 exception '" << e << "'\n";
|
||
|
return -1;
|
||
|
}
|
||
|
|
||
|
// *****************************************************************************
|
||
|
// local definitions
|
||
|
|
||
|
std::string readError(int rc, const std::string& path)
|
||
|
{
|
||
|
std::string error;
|
||
|
switch (rc) {
|
||
|
case -1:
|
||
|
error = path + ": Failed to open the file";
|
||
|
break;
|
||
|
case -2:
|
||
|
error = path + ": The file contains data of an unknown image type";
|
||
|
break;
|
||
|
case 1:
|
||
|
error = path + ": Couldn't read from the input stream";
|
||
|
break;
|
||
|
case 2:
|
||
|
error = path + ": This does not look like a JPEG image";
|
||
|
break;
|
||
|
case 3:
|
||
|
error = path + ": No Exif data found in the file";
|
||
|
break;
|
||
|
case -99:
|
||
|
error = path + ": Unsupported Exif or GPS data found in IFD 1";
|
||
|
break;
|
||
|
default:
|
||
|
error = path + ": Reading Exif data failed, rc = " + Exiv2::toString(rc);
|
||
|
break;
|
||
|
}
|
||
|
return error;
|
||
|
} // exifReadError
|
||
|
|
||
|
std::string writeError(int rc, const std::string& path)
|
||
|
{
|
||
|
std::string error;
|
||
|
switch (rc) {
|
||
|
case -1:
|
||
|
error = path + ": Failed to open the file";
|
||
|
break;
|
||
|
case -2:
|
||
|
error = path + ": The file contains data of an unknown image type";
|
||
|
break;
|
||
|
case -3:
|
||
|
error = path + ": Couldn't open temporary file";
|
||
|
break;
|
||
|
case -4:
|
||
|
error = path + ": Renaming temporary file failed";
|
||
|
break;
|
||
|
case 1:
|
||
|
error = path + ": Couldn't read from the input stream";
|
||
|
break;
|
||
|
case 2:
|
||
|
error = path + ": This does not look like a JPEG image";
|
||
|
break;
|
||
|
case 3:
|
||
|
error = path + ": No JFIF APP0 or Exif APP1 segment found in the file";
|
||
|
break;
|
||
|
case 4:
|
||
|
error = path + ": Writing to the output stream failed";
|
||
|
break;
|
||
|
default:
|
||
|
error = path + ": Reading Exif data failed, rc = " + Exiv2::toString(rc);
|
||
|
break;
|
||
|
}
|
||
|
return error;
|
||
|
} // writeError
|