diff --git a/man/man1/exiv2.1 b/man/man1/exiv2.1 index 304b51ef..19d3bc76 100644 --- a/man/man1/exiv2.1 +++ b/man/man1/exiv2.1 @@ -2,7 +2,7 @@ .\" First parameter, NAME, should be all caps .\" Second parameter, SECTION, should be 1-8, maybe w/ subsection .\" other parameters are allowed: see man(7), man(1) -.TH EXIV2 1 "Aug 25, 2019" +.TH EXIV2 1 "March 22, 2020" .\" Please adjust this date whenever revising the manpage. .\" .\" Some roff macros, for reference: @@ -533,14 +533,34 @@ The value is optional. Not providing any value is equivalent to an empty value ("") and is mainly useful to create an XMP array property, e.g., a bag. .sp 1 -The format of Exif \fBComment\fP values includes an optional charset -specification at the beginning: +The format of Exif \fBComment\fP values include an optional charset +specification at the beginning. Comments are used by the tags Exif.Photo.UserComment, Exif.GPSInfo.GPSProcessingMethod +and Exif.GPSInfo.GPSAreaInformation. Comments are stored as Undefined tags with an 8 byte encoding +definition follow by the encoded data. The charset is specified as follows: +.sp 1 +.B [charset=Ascii|Jis|Unicode|Undefined] \fIcomment\fP .br -.B [charset=Ascii|Jis|Unicode|Undefined ]\fIcomment\fP +charset=Undefined is the default .sp 1 -.B Undefined -is used by default if the value doesn't start with a charset -definition. +.nf +$ exiv2 -M'set Exif.Photo.UserComment charset=Ascii My photo' x.jpg +$ exiv2 -pa --grep UserComment x.jpg +Exif.Photo.UserComment Undefined 16 My photo +$ exiv2 -pv --grep UserComment x.jpg +0x9286 Photo UserComment Undefined 16 charset="Ascii" My photo + +$ exiv2 -M'set Exif.Photo.UserComment charset=Unicode \\u0052\\u006f\\u0062\\u0069\\u006e' x.jpg +$ exiv2 -pa --grep UserComment x.jpg +Exif.Photo.UserComment Undefined 18 Robin +$ exiv2 -pv --grep UserComment x.jpg +0x9286 Photo UserComment Undefined 18 charset="Unicode" Robin + +$ exiv2 -M'set Exif.GPSInfo.GPSProcessingMethod HYBRID-FIX' x.jpg +$ exiv2 -pa --grep ProcessingMethod x.jpg +Exif.GPSInfo.GPSProcessingMethod Undefined 18 HYBRID-FIX +$ exiv2 -pv --grep ProcessingMethod x.jpg +0x001b GPSInfo GPSProcessingMethod Undefined 18 HYBRID-FIX +.fi .sp 1 The format for an IPTC \fBDate\fP value is: .sp 1 @@ -661,7 +681,7 @@ Type Explanation The printing flag t = translated and is intended for human use. Scripts should never use translated values as they are localised and the format may change as Exiv2 evolves. The printing flag v reports the values recorded in the metadata and should be used by scripts. .ne 40 .SH CONFIGURATION FILE -Exiv2 can read an optional configuration file ~/.exiv2 on Unix systems and %USERPROFILE%\\exiv2.ini on Windows (using a Visual Studio build). Cygwin and MinGW/msys2 follow the unix convention and use ~/.exiv2 You can fine the location of the configuration file with the command: +Exiv2 can read an optional configuration file ~/.exiv2 on Unix systems and %USERPROFILE%\\exiv2.ini on Windows (using a Visual Studio build). Cygwin and MinGW/msys2 follow the unix convention and use ~/.exiv2 You can determine the location of the configuration file with the command: .br .sp 1 .nf diff --git a/src/actions.cpp b/src/actions.cpp index ff9f28b0..826d9e8b 100644 --- a/src/actions.cpp +++ b/src/actions.cpp @@ -696,7 +696,15 @@ namespace Action { return true; } bool done = false; - if (0 == strcmp(md.key().c_str(), "Exif.Photo.UserComment")) { + // handle `comment` typeIDs + // $ bin/taglist | grep '\tComment,' | cut -d, -f 5 + // Exif.Photo.UserComment + // Exif.GPSInfo.GPSProcessingMethod + // Exif.GPSInfo.GPSAreaInformation + if( md.key() == "Exif.Photo.UserComment" + || md.key() == "Exif.GPSInfo.GPSProcessingMethod" + || md.key() == "Exif.GPSInfo.GPSAreaInformation" + ) { const Exiv2::CommentValue* pcv = dynamic_cast(&md.value()); if (pcv) { Exiv2::CommentValue::CharsetId csId = pcv->charsetId(); diff --git a/src/tags_int.cpp b/src/tags_int.cpp index add81946..8688d26f 100644 --- a/src/tags_int.cpp +++ b/src/tags_int.cpp @@ -1908,13 +1908,12 @@ namespace Exiv2 { gpsId, gpsTags, unsignedRational, 1, printValue), TagInfo(0x001b, "GPSProcessingMethod", N_("GPS Processing Method"), N_("A character string recording the name of the method used for location finding. " - "The first byte indicates the character code used, and this is followed by the name " - "of the method."), - gpsId, gpsTags, undefined, 0, printValue), + "The string encoding is defined using the same scheme as UserComment."), + gpsId, gpsTags, comment, 0, print0x9286), TagInfo(0x001c, "GPSAreaInformation", N_("GPS Area Information"), - N_("A character string recording the name of the GPS area. The first byte indicates " - "the character code used, and this is followed by the name of the GPS area."), - gpsId, gpsTags, undefined, 0, printValue), + N_("A character string recording the name of the GPS area." + "The string encoding is defined using the same scheme as UserComment."), + gpsId, gpsTags, comment, 0, print0x9286), TagInfo(0x001d, "GPSDateStamp", N_("GPS Date Stamp"), N_("A character string recording date and time information relative to UTC " "(Coordinated Universal Time). The format is \"YYYY:MM:DD.\"."), @@ -2229,38 +2228,23 @@ namespace Exiv2 { std::ostream& printFloat(std::ostream& os, const Value& value, const ExifData*) { Rational r = value.toRational(); - if (r.second != 0) return os << static_cast(r.first) / r.second; - return os << "(" << value << ")"; + if (r.second != 0) { + os << value.toFloat() ; + } else { + os << "(" << value << ")"; + } + return os; } // printFloat std::ostream& printDegrees(std::ostream& os, const Value& value, const ExifData*) { std::ios::fmtflags f( os.flags() ); if (value.count() == 3) { - std::ostringstream oss; - oss.copyfmt(os); static const char* unit[] = { "deg", "'", "\"" }; - static const int prec[] = { 7, 5, 3 }; - int n; - for (n = 2; n > 0; --n) { - if (value.toRational(n).first != 0) break; + for (int i = 0; i < value.count() ; ++i) { + const int v = (int) (value.toFloat(i)+0.5f); // nearest integer + os << (i != 0? " " : "") << v << unit[i]; } - for (int i = 0; i < n + 1; ++i) { - const uint32_t z = (uint32_t) value.toRational(i).first; - const uint32_t d = (uint32_t) value.toRational(i).second; - if (d == 0) - { - os << "(" << value << ")"; - os.flags(f); - return os; - } - // Hack: Need Value::toDouble - double b = static_cast(z)/d; - const int p = z % d == 0 ? 0 : prec[i]; - os << std::fixed << std::setprecision(p) << b - << unit[i] << " "; - } - os.copyfmt(oss); } else { os << value; diff --git a/src/tiffcomposite_int.cpp b/src/tiffcomposite_int.cpp index 8c792c00..a6bf925b 100644 --- a/src/tiffcomposite_int.cpp +++ b/src/tiffcomposite_int.cpp @@ -1836,14 +1836,33 @@ namespace Exiv2 { return len; } // TiffImageEntry::doSizeImage + static const TagInfo* findTagInfo(uint16_t tag,IfdId group) + { + const TagInfo* result = NULL ; + const TagInfo* tags = group == exifId ? Internal::exifTagList() + : group == gpsId ? Internal::gpsTagList() + : NULL + ; + if ( tags ) { + for ( size_t idx = 0; result==NULL && tags[idx].tag_ != 0xffff; ++idx) { + if ( tags[idx].tag_ == tag ) { + result = tags+idx; + } + } + } + return result; + } + // ************************************************************************* // free functions TypeId toTypeId(TiffType tiffType, uint16_t tag, IfdId group) { TypeId ti = TypeId(tiffType); - // On the fly type conversion for Exif.Photo.UserComment - if (tag == 0x9286 && group == exifId && ti == undefined) { - ti = comment; + // On the fly type conversion for Exif.Photo.UserComment, Exif.GPSProcessingMethod, GPSAreaInformation + if ( const TagInfo* pTag = ti == undefined ? findTagInfo(tag,group) : NULL ) { + if ( pTag->typeId_ == comment ) { + ti = comment; + } } // http://dev.exiv2.org/boards/3/topics/1337 change unsignedByte to signedByte // Exif.NikonAFT.AFFineTuneAdj || Exif.Pentax.Temperature diff --git a/test/data/IMG_0246.exv b/test/data/IMG_0246.exv index 63d34c73..bf54ec9f 100644 Binary files a/test/data/IMG_0246.exv and b/test/data/IMG_0246.exv differ diff --git a/test/data/geotag-test.out b/test/data/geotag-test.out index 36e7d353..0d49855c 100644 --- a/test/data/geotag-test.out +++ b/test/data/geotag-test.out @@ -1,14 +1,14 @@ --- show GPSInfo tags --- Exif.GPSInfo.GPSVersionID Byte 4 2.2.0.0 Exif.GPSInfo.GPSLatitudeRef Ascii 2 North -Exif.GPSInfo.GPSLatitude Rational 3 36deg 26' 54" +Exif.GPSInfo.GPSLatitude Rational 3 36deg 26' 54" Exif.GPSInfo.GPSLongitudeRef Ascii 2 West -Exif.GPSInfo.GPSLongitude Rational 3 116deg 51' 18" +Exif.GPSInfo.GPSLongitude Rational 3 116deg 51' 18" Exif.GPSInfo.GPSAltitudeRef Byte 1 Below sea level Exif.GPSInfo.GPSAltitude Rational 1 14.3 m Exif.GPSInfo.GPSTimeStamp Rational 3 09:54:28 Exif.GPSInfo.GPSMapDatum Ascii 7 WGS-84 -Exif.GPSInfo.GPSProcessingMethod Undefined 18 65 83 67 73 73 0 0 0 72 89 66 82 73 68 45 70 73 88 +Exif.GPSInfo.GPSProcessingMethod Undefined 18 HYBRID-FIX Exif.GPSInfo.GPSDateStamp Ascii 20 2008:05:08 09:54:28 --- deleting the GPSInfo tags --- run geotag --- @@ -16,12 +16,12 @@ Exif.GPSInfo.GPSDateStamp Ascii 20 2008:05:08 09:54:28 --- show GPSInfo tags --- Exif.GPSInfo.GPSVersionID Byte 4 2.2.0.0 Exif.GPSInfo.GPSLatitudeRef Ascii 2 North -Exif.GPSInfo.GPSLatitude Rational 3 36deg 26' 54" +Exif.GPSInfo.GPSLatitude Rational 3 36deg 26' 54" Exif.GPSInfo.GPSLongitudeRef Ascii 2 West -Exif.GPSInfo.GPSLongitude Rational 3 116deg 51' 18" +Exif.GPSInfo.GPSLongitude Rational 3 116deg 51' 18" Exif.GPSInfo.GPSAltitudeRef Byte 1 Below sea level Exif.GPSInfo.GPSAltitude Rational 1 14.3 m Exif.GPSInfo.GPSTimeStamp Rational 3 09:54:28 Exif.GPSInfo.GPSMapDatum Ascii 7 WGS-84 -Exif.GPSInfo.GPSProcessingMethod Undefined 18 65 83 67 73 73 0 0 0 72 89 66 82 73 68 45 70 73 88 +Exif.GPSInfo.GPSProcessingMethod Undefined 58 65 83 67 73 73 0 0 0 72 89 66 82 73 68 45 70 73 88 Exif.GPSInfo.GPSDateStamp Ascii 20 2008:05:08 09:54:28 diff --git a/tests/bugfixes/redmine/test_issue_1024.py b/tests/bugfixes/redmine/test_issue_1024.py index 5943691c..d98d530d 100644 --- a/tests/bugfixes/redmine/test_issue_1024.py +++ b/tests/bugfixes/redmine/test_issue_1024.py @@ -10,9 +10,9 @@ class CheckRegularExpressionSupport(metaclass=system_tests.CaseMeta): commands = [ "$exiv2 -pa --grep gpsl/i $filename" ] stdout = [ """Exif.GPSInfo.GPSLatitudeRef Ascii 2 North -Exif.GPSInfo.GPSLatitude Rational 3 52deg 3.81700' +Exif.GPSInfo.GPSLatitude Rational 3 52deg 4' 0" Exif.GPSInfo.GPSLongitudeRef Ascii 2 East -Exif.GPSInfo.GPSLongitude Rational 3 1deg 13.81940' +Exif.GPSInfo.GPSLongitude Rational 3 1deg 14' 0" """ ] stderr = [""] diff --git a/tests/bugfixes/redmine/test_issue_1137.py b/tests/bugfixes/redmine/test_issue_1137.py index 8e465b18..8cdecf71 100644 --- a/tests/bugfixes/redmine/test_issue_1137.py +++ b/tests/bugfixes/redmine/test_issue_1137.py @@ -36,8 +36,8 @@ set Exif.GPSInfo.GPSLongitude 1/1 495984/10000 0/1 output_grep_GPSL, "", """Exif.GPSInfo.GPSLatitudeRef Ascii 2 North -Exif.GPSInfo.GPSLatitude Rational 3 51deg 10.69690' +Exif.GPSInfo.GPSLatitude Rational 3 51deg 11' 0" Exif.GPSInfo.GPSLongitudeRef Ascii 2 West -Exif.GPSInfo.GPSLongitude Rational 3 1deg 49.59840' +Exif.GPSInfo.GPSLongitude Rational 3 1deg 50' 0" """ ] diff --git a/tests/bugfixes/redmine/test_issue_528.py b/tests/bugfixes/redmine/test_issue_528.py index d8ddebeb..7db691e2 100644 --- a/tests/bugfixes/redmine/test_issue_528.py +++ b/tests/bugfixes/redmine/test_issue_528.py @@ -70,9 +70,9 @@ Exif.Photo.Saturation Short 1 Normal Exif.Image.GPSTag Long 1 867 Exif.GPSInfo.GPSVersionID Byte 4 2.0.0.0 Exif.GPSInfo.GPSLatitudeRef Ascii 2 North -Exif.GPSInfo.GPSLatitude Rational 3 47deg 36' 58.020" +Exif.GPSInfo.GPSLatitude Rational 3 47deg 36' 58" Exif.GPSInfo.GPSLongitudeRef Ascii 2 East -Exif.GPSInfo.GPSLongitude Rational 3 1deg 31' 0.940" +Exif.GPSInfo.GPSLongitude Rational 3 1deg 31' 1" Exif.GPSInfo.GPSAltitudeRef Byte 1 Above sea level Exif.GPSInfo.GPSAltitude Rational 1 86 m Exif.Thumbnail.Compression Short 1 JPEG (old-style)