Feature #1137
Enable piping of selective copy of metadata between images
100%
Description
This was discussed on the forum. http://dev.exiv2.org/boards/3/topics/2329
I've added two features:
1 Option mfilename will access -m to mean standard-input
2 Option -PV is identical to -Pv AND adds the word 'set ' at the beginning of every output metadatum.
This enables the user to construct a pipeline such as this to copy the GPS (Latitude and Longitude) from one image to another.
$ exiv2 -PkV --grep GPSL http://dev.exiv2.org/attachments/download/805/DSC_7154.jpg | exiv2 -m- robin.jpgIn the discussion on the forum, I used utility 'sed' to generate the 'set ' word on every line of the output. For the convenience of Windows users (who will not have sed as a preinstalled command), the -PV option is provided.
In the discussion on the forum, I used a temporary file 'foo.cmd' to store the output of sed and read it into exiv2 with the mfoo.cmd option. The new feature that -m represents stdin is more convenient and applies to all platforms. The m option can of course be used by exiv2 and read from a pipe being filled by any application. So this is a useful scripting feature for exiv2.
Breaking this down:
$ exiv2 -PkV --grep GPSL http://dev.exiv2.org/attachments/download/805/DSC_7154.jpg set Exif.GPSInfo.GPSLatitudeRef N set Exif.GPSInfo.GPSLatitude 51/1 106969/10000 0/1 set Exif.GPSInfo.GPSLongitudeRef W set Exif.GPSInfo.GPSLongitude 1/1 495984/10000 0/1And applying it to an empty image:
$ curl -O --silent http://clanmills.com/robin.jpg $ exiv2 -pa robin.jpg $Using the pipe:
$ exiv2 -PkV --grep GPSL http://dev.exiv2.org/attachments/download/805/DSC_7154.jpg | exiv2 -m- robin.jpgAnd examining the metadata:
$ exiv2 -pa robin.jpg Exif.Image.GPSTag Long 1 26 Exif.GPSInfo.GPSLatitudeRef Ascii 2 North Exif.GPSInfo.GPSLatitude Rational 3 51deg 10.69690' Exif.GPSInfo.GPSLongitudeRef Ascii 2 West Exif.GPSInfo.GPSLongitude Rational 3 1deg 49.59840' $
Files
Associated revisions
#1137. Updated manpage to document m and -pV and Added regression detector for both new options to test suite.
History
Updated by Robin Mills almost 6 years ago
- % Done changed from 0 to 80
- Estimated time changed from 2.00 h to 3.00 h
I'm going to mark this as 80% done as something might come up in the next few weeks.
The code to read the command files is in src/exiv2.cpp/parseCmdFiles(). I was a little surprised to see that it doesn't use basicio, so it's not possible to use -mhttp://this/that. The parsing of the command files uses std::getline(). getline is not part of the basicio API. The code could be modified to "suck up" the data using basicio into a temporary file and parsed with std::getline().
It's possible to argue at the -PV option should also imply -Pk as a convenience.
Updated by Phil Harvey almost 6 years ago
Robin Mills wrote:
$ exiv2 -PkV --grep GPSL http://dev.exiv2.org/attachments/download/805/DSC_7154.jpg | exiv2 -m- robin.jpg
The equivalent ExifTool command is:
$ exiftool -tagsfromfile http://dev.exiv2.org/attachments/download/805/DSC_7154.jpg "-gpsl*" robin.jpg
which avoids the need for a pipe. I wonder if a similar Exiv2 feature would be useful. Copying specific tags from one file to another is a very common operation.
Updated by Robin Mills almost 6 years ago
- % Done changed from 80 to 50
- Estimated time changed from 3.00 h to 6.00 h
Ah, that's interesting, Phil. If you've thought of this, I don't have a stupid idea! Mind you, to give credit for the idea, it's Nick who asked if we could do something like this.
I'll say this is 50% done and bump the estimate from 3 to 6 hours. Something to think about on a wet afternoon in England (shouldn't need to wait long for that in November).
The syntax of the exiv2 command is:
$ exiv2 [options] [action] fileWe generally say "do abc ...." to one or more files and our insert/extract/preview/sidecar files are usually paired by name with the file. The pipe idea fits nicely into that model as we are typically reading, or writing. A command-option such as -tagsfromfile is a departure from our usual semantics as we are reading from one source and writing to one or more outputs. Maybe the syntax could be:
$ exiv2 -PkV1 --grep GPSL http://dev.exiv2.org/attachments/download/805/DSC_7154.jpg robin.jpgThe purpose of the '1' is to say read from the first, and apply to the rest. Without the '1', the command:
$ exiv2 -PkV --grep GPSL http://dev.exiv2.org/attachments/download/805/DSC_7154.jpg robin.jpgWould say "Report by reading both DSC_7154.jpg AND robin.jpg". Oh, I'm getting excited. The command:
$ exiv2 -PkV+ --grep GPSL http://dev.exiv2.org/attachments/download/805/DSC_7154.jpg robin.jpg foo.jpg man.jpgWould be to pair the files, so copy from DSC... into robin.jpg, copy from foo.jpg to man.jpg.
Updated by Phil Harvey almost 6 years ago
The pairing idea is interesting. ExifTool has an automated way to do this which allows, for example, someone to copy GPS from sidecar XMP files to the corresponding JPG's:
exiftool -tagsfromfile %d%f.xmp "-gps*" some_directory/*.jpg
Which is also very useful.
ExifTool also allows copying from multiple sources, ie) to copy Make and Model from another JPG, and GPS tags from the XMP sidecar:
exiftool -tagsfromfile other_directory/%f.jpg -make -model -tagsfromfile %d%f.xmp "-gps*" some_directory/*.jpg
but this feature is rarely used. However, if the syntax would allow it and it was easy to implement then it might be nice to have this ability too.
Updated by Robin Mills almost 6 years ago
- File 1173.patch 1173.patch added
- % Done changed from 50 to 90
I have implemented this and attach a patch. I'm not going to submit this to trunk at the time, for a variety of reasons:
- There is an alternative to this using the pipe design.
- Let's wait for feedback concerning the 'set a.b.c value' commands. Life may be more complicated than this!
- The -P1 and -P+ options are new semantics for the exiv2 application. I'd like to pause and think before jumping into a major semantic change.
- We should avoid adding complicated stuff to the exiv2 application as its purpose is to be our test harness and "more complex" sample application.
So Phil: As always, I appreciate your input and encouragement. And I want you to know that I have spent a rainy afternoon implementing this. For the moment, I prefer to leave things as they are.
Demo:
$ curl -O --silent http://clanmills.com/robin.jpg ; exiv2 -pa robin.jpg ; exiv2 -P1V --grep GPSL ~/temp/Stonehenge.jpg robin.jpg ; exiv2 -pa robin.jpg Exif.Image.GPSTag Long 1 26 Exif.GPSInfo.GPSLatitudeRef Ascii 2 North Exif.GPSInfo.GPSLatitude Rational 3 51deg 10.69690' Exif.GPSInfo.GPSLongitudeRef Ascii 2 West Exif.GPSInfo.GPSLongitude Rational 3 1deg 49.59840' 779 rmills@rmillsmbp:~/gnu/exiv2/trunk $Implementing the -P+ option is a mod to the code in exiv2.cpp around line 930.
// #1137 // when -P1 is set (prFirst), pop the first file, print the metadata to stream and parse // set the action to modify to read the generated commands // // implementing the -P+ (prPair) feature is a simple variation of this code // to read (and subsequently remove) every other file in params->files_ to stream // if (rc == 0 && Params::instance().printItems_ & Params::prFirst ) { Params& params = Params::instance(); // Cancel prFirst params.printItems_ |= !Params::prFirst; // Read and pop the first file std::string file = params.files_[0]; Exiv2::Image::AutoPtr image = Exiv2::ImageFactory::open(file); assert(image.get() != 0); image->readMetadata(); params.files_.erase (Params::instance().files_.begin()); // Write the 'set' commands and read them into modifyCmds_ Action::Print* printAction = new Action::Print(); std::ostringstream os ; printAction->printMetadata(image.get(),os); delete printAction; std::istringstream is(os.str()); parseCmdStream(modifyCmds_,is,file); // Change action to modify params.action_ = Action::modify; }
Updated by Robin Mills almost 6 years ago
Nick:
I've made you a watcher of this issue. So you'll get an email when this issue is updated. You'll see that Phil and I have had a little discussion about this.
Updated by Nick Henshaw almost 6 years ago
Robin Mills wrote:
Nick:
I've made you a watcher of this issue. So you'll get an email when this issue is updated. You'll see that Phil and I have had a little discussion about this.
Thanks Robin
I can see that you have a number of solution options, and it's dificult for me, as a newby, to comment on the suitability of piping, copying, pairing.
However from a "user" point of view, the typical scenario is:
I have some pics taken with my phone (with GPS and usually telling the right local time), and some with my camera (elderly DSLR, GPS-ignorant and usually telling the wrong local time). The camera pics are generally in clumps - I am less likely to wander and snap with this one, more likely (on balance) to get it out, take a few snaps in one place, put it away. So on the assumption that I have taken at least one pic with my phone in the same location, my typical requirement is to copy (in particular) GPS data from one phone pic to multiple camera pics.
Having said that, if I am generating exiv2 commands from lists, it is easier for me to generate multiple commands than to put multiple destinations on a single command line.
So:
exiv2 <params> Phonepic.JPG Camerapic1.JPG
exiv2 <params> Phonepic.JPG Camerapic2.JPG
exiv2 <params> Phonepic.JPG Camerapic3.JPG
is easier to generate than:
exiv2 <params> Phonepic.JPG Camerapic1.JPG Camerapic2.JPG Camerapic3.JPG
Don't know if this helps!
Nick
Updated by Robin Mills almost 6 years ago
Well you know how it is, Nick. These things are just features. They are horses for courses. At the moment, I haven't submitted the patch, so you'll have to generate the commands:
exiv2 -PkV --grep GPSL Phonepic.jpg | exiv2 -m- Camerapic1.jpg exiv2 -PkV --grep GPSL Phonepic.jpg | exiv2 -m- Camerapic2.jpgor
exiv2 -PkV --grep GPSL Phonepic.jpg > gps.txt exiv2 -mgps.txt Camerapic1.jpg Camerpic2.jpg Camerapic3.jpgor (and simplest)
exiv2 -PkV --grep GPSL Phonepic.jpg | exiv2 -m- Camerapic1.jpg Camerpic2.jpg Camerapic3.jpgIncidentally, the reason I became interested in Exiv2 back in 2008 was to copy location data from the GPX file in my garmin running watch and update photos. I did that in Python and the script has been working without change for years. Today, I believe there are lots of applications that can read a GPX file and geotag your photos. I gave a 5 minute 'lightning' presentation about this at the Python 2010 Conference in Atlanta, GA. http://clanmills.com/2010/PyCon/RobinPyCon2010.mov
Last year I purchased a Nikon D5300 with a built-in GPS. Very convenient. I see the D5500 has removed the GPS feature. You can get standalone GPS devices which work with a variety of cameras. And it's possible that your phone can record a GPX file.
Updated by Robin Mills almost 6 years ago
I've just had another idea. We could write a script that calls exiv2 to get the time and location data from a directory of phone photos and writes a GPX file. So you do:
phone2gpx.bat c:\Pictures\From\Phone\ > foo.gpxThen you drop foo.gpx into a directory of camera photos, and an use a geotagging application (such as my gps.py script). Snuffing to it.
Updated by Robin Mills almost 6 years ago
- Status changed from Assigned to Closed
- % Done changed from 90 to 100
#1137. Implemented.