[gexiv2] Update gexiv2-dump tool
- From: Jens Georg <jensgeorg src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gexiv2] Update gexiv2-dump tool
- Date: Thu, 8 Apr 2021 14:51:39 +0000 (UTC)
commit c777329e8c0197d806c62a697754b567020a85d9
Author: postscript-dev <43813-postscript-dev users noreply gitlab gnome org>
Date: Thu Feb 18 16:48:51 2021 +0000
Update gexiv2-dump tool
+ Prevent incompatibilities with old version by renaming to gexiv2-tool.
+ Only processes a single image file
+ Add options to print different combinations of tags to screen
+ Add option to output information about a tag (e.g. description, etc)
+ Add option to output Xmp namespace values
tools/gexiv2-dump.vala | 51 -----------
tools/gexiv2-tool.vala | 240 +++++++++++++++++++++++++++++++++++++++++++++++++
tools/meson.build | 4 +-
3 files changed, 242 insertions(+), 53 deletions(-)
---
diff --git a/tools/gexiv2-tool.vala b/tools/gexiv2-tool.vala
new file mode 100644
index 0000000..64579d7
--- /dev/null
+++ b/tools/gexiv2-tool.vala
@@ -0,0 +1,240 @@
+/*
+ * gexiv2-tool.vala
+ *
+ * Author(s)
+ * Jim Nelson <jim yorba org>
+ *
+ * This is free software. See COPYING for details.
+ */
+
+// Global variables used in parsing program paramters
+bool print_exif_tags = false;
+bool print_iptc_tags = false;
+bool print_xmp_tags = false;
+bool print_xmp_ns = false;
+bool print_tag_details = false;
+string print_single_tag;
+
+// Command line optional parameters
+const GLib.OptionEntry[] options = {
+ // [-exif]
+ {"exif", 'e', 0, OptionArg.NONE, ref print_exif_tags, "Print out Exif tags from FILE", null},
+
+ // [-iptc]
+ {"iptc", 'i', 0, OptionArg.NONE, ref print_iptc_tags, "Print out Iptc tags from FILE", null},
+
+ // [-xmp]
+ {"xmp", 'x', 0, OptionArg.NONE, ref print_xmp_tags, "Print out Xmp tags from FILE", null},
+
+ // [-xns]
+ {"xns", 'n', 0, OptionArg.NONE, ref print_xmp_ns, "Print out Xmp namespaces from FILE", null},
+
+ // [-details]
+ {"details", 'd', 0, OptionArg.NONE, ref print_tag_details, "Print additional tag details (interpreted
value, label, type and description)", null},
+
+ // [-tag TAG]
+ {"tag", 't', 0, OptionArg.STRING, ref print_single_tag, "Only print a specific tag's data from FILE
(overrides -e, -i and -x)", null},
+
+ // list terminator
+ {null}
+};
+
+/**
+ * main:
+ * @args: Program arguments
+ *
+ * Prints out image metadata from a file.
+ *
+ * The supported image formats can be found at <ulink url="https://www.exiv2.org/manpage.html"></ulink>
+ * and the Exiv2 Tag Reference at <ulink url="https://www.exiv2.org/metadata.html"></ulink>.
+ *
+ * Returns: 0 for success or error code
+ */
+int main(string[] args) {
+
+ var program_name = extract_filename(args[0]);
+ print_single_tag = "";
+
+ // Setup and parse program parameters
+ OptionContext opt_context;
+ try {
+ string summary = "";
+ summary = summary + "Prints out metadata in an image file. If no optional parameters are
specified,\n";
+ summary = summary + "then the default is print all tags (\"-e -i -x\"). The order of parameters
is\n";
+ summary = summary + "not respected.\n";
+
+ string desc = "";
+ desc = desc + "Image metadata is stored in 3 types: Exif, Iptc and Xmp and a file may contain\n";
+ desc = desc + "more than one type. Each tag is in the format 'familyName.groupName.tagName',\n";
+ desc = desc + "e.g. 'Exif.Image.DateTime'. Each unique Xmp groupName has a namespace, e.g.\n";
+ desc = desc + "The standard registration for 'dc' is 'http://purl.org/dc/elements/1.1/'\n";
+ desc = desc + " \n";
+ desc = desc + "Supported image formats can be found at https://www.exiv2.org/manpage.html and\n";
+ desc = desc + "Exiv2 metadata tag references at https://www.exiv2.org/metadata.html\n";
+ desc = desc + " \n";
+ desc = desc + "Examples:\n";
+ desc = desc + " " + program_name + " FILE - Print all the tags in FILE
(\"-e -i -x\")\n";
+ desc = desc + " " + program_name + " -d FILE - Print all the tag details in
FILE (\"-d -e -i -x\")\n";
+ desc = desc + " " + program_name + " -x -n FILE - Print the Xmp namespaces and
Xmp tag values in FILE\n";
+ desc = desc + " " + program_name + " -d -e -i FILE - Print the Exif and Iptc tag
details in FILE\n";
+ desc = desc + " " + program_name + " -t Xmp.dc.subject -d -e FILE - Print only the 'Xmp.dc.subject'
tag details in FILE\n";
+
+ opt_context = new OptionContext("FILE");
+ opt_context.set_description(desc);
+ opt_context.set_summary(summary);
+ opt_context.set_help_enabled(true);
+ opt_context.add_main_entries(options, null);
+ opt_context.parse(ref args);
+
+ // Only 1 required parameter allowed
+ if (args.length < 2) {
+ printerr("%s error: no FILE provided\n", program_name);
+ print(opt_context.get_help(true, null));
+ return 1;
+ }
+
+ if (args.length > 2) {
+ printerr("%s error: Invalid parameters\n", program_name);
+ print(opt_context.get_help(true, null));
+ return 1;
+ }
+
+ // If no user selected tag type options then print them all
+ if (!print_exif_tags && !print_iptc_tags && !print_xmp_tags) {
+ print_exif_tags = true;
+ print_iptc_tags = true;
+ print_xmp_tags = true;
+ }
+
+ // Try to open the user's file
+ GExiv2.Metadata metadata = new GExiv2.Metadata();
+ var file = File.new_for_commandline_arg(args[1]);
+ metadata.from_stream(file.read());
+
+ // Get tag names from file
+ var exif_tags = metadata.get_exif_tags();
+ var iptc_tags = metadata.get_iptc_tags();
+ var xmp_tags = metadata.get_xmp_tags();
+
+ // Print user selected options
+ if (print_single_tag != "") {
+ if (print_single_tag in exif_tags || print_single_tag in iptc_tags || print_single_tag in
xmp_tags) {
+ if (print_xmp_ns) {
+ // Print namespace for the specific tag only
+ string[] tags = {print_single_tag};
+ print_all_xmp_namespaces(tags);
+ }
+ print_tag(metadata, print_single_tag, print_tag_details);
+ } else {
+ string error_message = "Tag `" + print_single_tag + "' not found in metadata";
+ throw new GLib.Error(Quark.from_string(program_name), 1, error_message);
+ }
+ } else {
+ if (print_xmp_ns) {
+ print_all_xmp_namespaces(xmp_tags);
+ }
+ if (print_exif_tags) {
+ foreach (var tag in exif_tags) {
+ print_tag(metadata, tag, print_tag_details);
+ }
+ }
+ if (print_iptc_tags) {
+ foreach (var tag in iptc_tags) {
+ print_tag(metadata, tag, print_tag_details);
+ }
+ }
+ if (print_xmp_tags) {
+ foreach (var tag in xmp_tags) {
+ print_tag(metadata, tag, print_tag_details);
+ }
+ }
+ }
+ } catch (OptionError e) {
+ printerr("%s error: %s\n", program_name, e.message);
+ print(opt_context.get_help(true, null));
+ return 1;
+ } catch (Error err) {
+ printerr("%s error: Processing metadata for '%s': %s (%i)\n",
+ program_name,
+ args[1],
+ err.message,
+ err.code);
+ return 2;
+ }
+
+ return 0;
+}
+
+/**
+ * print_tag:
+ * @metadata: An instance of #GExiv2Metadata
+ * @tag: The tag to print out
+ * @print_details: Whether to print the tag details in addition to the tag value
+ *
+ * Prints out either the tag values or the tag details for the tag
+ *
+ * Returns:
+ */
+void print_tag(GExiv2.Metadata metadata, string tag, bool print_details) throws Error {
+ if (print_details) {
+ print("%-64s%s\n", "Tag", tag);
+ print("%-64s%s\n", " Value", metadata.try_get_tag_string(tag));
+ print("%-64s%s\n", " Interpreted value", metadata.get_tag_interpreted_string(tag));
+ print("%-64s%s\n", " Label", GExiv2.Metadata.get_tag_label(tag));
+ print("%-64s%s\n", " Type", GExiv2.Metadata.get_tag_type(tag));
+ print("%-64s%s\n", " Description", GExiv2.Metadata.get_tag_description(tag));
+ } else {
+ print("%-64s%s\n", tag, metadata.get_tag_interpreted_string(tag));
+ }
+}
+
+/**
+ * print_all_xmp_namespaces:
+ * @xmp_tags: A list of Xmp tags
+ *
+ * Prints list of namespaces from Xmp tags with duplicate groupName tags removed.
+ * e.g. "Xmp.dc.subject" has the namespace "http://purl.org/dc/elements/1.1/"
+ *
+ * Returns:
+ */
+void print_all_xmp_namespaces(string[] xmp_tags) throws Error {
+
+ var last_groupName = ""; // Previous iteration's value
+
+ foreach (var tag in xmp_tags) {
+
+ // Extract groupName from tag (format: "familyName.groupName.tagName")
+ var groupName = tag.split(".", 3)[1];
+
+ // Only output one example of a groupName's namespace
+ if (last_groupName != groupName) {
+ print("Xmp ns: %-56s%s\n", groupName, GExiv2.Metadata.get_xmp_namespace_for_tag(groupName));
+ last_groupName = groupName;
+ }
+ }
+}
+
+/**
+ * extract_filename:
+ * @filename_and_path:
+ *
+ * Extract the filename part from the path+filename
+ * e.g. "/usr/home/username/program" would return "program"
+ * or "C:\temp\program.exe" would return "program.exe"
+ *
+ * Returns: (transfer full) The filename
+ */
+string extract_filename(string filename_and_path) {
+ var pos = 0;
+ for (var i = filename_and_path.length - 1; i >= 0; i--) {
+ if (filename_and_path[i] == '/') {
+ pos = i + 1;
+ break;
+ }
+ if (filename_and_path[i] == '\\') {
+ pos = i + 1;
+ break;
+ }
+ }
+ return filename_and_path.substring(pos, filename_and_path.length - pos);
+}
\ No newline at end of file
diff --git a/tools/meson.build b/tools/meson.build
index 302141d..f6af618 100644
--- a/tools/meson.build
+++ b/tools/meson.build
@@ -1,6 +1,6 @@
if vapi_available
- executable('gexiv2-dump',
- 'gexiv2-dump.vala',
+ executable('gexiv2-tool',
+ 'gexiv2-tool.vala',
include_directories : include_directories('..'),
dependencies : [gobject, vapi, gio],
vala_args: ['--disable-since-check'],
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]