[PATCH] New sample "editxmp": edit XMP metadata in an external editor

Andrew Cady d at jerkface.net
Sun Jan 24 22:25:04 PST 2010


This is a new command for the samples directory that is somewhat useful
as an application.  It uses a common unixy technique to allow the user
to edit XMP metadata: it reads the XMP metadata from a file, saves the
metadata as text to a temporary file, and launches a text editor on the
temporary file; if the user saves it, then the metadata is written back
into the original file.  As an example, it shows the whole cycle an
editor must use, and could serve as a starting point for an XMP editor
that was a little less brain-dead about the meaning of XMP data.
---
 .gitignore                 |    1 +
 samples/source/EditXMP.cpp |  100 ++++++++++++++++++++++++++++++++++++++++++++
 samples/source/Makefile.am |    4 ++
 3 files changed, 105 insertions(+), 0 deletions(-)
 create mode 100644 samples/source/EditXMP.cpp

diff --git a/.gitignore b/.gitignore
index 851d0e8..5618caa 100644
--- a/.gitignore
+++ b/.gitignore
@@ -43,3 +43,4 @@ samples/source/customschema
 samples/source/modifyingxmp
 samples/source/readingxmp
 samples/source/xmpcoverageLog.txt
+samples/source/editxmp
diff --git a/samples/source/EditXMP.cpp b/samples/source/EditXMP.cpp
new file mode 100644
index 0000000..52b9dfd
--- /dev/null
+++ b/samples/source/EditXMP.cpp
@@ -0,0 +1,100 @@
+#include <cstdio>
+#include <cstdlib>
+#include <cstring>
+#include <errno.h>
+#include <error.h>
+#include <string>
+
+#define TXMP_STRING_TYPE  std::string
+#define XMP_INCLUDE_XMPFILES 1
+#include "XMP.hpp"
+#include "XMP.incl_cpp"
+
+using namespace std;
+
+int externally_edit_string(string s)
+// returns fd of file containing edited string
+{
+  char *tmpdir = getenv("TMPDIR");
+  if (!tmpdir) tmpdir = P_tmpdir;
+  char *tmp_template = "/tmpedit.XXXXXX";
+
+  char *tmpfile =
+    (char *) malloc(strlen(tmpdir) + strlen(tmp_template) + 1);
+  strcpy(tmpfile, tmpdir);
+  strcat(tmpfile, tmp_template);
+
+  int fd;
+  if ((fd = mkstemp(tmpfile)) < 0)
+    error(-1, errno, "mkstemp() error");
+  if (write(fd, s.c_str(), s.length()) < 0)
+    error(-1, errno, "write() error");
+  if (fsync(fd) < 0)
+    error(-1, errno, "fsync() error");
+
+  char *editor = getenv("VISUAL");
+  if (!editor) editor = getenv("EDITOR");
+  if (!editor) editor = "vi";
+  string cmd = string(editor) + " " + tmpfile;
+
+  int ret = system(cmd.c_str());
+  if (ret)
+    error(-1, ret < 0 ? errno : 0, "system() error");
+
+  if (lseek(fd, 0, SEEK_SET) < 0)
+    error(-1, errno, "lseek() error");
+
+  return fd;
+}
+
+extern "C"
+int main (int argc, const char *argv[])
+{
+  if (argc != 2) {
+    printf("usage: %s <file>\n", program_invocation_name);
+    puts( "Environment variables VISUAL and EDITOR are used "
+          "to determine the text editor; 'vi' is the default." );
+    return 0;
+  }
+  const char *filename = argv[1];
+
+  // initialize XMP
+  if (!SXMPMeta::Initialize())
+    error(-1, 0, "SXMPMeta::Initialize() error");
+  if (!SXMPFiles::Initialize())
+    error(-1, 0, "SXMPFiles::Initialize() error" );
+
+  SXMPMeta  xmpMeta;  
+  SXMPFiles xmpFile;
+  XMP_PacketInfo xmpPacket;
+
+  xmpFile.OpenFile(filename, kXMP_UnknownFile,
+		   kXMPFiles_OpenForUpdate|kXMPFiles_OpenOnlyXMP);
+  if (!xmpFile.GetXMP (&xmpMeta, 0, &xmpPacket))
+    error(-1, 0, "xmpFile.GetXMP() error.  "
+    		 "There may be no XMP metadata in this file.");
+
+  // read the meta-data
+  string s;
+  xmpMeta.SerializeToBuffer(&s,
+    kXMP_OmitPacketWrapper|kXMP_UseCompactFormat);
+
+  // edit and write the meta-data
+  int fd;
+  if (fd = externally_edit_string(s)) {
+    char buf[1024*8];
+    ssize_t n;
+    while (n = read(fd, buf, sizeof(buf))) {
+      if (n < 0) error(-1, errno, "read() error");
+      xmpMeta.ParseFromBuffer(buf, n, kXMP_ParseMoreBuffers);
+    }
+    xmpMeta.ParseFromBuffer(buf, 0, 0);
+    xmpFile.PutXMP(xmpMeta);
+  }
+
+  // cleanup XMP
+  xmpFile.CloseFile();
+  SXMPFiles::Terminate();
+  SXMPMeta::Terminate();
+  return 0;
+}
diff --git a/samples/source/Makefile.am b/samples/source/Makefile.am
index 1715096..443b2dd 100644
--- a/samples/source/Makefile.am
+++ b/samples/source/Makefile.am
@@ -39,6 +39,7 @@ noinst_PROGRAMS = xmpcoverage xmpfilescoverage dumpxmp dumpmainxmp\
 	customschema \
 	modifyingxmp \
 	readingxmp \
+	editxmp \
 	$(NULL)
 
 AM_CXXFLAGS = -fexceptions -funsigned-char -fPIC \
@@ -74,3 +75,6 @@ dumpxmp_LDADD = $(XMPLIBS)
 
 dumpmainxmp_SOURCES = DumpMainXMP.cpp
 dumpmainxmp_LDADD = $(XMPLIBS)
+
+editxmp_SOURCES = EditXMP.cpp
+editxmp_LDADD = $(XMPLIBS)
-- 
1.5.6.5



More information about the Exempi-devel mailing list