Skip to content

Commit

Permalink
Add tag description option to exiv2 app (#2279)
Browse files Browse the repository at this point in the history
* Add `tagDesc()` to (Exif|Xmp|Iptc) Datums and Keys
* Add `--Print d` option to exiv2 app
* Add testing for all exiv2 application `--Print` options
* Update manpage
  • Loading branch information
postscript-dev authored Jul 12, 2022
1 parent 0558662 commit dc4ae73
Show file tree
Hide file tree
Showing 18 changed files with 92 additions and 26 deletions.
6 changes: 6 additions & 0 deletions app/actions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -498,6 +498,12 @@ bool Print::printMetadatum(const Exiv2::Metadatum& md, const Exiv2::Image* pImag
first = false;
std::cout << std::setw(30) << std::setfill(' ') << std::left << md.tagLabel();
}
if (Params::instance().printItems_ & Params::prDesc) {
if (!first)
std::cout << " ";
first = false;
std::cout << std::setw(30) << std::setfill(' ') << std::left << md.tagDesc();
}
if (Params::instance().printItems_ & Params::prType) {
if (!first)
std::cout << " ";
Expand Down
13 changes: 9 additions & 4 deletions app/exiv2.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -283,14 +283,16 @@ void Params::help(std::ostream& os) const {
<< _(" X : Extract \"raw\" XMP\n")
<< _(" -P flgs Print flags for fine control of tag lists ('print' action):\n")
<< _(" E : Exif tags\n") << _(" I : IPTC tags\n") << _(" X : XMP tags\n")
<< _(" x : Tag number (Exif and IPTC only)\n")
<< _(" x : Tag number for Exif or IPTC tags (in hexadecimal)\n")
<< _(" g : Group name (e.g. Exif.Photo.UserComment, Photo)\n")
<< _(" k : Key (e.g. Exif.Photo.UserComment)\n")
<< _(" l : Tag label (e.g. Exif.Photo.UserComment, 'User comment')\n")
<< _(" d : Tag description\n")
<< _(" n : Tag name (e.g. Exif.Photo.UserComment, UserComment)\n") << _(" y : Type\n")
<< _(" c : Number of components (count)\n")
<< _(" s : Size in bytes (Ascii and Comment types include NULL)\n")
<< _(" v : Plain data value, untranslated (vanilla)\n")
<< _(" y : Type\n") << _(" c : Number of components (count)\n")
<< _(" s : Size in bytes of vanilla value (may include NULL)\n")
<< _(" v : Plain data value of untranslated (vanilla)\n")
<< _(" V : Plain data value, data type and the word 'set'\n")
<< _(" t : Interpreted (translated) human readable values\n")
<< _(" h : Hex dump of the data\n")
<< _(" -d tgt1 Delete target(s) for the 'delete' action. Possible targets are:\n")
Expand Down Expand Up @@ -720,6 +722,9 @@ int Params::evalPrintFlags(const std::string& optArg) {
case 'V':
printItems_ |= prSet | prKey | prType | prValue;
break;
case 'd':
printItems_ |= prDesc;
break;
default:
std::cerr << progname() << ": " << _("Unrecognized print item") << " `" << i << "'\n";
rc = 1;
Expand Down
3 changes: 2 additions & 1 deletion app/exiv2app.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,7 +151,8 @@ class Params : public Util::Getopt {
prValue = 256,
prTrans = 512,
prHex = 1024,
prSet = 2048
prSet = 2048,
prDesc = 4096
};

//! Enumerates common targets, bitmap
Expand Down
31 changes: 15 additions & 16 deletions exiv2.md
Original file line number Diff line number Diff line change
Expand Up @@ -566,34 +566,33 @@ as well as data columns included in the print output. Valid flags are:
| g | Group name (e.g., for Exif.Photo.UserComment, outputs Photo) |
| k | Key (e.g., Exif.Photo.UserComment) |
| l | Tag label (human-readable tagname, e.g., for Exif.Photo.UserComment, outputs 'User comment') |
| n | Tagname (e.g., for Exif.Photo.UserComment, outputs UserComment) |
| d | Tag description |
| n | Tag name (e.g., for Exif.Photo.UserComment, outputs UserComment) |
| y | Type (for available types, see [Exif/IPTC/XMP types](#exiv2_types)) |
| c | Number of components (for single entry types, the number of **sizeof('type')** in 'size'. For multi-entry types, the number of entries. See [Exif/IPTC/XMP types](#exiv2_types)) |
| s | Size in bytes of vanilla output (see note in [Exif 'Comment' values](#exif_comment_values)). Some types include a *NULL* character in the size (see [Exif/IPTC/XMP types](#exiv2_types)) |
| v | Plain data value (vanilla values, i.e., untranslated) |
| V | Plain data value, data type and the word 'set ' (see ['MODIFY' COMMANDS](#modify_cmds))|
| V | Plain data value, data type and the word 'set' (see ['MODIFY' COMMANDS](#modify_cmds))|
| t | Interpreted (translated) human-readable data values (includes plain vanilla values) |
| h | Hex dump of the data |

**--Print** *flgs* can be combined with [--grep str](#grep_str) or
[--key key](#key_key) to further filter the output.

<div id="Print_flgs_order">

The order of the values in *flgs* is not respected. For example, the order
of the columns, using some tags from *Stonehenge.jpg*, is as follows:
The order of the values in *flgs* is not respected and is output as follows:

```
$ curl --silent -O https://www.exiv2.org/Stonehenge.jpg
$ exiv2 --Print xgknlycst Stonehenge.jpg
```
| Tag number<br>(x) | Plain 'set'<br>(V) | Group<br>(g) | Key<br>(k) | Tagname<br>(n) | Tagname label<br>(l) |Description<br>(d) | Type<br>(y) | Comp<br>(c) | Size<br>(s) | Value<br>(v) | Translated<br>(t) |
|:------ |:---- |:------ |:------ |:------ |:------ |:------ |:------ |:------ |:------ |:--- |:------ |

| Tag number<br>(x) | Plain 'set'<br>(V) | Group<br>(g) | Key<br>(k) | Tagname<br>(n) | Tagname label<br>(l) | Type<br>(y) | Comp<br>(c) | Size<br>(s) | Value<br>(E, I, X, v, t) | Translated<br>(t) |
|:------ |:---- |:------ |:------ |:------ |:------ |:------ |:------ |:------ |:------ |:------ |
| 0x0110 | set | Image | Exif.Image.Model | Model | Model | Ascii | 12 | 12 | NIKON D5300 | NIKON D5300 |
| 0x0006 | set | NikonIi | Exif.NikonIi.ISO2 | ISO2 | ISO 2 | Byte | 1 | 1 | 72 | 200 |
| 0x0000 | set | xmp | Xmp.xmp.Rating | Rating | Rating | XmpText | 1 | 1 | 0 | 0 |
| 0x0000 | set | dc | Xmp.dc.Family | Family | Family | XmpBag | 1 | 5 | Robin | Robin |
For example,

**--Print** *flgs* can be combined with [--grep str](#grep_str) or
[--key key](#key_key) to further filter the output.
```bash
$ curl --silent -O https://www.exiv2.org/Stonehenge.jpg
$ exiv2 --Print xVgknldycsvt -K Exif.Nikon3.Quality Stonehenge.jpg
0x0004 set Nikon3 Exif.Nikon3.Quality Quality Quality Image quality setting Ascii 8 8 NORMAL NORMAL
```

<div id="delete_tgt1">

Expand Down
1 change: 1 addition & 0 deletions include/exiv2/datasets.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -280,6 +280,7 @@ class EXIV2API IptcKey : public Key {
[[nodiscard]] std::string groupName() const override;
[[nodiscard]] std::string tagName() const override;
[[nodiscard]] std::string tagLabel() const override;
[[nodiscard]] std::string tagDesc() const override;
[[nodiscard]] uint16_t tag() const override;
[[nodiscard]] UniquePtr clone() const;
//! Return the name of the record
Expand Down
1 change: 1 addition & 0 deletions include/exiv2/exif.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,7 @@ class EXIV2API Exifdatum : public Metadatum {
[[nodiscard]] std::string groupName() const override;
[[nodiscard]] std::string tagName() const override;
[[nodiscard]] std::string tagLabel() const override;
[[nodiscard]] std::string tagDesc() const override;
[[nodiscard]] uint16_t tag() const override;
//! Return the IFD id as an integer. (Do not use, this is meant for library internal use.)
[[nodiscard]] IfdId ifdId() const;
Expand Down
1 change: 1 addition & 0 deletions include/exiv2/iptc.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,7 @@ class EXIV2API Iptcdatum : public Metadatum {
*/
[[nodiscard]] std::string tagName() const override;
[[nodiscard]] std::string tagLabel() const override;
[[nodiscard]] std::string tagDesc() const override;
//! Return the tag (aka dataset) number
[[nodiscard]] uint16_t tag() const override;
[[nodiscard]] TypeId typeId() const override;
Expand Down
4 changes: 4 additions & 0 deletions include/exiv2/metadatum.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -52,6 +52,8 @@ class EXIV2API Key {
[[nodiscard]] virtual std::string tagName() const = 0;
//! Return a label for the tag
[[nodiscard]] virtual std::string tagLabel() const = 0;
//! Return a description for the tag
[[nodiscard]] virtual std::string tagDesc() const = 0;
//! Return the tag number
[[nodiscard]] virtual uint16_t tag() const = 0;
/*!
Expand Down Expand Up @@ -181,6 +183,8 @@ class EXIV2API Metadatum {
[[nodiscard]] virtual std::string tagName() const = 0;
//! Return a label for the tag
[[nodiscard]] virtual std::string tagLabel() const = 0;
//! Return a description for the tag
[[nodiscard]] virtual std::string tagDesc() const = 0;
//! Return the tag
[[nodiscard]] virtual uint16_t tag() const = 0;
//! Return the type id of the value
Expand Down
1 change: 1 addition & 0 deletions include/exiv2/properties.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -263,6 +263,7 @@ class EXIV2API XmpKey : public Key {
[[nodiscard]] std::string groupName() const override;
[[nodiscard]] std::string tagName() const override;
[[nodiscard]] std::string tagLabel() const override;
[[nodiscard]] std::string tagDesc() const override;
//! Properties don't have a tag number. Return 0.
[[nodiscard]] uint16_t tag() const override;

Expand Down
3 changes: 1 addition & 2 deletions include/exiv2/tags.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -339,8 +339,7 @@ class EXIV2API ExifKey : public Key {
[[nodiscard]] std::string tagName() const override;
[[nodiscard]] uint16_t tag() const override;
[[nodiscard]] std::string tagLabel() const override;
//! Return the tag description.
[[nodiscard]] std::string tagDesc() const; // Todo: should be in the base class
[[nodiscard]] std::string tagDesc() const override;
//! Return the default type id for this tag.
[[nodiscard]] TypeId defaultTypeId() const; // Todo: should be in the base class

Expand Down
1 change: 1 addition & 0 deletions include/exiv2/xmp_exiv2.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,6 +103,7 @@ class EXIV2API Xmpdatum : public Metadatum {
//! Return the property name.
[[nodiscard]] std::string tagName() const override;
[[nodiscard]] std::string tagLabel() const override;
[[nodiscard]] std::string tagDesc() const override;
//! Properties don't have a tag number. Return 0.
[[nodiscard]] uint16_t tag() const override;
[[nodiscard]] TypeId typeId() const override;
Expand Down
4 changes: 4 additions & 0 deletions src/datasets.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -531,6 +531,10 @@ std::string IptcKey::tagLabel() const {
return IptcDataSets::dataSetTitle(tag_, record_);
}

std::string IptcKey::tagDesc() const {
return IptcDataSets::dataSetDesc(tag_, record_);
}

uint16_t IptcKey::tag() const {
return tag_;
}
Expand Down
4 changes: 4 additions & 0 deletions src/exif.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -292,6 +292,10 @@ std::string Exifdatum::tagLabel() const {
return key_ ? key_->tagLabel() : "";
}

std::string Exifdatum::tagDesc() const {
return key_ ? key_->tagDesc() : "";
}

uint16_t Exifdatum::tag() const {
return key_ ? key_->tag() : 0xffff;
}
Expand Down
4 changes: 4 additions & 0 deletions src/iptc.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,10 @@ std::string Iptcdatum::tagLabel() const {
return key_ ? key_->tagLabel() : "";
}

std::string Iptcdatum::tagDesc() const {
return key_ ? key_->tagDesc() : "";
}

uint16_t Iptcdatum::tag() const {
return key_ ? key_->tag() : 0;
}
Expand Down
7 changes: 7 additions & 0 deletions src/properties.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5139,6 +5139,13 @@ std::string XmpKey::tagLabel() const {
return pt;
}

std::string XmpKey::tagDesc() const {
const char* pt = XmpProperties::propertyDesc(*this);
if (!pt)
return "";
return pt;
}

uint16_t XmpKey::tag() const {
return 0;
}
Expand Down
4 changes: 4 additions & 0 deletions src/xmp.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -326,6 +326,10 @@ std::string Xmpdatum::tagLabel() const {
return p_->key_ ? p_->key_->tagLabel() : "";
}

std::string Xmpdatum::tagDesc() const {
return p_->key_ ? p_->key_->tagDesc() : "";
}

uint16_t Xmpdatum::tag() const {
return p_->key_ ? p_->key_->tag() : 0;
}
Expand Down
9 changes: 6 additions & 3 deletions test/data/test_reference_files/exiv2-test.out
Original file line number Diff line number Diff line change
Expand Up @@ -90,15 +90,18 @@ Options:
E : Exif tags
I : IPTC tags
X : XMP tags
x : Tag number (Exif and IPTC only)
x : Tag number for Exif or IPTC tags (in hexadecimal)
g : Group name (e.g. Exif.Photo.UserComment, Photo)
k : Key (e.g. Exif.Photo.UserComment)
l : Tag label (e.g. Exif.Photo.UserComment, 'User comment')
d : Tag description
n : Tag name (e.g. Exif.Photo.UserComment, UserComment)
y : Type
y : Type
c : Number of components (count)
s : Size in bytes (Ascii and Comment types include NULL)
v : Plain data value, untranslated (vanilla)
s : Size in bytes of vanilla value (may include NULL)
v : Plain data value of untranslated (vanilla)
V : Plain data value, data type and the word 'set'
t : Interpreted (translated) human readable values
h : Hex dump of the data
-d tgt1 Delete target(s) for the 'delete' action. Possible targets are:
Expand Down
21 changes: 21 additions & 0 deletions tests/bash_tests/test_pr_2279.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,21 @@
# -*- coding: utf-8 -*-

import system_tests

class TestExifIPTCXmpTagOutput(metaclass=system_tests.CaseMeta):
url = "https://github.com/Exiv2/exiv2/pull/2279"

# Test the exiv2 application's `--Print` command
filename = "$data_path/Stonehenge.exv"
commands = ["$exiv2 --Print xVgknldycsvt --key Exif.Image.Model $filename",
"$exiv2 --Print xVgknldycsvt --key Iptc.Application2.Caption $filename",
"$exiv2 --Print xVgknldycsvt --key Xmp.dc.description $filename"]
stderr = [""] * len(commands)
stdout = ["""0x0110 set Image Exif.Image.Model Model Model The model name or model number of the equipment. This is the model name or number of the DSC, scanner, video digitizer or other equipment that generated the image. When the field is left blank, it is treated as unknown. Ascii 12 12 NIKON D5300 NIKON D5300
""",
"""0x0078 set Application2 Iptc.Application2.Caption Caption Caption A textual description of the object data. String 12 12 Classic View Classic View
""",
"""0x0000 set dc Xmp.dc.description description Description A textual description of the content of the resource. Multiple values may be present for different languages. LangAlt 1 29 lang="x-default" Classic View lang="x-default" Classic View
"""
]
retval = [0] * len(commands)

0 comments on commit dc4ae73

Please sign in to comment.