From a8608d8c130bffd15873bd062fc8b54591b92b95 Mon Sep 17 00:00:00 2001 From: Fabien VAUCHELLES Date: Fri, 5 Apr 2013 00:01:48 +0200 Subject: [PATCH 001/148] Added Tag writing --- .../com/thebuzzmedia/exiftool/ExifTool.java | 151 ++++++++++++++++++ 1 file changed, 151 insertions(+) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 4950663a..cde25ee7 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -25,6 +25,7 @@ import java.util.HashSet; import java.util.List; import java.util.Map; +import java.util.Map.Entry; import java.util.Set; import java.util.StringTokenizer; import java.util.Timer; @@ -1215,6 +1216,156 @@ public Map getImageMeta(File image, Format format, Tag... tags) return resultMap; } + + public void setImageMeta(File image, Map tags) + throws IllegalArgumentException, SecurityException, IOException { + setImageMeta(image, Format.NUMERIC, tags); + } + + public void setImageMeta(File image, Format format, Map tags ) + throws IllegalArgumentException, SecurityException, IOException { + if (image == null) + throw new IllegalArgumentException( + "image cannot be null and must be a valid stream of image data."); + if (format == null) + throw new IllegalArgumentException("format cannot be null"); + if (tags == null || tags.size() == 0) + throw new IllegalArgumentException( + "tags cannot be null and must contain 1 or more Tag to query the image for."); + if (!image.canWrite()) + throw new SecurityException( + "Unable to read the given image [" + + image.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + + long startTime = System.currentTimeMillis(); + + if (DEBUG) + log("Writing %d tags to image: %s", tags.size(), + image.getAbsolutePath()); + + long exifToolCallElapsedTime = 0; + + /* + * Using ExifTool in daemon mode (-stay_open True) executes different + * code paths below. So establish the flag for this once and it is + * reused a multitude of times later in this method to figure out where + * to branch to. + */ + boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + + // Clear process args + args.clear(); + + if (stayOpen) { + log("\tUsing ExifTool in daemon mode (-stay_open True)..."); + + // Always reset the cleanup task. + resetCleanupTask(); + + /* + * If this is our first time calling getImageMeta with a stayOpen + * connection, set up the persistent process and run it so it is + * ready to receive commands from us. + */ + if (streams == null) { + log("\tStarting daemon ExifTool process and creating read/write streams (this only happens once)..."); + + args.add(EXIF_TOOL_PATH); + args.add("-stay_open"); + args.add("True"); + args.add("-@"); + args.add("-"); + + // Begin the persistent ExifTool process. + streams = startExifToolProcess(args); + } + + log("\tStreaming arguments to ExifTool process..."); + + if (format == Format.NUMERIC) + streams.writer.write("-n\n"); // numeric output + + streams.writer.write("-S\n"); // compact output + + for ( Entry entry :tags.entrySet() ) { + streams.writer.write('-'); + streams.writer.write(entry.getKey().name); + streams.writer.write("='"); + streams.writer.write(entry.getValue()); + streams.writer.write("'\n"); + } + + streams.writer.write(image.getAbsolutePath()); + streams.writer.write("\n"); + + log("\tExecuting ExifTool..."); + + // Begin tracking the duration ExifTool takes to respond. + exifToolCallElapsedTime = System.currentTimeMillis(); + + // Run ExifTool on our file with all the given arguments. + streams.writer.write("-execute\n"); + streams.writer.flush(); + } else { + log("\tUsing ExifTool in non-daemon mode (-stay_open False)..."); + + /* + * Since we are not using a stayOpen process, we need to setup the + * execution arguments completely each time. + */ + args.add(EXIF_TOOL_PATH); + + if (format == Format.NUMERIC) + args.add("-n"); // numeric output + + args.add("-S"); // compact output + + for ( Entry entry :tags.entrySet() ) + args.add("-" + entry.getKey().name + "='" + entry.getValue() + "'" ); + + args.add(image.getAbsolutePath()); + + // Run the ExifTool with our args. + streams = startExifToolProcess(args); + + // Begin tracking the duration ExifTool takes to respond. + exifToolCallElapsedTime = System.currentTimeMillis(); + } + + log("\tReading response back from ExifTool..."); + + String line = null; + + while ((line = streams.reader.readLine()) != null) { + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need to + * look for it and break from this loop when we see it otherwise + * this process will hang indefinitely blocking on the input stream + * with no data to read. + */ + if (stayOpen && line.equals("{ready}")) + break; + } + + // Print out how long the call to external ExifTool process took. + log("\tFinished reading ExifTool response in %d ms.", + (System.currentTimeMillis() - exifToolCallElapsedTime)); + + /* + * If we are not using a persistent ExifTool process, then after running + * the command above, the process exited in which case we need to clean + * our streams up since it no longer exists. If we were using a + * persistent ExifTool process, leave the streams open for future calls. + */ + if (!stayOpen) + streams.close(); + + if (DEBUG) + log("\tImage Meta Processed in %d ms [write %d tags]", + (System.currentTimeMillis() - startTime), tags.size()); + } /** * Helper method used to make canceling the current task and scheduling a From e447e4674408b0d1f1f95265b309959e4a05c46e Mon Sep 17 00:00:00 2001 From: Riyad Kalla Date: Thu, 4 Apr 2013 16:12:48 -0700 Subject: [PATCH 002/148] Update README Updated status of 1.2 --- README | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/README b/README index fb1cf048..0868be33 100644 --- a/README +++ b/README @@ -11,6 +11,7 @@ Changelog --------- 1.2 (In progress...) * Added support for the "CreationDate" QuickTime tag to the Tag enum. + * Merged support for WRITING meta tags from Fabien Vauchelles 1.1 * Initial public release. @@ -209,4 +210,4 @@ imgscalr - http://www.thebuzzmedia.com/software/imgscalr-java-image-scaling-libr Contact ------- If you have questions, comments or bug reports for this software please contact -us at: software@thebuzzmedia.com \ No newline at end of file +us at: software@thebuzzmedia.com From 6d757b3e8cd282c11009e56c8e9abd6058fe2381 Mon Sep 17 00:00:00 2001 From: Fabien VAUCHELLES Date: Fri, 5 Apr 2013 19:37:55 +0200 Subject: [PATCH 003/148] add reading and writing for all every tags --- .../com/thebuzzmedia/exiftool/ExifTool.java | 307 +++++++++++++++++- 1 file changed, 304 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index cde25ee7..30ea9386 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -1217,6 +1217,157 @@ public Map getImageMeta(File image, Format format, Tag... tags) return resultMap; } + public Map getAllImageMetas(File image) + throws IllegalArgumentException, SecurityException, IOException { + return getAllImageMetas(image, Format.NUMERIC); + } + + public Map getAllImageMetas(File image, Format format) + throws IllegalArgumentException, SecurityException, IOException { + if (image == null) + throw new IllegalArgumentException( + "image cannot be null and must be a valid stream of image data."); + if (format == null) + throw new IllegalArgumentException("format cannot be null"); + if (!image.canRead()) + throw new SecurityException( + "Unable to read the given image [" + + image.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + + long startTime = System.currentTimeMillis(); + + /* + * Create a result map big enough to hold results for each of the tags + * and avoid collisions while inserting. + */ + Map resultMap = new HashMap(); + + if (DEBUG) + log("Querying all tags from image: %s", image.getAbsolutePath()); + + long exifToolCallElapsedTime = 0; + + /* + * Using ExifTool in daemon mode (-stay_open True) executes different + * code paths below. So establish the flag for this once and it is + * reused a multitude of times later in this method to figure out where + * to branch to. + */ + boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + + // Clear process args + args.clear(); + + if (stayOpen) { + log("\tUsing ExifTool in daemon mode (-stay_open True)..."); + + // Always reset the cleanup task. + resetCleanupTask(); + + /* + * If this is our first time calling getImageMeta with a stayOpen + * connection, set up the persistent process and run it so it is + * ready to receive commands from us. + */ + if (streams == null) { + log("\tStarting daemon ExifTool process and creating read/write streams (this only happens once)..."); + + args.add(EXIF_TOOL_PATH); + args.add("-stay_open"); + args.add("True"); + args.add("-@"); + args.add("-"); + + // Begin the persistent ExifTool process. + streams = startExifToolProcess(args); + } + + log("\tStreaming arguments to ExifTool process..."); + + if (format == Format.NUMERIC) + streams.writer.write("-n\n"); // numeric output + + streams.writer.write("-S\n"); // compact output + + streams.writer.write(image.getAbsolutePath()); + streams.writer.write("\n"); + + log("\tExecuting ExifTool..."); + + // Begin tracking the duration ExifTool takes to respond. + exifToolCallElapsedTime = System.currentTimeMillis(); + + // Run ExifTool on our file with all the given arguments. + streams.writer.write("-execute\n"); + streams.writer.flush(); + } else { + log("\tUsing ExifTool in non-daemon mode (-stay_open False)..."); + + /* + * Since we are not using a stayOpen process, we need to setup the + * execution arguments completely each time. + */ + args.add(EXIF_TOOL_PATH); + + if (format == Format.NUMERIC) + args.add("-n"); // numeric output + + args.add("-S"); // compact output + + args.add(image.getAbsolutePath()); + + // Run the ExifTool with our args. + streams = startExifToolProcess(args); + + // Begin tracking the duration ExifTool takes to respond. + exifToolCallElapsedTime = System.currentTimeMillis(); + } + + log("\tReading response back from ExifTool..."); + + String line = null; + + while ((line = streams.reader.readLine()) != null) { + String[] pair = TAG_VALUE_PATTERN.split(line); + + if (pair != null && pair.length == 2) { + resultMap.put(pair[0], pair[1]); + log("\t\tRead Tag [name=%s, value=%s]", pair[0], pair[1]); + } + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need to + * look for it and break from this loop when we see it otherwise + * this process will hang indefinitely blocking on the input stream + * with no data to read. + */ + if (stayOpen && line.equals("{ready}")) + break; + } + + // Print out how long the call to external ExifTool process took. + log("\tFinished reading ExifTool response in %d ms.", + (System.currentTimeMillis() - exifToolCallElapsedTime)); + + /* + * If we are not using a persistent ExifTool process, then after running + * the command above, the process exited in which case we need to clean + * our streams up since it no longer exists. If we were using a + * persistent ExifTool process, leave the streams open for future calls. + */ + if (!stayOpen) + streams.close(); + + if (DEBUG) + log("\tImage Meta Processed in %d ms [found %d values]", + (System.currentTimeMillis() - startTime), + resultMap.size()); + + return resultMap; + } + public void setImageMeta(File image, Map tags) throws IllegalArgumentException, SecurityException, IOException { setImageMeta(image, Format.NUMERIC, tags); @@ -1291,9 +1442,9 @@ public void setImageMeta(File image, Format format, Map tags ) for ( Entry entry :tags.entrySet() ) { streams.writer.write('-'); streams.writer.write(entry.getKey().name); - streams.writer.write("='"); + streams.writer.write("="); streams.writer.write(entry.getValue()); - streams.writer.write("'\n"); + streams.writer.write("\n"); } streams.writer.write(image.getAbsolutePath()); @@ -1322,7 +1473,157 @@ public void setImageMeta(File image, Format format, Map tags ) args.add("-S"); // compact output for ( Entry entry :tags.entrySet() ) - args.add("-" + entry.getKey().name + "='" + entry.getValue() + "'" ); + args.add("-" + entry.getKey().name + "=" + entry.getValue() ); + + args.add(image.getAbsolutePath()); + + // Run the ExifTool with our args. + streams = startExifToolProcess(args); + + // Begin tracking the duration ExifTool takes to respond. + exifToolCallElapsedTime = System.currentTimeMillis(); + } + + log("\tReading response back from ExifTool..."); + + String line = null; + + while ((line = streams.reader.readLine()) != null) { + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need to + * look for it and break from this loop when we see it otherwise + * this process will hang indefinitely blocking on the input stream + * with no data to read. + */ + if (stayOpen && line.equals("{ready}")) + break; + } + + // Print out how long the call to external ExifTool process took. + log("\tFinished reading ExifTool response in %d ms.", + (System.currentTimeMillis() - exifToolCallElapsedTime)); + + /* + * If we are not using a persistent ExifTool process, then after running + * the command above, the process exited in which case we need to clean + * our streams up since it no longer exists. If we were using a + * persistent ExifTool process, leave the streams open for future calls. + */ + if (!stayOpen) + streams.close(); + + if (DEBUG) + log("\tImage Meta Processed in %d ms [write %d tags]", + (System.currentTimeMillis() - startTime), tags.size()); + } + + public void setAllImageMetas(File image, Map tags) + throws IllegalArgumentException, SecurityException, IOException { + setAllImageMetas(image, Format.NUMERIC, tags); + } + + public void setAllImageMetas(File image, Format format, Map tags ) + throws IllegalArgumentException, SecurityException, IOException { + if (image == null) + throw new IllegalArgumentException( + "image cannot be null and must be a valid stream of image data."); + if (format == null) + throw new IllegalArgumentException("format cannot be null"); + if (tags == null || tags.size() == 0) + throw new IllegalArgumentException( + "tags cannot be null and must contain 1 or more Tag to query the image for."); + if (!image.canWrite()) + throw new SecurityException( + "Unable to read the given image [" + + image.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + + long startTime = System.currentTimeMillis(); + + if (DEBUG) + log("Writing %d tags to image: %s", tags.size(), + image.getAbsolutePath()); + + long exifToolCallElapsedTime = 0; + + /* + * Using ExifTool in daemon mode (-stay_open True) executes different + * code paths below. So establish the flag for this once and it is + * reused a multitude of times later in this method to figure out where + * to branch to. + */ + boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + + // Clear process args + args.clear(); + + if (stayOpen) { + log("\tUsing ExifTool in daemon mode (-stay_open True)..."); + + // Always reset the cleanup task. + resetCleanupTask(); + + /* + * If this is our first time calling getImageMeta with a stayOpen + * connection, set up the persistent process and run it so it is + * ready to receive commands from us. + */ + if (streams == null) { + log("\tStarting daemon ExifTool process and creating read/write streams (this only happens once)..."); + + args.add(EXIF_TOOL_PATH); + args.add("-stay_open"); + args.add("True"); + args.add("-@"); + args.add("-"); + + // Begin the persistent ExifTool process. + streams = startExifToolProcess(args); + } + + log("\tStreaming arguments to ExifTool process..."); + + if (format == Format.NUMERIC) + streams.writer.write("-n\n"); // numeric output + + streams.writer.write("-S\n"); // compact output + + for ( Entry entry :tags.entrySet() ) { + streams.writer.write('-'); + streams.writer.write(entry.getKey()); + streams.writer.write("="); + streams.writer.write(entry.getValue()); + streams.writer.write("\n"); + } + + streams.writer.write(image.getAbsolutePath()); + streams.writer.write("\n"); + + log("\tExecuting ExifTool..."); + + // Begin tracking the duration ExifTool takes to respond. + exifToolCallElapsedTime = System.currentTimeMillis(); + + // Run ExifTool on our file with all the given arguments. + streams.writer.write("-execute\n"); + streams.writer.flush(); + } else { + log("\tUsing ExifTool in non-daemon mode (-stay_open False)..."); + + /* + * Since we are not using a stayOpen process, we need to setup the + * execution arguments completely each time. + */ + args.add(EXIF_TOOL_PATH); + + if (format == Format.NUMERIC) + args.add("-n"); // numeric output + + args.add("-S"); // compact output + + for ( Entry entry :tags.entrySet() ) + args.add("-" + entry.getKey() + "=" + entry.getValue() ); args.add(image.getAbsolutePath()); From 756e9b5e74be3837596458b9c721ba3e946a216b Mon Sep 17 00:00:00 2001 From: Mickael Jeanroy Date: Mon, 13 May 2013 21:04:11 +0200 Subject: [PATCH 004/148] Add LensID in possible tag values LensID is a tag that provide information to identify lens type. For example, "241" means "Canon EF 50mm F1.2L USM". It's not always a numerical identifier, it can be a string that give informations about the lens type. Be careful, lens id is not always specified in exif metadata. --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index cde25ee7..914be9ee 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -746,7 +746,7 @@ public enum Tag { "GPSDestBearing", Double.class), GPS_BEARING_REF( "GPSDestBearingRef", String.class), GPS_TIMESTAMP( "GPSTimeStamp", String.class), ROTATION("Rotation",Integer.class), - EXIF_VERSION("ExifVersion",String.class); + EXIF_VERSION("ExifVersion",String.class), LENS_ID("LensID",String.class); private static final Map TAG_LOOKUP_MAP; @@ -1445,4 +1445,4 @@ public Feature getFeature() { return feature; } } -} \ No newline at end of file +} From a4726d5e96371457ff3c4f92d6df8ff95baf3052 Mon Sep 17 00:00:00 2001 From: unknown Date: Fri, 11 Oct 2013 14:44:56 -0400 Subject: [PATCH 005/148] Added FILE_TYPE Tag. Added Sidecar class for merging sidecar xmp files. --- .../com/thebuzzmedia/exiftool/ExifTool.java | 205 +++++++++++++++++- 1 file changed, 204 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index cde25ee7..e79a2320 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -746,7 +746,7 @@ public enum Tag { "GPSDestBearing", Double.class), GPS_BEARING_REF( "GPSDestBearingRef", String.class), GPS_TIMESTAMP( "GPSTimeStamp", String.class), ROTATION("Rotation",Integer.class), - EXIF_VERSION("ExifVersion",String.class); + EXIF_VERSION("ExifVersion",String.class), FILE_TYPE("FileType",String.class); private static final Map TAG_LOOKUP_MAP; @@ -1445,4 +1445,207 @@ public Feature getFeature() { return feature; } } + + /** + * Class used to handle XMP Sidecar files using exiftool. + * + * @author Clinton LaForest (clafore@bgsu.edu) + * @since 1.2_thespiritx + */ + public class Sidecar { + public Sidecar(Feature feature) { + + } + + /** + * Used to merge a XMP Sidecar file with an image. + * + * @param xmp + * The xmp sidecar file. + * + * @param file + * The image file. + * + * @param preserve + * true - preserves name mappings + * false - uses preferred name mappings + * + * @return void + * + */ + public void merge(File xmp, File file, Boolean preserve) { + if (xmp == null) + throw new IllegalArgumentException( + "xmp cannot be null and must be a valid xmp sidecar stream."); + if (file == null) + throw new IllegalArgumentException("file cannot be null"); + if (preserve == null) + preserve = false; + if (!file.canWrite()) + throw new SecurityException( + "Unable to read the given image [" + + file.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + + long startTime = System.currentTimeMillis(); + + if (DEBUG) + log("Writing %s tags to image: %s", xmp.getAbsolutePath(), file.getAbsolutePath()); + + long exifToolCallElapsedTime = 0; + + /* + * Using ExifTool in daemon mode (-stay_open True) executes different + * code paths below. So establish the flag for this once and it is + * reused a multitude of times later in this method to figure out where + * to branch to. + */ + boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + + args.clear(); + + if (stayOpen) { + log("\tUsing ExifTool in daemon mode (-stay_open True)..."); + + // Always reset the cleanup task. + resetCleanupTask(); + + /* + * If this is our first time calling getImageMeta with a stayOpen + * connection, set up the persistent process and run it so it is + * ready to receive commands from us. + */ + if (streams == null) { + log("\tStarting daemon ExifTool process and creating read/write streams (this only happens once)..."); + + args.add(EXIF_TOOL_PATH); + args.add("-stay_open"); + args.add("True"); + args.add("-@"); + args.add("-"); + + // Begin the persistent ExifTool process. + streams = startExifToolProcess(args); + } + + log("\tStreaming arguments to ExifTool process..."); + + try { + streams.writer.write("-tagsfromfile\n"); + + streams.writer.write(file.getAbsolutePath()); + streams.writer.write("\n"); + + if(preserve){ + streams.writer.write("-all:all"); + streams.writer.write("\n"); + } else { + streams.writer.write("-xmp"); + streams.writer.write("\n"); + } + + streams.writer.write(xmp.getAbsolutePath()); + streams.writer.write("\n"); + + log("\tExecuting ExifTool..."); + + // Begin tracking the duration ExifTool takes to respond. + exifToolCallElapsedTime = System.currentTimeMillis(); + + // Run ExifTool on our file with all the given arguments. + streams.writer.write("-execute\n"); + streams.writer.flush(); + + } catch (IOException e) { + log("\tError received in stayopen stream: %s", + e.getMessage()); + } // compact output + } else { + log("\tUsing ExifTool in non-daemon mode (-stay_open False)..."); + + /* + * Since we are not using a stayOpen process, we need to setup the + * execution arguments completely each time. + */ + args.add(EXIF_TOOL_PATH); + + args.add("-tagsfromfile"); // compact output + + args.add(file.getAbsolutePath()); + + if(preserve) { + args.add("-all:all"); + } else { + args.add("-xmp"); + } + + args.add(xmp.getAbsolutePath()); + + // Run the ExifTool with our args. + streams = startExifToolProcess(args); + + // Begin tracking the duration ExifTool takes to respond. + exifToolCallElapsedTime = System.currentTimeMillis(); + } + + log("\tReading response back from ExifTool..."); + + String line = null; + + try { + while ((line = streams.reader.readLine()) != null) { + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need to + * look for it and break from this loop when we see it otherwise + * this process will hang indefinitely blocking on the input stream + * with no data to read. + */ + if (stayOpen && line.equals("{ready}")) + break; + } + } catch (IOException e) { + log("\tError received in response: %d", + e.getMessage()); + } + + // Print out how long the call to external ExifTool process took. + log("\tFinished reading ExifTool response in %d ms.", + (System.currentTimeMillis() - exifToolCallElapsedTime)); + + /* + * If we are not using a persistent ExifTool process, then after running + * the command above, the process exited in which case we need to clean + * our streams up since it no longer exists. If we were using a + * persistent ExifTool process, leave the streams open for future calls. + */ + if (!stayOpen) + streams.close(); + + if (DEBUG) + log("\tImage Meta Processed in %d ms [write %s tags]", + (System.currentTimeMillis() - startTime), xmp.getAbsolutePath()); + + } + + /** + * Used to export a XMP Sidecar file from an image. + * + * @param xmp + * The xmp sidecar file. + * + * @param file + * The image file. + * + * @param preserve + * true - preserves name mappings + * false - uses preferred name mappings + * + * @return void + * + */ + public void export(File xmp, File file, boolean preserve) { + + } + } } \ No newline at end of file From 8280c5e97884774a3db1297949cb321a4b3746d8 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 12 Oct 2013 09:27:00 -1000 Subject: [PATCH 006/148] Add subsec time to tags --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 914be9ee..04d6fec5 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -202,7 +202,7 @@ * written the 2nd most robust image metadata library I have come across: Metadata Extractor * that you might want to look at. - * + * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ @@ -359,15 +359,15 @@ public class ExifTool { * The external call to ExifTool to confirm feature support is only ever * done once per JVM session and stored in a static final * {@link Map} that all instances of this class share. - * + * * @param feature * The feature to check support for in the underlying ExifTool * install. - * + * * @return true if support for the given {@link Feature} was * confirmed to work with the currently installed ExifTool or * false if it is not supported. - * + * * @throws IllegalArgumentException * if feature is null. * @throws RuntimeException @@ -746,7 +746,8 @@ public enum Tag { "GPSDestBearing", Double.class), GPS_BEARING_REF( "GPSDestBearingRef", String.class), GPS_TIMESTAMP( "GPSTimeStamp", String.class), ROTATION("Rotation",Integer.class), - EXIF_VERSION("ExifVersion",String.class), LENS_ID("LensID",String.class); + EXIF_VERSION("ExifVersion",String.class), LENS_ID("LensID",String.class), + SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class); private static final Map TAG_LOOKUP_MAP; From 1d13dcd9dc55f332b54d001dc07d4b2b674b2da4 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 12 Oct 2013 09:44:51 -1000 Subject: [PATCH 007/148] Reformatted list of tags to be alphabetical. --- .../com/thebuzzmedia/exiftool/ExifTool.java | 94 +++++++++++-------- 1 file changed, 55 insertions(+), 39 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 04d6fec5..ca8eb913 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -711,45 +711,61 @@ public enum Format { * @since 1.1 */ public enum Tag { - ISO("ISO", Integer.class), APERTURE("ApertureValue", Double.class), WHITE_BALANCE( - "WhiteBalance", Integer.class), CONTRAST("Contrast", - Integer.class), SATURATION("Saturation", Integer.class), SHARPNESS( - "Sharpness", Integer.class), SHUTTER_SPEED("ShutterSpeedValue", - Double.class), DIGITAL_ZOOM_RATIO("DigitalZoomRatio", - Double.class), IMAGE_WIDTH("ImageWidth", Integer.class), IMAGE_HEIGHT( - "ImageHeight", Integer.class), X_RESOLUTION("XResolution", - Double.class), Y_RESOLUTION("YResolution", Double.class), FLASH( - "Flash", Integer.class), METERING_MODE("MeteringMode", - Integer.class), FOCAL_LENGTH("FocalLength", Double.class), FOCAL_LENGTH_35MM( - "FocalLengthIn35mmFormat", Integer.class), EXPOSURE_TIME( - "ExposureTime", Double.class), EXPOSURE_COMPENSATION( - "ExposureCompensation", Double.class), EXPOSURE_PROGRAM( - "ExposureProgram", Integer.class), ORIENTATION("Orientation", - Integer.class), COLOR_SPACE("ColorSpace", Integer.class), SENSING_METHOD( - "SensingMethod", Integer.class), SOFTWARE("Software", - String.class), MAKE("Make", String.class), MODEL("Model", - String.class), LENS_MAKE("LensMake", String.class), LENS_MODEL( - "LensModel", String.class), OWNER_NAME("OwnerName", - String.class), TITLE("XPTitle", String.class), AUTHOR( - "XPAuthor", String.class), SUBJECT("XPSubject", String.class), KEYWORDS( - "XPKeywords", String.class), COMMENT("XPComment", String.class), RATING( - "Rating", Integer.class), RATING_PERCENT("RatingPercent", - Integer.class), DATE_TIME_ORIGINAL("DateTimeOriginal", - String.class), CREATION_DATE("CreationDate", String.class), GPS_LATITUDE( - "GPSLatitude", Double.class), GPS_LATITUDE_REF( - "GPSLatitudeRef", String.class), GPS_LONGITUDE("GPSLongitude", - Double.class), GPS_LONGITUDE_REF("GPSLongitudeRef", - String.class), GPS_ALTITUDE("GPSAltitude", Double.class), GPS_ALTITUDE_REF( - "GPSAltitudeRef", Integer.class), GPS_SPEED("GPSSpeed", - Double.class), GPS_SPEED_REF("GPSSpeedRef", String.class), GPS_PROCESS_METHOD( - "GPSProcessingMethod", String.class), GPS_BEARING( - "GPSDestBearing", Double.class), GPS_BEARING_REF( - "GPSDestBearingRef", String.class), GPS_TIMESTAMP( - "GPSTimeStamp", String.class), ROTATION("Rotation",Integer.class), - EXIF_VERSION("ExifVersion",String.class), LENS_ID("LensID",String.class), - SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class); - - private static final Map TAG_LOOKUP_MAP; + APERTURE("ApertureValue", Double.class), + AUTHOR("XPAuthor", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATION_DATE("CreationDate", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + FLASH("Flash", Integer.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS_ID("LensID", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SENSING_METHOD("SensingMethod", Integer.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SUBJECT("XPSubject", String.class), + SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class); + + private static final Map TAG_LOOKUP_MAP; /** * Initializer used to init the static final tag/name From e24206ff24eef56449f63d469b672be5cbcb58e3 Mon Sep 17 00:00:00 2001 From: Giles Winstanley Date: Mon, 4 Nov 2013 17:53:31 +0000 Subject: [PATCH 008/148] Added EXIF tags: Artist/Copyright. --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 914be9ee..4ef5f51a 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -746,7 +746,8 @@ public enum Tag { "GPSDestBearing", Double.class), GPS_BEARING_REF( "GPSDestBearingRef", String.class), GPS_TIMESTAMP( "GPSTimeStamp", String.class), ROTATION("Rotation",Integer.class), - EXIF_VERSION("ExifVersion",String.class), LENS_ID("LensID",String.class); + EXIF_VERSION("ExifVersion",String.class), LENS_ID("LensID",String.class), + COPYRIGHT("Copyright", String.class), ARTIST("Artist", String.class); private static final Map TAG_LOOKUP_MAP; From af50985c1a13778b8825d0b236e093f6cd85ce69 Mon Sep 17 00:00:00 2001 From: Justin Gordon Date: Sat, 12 Oct 2013 09:27:00 -1000 Subject: [PATCH 009/148] Add subsec time to tags --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 11 ++++++----- 1 file changed, 6 insertions(+), 5 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 4ef5f51a..e43d47a6 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -202,7 +202,7 @@ * written the 2nd most robust image metadata library I have come across: Metadata Extractor * that you might want to look at. - * + * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ @@ -359,15 +359,15 @@ public class ExifTool { * The external call to ExifTool to confirm feature support is only ever * done once per JVM session and stored in a static final * {@link Map} that all instances of this class share. - * + * * @param feature * The feature to check support for in the underlying ExifTool * install. - * + * * @return true if support for the given {@link Feature} was * confirmed to work with the currently installed ExifTool or * false if it is not supported. - * + * * @throws IllegalArgumentException * if feature is null. * @throws RuntimeException @@ -747,7 +747,8 @@ public enum Tag { "GPSDestBearingRef", String.class), GPS_TIMESTAMP( "GPSTimeStamp", String.class), ROTATION("Rotation",Integer.class), EXIF_VERSION("ExifVersion",String.class), LENS_ID("LensID",String.class), - COPYRIGHT("Copyright", String.class), ARTIST("Artist", String.class); + COPYRIGHT("Copyright", String.class), ARTIST("Artist", String.class), + SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class); private static final Map TAG_LOOKUP_MAP; From cac645c2f0739345f420040c8513e49613f13196 Mon Sep 17 00:00:00 2001 From: Chris Turchin Date: Thu, 23 Jan 2014 02:29:57 +0100 Subject: [PATCH 010/148] added new tags, tag groups and functions - ICC, Thumbnail, File information - methods to saveToXml, extract ICC profile and extract thumbnail. --- .../com/thebuzzmedia/exiftool/ExifTool.java | 1874 +++++++++-------- 1 file changed, 1015 insertions(+), 859 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 829a2100..25737508 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -13,16 +13,32 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.thebuzzmedia.exiftool; -import org.apache.log4j.Logger; +package com.thebuzzmedia.exiftool; -import java.io.*; -import java.util.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.FileWriter; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; +import org.apache.commons.io.FilenameUtils; +import org.apache.log4j.Logger; + /** * Class used to provide a Java-like interface to Phil Harvey's excellent, * Perl-based - * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} - * convenience method for parsing given String values according to - * the Tag hint automatically for you if that is what you plan on doing, - * otherwise feel free to handle the return values anyway you want. + * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} convenience + * method for parsing given String values according to the Tag hint + * automatically for you if that is what you plan on doing, otherwise feel free + * to handle the return values anyway you want. *

ExifTool -stay_open Support

* ExifTool
* Because this feature requires ExifTool 8.36 or later, this class will * actually verify support for the feature in the version of ExifTool pointed at - * by {@link #exifCmd} before successfully instantiating the class and - * will notify you via an {@link UnsupportedFeatureException} if the native - * ExifTool doesn't support the requested feature. + * by {@link #exifCmd} before successfully instantiating the class and will + * notify you via an {@link UnsupportedFeatureException} if the native ExifTool + * doesn't support the requested feature. *

* In the event of an {@link UnsupportedFeatureException}, the caller can either * upgrade the native ExifTool upgrade to the version required or simply avoid @@ -199,813 +215,946 @@ */ public class ExifTool { - public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; - public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; - - /** - * Name used to identify the (optional) cleanup {@link Thread}. - *

- * This is only provided to make debugging and profiling easier for - * implementers making use of this class such that the resources this class - * creates and uses (i.e. Threads) are readily identifiable in a running VM. - *

- * Default value is "ExifTool Cleanup Thread". - */ - private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; - - /** - * Compiled {@link Pattern} of ": " used to split compact output from - * ExifTool evenly into name/value pairs. - */ + public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + + /** + * Name used to identify the (optional) cleanup {@link Thread}. + *

+ * This is only provided to make debugging and profiling easier for + * implementers making use of this class such that the resources this class + * creates and uses (i.e. Threads) are readily identifiable in a running VM. + *

+ * Default value is "ExifTool Cleanup Thread". + */ + private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; + + /** + * Compiled {@link Pattern} of ": " used to split compact output from + * ExifTool evenly into name/value pairs. + */ private static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); - private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - - private static Logger log = Logger.getLogger(ExifTool.class); - - /** - * The absolute path to the ExifTool executable on the host system running - * this class as defined by the "exiftool.path" system - * property. - *

- * If ExifTool is on your system path and running the command "exiftool" - * successfully executes it, leaving this value unchanged will work fine on - * any platform. If the ExifTool executable is named something else or not - * in the system path, then this property will need to be set to point at it - * before using this class. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.path=/path/to/exiftool - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * On Windows be sure to double-escape the path to the tool, for example: - * - * -Dexiftool.path=C:\\Tools\\exiftool.exe - * - *

- * Default value is "exiftool". - *

Relative Paths

- * Relative path values (e.g. "bin/tools/exiftool") are executed with - * relation to the base directory the VM process was started in. Essentially - * the directory that new File(".").getAbsolutePath() points at - * during runtime. - */ - private final String exifCmd; - - /** - * Interval (in milliseconds) of inactivity before the cleanup thread wakes - * up and cleans up the daemon ExifTool process and the read/write streams - * used to communicate with it when the {@link Feature#STAY_OPEN} feature is - * used. - *

- * Ever time a call to getImageMeta is processed, the timer - * keeping track of cleanup is reset; more specifically, this class has to - * experience no activity for this duration of time before the cleanup - * process is fired up and cleans up the host OS process and the stream - * resources. - *

- * Any subsequent calls to getImageMeta after a cleanup simply - * re-initializes the resources. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.processCleanupDelay=600000 - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * Setting this value to 0 disables the automatic cleanup thread completely - * and the caller will need to manually cleanup the external ExifTool - * process and read/write streams by calling {@link #close()}. - *

- * Default value is 600,000 (10 minutes). - */ - private final long processCleanupDelay; - - private final Map featureSupportedMap = new HashMap(); - private final Set featureSet = EnumSet.noneOf(Feature.class); - private final ReentrantLock lock = new ReentrantLock(); - private final VersionNumber exifVersion; - private final Timer cleanupTimer; - private TimerTask currentCleanupTask = null; - private AtomicBoolean shuttingDown = new AtomicBoolean(false); - private volatile ExifProcess process; - private int timeoutWhenKeepAlive = 0; - - public ExifTool(){ - this((Feature[]) null); - } - - /** - * In this constructor, exifToolPath and processCleanupDelay are gotten from system properties - * exiftool.path and exiftool.processCleanupDelay. processCleanupDelay is optional. If not found, - * the default is used. - */ - public ExifTool (Feature ... features){ + private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + + private static Logger log = Logger.getLogger(ExifTool.class); + + /** + * The absolute path to the ExifTool executable on the host system running + * this class as defined by the "exiftool.path" system + * property. + *

+ * If ExifTool is on your system path and running the command "exiftool" + * successfully executes it, leaving this value unchanged will work fine on + * any platform. If the ExifTool executable is named something else or not + * in the system path, then this property will need to be set to point at it + * before using this class. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.path=/path/to/exiftool + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * On Windows be sure to double-escape the path to the tool, for example: + * + * -Dexiftool.path=C:\\Tools\\exiftool.exe + * + *

+ * Default value is "exiftool". + *

Relative Paths

+ * Relative path values (e.g. "bin/tools/exiftool") are executed with + * relation to the base directory the VM process was started in. Essentially + * the directory that new File(".").getAbsolutePath() points at + * during runtime. + */ + private final String exifCmd; + + /** + * Interval (in milliseconds) of inactivity before the cleanup thread wakes + * up and cleans up the daemon ExifTool process and the read/write streams + * used to communicate with it when the {@link Feature#STAY_OPEN} feature is + * used. + *

+ * Ever time a call to getImageMeta is processed, the timer + * keeping track of cleanup is reset; more specifically, this class has to + * experience no activity for this duration of time before the cleanup + * process is fired up and cleans up the host OS process and the stream + * resources. + *

+ * Any subsequent calls to getImageMeta after a cleanup simply + * re-initializes the resources. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.processCleanupDelay=600000 + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * Setting this value to 0 disables the automatic cleanup thread completely + * and the caller will need to manually cleanup the external ExifTool + * process and read/write streams by calling {@link #close()}. + *

+ * Default value is 600,000 (10 minutes). + */ + private final long processCleanupDelay; + + private final Map featureSupportedMap = new HashMap(); + private final Set featureSet = EnumSet.noneOf(Feature.class); + private final ReentrantLock lock = new ReentrantLock(); + private final VersionNumber exifVersion; + private final Timer cleanupTimer; + private TimerTask currentCleanupTask = null; + private AtomicBoolean shuttingDown = new AtomicBoolean(false); + private volatile ExifProcess process; + private int timeoutWhenKeepAlive = 0; + + public ExifTool() { + this((Feature[]) null); + } + + /** + * In this constructor, exifToolPath and processCleanupDelay are gotten from + * system properties exiftool.path and exiftool.processCleanupDelay. + * processCleanupDelay is optional. If not found, the default is used. + */ + public ExifTool(Feature... features) { this( System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, DEFAULT_PROCESS_CLEANUP_DELAY), features ); - } - - public ExifTool(String exifToolPath) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); - } - - public ExifTool(String exifToolPath, Feature ... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); - } - - public ExifTool(String exifCmd, long processCleanupDelay, Feature ... features) { - this.exifCmd = exifCmd; - this.processCleanupDelay = processCleanupDelay; - this.exifVersion = ExifProcess.readVersion(exifCmd); - if (features != null && features.length > 0) { - for (Feature feature : features) { - if ( ! feature.isSupported(exifVersion) ) { - throw new UnsupportedFeatureException(feature); - } - this.featureSet.add(feature); - this.featureSupportedMap.put(feature,true); - } } - /* - * Now that initialization is done, init the cleanup timer if we are - * using STAY_OPEN and the delay time set is non-zero. - */ - if (isFeatureEnabled(Feature.STAY_OPEN) ) { - cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - } else { - cleanupTimer = null; - } - } - - /** - * Limits the amount of time (in mills) an exif operation can take. Setting value to greater than 0 to enable. - */ - public ExifTool setRunTimeout(int mills) { - timeoutWhenKeepAlive = mills; - return this; - } - - /** - * Used to determine if the given {@link Feature} is supported by the - * underlying native install of ExifTool pointed at by - * {@link #exifCmd}. - *

- * If support for the given feature has not been checked for yet, this - * method will automatically call out to ExifTool and ensure the requested - * feature is supported in the current local install. - *

- * The external call to ExifTool to confirm feature support is only ever - * done once per JVM session and stored in a static final - * {@link Map} that all instances of this class share. - * - * @param feature - * The feature to check support for in the underlying ExifTool - * install. - * - * @return true if support for the given {@link Feature} was - * confirmed to work with the currently installed ExifTool or - * false if it is not supported. - * - * @throws IllegalArgumentException - * if feature is null. - * @throws RuntimeException - * if any exception occurs while attempting to start the - * external ExifTool process to verify feature support. - */ - public boolean isFeatureSupported(Feature feature) throws RuntimeException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); + public ExifTool(String exifToolPath) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); } - Boolean supported = featureSupportedMap.get(feature); + public ExifTool(String exifToolPath, Feature... features) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); + } - /* - * If there is no Boolean flag for the feature, support for it hasn't - * been checked yet with the native ExifTool install, so we need to do - * that. - */ - if (supported == null) { - log.debug("Support for feature %s has not been checked yet, checking..."); - supported = feature.isSupported(exifVersion); - featureSupportedMap.put(feature,supported); + public ExifTool(String exifCmd, long processCleanupDelay, Feature ... features) { + this.exifCmd = exifCmd; + this.processCleanupDelay = processCleanupDelay; + this.exifVersion = ExifProcess.readVersion(exifCmd); + if (features != null && features.length > 0) { + for (Feature feature : features) { + if (!feature.isSupported(exifVersion)) { + throw new UnsupportedFeatureException(feature); } + this.featureSet.add(feature); + this.featureSupportedMap.put(feature, true); + } + } - return supported; + /* + * Now that initialization is done, init the cleanup timer if we are + * using STAY_OPEN and the delay time set is non-zero. + */ + if (isFeatureEnabled(Feature.STAY_OPEN)) { + cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); + } else { + cleanupTimer = null; } + } + /** + * Limits the amount of time (in mills) an exif operation can take. Setting + * value to greater than 0 to enable. + */ + public ExifTool setRunTimeout(int mills) { + timeoutWhenKeepAlive = mills; + return this; + } + /** + * Used to determine if the given {@link Feature} is supported by the + * underlying native install of ExifTool pointed at by {@link #exifCmd}. + *

+ * If support for the given feature has not been checked for yet, this + * method will automatically call out to ExifTool and ensure the requested + * feature is supported in the current local install. + *

+ * The external call to ExifTool to confirm feature support is only ever + * done once per JVM session and stored in a static final + * {@link Map} that all instances of this class share. + * + * @param feature + * The feature to check support for in the underlying ExifTool + * install. + * + * @return true if support for the given {@link Feature} was + * confirmed to work with the currently installed ExifTool or + * false if it is not supported. + * + * @throws IllegalArgumentException + * if feature is null. + * @throws RuntimeException + * if any exception occurs while attempting to start the + * external ExifTool process to verify feature support. + */ + public boolean isFeatureSupported(Feature feature) throws RuntimeException { + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); + } + Boolean supported = featureSupportedMap.get(feature); + /* + * If there is no Boolean flag for the feature, support for it hasn't + * been checked yet with the native ExifTool install, so we need to do + * that. + */ + if (supported == null) { + log.debug("Support for feature %s has not been checked yet, checking..."); + supported = feature.isSupported(exifVersion); + featureSupportedMap.put(feature, supported); + } - /** - * Used to startup the external ExifTool process and open the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. This method has no effect if the stay open feature is not enabled. - */ - public void startup(){ - if (featureSet.contains(Feature.STAY_OPEN)){ - shuttingDown.set(false); - ensureProcessRunning(); - } - } - private void ensureProcessRunning(){ - if (process ==null || process.isClosed()) { - synchronized (this){ - if (process ==null || process.isClosed() ){ - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = ExifProcess.startup(exifCmd); - } - } + return supported; } - if ( processCleanupDelay > 0 ) { - synchronized (this) { - if ( currentCleanupTask != null ) { - currentCleanupTask.cancel(); - currentCleanupTask = null; - } - currentCleanupTask = new TimerTask() { - @Override - public void run() { - log.info("Auto cleanup task running..."); - process.close(); - } - }; - cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); - } - } - } - - /** - * This is same as {@link #close()}, added for consistency with {@link #startup()} - */ - public void shutdown(){ - close(); - } + /** + * Used to startup the external ExifTool process and open the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. This method has no effect if the stay open feature is not + * enabled. + */ + public void startup() { + if (featureSet.contains(Feature.STAY_OPEN)) { + shuttingDown.set(false); + ensureProcessRunning(); + } + } - /** - * Used to shutdown the external ExifTool process and close the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. - *

- * NOTE: Calling this method does not preclude this - * instance of {@link ExifTool} from being re-used, it merely disposes of - * the native and internal resources until the next call to - * getImageMeta causes them to be re-instantiated. - *

- * The cleanup thread will automatically call this after an interval of - * inactivity defined by {@link #processCleanupDelay}. - *

- * Calling this method on an instance of this class without - * {@link Feature#STAY_OPEN} support enabled has no effect. - */ - public synchronized void close() { - shuttingDown.set(true); - if ( process != null ) { - process.close(); + private void ensureProcessRunning() { + if (process == null || process.isClosed()) { + synchronized (this) { + if (process == null || process.isClosed()) { + log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = ExifProcess.startup(exifCmd); + } + } + } + if (processCleanupDelay > 0) { + synchronized (this) { + if (currentCleanupTask != null) { + currentCleanupTask.cancel(); + currentCleanupTask = null; + } + currentCleanupTask = new TimerTask() { + @Override + public void run() { + log.info("Auto cleanup task running..."); + process.close(); + } + }; + cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); + } + } } - if(currentCleanupTask != null) { - currentCleanupTask.cancel(); - currentCleanupTask = null; + + /** + * This is same as {@link #close()}, added for consistency with + * {@link #startup()} + */ + public void shutdown() { + close(); } + + /** + * Used to shutdown the external ExifTool process and close the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. + *

+ * NOTE: Calling this method does not preclude this + * instance of {@link ExifTool} from being re-used, it merely disposes of + * the native and internal resources until the next call to + * getImageMeta causes them to be re-instantiated. + *

+ * The cleanup thread will automatically call this after an interval of + * inactivity defined by {@link #processCleanupDelay}. + *

+ * Calling this method on an instance of this class without + * {@link Feature#STAY_OPEN} support enabled has no effect. + */ + public synchronized void close() { + shuttingDown.set(true); + if (process != null) { + process.close(); + } + if (currentCleanupTask != null) { + currentCleanupTask.cancel(); + currentCleanupTask = null; } + } - public boolean isStayOpen() { - return featureSet.contains(Feature.STAY_OPEN); - } + public boolean isStayOpen() { + return featureSet.contains(Feature.STAY_OPEN); + } - /** - * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support - * enabled, this method is used to determine if there is currently a running - * ExifTool process associated with this class. - *

- * Any dependent processes and streams can be shutdown using - * {@link #close()} and this class will automatically re-create them on the - * next call to getImageMeta if necessary. - * - * @return true if there is an external ExifTool process in - * daemon mode associated with this class utilizing the - * {@link Feature#STAY_OPEN} feature, otherwise returns - * false. - */ - public boolean isRunning() { - return process != null && ! process.isClosed(); - } + /** + * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support + * enabled, this method is used to determine if there is currently a running + * ExifTool process associated with this class. + *

+ * Any dependent processes and streams can be shutdown using + * {@link #close()} and this class will automatically re-create them on the + * next call to getImageMeta if necessary. + * + * @return true if there is an external ExifTool process in + * daemon mode associated with this class utilizing the + * {@link Feature#STAY_OPEN} feature, otherwise returns + * false. + */ + public boolean isRunning() { + return process != null && !process.isClosed(); + } - /** - * Used to determine if the given {@link Feature} has been enabled for this - * particular instance of {@link ExifTool}. - *

- * This method is different from {@link #isFeatureSupported(Feature)}, which - * checks if the given feature is supported by the underlying ExifTool - * install where as this method tells the caller if the given feature has - * been enabled for use in this particular instance. - * - * @param feature - * The feature to check if it has been enabled for us or not on - * this instance. - * - * @return true if the given {@link Feature} is currently - * enabled on this instance of {@link ExifTool}, otherwise returns - * false. - * - * @throws IllegalArgumentException - * if feature is null. - */ + /** + * Used to determine if the given {@link Feature} has been enabled for this + * particular instance of {@link ExifTool}. + *

+ * This method is different from {@link #isFeatureSupported(Feature)}, which + * checks if the given feature is supported by the underlying ExifTool + * install where as this method tells the caller if the given feature has + * been enabled for use in this particular instance. + * + * @param feature + * The feature to check if it has been enabled for us or not on + * this instance. + * + * @return true if the given {@link Feature} is currently + * enabled on this instance of {@link ExifTool}, otherwise returns + * false. + * + * @throws IllegalArgumentException + * if feature is null. + */ public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); - } - return featureSet.contains(feature); + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); } + return featureSet.contains(feature); + } - public Map getImageMeta(File image, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { + public Map getImageMeta(File image, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { - return getImageMeta(image, Format.NUMERIC, tags); - } + return getImageMeta(image, Format.NUMERIC, tags); + } - public Map getImageMeta(File image, Format format, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { + public Map getImageMeta(File image, Format format, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { - String [] stringTags = new String[tags.length]; - int i=0; - for (Tag tag : tags){ - stringTags[i++] = tag.getName(); - } + String[] stringTags = new String[tags.length]; + int i = 0; + for (Tag tag : tags) { + stringTags[i++] = tag.getName(); + } Map result = getImageMeta(image, format, true, stringTags); - return mapByTag(result); - } + return mapByTag(result); + } public Map getImageMeta(File image, Format format, TagGroup... tags) throws IllegalArgumentException, SecurityException, IOException { - String [] stringTags = new String[tags.length]; - int i=0; - for (TagGroup tag : tags){ - stringTags[i++] = tag.getValue(); + String[] stringTags = new String[tags.length]; + int i = 0; + for (TagGroup tag : tags) { + stringTags[i++] = tag.getValue(); + } + return getImageMeta(image, format, false, stringTags); } - return getImageMeta(image, format, false, stringTags); - } private Map getImageMeta(final File image, final Format format, final boolean suppressDuplicates, final String... tags) throws IllegalArgumentException, SecurityException, IOException { - //Validate input and create Arg Array - final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); - List args = new ArrayList(tags.length+4); - if (format == null){ - throw new IllegalArgumentException("format cannot be null"); - } else if (format == Format.NUMERIC){ - args.add("-n"); // numeric output - } - if (!suppressDuplicates){ - args.add("-a"); //suppress duplicates - } - args.add("-S"); // compact output + // Validate input and create Arg Array + final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + List args = new ArrayList(tags.length + 4); + if (format == null) { + throw new IllegalArgumentException("format cannot be null"); + } else if (format == Format.NUMERIC) { + args.add("-n"); // numeric output + } + if (!suppressDuplicates) { + args.add("-a"); // suppress duplicates + } + args.add("-S"); // compact output - if (tags == null || tags.length == 0){ + if (tags == null || tags.length == 0) { throw new IllegalArgumentException("tags cannot be null and must contain 1 or more Tag to query the image for."); - } - for (String tag : tags) { - args.add("-" + tag); - } - if (image == null){ + } + for (String tag : tags) { + args.add("-" + tag); + } + if (image == null) { throw new IllegalArgumentException("image cannot be null and must be a valid stream of image data."); - } - if (!image.canRead()){ + } + if (!image.canRead()) { throw new SecurityException("Unable to read the given image ["+image.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); - } - args.add(image.getAbsolutePath()); + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + } + args.add(image.getAbsolutePath()); - //start process - long startTime = System.currentTimeMillis(); + // start process + long startTime = System.currentTimeMillis(); log.debug(String.format("Querying %d tags from image: %s", tags.length, image.getAbsolutePath())); - /* - * Using ExifTool in daemon mode (-stay_open True) executes different - * code paths below. So establish the flag for this once and it is - * reused a multitude of times later in this method to figure out where - * to branch to. - */ - Map resultMap; - if (stayOpen) { - log.debug("Using ExifTool in daemon mode (-stay_open True)..."); - resultMap = processStayOpen(args); - } else { - log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd,args); - } + /* + * Using ExifTool in daemon mode (-stay_open True) executes different + * code paths below. So establish the flag for this once and it is + * reused a multitude of times later in this method to figure out where + * to branch to. + */ + Map resultMap; + if (stayOpen) { + log.debug("Using ExifTool in daemon mode (-stay_open True)..."); + resultMap = processStayOpen(args); + } else { + log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); + resultMap = ExifProcess.executeToResults(exifCmd, args); + } - // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()){ + // Print out how long the call to external ExifTool process took. + if (log.isDebugEnabled()) { log.debug(String.format("Image Meta Processed in %d ms [queried %d tags and found %d values]", (System.currentTimeMillis() - startTime), tags.length, resultMap.size())); + } + + return resultMap; + } + + /** + * extract image metadata to exiftool's internal xml format. + * + * @param input + * the input file + * @return command output as xml string + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public String getImageMetadataXml(File input, boolean includeBinary) + throws IOException { + List args = new ArrayList(); + args.add("-X"); + if (includeBinary) + args.add("-b"); + args.add(input.getAbsolutePath()); + + return ExifProcess.executeToString(exifCmd, args); } - return resultMap; + /** + * extract image metadata to exiftool's internal xml format. + * + * @param input + * the input file + * @param output + * the output file + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public void getImageMetadataXml(File input, File output, + boolean includeBinary) throws IOException { + + String result = getImageMetadataXml(input, includeBinary); + + try (FileWriter w = new FileWriter(output)) { + w.write(result); } + } + + /** + * output icc profile from input to output. + * + * @param input + * the input file + * @param output + * the output file for icc data + * @return the command result from standard output e.g. + * "1 output files created" + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public String getImageIccProfile(File input, File output) + throws IOException { - /** - * Will attempt 3 times to use the running exif process, and if unable to complete successfully will throw IOException - */ + List args = new ArrayList(); + args.add("-icc_profile"); + args.add(input.getAbsolutePath()); + + args.add("-o"); + args.add(output.getAbsolutePath()); + + return ExifProcess.executeToString(exifCmd, args); + } + + /** + * Extract thumbnail from the given tag. + * + * @param input + * the input file + * @param tag + * the tag containing binary data + * @return the thumbnail file created. it is in the same folder as the input + * file because of the syntax of exiftool and has the suffix + * ".thumb.jpg" + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public File extractThumbnail(File input, Tag tag) throws IOException { + + List args = new ArrayList(); + String suffix = ".thumb.jpg"; + String thumbname = FilenameUtils.getBaseName(input.getName()) + suffix; + + args.add("-" + tag.getName()); + args.add(input.getAbsolutePath()); + args.add("-b"); + args.add("-w"); + args.add(suffix); + String result = ExifProcess.executeToString(exifCmd, args); + File thumbnail = new File(input.getParent() + File.separator + + thumbname); + if (!thumbnail.exists()) + throw new IOException("could not create thumbnail: " + result); + return thumbnail; + } + + /** + * Will attempt 3 times to use the running exif process, and if unable to + * complete successfully will throw IOException + */ private Map processStayOpen(List args) throws IOException { - int attempts = 0; - while (attempts < 3 && ! shuttingDown.get()){ - attempts++; - //make sure process is started - ensureProcessRunning(); - TimerTask attemptTimer = null; - try { - if ( timeoutWhenKeepAlive > 0 ) { - attemptTimer = new TimerTask() { - public void run() { + int attempts = 0; + while (attempts < 3 && !shuttingDown.get()) { + attempts++; + // make sure process is started + ensureProcessRunning(); + TimerTask attemptTimer = null; + try { + if (timeoutWhenKeepAlive > 0) { + attemptTimer = new TimerTask() { + @Override + public void run() { log.warn("Process ran too long closing, max "+timeoutWhenKeepAlive+" mills"); - process.close(); - } - }; - cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); - } - log.debug("Streaming arguments to ExifTool process..."); - return process.sendArgs(args); - } catch (IOException ex){ + process.close(); + } + }; + cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); + } + log.debug("Streaming arguments to ExifTool process..."); + return process.sendArgs(args); + } catch (IOException ex) { if ( STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) && ! shuttingDown.get() ){ //only catch "Stream Closed" error (happens when process has died) log.warn(String.format("Caught IOException(\"%s\"), will restart daemon",STREAM_CLOSED_MESSAGE)); - process.close(); - } else { - throw ex; - } - } finally { + process.close(); + } else { + throw ex; + } + } finally { if ( attemptTimer != null ) attemptTimer.cancel(); - } - } - if ( shuttingDown.get() ) { - throw new IOException("Shutting Down"); + } + } + if (shuttingDown.get()) { + throw new IOException("Shutting Down"); + } + throw new IOException("Ran out of attempts"); } - throw new IOException("Ran out of attempts"); - } - - private static Map mapByTag(Map stringMap){ - Map tagMap = new HashMap(Tag.values().length); - for (Tag tag : Tag.values()){ - if (stringMap.containsKey(tag.getName())){ - tagMap.put(tag, stringMap.get(tag.getName())); - } + + private static Map mapByTag(Map stringMap) { + Map tagMap = new HashMap(Tag.values().length); + for (Tag tag : Tag.values()) { + if (stringMap.containsKey(tag.getName())) { + tagMap.put(tag, stringMap.get(tag.getName())); + } + } + return tagMap; } - return tagMap; - } - - - //================================================================================ - /** - * Represents an Exif Process. - */ - public static class ExifProcess { - private final ReentrantLock closeLock = new ReentrantLock(false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; - private volatile boolean closed = false; - - public static VersionNumber readVersion(String exifCmd) { + + // ================================================================================ + /** + * Represents an Exif Process. + */ + public static class ExifProcess { + private final ReentrantLock closeLock = new ReentrantLock(false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader reader; + private final OutputStreamWriter writer; + private volatile boolean closed = false; + + public static VersionNumber readVersion(String exifCmd) { ExifProcess process =_execute(false, Arrays.asList(exifCmd,"-ver")); - try { - return new VersionNumber(process.readLine()); - } catch (IOException ex) { + try { + return new VersionNumber(process.readLine()); + } catch (IOException ex) { throw new RuntimeException(String.format("Unable to check version number of ExifTool: %s",exifCmd)); - } finally { - process.close(); - } - } + } finally { + process.close(); + } + } public static Map executeToResults(String exifCmd, List args) throws IOException { - List newArgs = new ArrayList(args.size()+1); - newArgs.add(exifCmd); - newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); - try { - return process.readResponse(); - } finally { - process.close(); - } - } + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { + return process.readResponse(); + } finally { + process.close(); + } + } - public static ExifProcess startup(String exifCmd) { + public static String executeToString(String exifCmd, List args) + throws IOException { + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { + return process.readResponseString(); + } finally { + process.close(); + } + } + + public static ExifProcess startup(String exifCmd) { List args = Arrays.asList(exifCmd,"-stay_open", "True", "-@", "-"); - return _execute(true, args); - } + return _execute(true, args); + } - public static ExifProcess _execute(boolean keepAlive, List args) { + public static ExifProcess _execute(boolean keepAlive, List args) { log.debug(String.format("Attempting to start external ExifTool process using args: %s", args)); - try { - Process process = new ProcessBuilder(args).start(); - log.debug("\tSuccessful"); - return new ExifProcess(keepAlive,process); - } catch (Exception e) { - String message = "Unable to start external ExifTool process using the execution arguments: " - + args - + ". Ensure ExifTool is installed correctly and runs using the command path '" - + args.get(0) - + "' as specified by the 'exiftool.path' system property."; - - log.debug(message); - throw new RuntimeException(message, e); - } - } + try { + Process process = new ProcessBuilder(args).start(); + log.debug("\tSuccessful"); + return new ExifProcess(keepAlive, process); + } catch (Exception e) { + String message = "Unable to start external ExifTool process using the execution arguments: " + + args + + ". Ensure ExifTool is installed correctly and runs using the command path '" + + args.get(0) + + "' as specified by the 'exiftool.path' system property."; + + log.debug(message); + throw new RuntimeException(message, e); + } + } - public ExifProcess(boolean keepAlive,Process process) { - this.keepAlive = keepAlive; - this.process = process; + public ExifProcess(boolean keepAlive, Process process) { + this.keepAlive = keepAlive; + this.process = process; this.reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream()); - } + this.writer = new OutputStreamWriter(process.getOutputStream()); + } public synchronized Map sendArgs(List args) throws IOException { - StringBuilder builder = new StringBuilder(); - for(String arg : args) { - builder.append(arg).append("\n"); - } - builder.append("-execute\n"); - writeFlush(builder.toString()); - return readResponse(); - } - + StringBuilder builder = new StringBuilder(); + for (String arg : args) { + builder.append(arg).append("\n"); + } + builder.append("-execute\n"); + writeFlush(builder.toString()); + return readResponse(); + } - public synchronized void writeFlush(String message) throws IOException { + public synchronized void writeFlush(String message) throws IOException { if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - writer.write(message); - writer.flush(); - } + writer.write(message); + writer.flush(); + } - public synchronized String readLine() throws IOException { + public synchronized String readLine() throws IOException { if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - return reader.readLine(); - } + return reader.readLine(); + } public synchronized Map readResponse() throws IOException { if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - Map resultMap = new HashMap(500); - String line; + log.debug("Reading response back from ExifTool..."); + Map resultMap = new HashMap(500); + String line; - while ((line = reader.readLine()) != null) { + while ((line = reader.readLine()) != null) { if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - String[] pair = TAG_VALUE_PATTERN.split(line, 2); + String[] pair = TAG_VALUE_PATTERN.split(line, 2); - if (pair.length == 2) { - resultMap.put(pair[0], pair[1]); + if (pair.length == 2) { + resultMap.put(pair[0], pair[1]); log.debug(String.format("\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); - } - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need to - * look for it and break from this loop when we see it otherwise - * this process will hang indefinitely blocking on the input stream - * with no data to read. - */ - if (keepAlive && line.equals("{ready}")){ - break; - } - } - return resultMap; - } + } - public boolean isClosed() { - return closed; - } + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } + } + return resultMap; + } - public void close() { - if ( ! closed ) { - closeLock.lock(); - try { - if ( ! closed ) { - closed = true; - log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - try { - writer.write("-stay_open\nFalse\n"); - writer.flush(); - } catch (IOException ex) { - //log.error(ex,ex); - } - try { - log.debug("Closing Read stream..."); - reader.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log.debug("Closing Write stream..."); - writer.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - log.debug("Read/Write streams successfully closed."); - - try { - process.destroy(); - } catch (Exception e) { - // - } - //process = null; - - } - } finally { - closeLock.unlock(); - } - } + public synchronized String readResponseString() throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + log.debug("Reading response back from ExifTool..."); + String line; + StringBuilder result = new StringBuilder(); + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } else + result.append(line); + } + return result.toString(); + } + + public boolean isClosed() { + return closed; + } + + public void close() { + if (!closed) { + closeLock.lock(); + try { + if (!closed) { + closed = true; + log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); + try { + writer.write("-stay_open\nFalse\n"); + writer.flush(); + } catch (IOException ex) { + // log.error(ex,ex); + } + try { + log.debug("Closing Read stream..."); + reader.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + log.debug("Closing Write stream..."); + writer.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + log.debug("Read/Write streams successfully closed."); + + try { + process.destroy(); + } catch (Exception e) { + // + } + // process = null; + + } + } finally { + closeLock.unlock(); + } + } + } } - } - - //================================================================================ - /** - * Enum used to define the different kinds of features in the native - * ExifTool executable that this class can help you take advantage of. - *

- * These flags are different from {@link Tag}s in that a "feature" is - * determined to be a special functionality of the underlying ExifTool - * executable that requires a different code-path in this class to take - * advantage of; for example, -stay_open True support. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Feature { + + // ================================================================================ /** - * Enum used to specify that you wish to launch the underlying ExifTool - * process with -stay_open True support turned on that this - * class can then take advantage of. + * Enum used to define the different kinds of features in the native + * ExifTool executable that this class can help you take advantage of. *

- * Required ExifTool version is 8.36 or higher. + * These flags are different from {@link Tag}s in that a "feature" is + * determined to be a special functionality of the underlying ExifTool + * executable that requires a different code-path in this class to take + * advantage of; for example, -stay_open True support. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 */ - STAY_OPEN(8,36); + public enum Feature { + /** + * Enum used to specify that you wish to launch the underlying ExifTool + * process with -stay_open True support turned on that this + * class can then take advantage of. + *

+ * Required ExifTool version is 8.36 or higher. + */ + STAY_OPEN(8, 36); private VersionNumber requireVersion; - private Feature(int... numbers) { - this.requireVersion = new VersionNumber(numbers); + private Feature(int... numbers) { + this.requireVersion = new VersionNumber(numbers); + } + + /** + * Used to get the version of ExifTool required by this feature in order + * to work. + * + * @return the version of ExifTool required by this feature in order to + * work. + */ + VersionNumber getVersion() { + return requireVersion; + } + + boolean isSupported(VersionNumber exifVersionNumber) { + return requireVersion.isBeforeOrEqualTo(exifVersionNumber); + } } + + // ================================================================================ /** - * Used to get the version of ExifTool required by this feature in order - * to work. - * - * @return the version of ExifTool required by this feature in order to - * work. + * Version Number used to determine if one version is after another. */ - VersionNumber getVersion() { - return requireVersion; - } - - boolean isSupported(VersionNumber exifVersionNumber) { - return requireVersion.isBeforeOrEqualTo(exifVersionNumber); - } - } - - //================================================================================ - /** - * Version Number used to determine if one version is after another. - */ - static class VersionNumber { - private final int[] numbers; - - public VersionNumber(String str) { - String[] versionParts = str.trim().split("\\."); - this.numbers = new int[versionParts.length]; - for(int i=0; i other.numbers[i] ) { - return false; - } else if ( this.numbers[i] < other.numbers[i] ) { - return true; - } - } + public boolean isBeforeOrEqualTo(VersionNumber other) { + int max = Math.min(this.numbers.length, other.numbers.length); + for (int i = 0; i < max; i++) { + if (this.numbers[i] > other.numbers[i]) { + return false; + } else if (this.numbers[i] < other.numbers[i]) { + return true; + } + } //assume missing number as zero, so if the current process number is more digits it is a higher version - return this.numbers.length <= other.numbers.length; + return this.numbers.length <= other.numbers.length; + } + + public String toString() { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < numbers.length; i++) { + if (builder.length() > 0) { + builder.append("."); + } + builder.append(numbers[i]); + } + return builder.toString(); + } } - public String toString() { - StringBuilder builder = new StringBuilder(); - for(int i=0; i 0 ) { - builder.append("."); - } - builder.append(numbers[i]); - } - return builder.toString(); + // ================================================================================ + /** + * Enum used to define the 2 different output formats that {@link Tag} + * values can be returned in: numeric or human-readable text. + *

+ * ExifTool, via the -n command line arg, is capable of + * returning most values in their raw numeric form (e.g. + * Aperture="2.8010323841") as well as a more human-readable/friendly format + * (e.g. Aperture="2.8"). + *

+ * While the {@link Tag}s defined on this class do provide a hint at the + * type of the result (see {@link Tag#getType()}), that hint only applies + * when the {@link Format#NUMERIC} form of the value is returned. + *

+ * If the caller finds the human-readable format easier to process, + * {@link Format#HUMAN_READABLE} can be specified when calling + * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned + * {@link String} values processed manually by the caller. + *

+ * In order to see the types of values that are returned when + * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive + * ExifTool Tag Guide. + *

+ * This makes sense with some values like Aperture that in + * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high + * precision values that are near the intended value (e.g. + * "2.79999992203711" instead of just returning "2.8"). On the other hand, + * other values (like Orientation) are easier to parse when their numeric + * value (1-8) is returned instead of a much longer friendly name (e.g. + * "Mirror horizontal and rotate 270 CW"). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Format { + NUMERIC, HUMAN_READABLE } - } - - - //================================================================================ - /** - * Enum used to define the 2 different output formats that {@link Tag} - * values can be returned in: numeric or human-readable text. - *

- * ExifTool, via the -n command line arg, is capable of - * returning most values in their raw numeric form (e.g. - * Aperture="2.8010323841") as well as a more human-readable/friendly format - * (e.g. Aperture="2.8"). - *

- * While the {@link Tag}s defined on this class do provide a hint at the - * type of the result (see {@link Tag#getType()}), that hint only applies - * when the {@link Format#NUMERIC} form of the value is returned. - *

- * If the caller finds the human-readable format easier to process, - * {@link Format#HUMAN_READABLE} can be specified when calling - * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned - * {@link String} values processed manually by the caller. - *

- * In order to see the types of values that are returned when - * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive - * ExifTool Tag Guide. - *

- * This makes sense with some values like Aperture that in - * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high - * precision values that are near the intended value (e.g. - * "2.79999992203711" instead of just returning "2.8"). On the other hand, - * other values (like Orientation) are easier to parse when their numeric - * value (1-8) is returned instead of a much longer friendly name (e.g. - * "Mirror horizontal and rotate 270 CW"). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Format { - NUMERIC, HUMAN_READABLE - } - //================================================================================ - /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifTool. - *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default {@link Format#NUMERIC} value format - * is used. - *

- * All replies from ExifTool are parsed as {@link String}s and using the - * type hint from each {@link Tag} can easily be converted to the correct - * data format by using the provided {@link Tag#parseValue(String)} - * method. - *

- * This class does not make an attempt at converting the value automatically - * in case the caller decides they would prefer tag values returned in - * {@link Format#HUMAN_READABLE} format and to avoid any compatibility - * issues with future versions of ExifTool if a tag's return value is - * changed. This approach to leaving returned tag values as strings until - * the caller decides they want to parse them is a safer and more robust - * approach. - *

- * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. - *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. - *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. - *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Tag { - //single entry tags + + // ================================================================================ + /** + * Enum used to pre-define a convenient list of tags that can be easily + * extracted from images using this class with an external install of + * ExifTool. + *

+ * Each tag defined also includes a type hint for the parsed value + * associated with it when the default {@link Format#NUMERIC} value format + * is used. + *

+ * All replies from ExifTool are parsed as {@link String}s and using the + * type hint from each {@link Tag} can easily be converted to the correct + * data format by using the provided {@link Tag#parseValue(String)} method. + *

+ * This class does not make an attempt at converting the value automatically + * in case the caller decides they would prefer tag values returned in + * {@link Format#HUMAN_READABLE} format and to avoid any compatibility + * issues with future versions of ExifTool if a tag's return value is + * changed. This approach to leaving returned tag values as strings until + * the caller decides they want to parse them is a safer and more robust + * approach. + *

+ * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or + * process the returned {@link String} values any way they wish. + *

Tag Support

+ * ExifTool is capable of parsing almost every tag known to man (1000+), but + * this class makes an attempt at pre-defining a convenient list of the most + * common tags for use. + *

+ * This list was determined by looking at the common metadata tag values + * written to images by popular mobile devices (iPhone, Android) as well as + * cameras like simple point and shoots as well as DSLRs. As an additional + * source of input the list of supported/common EXIF formats that Flickr + * supports was also reviewed to ensure the most common/useful tags were + * being covered here. + *

+ * Please email me or file an issue + * if you think this list is missing a commonly used tag that should be + * added to it. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Tag { + // single entry tags APERTURE("ApertureValue", Double.class), AUTHOR("XPAuthor", String.class), COLOR_SPACE("ColorSpace", Integer.class), @@ -1061,172 +1210,179 @@ public enum Tag { WHITE_BALANCE("WhiteBalance", Integer.class), X_RESOLUTION("XResolution", Double.class), Y_RESOLUTION("YResolution", Double.class), - ; + // select ICC metadata + ICC_DESCRIPTION("ProfileDescription", String.class), + ICC_COLORSPACEDATA( "ColorSpaceData", String.class), + // actually binary data, but what are we doing to do here??? Just use to + // save to file... + THUMBNAIL_IMAGE("ThumbnailImage", String.class), + THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class); - /** - * Used to get the {@link Tag} identified by the given, case-sensitive, - * tag name. - * - * @param name - * The case-sensitive name of the tag that will be searched - * for. - * - * @return the {@link Tag} identified by the given, case-sensitive, tag - * name or null if one couldn't be found. - */ - public static Tag forName(String name) { - for (Tag tag : Tag.values()){ - if (tag.getName().equals(name)){ - return tag; - } - } - return null; - } + /** + * Used to get the {@link Tag} identified by the given, case-sensitive, + * tag name. + * + * @param name + * The case-sensitive name of the tag that will be searched + * for. + * + * @return the {@link Tag} identified by the given, case-sensitive, tag + * name or null if one couldn't be found. + */ + public static Tag forName(String name) { + for (Tag tag : Tag.values()) { + if (tag.getName().equals(name)) { + return tag; + } + } + return null; + } - /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifTool process) into the type described - * by the associated {@link Tag}. - * - * @param - * The type of the returned value. - * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. - * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). - * - * @throws IllegalArgumentException - * if tag is null. - * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). - * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. - */ - @SuppressWarnings("unchecked") - public T parseValue(String value) throws IllegalArgumentException { - - if (value != null) { - if (Boolean.class.isAssignableFrom(this.getType())){ - return (T) Boolean.valueOf(value); - } else if (Byte.class.isAssignableFrom(this.getType())){ - return (T) Byte.valueOf(Byte.parseByte(value)); - } else if (Integer.class.isAssignableFrom(this.getType())){ - return (T) Integer.valueOf(Integer.parseInt(value)); - } else if (Short.class.isAssignableFrom(this.getType())){ - return (T) Short.valueOf(Short.parseShort(value)); - } else if (Long.class.isAssignableFrom(this.getType())){ - return (T) Long.valueOf(Long.parseLong(value)); - } else if (Float.class.isAssignableFrom(this.getType())){ - return (T) Float.valueOf(Float.parseFloat(value)); - } else if (Double.class.isAssignableFrom(this.getType())){ - return (T) parseDouble(value); - } else if (Character.class.isAssignableFrom(this.getType())){ - return (T) Character.valueOf(value.charAt(0)); - } else if (String.class.isAssignableFrom(this.getType())){ - return (T) value; - } - } - return null; - } + /** + * Convenience method used to convert the given string Tag value + * (returned from the external ExifTool process) into the type described + * by the associated {@link Tag}. + * + * @param + * The type of the returned value. + * @param value + * The {@link String} representation of the tag's value as + * parsed from the image. + * + * @return the given string value converted to a native Java type (e.g. + * Integer, Double, etc.). + * + * @throws IllegalArgumentException + * if tag is null. + * @throws NumberFormatException + * if any exception occurs while trying to parse the given + * value to any of the supported numeric types + * in Java via calls to the respective parseXXX + * methods defined on all the numeric wrapper classes (e.g. + * {@link Integer#parseInt(String)} , + * {@link Double#parseDouble(String)} and so on). + * @throws ClassCastException + * if the type defined by T is incompatible + * with the type defined by {@link Tag#getType()} returned + * by the tag argument passed in. This class + * performs an implicit/unchecked cast to the type + * T before returning the parsed result of the + * type indicated by {@link Tag#getType()}. If the types do + * not match, a ClassCastException will be + * generated by the VM. + */ + @SuppressWarnings("unchecked") + public T parseValue(String value) throws IllegalArgumentException { + + if (value != null) { + if (Boolean.class.isAssignableFrom(this.getType())) { + return (T) Boolean.valueOf(value); + } else if (Byte.class.isAssignableFrom(this.getType())) { + return (T) Byte.valueOf(Byte.parseByte(value)); + } else if (Integer.class.isAssignableFrom(this.getType())) { + return (T) Integer.valueOf(Integer.parseInt(value)); + } else if (Short.class.isAssignableFrom(this.getType())) { + return (T) Short.valueOf(Short.parseShort(value)); + } else if (Long.class.isAssignableFrom(this.getType())) { + return (T) Long.valueOf(Long.parseLong(value)); + } else if (Float.class.isAssignableFrom(this.getType())) { + return (T) Float.valueOf(Float.parseFloat(value)); + } else if (Double.class.isAssignableFrom(this.getType())) { + return (T) parseDouble(value); + } else if (Character.class.isAssignableFrom(this.getType())) { + return (T) Character.valueOf(value.charAt(0)); + } else if (String.class.isAssignableFrom(this.getType())) { + return (T) value; + } + } + return null; + } - private Double parseDouble(String in) { - if (in.contains("/")) { - String[] enumeratorAndDivisor = in.split("/"); + private Double parseDouble(String in) { + if (in.contains("/")) { + String[] enumeratorAndDivisor = in.split("/"); return Double.parseDouble(enumeratorAndDivisor[0]) / Double.parseDouble(enumeratorAndDivisor[1]); - } else { - return Double.parseDouble(in); - } - } + } else { + return Double.parseDouble(in); + } + } - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ - public String getName() { - return name; - } + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ + public String getName() { + return name; + } - /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifTool Tag Guide. - * - * @return a hint for the native type of this tag's value. - */ - public Class getType() { - return type; - } + /** + * Used to get a hint for the native type of this tag's value as + * specified by Phil Harvey's ExifTool Tag Guide. + * + * @return a hint for the native type of this tag's value. + */ + public Class getType() { + return type; + } - private String name; - private Class type; + private String name; + private Class type; - private Tag(String name, Class type) { - this.name = name; - this.type = type; + private Tag(String name, Class type) { + this.name = name; + this.type = type; + } } - } - //================================================================================ - public enum TagGroup { + // ================================================================================ + public enum TagGroup { EXIF("EXIF","exif:all"), IPTC("IPTC", "iptc:all"), XMP("XMP", "xmp:all"), - ALL("ALL", "all"); + ALL("ALL", "all"), + FILE("FILE", "file:all"), + ICC("ICC", "icc_profile:all"); - private final String name; - private final String value; + private final String name; + private final String value; - private TagGroup(String name, String value) { - this.name = name; - this.value = value; - } + private TagGroup(String name, String value) { + this.name = name; + this.value = value; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public String getValue() { - return value; + public String getValue() { + return value; + } } - } - - - //================================================================================ - /** - * Class used to define an exception that occurs when the caller attempts to - * use a {@link Feature} that the underlying native ExifTool install does - * not support (i.e. the version isn't new enough). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public class UnsupportedFeatureException extends RuntimeException { - private static final long serialVersionUID = -1332725983656030770L; - - public UnsupportedFeatureException(Feature feature) { - super( - "Use of feature [" - + feature.toString() - + "] requires version " - + feature.getVersion() - + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); - } + // ================================================================================ + /** + * Class used to define an exception that occurs when the caller attempts to + * use a {@link Feature} that the underlying native ExifTool install does + * not support (i.e. the version isn't new enough). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public class UnsupportedFeatureException extends RuntimeException { + private static final long serialVersionUID = -1332725983656030770L; + + public UnsupportedFeatureException(Feature feature) { + super( + "Use of feature [" + + feature.toString() + + "] requires version " + + feature.getVersion() + + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); } + + } } \ No newline at end of file From 3a61fd66e7eb9081556dfcd71d6ca78b2303b3c1 Mon Sep 17 00:00:00 2001 From: Chris Turchin Date: Thu, 23 Jan 2014 02:58:08 +0100 Subject: [PATCH 011/148] Revert "added new tags, tag groups and functions" This reverts commit cac645c2f0739345f420040c8513e49613f13196. --- .../com/thebuzzmedia/exiftool/ExifTool.java | 1874 ++++++++--------- 1 file changed, 859 insertions(+), 1015 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 25737508..829a2100 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -13,32 +13,16 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.thebuzzmedia.exiftool; -import java.io.BufferedReader; -import java.io.File; -import java.io.FileWriter; -import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.Timer; -import java.util.TimerTask; +import org.apache.log4j.Logger; + +import java.io.*; +import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; -import org.apache.commons.io.FilenameUtils; -import org.apache.log4j.Logger; - /** * Class used to provide a Java-like interface to Phil Harvey's excellent, * Perl-based - * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} convenience - * method for parsing given String values according to the Tag hint - * automatically for you if that is what you plan on doing, otherwise feel free - * to handle the return values anyway you want. + * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} + * convenience method for parsing given String values according to + * the Tag hint automatically for you if that is what you plan on doing, + * otherwise feel free to handle the return values anyway you want. *

ExifTool -stay_open Support

* ExifTool * Because this feature requires ExifTool 8.36 or later, this class will * actually verify support for the feature in the version of ExifTool pointed at - * by {@link #exifCmd} before successfully instantiating the class and will - * notify you via an {@link UnsupportedFeatureException} if the native ExifTool - * doesn't support the requested feature. + * by {@link #exifCmd} before successfully instantiating the class and + * will notify you via an {@link UnsupportedFeatureException} if the native + * ExifTool doesn't support the requested feature. *

* In the event of an {@link UnsupportedFeatureException}, the caller can either * upgrade the native ExifTool upgrade to the version required or simply avoid @@ -215,946 +199,813 @@ */ public class ExifTool { - public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; - public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; - - /** - * Name used to identify the (optional) cleanup {@link Thread}. - *

- * This is only provided to make debugging and profiling easier for - * implementers making use of this class such that the resources this class - * creates and uses (i.e. Threads) are readily identifiable in a running VM. - *

- * Default value is "ExifTool Cleanup Thread". - */ - private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; - - /** - * Compiled {@link Pattern} of ": " used to split compact output from - * ExifTool evenly into name/value pairs. - */ + public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + + /** + * Name used to identify the (optional) cleanup {@link Thread}. + *

+ * This is only provided to make debugging and profiling easier for + * implementers making use of this class such that the resources this class + * creates and uses (i.e. Threads) are readily identifiable in a running VM. + *

+ * Default value is "ExifTool Cleanup Thread". + */ + private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; + + /** + * Compiled {@link Pattern} of ": " used to split compact output from + * ExifTool evenly into name/value pairs. + */ private static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); - private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - - private static Logger log = Logger.getLogger(ExifTool.class); - - /** - * The absolute path to the ExifTool executable on the host system running - * this class as defined by the "exiftool.path" system - * property. - *

- * If ExifTool is on your system path and running the command "exiftool" - * successfully executes it, leaving this value unchanged will work fine on - * any platform. If the ExifTool executable is named something else or not - * in the system path, then this property will need to be set to point at it - * before using this class. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.path=/path/to/exiftool - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * On Windows be sure to double-escape the path to the tool, for example: - * - * -Dexiftool.path=C:\\Tools\\exiftool.exe - * - *

- * Default value is "exiftool". - *

Relative Paths

- * Relative path values (e.g. "bin/tools/exiftool") are executed with - * relation to the base directory the VM process was started in. Essentially - * the directory that new File(".").getAbsolutePath() points at - * during runtime. - */ - private final String exifCmd; - - /** - * Interval (in milliseconds) of inactivity before the cleanup thread wakes - * up and cleans up the daemon ExifTool process and the read/write streams - * used to communicate with it when the {@link Feature#STAY_OPEN} feature is - * used. - *

- * Ever time a call to getImageMeta is processed, the timer - * keeping track of cleanup is reset; more specifically, this class has to - * experience no activity for this duration of time before the cleanup - * process is fired up and cleans up the host OS process and the stream - * resources. - *

- * Any subsequent calls to getImageMeta after a cleanup simply - * re-initializes the resources. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.processCleanupDelay=600000 - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * Setting this value to 0 disables the automatic cleanup thread completely - * and the caller will need to manually cleanup the external ExifTool - * process and read/write streams by calling {@link #close()}. - *

- * Default value is 600,000 (10 minutes). - */ - private final long processCleanupDelay; - - private final Map featureSupportedMap = new HashMap(); - private final Set featureSet = EnumSet.noneOf(Feature.class); - private final ReentrantLock lock = new ReentrantLock(); - private final VersionNumber exifVersion; - private final Timer cleanupTimer; - private TimerTask currentCleanupTask = null; - private AtomicBoolean shuttingDown = new AtomicBoolean(false); - private volatile ExifProcess process; - private int timeoutWhenKeepAlive = 0; - - public ExifTool() { - this((Feature[]) null); - } - - /** - * In this constructor, exifToolPath and processCleanupDelay are gotten from - * system properties exiftool.path and exiftool.processCleanupDelay. - * processCleanupDelay is optional. If not found, the default is used. - */ - public ExifTool(Feature... features) { + private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + + private static Logger log = Logger.getLogger(ExifTool.class); + + /** + * The absolute path to the ExifTool executable on the host system running + * this class as defined by the "exiftool.path" system + * property. + *

+ * If ExifTool is on your system path and running the command "exiftool" + * successfully executes it, leaving this value unchanged will work fine on + * any platform. If the ExifTool executable is named something else or not + * in the system path, then this property will need to be set to point at it + * before using this class. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.path=/path/to/exiftool + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * On Windows be sure to double-escape the path to the tool, for example: + * + * -Dexiftool.path=C:\\Tools\\exiftool.exe + * + *

+ * Default value is "exiftool". + *

Relative Paths

+ * Relative path values (e.g. "bin/tools/exiftool") are executed with + * relation to the base directory the VM process was started in. Essentially + * the directory that new File(".").getAbsolutePath() points at + * during runtime. + */ + private final String exifCmd; + + /** + * Interval (in milliseconds) of inactivity before the cleanup thread wakes + * up and cleans up the daemon ExifTool process and the read/write streams + * used to communicate with it when the {@link Feature#STAY_OPEN} feature is + * used. + *

+ * Ever time a call to getImageMeta is processed, the timer + * keeping track of cleanup is reset; more specifically, this class has to + * experience no activity for this duration of time before the cleanup + * process is fired up and cleans up the host OS process and the stream + * resources. + *

+ * Any subsequent calls to getImageMeta after a cleanup simply + * re-initializes the resources. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.processCleanupDelay=600000 + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * Setting this value to 0 disables the automatic cleanup thread completely + * and the caller will need to manually cleanup the external ExifTool + * process and read/write streams by calling {@link #close()}. + *

+ * Default value is 600,000 (10 minutes). + */ + private final long processCleanupDelay; + + private final Map featureSupportedMap = new HashMap(); + private final Set featureSet = EnumSet.noneOf(Feature.class); + private final ReentrantLock lock = new ReentrantLock(); + private final VersionNumber exifVersion; + private final Timer cleanupTimer; + private TimerTask currentCleanupTask = null; + private AtomicBoolean shuttingDown = new AtomicBoolean(false); + private volatile ExifProcess process; + private int timeoutWhenKeepAlive = 0; + + public ExifTool(){ + this((Feature[]) null); + } + + /** + * In this constructor, exifToolPath and processCleanupDelay are gotten from system properties + * exiftool.path and exiftool.processCleanupDelay. processCleanupDelay is optional. If not found, + * the default is used. + */ + public ExifTool (Feature ... features){ this( System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, DEFAULT_PROCESS_CLEANUP_DELAY), features ); - } + } - public ExifTool(String exifToolPath) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); - } + public ExifTool(String exifToolPath) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); + } - public ExifTool(String exifToolPath, Feature... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); - } + public ExifTool(String exifToolPath, Feature ... features) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); + } public ExifTool(String exifCmd, long processCleanupDelay, Feature ... features) { - this.exifCmd = exifCmd; - this.processCleanupDelay = processCleanupDelay; - this.exifVersion = ExifProcess.readVersion(exifCmd); - if (features != null && features.length > 0) { - for (Feature feature : features) { - if (!feature.isSupported(exifVersion)) { - throw new UnsupportedFeatureException(feature); - } - this.featureSet.add(feature); - this.featureSupportedMap.put(feature, true); - } - } + this.exifCmd = exifCmd; + this.processCleanupDelay = processCleanupDelay; + this.exifVersion = ExifProcess.readVersion(exifCmd); + if (features != null && features.length > 0) { + for (Feature feature : features) { + if ( ! feature.isSupported(exifVersion) ) { + throw new UnsupportedFeatureException(feature); + } + this.featureSet.add(feature); + this.featureSupportedMap.put(feature,true); + } + } - /* - * Now that initialization is done, init the cleanup timer if we are - * using STAY_OPEN and the delay time set is non-zero. + /* + * Now that initialization is done, init the cleanup timer if we are + * using STAY_OPEN and the delay time set is non-zero. + */ + if (isFeatureEnabled(Feature.STAY_OPEN) ) { + cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); + } else { + cleanupTimer = null; + } + } + + /** + * Limits the amount of time (in mills) an exif operation can take. Setting value to greater than 0 to enable. + */ + public ExifTool setRunTimeout(int mills) { + timeoutWhenKeepAlive = mills; + return this; + } + + /** + * Used to determine if the given {@link Feature} is supported by the + * underlying native install of ExifTool pointed at by + * {@link #exifCmd}. + *

+ * If support for the given feature has not been checked for yet, this + * method will automatically call out to ExifTool and ensure the requested + * feature is supported in the current local install. + *

+ * The external call to ExifTool to confirm feature support is only ever + * done once per JVM session and stored in a static final + * {@link Map} that all instances of this class share. + * + * @param feature + * The feature to check support for in the underlying ExifTool + * install. + * + * @return true if support for the given {@link Feature} was + * confirmed to work with the currently installed ExifTool or + * false if it is not supported. + * + * @throws IllegalArgumentException + * if feature is null. + * @throws RuntimeException + * if any exception occurs while attempting to start the + * external ExifTool process to verify feature support. */ - if (isFeatureEnabled(Feature.STAY_OPEN)) { - cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - } else { - cleanupTimer = null; - } + public boolean isFeatureSupported(Feature feature) throws RuntimeException { + if (feature == null){ + throw new IllegalArgumentException("feature cannot be null"); } - /** - * Limits the amount of time (in mills) an exif operation can take. Setting - * value to greater than 0 to enable. - */ - public ExifTool setRunTimeout(int mills) { - timeoutWhenKeepAlive = mills; - return this; - } + Boolean supported = featureSupportedMap.get(feature); - /** - * Used to determine if the given {@link Feature} is supported by the - * underlying native install of ExifTool pointed at by {@link #exifCmd}. - *

- * If support for the given feature has not been checked for yet, this - * method will automatically call out to ExifTool and ensure the requested - * feature is supported in the current local install. - *

- * The external call to ExifTool to confirm feature support is only ever - * done once per JVM session and stored in a static final - * {@link Map} that all instances of this class share. - * - * @param feature - * The feature to check support for in the underlying ExifTool - * install. - * - * @return true if support for the given {@link Feature} was - * confirmed to work with the currently installed ExifTool or - * false if it is not supported. - * - * @throws IllegalArgumentException - * if feature is null. - * @throws RuntimeException - * if any exception occurs while attempting to start the - * external ExifTool process to verify feature support. - */ - public boolean isFeatureSupported(Feature feature) throws RuntimeException { - if (feature == null) { - throw new IllegalArgumentException("feature cannot be null"); + /* + * If there is no Boolean flag for the feature, support for it hasn't + * been checked yet with the native ExifTool install, so we need to do + * that. + */ + if (supported == null) { + log.debug("Support for feature %s has not been checked yet, checking..."); + supported = feature.isSupported(exifVersion); + featureSupportedMap.put(feature,supported); + } + + return supported; } - Boolean supported = featureSupportedMap.get(feature); - /* - * If there is no Boolean flag for the feature, support for it hasn't - * been checked yet with the native ExifTool install, so we need to do - * that. - */ - if (supported == null) { - log.debug("Support for feature %s has not been checked yet, checking..."); - supported = feature.isSupported(exifVersion); - featureSupportedMap.put(feature, supported); - } - return supported; - } - /** - * Used to startup the external ExifTool process and open the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. This method has no effect if the stay open feature is not - * enabled. - */ - public void startup() { - if (featureSet.contains(Feature.STAY_OPEN)) { - shuttingDown.set(false); - ensureProcessRunning(); - } - } - private void ensureProcessRunning() { - if (process == null || process.isClosed()) { - synchronized (this) { - if (process == null || process.isClosed()) { - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = ExifProcess.startup(exifCmd); - } - } - } - if (processCleanupDelay > 0) { - synchronized (this) { - if (currentCleanupTask != null) { - currentCleanupTask.cancel(); - currentCleanupTask = null; - } - currentCleanupTask = new TimerTask() { - @Override - public void run() { - log.info("Auto cleanup task running..."); - process.close(); - } - }; - cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); - } - } + /** + * Used to startup the external ExifTool process and open the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. This method has no effect if the stay open feature is not enabled. + */ + public void startup(){ + if (featureSet.contains(Feature.STAY_OPEN)){ + shuttingDown.set(false); + ensureProcessRunning(); } - - /** - * This is same as {@link #close()}, added for consistency with - * {@link #startup()} - */ - public void shutdown() { - close(); + } + private void ensureProcessRunning(){ + if (process ==null || process.isClosed()) { + synchronized (this){ + if (process ==null || process.isClosed() ){ + log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = ExifProcess.startup(exifCmd); + } + } } - - /** - * Used to shutdown the external ExifTool process and close the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. - *

- * NOTE: Calling this method does not preclude this - * instance of {@link ExifTool} from being re-used, it merely disposes of - * the native and internal resources until the next call to - * getImageMeta causes them to be re-instantiated. - *

- * The cleanup thread will automatically call this after an interval of - * inactivity defined by {@link #processCleanupDelay}. - *

- * Calling this method on an instance of this class without - * {@link Feature#STAY_OPEN} support enabled has no effect. - */ - public synchronized void close() { - shuttingDown.set(true); - if (process != null) { - process.close(); - } - if (currentCleanupTask != null) { - currentCleanupTask.cancel(); - currentCleanupTask = null; - } + if ( processCleanupDelay > 0 ) { + synchronized (this) { + if ( currentCleanupTask != null ) { + currentCleanupTask.cancel(); + currentCleanupTask = null; + } + currentCleanupTask = new TimerTask() { + @Override + public void run() { + log.info("Auto cleanup task running..."); + process.close(); + } + }; + cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); + } } + } - public boolean isStayOpen() { - return featureSet.contains(Feature.STAY_OPEN); - } + /** + * This is same as {@link #close()}, added for consistency with {@link #startup()} + */ + public void shutdown(){ + close(); + } - /** - * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support - * enabled, this method is used to determine if there is currently a running - * ExifTool process associated with this class. - *

- * Any dependent processes and streams can be shutdown using - * {@link #close()} and this class will automatically re-create them on the - * next call to getImageMeta if necessary. - * - * @return true if there is an external ExifTool process in - * daemon mode associated with this class utilizing the - * {@link Feature#STAY_OPEN} feature, otherwise returns - * false. - */ - public boolean isRunning() { - return process != null && !process.isClosed(); + + /** + * Used to shutdown the external ExifTool process and close the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. + *

+ * NOTE: Calling this method does not preclude this + * instance of {@link ExifTool} from being re-used, it merely disposes of + * the native and internal resources until the next call to + * getImageMeta causes them to be re-instantiated. + *

+ * The cleanup thread will automatically call this after an interval of + * inactivity defined by {@link #processCleanupDelay}. + *

+ * Calling this method on an instance of this class without + * {@link Feature#STAY_OPEN} support enabled has no effect. + */ + public synchronized void close() { + shuttingDown.set(true); + if ( process != null ) { + process.close(); } + if(currentCleanupTask != null) { + currentCleanupTask.cancel(); + currentCleanupTask = null; + } + } - /** - * Used to determine if the given {@link Feature} has been enabled for this - * particular instance of {@link ExifTool}. - *

- * This method is different from {@link #isFeatureSupported(Feature)}, which - * checks if the given feature is supported by the underlying ExifTool - * install where as this method tells the caller if the given feature has - * been enabled for use in this particular instance. - * - * @param feature - * The feature to check if it has been enabled for us or not on - * this instance. - * - * @return true if the given {@link Feature} is currently - * enabled on this instance of {@link ExifTool}, otherwise returns - * false. - * - * @throws IllegalArgumentException - * if feature is null. - */ - public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException { - if (feature == null) { - throw new IllegalArgumentException("feature cannot be null"); + public boolean isStayOpen() { + return featureSet.contains(Feature.STAY_OPEN); + } + + /** + * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support + * enabled, this method is used to determine if there is currently a running + * ExifTool process associated with this class. + *

+ * Any dependent processes and streams can be shutdown using + * {@link #close()} and this class will automatically re-create them on the + * next call to getImageMeta if necessary. + * + * @return true if there is an external ExifTool process in + * daemon mode associated with this class utilizing the + * {@link Feature#STAY_OPEN} feature, otherwise returns + * false. + */ + public boolean isRunning() { + return process != null && ! process.isClosed(); } - return featureSet.contains(feature); + + /** + * Used to determine if the given {@link Feature} has been enabled for this + * particular instance of {@link ExifTool}. + *

+ * This method is different from {@link #isFeatureSupported(Feature)}, which + * checks if the given feature is supported by the underlying ExifTool + * install where as this method tells the caller if the given feature has + * been enabled for use in this particular instance. + * + * @param feature + * The feature to check if it has been enabled for us or not on + * this instance. + * + * @return true if the given {@link Feature} is currently + * enabled on this instance of {@link ExifTool}, otherwise returns + * false. + * + * @throws IllegalArgumentException + * if feature is null. + */ + public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException { + if (feature == null){ + throw new IllegalArgumentException("feature cannot be null"); } + return featureSet.contains(feature); + } - public Map getImageMeta(File image, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { + public Map getImageMeta(File image, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { - return getImageMeta(image, Format.NUMERIC, tags); - } + return getImageMeta(image, Format.NUMERIC, tags); + } - public Map getImageMeta(File image, Format format, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { + public Map getImageMeta(File image, Format format, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { - String[] stringTags = new String[tags.length]; - int i = 0; - for (Tag tag : tags) { - stringTags[i++] = tag.getName(); - } - Map result = getImageMeta(image, format, true, stringTags); - return mapByTag(result); + String [] stringTags = new String[tags.length]; + int i=0; + for (Tag tag : tags){ + stringTags[i++] = tag.getName(); } + Map result = getImageMeta(image, format, true, stringTags); + return mapByTag(result); + } public Map getImageMeta(File image, Format format, TagGroup... tags) throws IllegalArgumentException, SecurityException, IOException { - String[] stringTags = new String[tags.length]; - int i = 0; - for (TagGroup tag : tags) { - stringTags[i++] = tag.getValue(); - } - return getImageMeta(image, format, false, stringTags); + String [] stringTags = new String[tags.length]; + int i=0; + for (TagGroup tag : tags){ + stringTags[i++] = tag.getValue(); } + return getImageMeta(image, format, false, stringTags); + } private Map getImageMeta(final File image, final Format format, final boolean suppressDuplicates, final String... tags) throws IllegalArgumentException, SecurityException, IOException { - // Validate input and create Arg Array - final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); - List args = new ArrayList(tags.length + 4); - if (format == null) { - throw new IllegalArgumentException("format cannot be null"); - } else if (format == Format.NUMERIC) { - args.add("-n"); // numeric output - } - if (!suppressDuplicates) { - args.add("-a"); // suppress duplicates - } - args.add("-S"); // compact output + //Validate input and create Arg Array + final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + List args = new ArrayList(tags.length+4); + if (format == null){ + throw new IllegalArgumentException("format cannot be null"); + } else if (format == Format.NUMERIC){ + args.add("-n"); // numeric output + } + if (!suppressDuplicates){ + args.add("-a"); //suppress duplicates + } + args.add("-S"); // compact output - if (tags == null || tags.length == 0) { + if (tags == null || tags.length == 0){ throw new IllegalArgumentException("tags cannot be null and must contain 1 or more Tag to query the image for."); - } - for (String tag : tags) { - args.add("-" + tag); - } - if (image == null) { + } + for (String tag : tags) { + args.add("-" + tag); + } + if (image == null){ throw new IllegalArgumentException("image cannot be null and must be a valid stream of image data."); - } - if (!image.canRead()) { + } + if (!image.canRead()){ throw new SecurityException("Unable to read the given image ["+image.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); - } - args.add(image.getAbsolutePath()); + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + } + args.add(image.getAbsolutePath()); - // start process - long startTime = System.currentTimeMillis(); + //start process + long startTime = System.currentTimeMillis(); log.debug(String.format("Querying %d tags from image: %s", tags.length, image.getAbsolutePath())); - /* - * Using ExifTool in daemon mode (-stay_open True) executes different - * code paths below. So establish the flag for this once and it is - * reused a multitude of times later in this method to figure out where - * to branch to. - */ - Map resultMap; - if (stayOpen) { - log.debug("Using ExifTool in daemon mode (-stay_open True)..."); - resultMap = processStayOpen(args); - } else { - log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd, args); - } + /* + * Using ExifTool in daemon mode (-stay_open True) executes different + * code paths below. So establish the flag for this once and it is + * reused a multitude of times later in this method to figure out where + * to branch to. + */ + Map resultMap; + if (stayOpen) { + log.debug("Using ExifTool in daemon mode (-stay_open True)..."); + resultMap = processStayOpen(args); + } else { + log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); + resultMap = ExifProcess.executeToResults(exifCmd,args); + } - // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()) { + // Print out how long the call to external ExifTool process took. + if (log.isDebugEnabled()){ log.debug(String.format("Image Meta Processed in %d ms [queried %d tags and found %d values]", (System.currentTimeMillis() - startTime), tags.length, resultMap.size())); - } - - return resultMap; - } - - /** - * extract image metadata to exiftool's internal xml format. - * - * @param input - * the input file - * @return command output as xml string - * @throws IOException - * Signals that an I/O exception has occurred. - */ - public String getImageMetadataXml(File input, boolean includeBinary) - throws IOException { - List args = new ArrayList(); - args.add("-X"); - if (includeBinary) - args.add("-b"); - args.add(input.getAbsolutePath()); - - return ExifProcess.executeToString(exifCmd, args); } - /** - * extract image metadata to exiftool's internal xml format. - * - * @param input - * the input file - * @param output - * the output file - * @throws IOException - * Signals that an I/O exception has occurred. - */ - public void getImageMetadataXml(File input, File output, - boolean includeBinary) throws IOException { - - String result = getImageMetadataXml(input, includeBinary); - - try (FileWriter w = new FileWriter(output)) { - w.write(result); + return resultMap; } - } - - /** - * output icc profile from input to output. - * - * @param input - * the input file - * @param output - * the output file for icc data - * @return the command result from standard output e.g. - * "1 output files created" - * @throws IOException - * Signals that an I/O exception has occurred. - */ - public String getImageIccProfile(File input, File output) - throws IOException { - List args = new ArrayList(); - args.add("-icc_profile"); - args.add(input.getAbsolutePath()); - - args.add("-o"); - args.add(output.getAbsolutePath()); - - return ExifProcess.executeToString(exifCmd, args); - } - - /** - * Extract thumbnail from the given tag. - * - * @param input - * the input file - * @param tag - * the tag containing binary data - * @return the thumbnail file created. it is in the same folder as the input - * file because of the syntax of exiftool and has the suffix - * ".thumb.jpg" - * @throws IOException - * Signals that an I/O exception has occurred. - */ - public File extractThumbnail(File input, Tag tag) throws IOException { - - List args = new ArrayList(); - String suffix = ".thumb.jpg"; - String thumbname = FilenameUtils.getBaseName(input.getName()) + suffix; - - args.add("-" + tag.getName()); - args.add(input.getAbsolutePath()); - args.add("-b"); - args.add("-w"); - args.add(suffix); - String result = ExifProcess.executeToString(exifCmd, args); - File thumbnail = new File(input.getParent() + File.separator - + thumbname); - if (!thumbnail.exists()) - throw new IOException("could not create thumbnail: " + result); - return thumbnail; - } - - /** - * Will attempt 3 times to use the running exif process, and if unable to - * complete successfully will throw IOException - */ + /** + * Will attempt 3 times to use the running exif process, and if unable to complete successfully will throw IOException + */ private Map processStayOpen(List args) throws IOException { - int attempts = 0; - while (attempts < 3 && !shuttingDown.get()) { - attempts++; - // make sure process is started - ensureProcessRunning(); - TimerTask attemptTimer = null; - try { - if (timeoutWhenKeepAlive > 0) { - attemptTimer = new TimerTask() { - @Override - public void run() { + int attempts = 0; + while (attempts < 3 && ! shuttingDown.get()){ + attempts++; + //make sure process is started + ensureProcessRunning(); + TimerTask attemptTimer = null; + try { + if ( timeoutWhenKeepAlive > 0 ) { + attemptTimer = new TimerTask() { + public void run() { log.warn("Process ran too long closing, max "+timeoutWhenKeepAlive+" mills"); - process.close(); - } - }; - cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); - } - log.debug("Streaming arguments to ExifTool process..."); - return process.sendArgs(args); - } catch (IOException ex) { + process.close(); + } + }; + cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); + } + log.debug("Streaming arguments to ExifTool process..."); + return process.sendArgs(args); + } catch (IOException ex){ if ( STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) && ! shuttingDown.get() ){ //only catch "Stream Closed" error (happens when process has died) log.warn(String.format("Caught IOException(\"%s\"), will restart daemon",STREAM_CLOSED_MESSAGE)); - process.close(); - } else { - throw ex; - } - } finally { + process.close(); + } else { + throw ex; + } + } finally { if ( attemptTimer != null ) attemptTimer.cancel(); - } - } - if (shuttingDown.get()) { - throw new IOException("Shutting Down"); - } - throw new IOException("Ran out of attempts"); + } } - - private static Map mapByTag(Map stringMap) { - Map tagMap = new HashMap(Tag.values().length); - for (Tag tag : Tag.values()) { - if (stringMap.containsKey(tag.getName())) { - tagMap.put(tag, stringMap.get(tag.getName())); - } - } - return tagMap; + if ( shuttingDown.get() ) { + throw new IOException("Shutting Down"); } - - // ================================================================================ - /** - * Represents an Exif Process. - */ - public static class ExifProcess { - private final ReentrantLock closeLock = new ReentrantLock(false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; - private volatile boolean closed = false; - - public static VersionNumber readVersion(String exifCmd) { + throw new IOException("Ran out of attempts"); + } + + private static Map mapByTag(Map stringMap){ + Map tagMap = new HashMap(Tag.values().length); + for (Tag tag : Tag.values()){ + if (stringMap.containsKey(tag.getName())){ + tagMap.put(tag, stringMap.get(tag.getName())); + } + } + return tagMap; + } + + + //================================================================================ + /** + * Represents an Exif Process. + */ + public static class ExifProcess { + private final ReentrantLock closeLock = new ReentrantLock(false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader reader; + private final OutputStreamWriter writer; + private volatile boolean closed = false; + + public static VersionNumber readVersion(String exifCmd) { ExifProcess process =_execute(false, Arrays.asList(exifCmd,"-ver")); - try { - return new VersionNumber(process.readLine()); - } catch (IOException ex) { + try { + return new VersionNumber(process.readLine()); + } catch (IOException ex) { throw new RuntimeException(String.format("Unable to check version number of ExifTool: %s",exifCmd)); - } finally { - process.close(); - } - } + } finally { + process.close(); + } + } public static Map executeToResults(String exifCmd, List args) throws IOException { - List newArgs = new ArrayList(args.size() + 1); - newArgs.add(exifCmd); - newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); - try { - return process.readResponse(); - } finally { - process.close(); - } - } - - public static String executeToString(String exifCmd, List args) - throws IOException { - List newArgs = new ArrayList(args.size() + 1); - newArgs.add(exifCmd); - newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); - try { - return process.readResponseString(); - } finally { - process.close(); - } - } + List newArgs = new ArrayList(args.size()+1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { + return process.readResponse(); + } finally { + process.close(); + } + } - public static ExifProcess startup(String exifCmd) { + public static ExifProcess startup(String exifCmd) { List args = Arrays.asList(exifCmd,"-stay_open", "True", "-@", "-"); - return _execute(true, args); - } + return _execute(true, args); + } - public static ExifProcess _execute(boolean keepAlive, List args) { + public static ExifProcess _execute(boolean keepAlive, List args) { log.debug(String.format("Attempting to start external ExifTool process using args: %s", args)); - try { - Process process = new ProcessBuilder(args).start(); - log.debug("\tSuccessful"); - return new ExifProcess(keepAlive, process); - } catch (Exception e) { - String message = "Unable to start external ExifTool process using the execution arguments: " - + args - + ". Ensure ExifTool is installed correctly and runs using the command path '" - + args.get(0) - + "' as specified by the 'exiftool.path' system property."; - - log.debug(message); - throw new RuntimeException(message, e); - } - } + try { + Process process = new ProcessBuilder(args).start(); + log.debug("\tSuccessful"); + return new ExifProcess(keepAlive,process); + } catch (Exception e) { + String message = "Unable to start external ExifTool process using the execution arguments: " + + args + + ". Ensure ExifTool is installed correctly and runs using the command path '" + + args.get(0) + + "' as specified by the 'exiftool.path' system property."; + + log.debug(message); + throw new RuntimeException(message, e); + } + } - public ExifProcess(boolean keepAlive, Process process) { - this.keepAlive = keepAlive; - this.process = process; + public ExifProcess(boolean keepAlive,Process process) { + this.keepAlive = keepAlive; + this.process = process; this.reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream()); - } + this.writer = new OutputStreamWriter(process.getOutputStream()); + } public synchronized Map sendArgs(List args) throws IOException { - StringBuilder builder = new StringBuilder(); - for (String arg : args) { - builder.append(arg).append("\n"); - } - builder.append("-execute\n"); - writeFlush(builder.toString()); - return readResponse(); - } + StringBuilder builder = new StringBuilder(); + for(String arg : args) { + builder.append(arg).append("\n"); + } + builder.append("-execute\n"); + writeFlush(builder.toString()); + return readResponse(); + } - public synchronized void writeFlush(String message) throws IOException { + + public synchronized void writeFlush(String message) throws IOException { if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - writer.write(message); - writer.flush(); - } + writer.write(message); + writer.flush(); + } - public synchronized String readLine() throws IOException { + public synchronized String readLine() throws IOException { if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - return reader.readLine(); - } + return reader.readLine(); + } public synchronized Map readResponse() throws IOException { if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - Map resultMap = new HashMap(500); - String line; + log.debug("Reading response back from ExifTool..."); + Map resultMap = new HashMap(500); + String line; - while ((line = reader.readLine()) != null) { + while ((line = reader.readLine()) != null) { if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - String[] pair = TAG_VALUE_PATTERN.split(line, 2); + String[] pair = TAG_VALUE_PATTERN.split(line, 2); - if (pair.length == 2) { - resultMap.put(pair[0], pair[1]); + if (pair.length == 2) { + resultMap.put(pair[0], pair[1]); log.debug(String.format("\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); - } - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need - * to look for it and break from this loop when we see it - * otherwise this process will hang indefinitely blocking on the - * input stream with no data to read. - */ - if (keepAlive && line.equals("{ready}")) { - break; - } - } - return resultMap; - } - - public synchronized String readResponseString() throws IOException { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - String line; - StringBuilder result = new StringBuilder(); - while ((line = reader.readLine()) != null) { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need - * to look for it and break from this loop when we see it - * otherwise this process will hang indefinitely blocking on the - * input stream with no data to read. - */ - if (keepAlive && line.equals("{ready}")) { - break; - } else - result.append(line); - } - return result.toString(); - } - - public boolean isClosed() { - return closed; - } + } + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need to + * look for it and break from this loop when we see it otherwise + * this process will hang indefinitely blocking on the input stream + * with no data to read. + */ + if (keepAlive && line.equals("{ready}")){ + break; + } + } + return resultMap; + } - public void close() { - if (!closed) { - closeLock.lock(); - try { - if (!closed) { - closed = true; - log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - try { - writer.write("-stay_open\nFalse\n"); - writer.flush(); - } catch (IOException ex) { - // log.error(ex,ex); - } - try { - log.debug("Closing Read stream..."); - reader.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log.debug("Closing Write stream..."); - writer.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - log.debug("Read/Write streams successfully closed."); - - try { - process.destroy(); - } catch (Exception e) { - // - } - // process = null; - - } - } finally { - closeLock.unlock(); - } - } - } + public boolean isClosed() { + return closed; } - // ================================================================================ + public void close() { + if ( ! closed ) { + closeLock.lock(); + try { + if ( ! closed ) { + closed = true; + log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); + try { + writer.write("-stay_open\nFalse\n"); + writer.flush(); + } catch (IOException ex) { + //log.error(ex,ex); + } + try { + log.debug("Closing Read stream..."); + reader.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + log.debug("Closing Write stream..."); + writer.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + log.debug("Read/Write streams successfully closed."); + + try { + process.destroy(); + } catch (Exception e) { + // + } + //process = null; + + } + } finally { + closeLock.unlock(); + } + } + } + } + + //================================================================================ + /** + * Enum used to define the different kinds of features in the native + * ExifTool executable that this class can help you take advantage of. + *

+ * These flags are different from {@link Tag}s in that a "feature" is + * determined to be a special functionality of the underlying ExifTool + * executable that requires a different code-path in this class to take + * advantage of; for example, -stay_open True support. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Feature { /** - * Enum used to define the different kinds of features in the native - * ExifTool executable that this class can help you take advantage of. + * Enum used to specify that you wish to launch the underlying ExifTool + * process with -stay_open True support turned on that this + * class can then take advantage of. *

- * These flags are different from {@link Tag}s in that a "feature" is - * determined to be a special functionality of the underlying ExifTool - * executable that requires a different code-path in this class to take - * advantage of; for example, -stay_open True support. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 + * Required ExifTool version is 8.36 or higher. */ - public enum Feature { - /** - * Enum used to specify that you wish to launch the underlying ExifTool - * process with -stay_open True support turned on that this - * class can then take advantage of. - *

- * Required ExifTool version is 8.36 or higher. - */ - STAY_OPEN(8, 36); + STAY_OPEN(8,36); private VersionNumber requireVersion; - private Feature(int... numbers) { - this.requireVersion = new VersionNumber(numbers); - } - - /** - * Used to get the version of ExifTool required by this feature in order - * to work. - * - * @return the version of ExifTool required by this feature in order to - * work. - */ - VersionNumber getVersion() { - return requireVersion; - } - - boolean isSupported(VersionNumber exifVersionNumber) { - return requireVersion.isBeforeOrEqualTo(exifVersionNumber); - } + private Feature(int... numbers) { + this.requireVersion = new VersionNumber(numbers); } - - // ================================================================================ /** - * Version Number used to determine if one version is after another. + * Used to get the version of ExifTool required by this feature in order + * to work. + * + * @return the version of ExifTool required by this feature in order to + * work. */ - static class VersionNumber { - private final int[] numbers; - - public VersionNumber(String str) { - String[] versionParts = str.trim().split("\\."); - this.numbers = new int[versionParts.length]; - for (int i = 0; i < versionParts.length; i++) { - numbers[i] = Integer.parseInt(versionParts[i]); - } - } - - public VersionNumber(int... numbers) { - this.numbers = numbers; - } + VersionNumber getVersion() { + return requireVersion; + } - public boolean isBeforeOrEqualTo(VersionNumber other) { - int max = Math.min(this.numbers.length, other.numbers.length); - for (int i = 0; i < max; i++) { - if (this.numbers[i] > other.numbers[i]) { - return false; - } else if (this.numbers[i] < other.numbers[i]) { - return true; - } - } - //assume missing number as zero, so if the current process number is more digits it is a higher version - return this.numbers.length <= other.numbers.length; - } + boolean isSupported(VersionNumber exifVersionNumber) { + return requireVersion.isBeforeOrEqualTo(exifVersionNumber); + } + } + + //================================================================================ + /** + * Version Number used to determine if one version is after another. + */ + static class VersionNumber { + private final int[] numbers; + + public VersionNumber(String str) { + String[] versionParts = str.trim().split("\\."); + this.numbers = new int[versionParts.length]; + for(int i=0; i 0) { - builder.append("."); - } - builder.append(numbers[i]); - } - return builder.toString(); - } + public VersionNumber(int... numbers) { + this.numbers = numbers; } - // ================================================================================ - /** - * Enum used to define the 2 different output formats that {@link Tag} - * values can be returned in: numeric or human-readable text. - *

- * ExifTool, via the -n command line arg, is capable of - * returning most values in their raw numeric form (e.g. - * Aperture="2.8010323841") as well as a more human-readable/friendly format - * (e.g. Aperture="2.8"). - *

- * While the {@link Tag}s defined on this class do provide a hint at the - * type of the result (see {@link Tag#getType()}), that hint only applies - * when the {@link Format#NUMERIC} form of the value is returned. - *

- * If the caller finds the human-readable format easier to process, - * {@link Format#HUMAN_READABLE} can be specified when calling - * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned - * {@link String} values processed manually by the caller. - *

- * In order to see the types of values that are returned when - * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive - * ExifTool Tag Guide. - *

- * This makes sense with some values like Aperture that in - * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high - * precision values that are near the intended value (e.g. - * "2.79999992203711" instead of just returning "2.8"). On the other hand, - * other values (like Orientation) are easier to parse when their numeric - * value (1-8) is returned instead of a much longer friendly name (e.g. - * "Mirror horizontal and rotate 270 CW"). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Format { - NUMERIC, HUMAN_READABLE + public boolean isBeforeOrEqualTo(VersionNumber other) { + int max = Math.min(this.numbers.length, other.numbers.length); + for(int i=0; i other.numbers[i] ) { + return false; + } else if ( this.numbers[i] < other.numbers[i] ) { + return true; + } + } + //assume missing number as zero, so if the current process number is more digits it is a higher version + return this.numbers.length <= other.numbers.length; } - // ================================================================================ - /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifTool. - *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default {@link Format#NUMERIC} value format - * is used. - *

- * All replies from ExifTool are parsed as {@link String}s and using the - * type hint from each {@link Tag} can easily be converted to the correct - * data format by using the provided {@link Tag#parseValue(String)} method. - *

- * This class does not make an attempt at converting the value automatically - * in case the caller decides they would prefer tag values returned in - * {@link Format#HUMAN_READABLE} format and to avoid any compatibility - * issues with future versions of ExifTool if a tag's return value is - * changed. This approach to leaving returned tag values as strings until - * the caller decides they want to parse them is a safer and more robust - * approach. - *

- * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. - *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. - *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. - *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Tag { - // single entry tags + public String toString() { + StringBuilder builder = new StringBuilder(); + for(int i=0; i 0 ) { + builder.append("."); + } + builder.append(numbers[i]); + } + return builder.toString(); + } + } + + + //================================================================================ + /** + * Enum used to define the 2 different output formats that {@link Tag} + * values can be returned in: numeric or human-readable text. + *

+ * ExifTool, via the -n command line arg, is capable of + * returning most values in their raw numeric form (e.g. + * Aperture="2.8010323841") as well as a more human-readable/friendly format + * (e.g. Aperture="2.8"). + *

+ * While the {@link Tag}s defined on this class do provide a hint at the + * type of the result (see {@link Tag#getType()}), that hint only applies + * when the {@link Format#NUMERIC} form of the value is returned. + *

+ * If the caller finds the human-readable format easier to process, + * {@link Format#HUMAN_READABLE} can be specified when calling + * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned + * {@link String} values processed manually by the caller. + *

+ * In order to see the types of values that are returned when + * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive + * ExifTool Tag Guide. + *

+ * This makes sense with some values like Aperture that in + * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high + * precision values that are near the intended value (e.g. + * "2.79999992203711" instead of just returning "2.8"). On the other hand, + * other values (like Orientation) are easier to parse when their numeric + * value (1-8) is returned instead of a much longer friendly name (e.g. + * "Mirror horizontal and rotate 270 CW"). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Format { + NUMERIC, HUMAN_READABLE + } + //================================================================================ + /** + * Enum used to pre-define a convenient list of tags that can be easily + * extracted from images using this class with an external install of + * ExifTool. + *

+ * Each tag defined also includes a type hint for the parsed value + * associated with it when the default {@link Format#NUMERIC} value format + * is used. + *

+ * All replies from ExifTool are parsed as {@link String}s and using the + * type hint from each {@link Tag} can easily be converted to the correct + * data format by using the provided {@link Tag#parseValue(String)} + * method. + *

+ * This class does not make an attempt at converting the value automatically + * in case the caller decides they would prefer tag values returned in + * {@link Format#HUMAN_READABLE} format and to avoid any compatibility + * issues with future versions of ExifTool if a tag's return value is + * changed. This approach to leaving returned tag values as strings until + * the caller decides they want to parse them is a safer and more robust + * approach. + *

+ * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or + * process the returned {@link String} values any way they wish. + *

Tag Support

+ * ExifTool is capable of parsing almost every tag known to man (1000+), but + * this class makes an attempt at pre-defining a convenient list of the most + * common tags for use. + *

+ * This list was determined by looking at the common metadata tag values + * written to images by popular mobile devices (iPhone, Android) as well as + * cameras like simple point and shoots as well as DSLRs. As an additional + * source of input the list of supported/common EXIF formats that Flickr + * supports was also reviewed to ensure the most common/useful tags were + * being covered here. + *

+ * Please email me or file an issue + * if you think this list is missing a commonly used tag that should be + * added to it. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Tag { + //single entry tags APERTURE("ApertureValue", Double.class), AUTHOR("XPAuthor", String.class), COLOR_SPACE("ColorSpace", Integer.class), @@ -1210,179 +1061,172 @@ public enum Tag { WHITE_BALANCE("WhiteBalance", Integer.class), X_RESOLUTION("XResolution", Double.class), Y_RESOLUTION("YResolution", Double.class), - // select ICC metadata - ICC_DESCRIPTION("ProfileDescription", String.class), - ICC_COLORSPACEDATA( "ColorSpaceData", String.class), - // actually binary data, but what are we doing to do here??? Just use to - // save to file... - THUMBNAIL_IMAGE("ThumbnailImage", String.class), - THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class); + ; - /** - * Used to get the {@link Tag} identified by the given, case-sensitive, - * tag name. - * - * @param name - * The case-sensitive name of the tag that will be searched - * for. - * - * @return the {@link Tag} identified by the given, case-sensitive, tag - * name or null if one couldn't be found. - */ - public static Tag forName(String name) { - for (Tag tag : Tag.values()) { - if (tag.getName().equals(name)) { - return tag; - } - } - return null; - } + /** + * Used to get the {@link Tag} identified by the given, case-sensitive, + * tag name. + * + * @param name + * The case-sensitive name of the tag that will be searched + * for. + * + * @return the {@link Tag} identified by the given, case-sensitive, tag + * name or null if one couldn't be found. + */ + public static Tag forName(String name) { + for (Tag tag : Tag.values()){ + if (tag.getName().equals(name)){ + return tag; + } + } + return null; + } - /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifTool process) into the type described - * by the associated {@link Tag}. - * - * @param - * The type of the returned value. - * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. - * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). - * - * @throws IllegalArgumentException - * if tag is null. - * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). - * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. - */ - @SuppressWarnings("unchecked") - public T parseValue(String value) throws IllegalArgumentException { - - if (value != null) { - if (Boolean.class.isAssignableFrom(this.getType())) { - return (T) Boolean.valueOf(value); - } else if (Byte.class.isAssignableFrom(this.getType())) { - return (T) Byte.valueOf(Byte.parseByte(value)); - } else if (Integer.class.isAssignableFrom(this.getType())) { - return (T) Integer.valueOf(Integer.parseInt(value)); - } else if (Short.class.isAssignableFrom(this.getType())) { - return (T) Short.valueOf(Short.parseShort(value)); - } else if (Long.class.isAssignableFrom(this.getType())) { - return (T) Long.valueOf(Long.parseLong(value)); - } else if (Float.class.isAssignableFrom(this.getType())) { - return (T) Float.valueOf(Float.parseFloat(value)); - } else if (Double.class.isAssignableFrom(this.getType())) { - return (T) parseDouble(value); - } else if (Character.class.isAssignableFrom(this.getType())) { - return (T) Character.valueOf(value.charAt(0)); - } else if (String.class.isAssignableFrom(this.getType())) { - return (T) value; - } - } - return null; - } + /** + * Convenience method used to convert the given string Tag value + * (returned from the external ExifTool process) into the type described + * by the associated {@link Tag}. + * + * @param + * The type of the returned value. + * @param value + * The {@link String} representation of the tag's value as + * parsed from the image. + * + * @return the given string value converted to a native Java type (e.g. + * Integer, Double, etc.). + * + * @throws IllegalArgumentException + * if tag is null. + * @throws NumberFormatException + * if any exception occurs while trying to parse the given + * value to any of the supported numeric types + * in Java via calls to the respective parseXXX + * methods defined on all the numeric wrapper classes (e.g. + * {@link Integer#parseInt(String)} , + * {@link Double#parseDouble(String)} and so on). + * @throws ClassCastException + * if the type defined by T is incompatible + * with the type defined by {@link Tag#getType()} returned + * by the tag argument passed in. This class + * performs an implicit/unchecked cast to the type + * T before returning the parsed result of the + * type indicated by {@link Tag#getType()}. If the types do + * not match, a ClassCastException will be + * generated by the VM. + */ + @SuppressWarnings("unchecked") + public T parseValue(String value) throws IllegalArgumentException { + + if (value != null) { + if (Boolean.class.isAssignableFrom(this.getType())){ + return (T) Boolean.valueOf(value); + } else if (Byte.class.isAssignableFrom(this.getType())){ + return (T) Byte.valueOf(Byte.parseByte(value)); + } else if (Integer.class.isAssignableFrom(this.getType())){ + return (T) Integer.valueOf(Integer.parseInt(value)); + } else if (Short.class.isAssignableFrom(this.getType())){ + return (T) Short.valueOf(Short.parseShort(value)); + } else if (Long.class.isAssignableFrom(this.getType())){ + return (T) Long.valueOf(Long.parseLong(value)); + } else if (Float.class.isAssignableFrom(this.getType())){ + return (T) Float.valueOf(Float.parseFloat(value)); + } else if (Double.class.isAssignableFrom(this.getType())){ + return (T) parseDouble(value); + } else if (Character.class.isAssignableFrom(this.getType())){ + return (T) Character.valueOf(value.charAt(0)); + } else if (String.class.isAssignableFrom(this.getType())){ + return (T) value; + } + } + return null; + } - private Double parseDouble(String in) { - if (in.contains("/")) { - String[] enumeratorAndDivisor = in.split("/"); + private Double parseDouble(String in) { + if (in.contains("/")) { + String[] enumeratorAndDivisor = in.split("/"); return Double.parseDouble(enumeratorAndDivisor[0]) / Double.parseDouble(enumeratorAndDivisor[1]); - } else { - return Double.parseDouble(in); - } - } + } else { + return Double.parseDouble(in); + } + } - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ - public String getName() { - return name; - } + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ + public String getName() { + return name; + } - /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifTool Tag Guide. - * - * @return a hint for the native type of this tag's value. - */ - public Class getType() { - return type; - } + /** + * Used to get a hint for the native type of this tag's value as + * specified by Phil Harvey's ExifTool Tag Guide. + * + * @return a hint for the native type of this tag's value. + */ + public Class getType() { + return type; + } - private String name; - private Class type; + private String name; + private Class type; - private Tag(String name, Class type) { - this.name = name; - this.type = type; - } + private Tag(String name, Class type) { + this.name = name; + this.type = type; } + } - // ================================================================================ - public enum TagGroup { + //================================================================================ + public enum TagGroup { EXIF("EXIF","exif:all"), IPTC("IPTC", "iptc:all"), XMP("XMP", "xmp:all"), - ALL("ALL", "all"), - FILE("FILE", "file:all"), - ICC("ICC", "icc_profile:all"); + ALL("ALL", "all"); - private final String name; - private final String value; + private final String name; + private final String value; - private TagGroup(String name, String value) { - this.name = name; - this.value = value; - } + private TagGroup(String name, String value) { + this.name = name; + this.value = value; + } - public String getName() { - return name; - } + public String getName() { + return name; + } - public String getValue() { - return value; - } + public String getValue() { + return value; } + } - // ================================================================================ - /** - * Class used to define an exception that occurs when the caller attempts to - * use a {@link Feature} that the underlying native ExifTool install does - * not support (i.e. the version isn't new enough). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public class UnsupportedFeatureException extends RuntimeException { - private static final long serialVersionUID = -1332725983656030770L; - - public UnsupportedFeatureException(Feature feature) { - super( - "Use of feature [" - + feature.toString() - + "] requires version " - + feature.getVersion() - + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); - } - } + //================================================================================ + /** + * Class used to define an exception that occurs when the caller attempts to + * use a {@link Feature} that the underlying native ExifTool install does + * not support (i.e. the version isn't new enough). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public class UnsupportedFeatureException extends RuntimeException { + private static final long serialVersionUID = -1332725983656030770L; + + public UnsupportedFeatureException(Feature feature) { + super( + "Use of feature [" + + feature.toString() + + "] requires version " + + feature.getVersion() + + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); + } + + } } \ No newline at end of file From f874ee480aa278db9234f9ae15b9e5e799fc6017 Mon Sep 17 00:00:00 2001 From: Chris Turchin Date: Thu, 23 Jan 2014 03:01:56 +0100 Subject: [PATCH 012/148] formatting update eclipse... after will commit feature... --- .../com/thebuzzmedia/exiftool/ExifTool.java | 2217 +++++++++-------- 1 file changed, 1137 insertions(+), 1080 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 829a2100..9fad81b3 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -13,1201 +13,1256 @@ * See the License for the specific language governing permissions and * limitations under the License. */ -package com.thebuzzmedia.exiftool; -import org.apache.log4j.Logger; +package com.thebuzzmedia.exiftool; -import java.io.*; -import java.util.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; +import org.apache.log4j.Logger; + + /** * Class used to provide a Java-like interface to Phil Harvey's excellent, * Perl-based ExifTool. *

- * There are a number of other basic Java wrappers to ExifTool available online, - * but most of them only abstract out the actual Java-external-process execution - * logic and do no additional work to make integration with the external - * ExifTool any easier or intuitive from the perspective of the Java application - * written to make use of ExifTool. + * There are a number of other basic Java wrappers to ExifTool available online, but most of them only abstract out the + * actual Java-external-process execution logic and do no additional work to make integration with the external ExifTool + * any easier or intuitive from the perspective of the Java application written to make use of ExifTool. *

- * This class was written in order to make integration with ExifTool inside of a - * Java application seamless and performant with the goal being that the - * developer can treat ExifTool as if it were written in Java, garnering all of - * the benefits with none of the added headache of managing an external native - * process from Java. + * This class was written in order to make integration with ExifTool inside of a Java application seamless and + * performant with the goal being that the developer can treat ExifTool as if it were written in Java, garnering all of + * the benefits with none of the added headache of managing an external native process from Java. *

- * Phil Harvey's ExifTool is written in Perl and runs on all major platforms - * (including Windows) so no portability issues are introduced into your - * application by utilizing this class. + * Phil Harvey's ExifTool is written in Perl and runs on all major platforms (including Windows) so no portability + * issues are introduced into your application by utilizing this class. *

Usage

- * Assuming ExifTool is installed on the host system correctly and either in the - * system path or pointed to by {@link #exifCmd}, using this class to - * communicate with ExifTool is as simple as creating an instance ( - * ExifTool tool = new ExifTool()) and then making calls to - * {@link #getImageMeta(File, Tag...)} or - * {@link #getImageMeta(File, Format, Tag...)} with a list of {@link Tag}s you - * want to pull values for from the given image. + * Assuming ExifTool is installed on the host system correctly and either in the system path or pointed to by + * {@link #exifCmd}, using this class to communicate with ExifTool is as simple as creating an instance ( + * ExifTool tool = new ExifTool()) and then making calls to {@link #getImageMeta(File, Tag...)} or + * {@link #getImageMeta(File, Format, Tag...)} with a list of {@link Tag}s you want to pull values for from the given + * image. *

- * In this default mode, calls to getImageMeta will automatically - * start an external ExifTool process to handle the request. After ExifTool has - * parsed the tag values from the file, the external process exits and this - * class parses the result before returning it to the caller. + * In this default mode, calls to getImageMeta will automatically start an external ExifTool process to + * handle the request. After ExifTool has parsed the tag values from the file, the external process exits and this class + * parses the result before returning it to the caller. *

- * Results from calls to getImageMeta are returned in a {@link Map} - * with the {@link Tag} values as the keys and {@link String} values for every - * tag that had a value in the image file as the values. {@link Tag}s with no - * value found in the image are omitted from the result map. + * Results from calls to getImageMeta are returned in a {@link Map} with the {@link Tag} values as the keys + * and {@link String} values for every tag that had a value in the image file as the values. {@link Tag}s with no value + * found in the image are omitted from the result map. *

- * While each {@link Tag} provides a hint at which format the resulting value - * for that tag is returned as from ExifTool (see {@link Tag#getType()}), that - * only applies to values returned with an output format of - * {@link Format#NUMERIC} and it is ultimately up to the caller to decide how - * best to parse or convert the returned values. + * While each {@link Tag} provides a hint at which format the resulting value for that tag is returned as from ExifTool + * (see {@link Tag#getType()}), that only applies to values returned with an output format of {@link Format#NUMERIC} and + * it is ultimately up to the caller to decide how best to parse or convert the returned values. *

- * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} - * convenience method for parsing given String values according to - * the Tag hint automatically for you if that is what you plan on doing, + * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} convenience method for parsing given + * String values according to the Tag hint automatically for you if that is what you plan on doing, * otherwise feel free to handle the return values anyway you want. *

ExifTool -stay_open Support

- * ExifTool 8.36 added a new persistent-process feature that allows ExifTool to stay - * running in a daemon mode and continue accepting commands via a file or stdin. + * ExifTool 8.36 + * added a new persistent-process feature that allows ExifTool to stay running in a daemon mode and continue accepting + * commands via a file or stdin. *

- * This new mode is controlled via the -stay_open True/False - * command line argument and in a busy system that is making thousands of calls - * to ExifTool, can offer speed improvements of up to 60x (yes, + * This new mode is controlled via the -stay_open True/False command line argument and in a busy system + * that is making thousands of calls to ExifTool, can offer speed improvements of up to 60x (yes, * really that much). *

- * This feature was added to ExifTool shortly after user Christian Etter discovered - * the overhead for starting up a new Perl interpreter each time ExifTool is - * loaded accounts for roughly 98.4% of the total runtime. + * This feature was added to ExifTool shortly after user Christian Etter + * discovered the overhead for starting up a new Perl interpreter each time ExifTool is loaded accounts for roughly + * 98.4% of the total + * runtime. *

- * Support for using ExifTool in daemon mode is enabled by passing - * {@link Feature#STAY_OPEN} to the constructor of the class when creating an - * instance of this class and then simply using the class as you normally would. - * This class will manage a single ExifTool process running in daemon mode in - * the background to service all future calls to the class. + * Support for using ExifTool in daemon mode is enabled by passing {@link Feature#STAY_OPEN} to the constructor of the + * class when creating an instance of this class and then simply using the class as you normally would. This class will + * manage a single ExifTool process running in daemon mode in the background to service all future calls to the class. *

- * Because this feature requires ExifTool 8.36 or later, this class will - * actually verify support for the feature in the version of ExifTool pointed at - * by {@link #exifCmd} before successfully instantiating the class and - * will notify you via an {@link UnsupportedFeatureException} if the native - * ExifTool doesn't support the requested feature. + * Because this feature requires ExifTool 8.36 or later, this class will actually verify support for the feature in the + * version of ExifTool pointed at by {@link #exifCmd} before successfully instantiating the class and will notify you + * via an {@link UnsupportedFeatureException} if the native ExifTool doesn't support the requested feature. *

- * In the event of an {@link UnsupportedFeatureException}, the caller can either - * upgrade the native ExifTool upgrade to the version required or simply avoid - * using that feature to work around the exception. + * In the event of an {@link UnsupportedFeatureException}, the caller can either upgrade the native ExifTool upgrade to + * the version required or simply avoid using that feature to work around the exception. *

Automatic Resource Cleanup

- * When {@link Feature#STAY_OPEN} mode is used, there is the potential for - * leaking both host OS processes (native 'exiftool' processes) as well as the - * read/write streams used to communicate with it unless {@link #close()} is - * called to clean them up when done. Fortunately, this class - * provides an automatic cleanup mechanism that runs, by default, after 10mins - * of inactivity to clean up those stray resources. + * When {@link Feature#STAY_OPEN} mode is used, there is the potential for leaking both host OS processes (native + * 'exiftool' processes) as well as the read/write streams used to communicate with it unless {@link #close()} is called + * to clean them up when done. Fortunately, this class provides an automatic cleanup mechanism that + * runs, by default, after 10mins of inactivity to clean up those stray resources. *

- * The inactivity period can be controlled by modifying the - * {@link #processCleanupDelay} system variable. A value of 0 or - * less disabled the automatic cleanup process and requires you to cleanup - * ExifTool instances on your own by calling {@link #close()} manually. + * The inactivity period can be controlled by modifying the {@link #processCleanupDelay} system variable. A value of + * 0 or less disabled the automatic cleanup process and requires you to cleanup ExifTool instances on your + * own by calling {@link #close()} manually. *

- * Any class activity by way of calls to getImageMeta will always - * reset the inactivity timer, so in a busy system the cleanup thread could - * potentially never run, leaving the original host ExifTool process running - * forever (which is fine). + * Any class activity by way of calls to getImageMeta will always reset the inactivity timer, so in a busy + * system the cleanup thread could potentially never run, leaving the original host ExifTool process running forever + * (which is fine). *

- * This design was chosen to help make using the class and not introducing - * memory leaks and bugs into your code easier as well as making very inactive - * instances of this class light weight while not in-use by cleaning up after + * This design was chosen to help make using the class and not introducing memory leaks and bugs into your code easier + * as well as making very inactive instances of this class light weight while not in-use by cleaning up after * themselves. *

- * The only overhead incurred when opening the process back up is a 250-500ms - * lag while launching the VM interpreter again on the first call (depending on - * host machine speed and load). + * The only overhead incurred when opening the process back up is a 250-500ms lag while launching the VM interpreter + * again on the first call (depending on host machine speed and load). *

Reusing a "closed" ExifTool Instance

- * If you or the cleanup thread have called {@link #close()} on an instance of - * this class, cleaning up the host process and read/write streams, the instance - * of this class can still be safely used. Any followup calls to - * getImageMeta will simply re-instantiate all the required - * resources necessary to service the call (honoring any {@link Feature}s set). + * If you or the cleanup thread have called {@link #close()} on an instance of this class, cleaning up the host process + * and read/write streams, the instance of this class can still be safely used. Any followup calls to + * getImageMeta will simply re-instantiate all the required resources necessary to service the call + * (honoring any {@link Feature}s set). *

- * This can be handy behavior to be aware of when writing scheduled processing - * jobs that may wake up every hour and process thousands of pictures then go - * back to sleep. In order for the process to execute as fast as possible, you - * would want to use ExifTool in daemon mode (pass {@link Feature#STAY_OPEN} to - * the constructor of this class) and when done, instead of {@link #close()}-ing - * the instance of this class and throwing it out, you can keep the reference + * This can be handy behavior to be aware of when writing scheduled processing jobs that may wake up every hour and + * process thousands of pictures then go back to sleep. In order for the process to execute as fast as possible, you + * would want to use ExifTool in daemon mode (pass {@link Feature#STAY_OPEN} to the constructor of this class) and when + * done, instead of {@link #close()}-ing the instance of this class and throwing it out, you can keep the reference * around and re-use it again when the job executes again an hour later. *

Performance

- * Extra care is taken to ensure minimal object creation or unnecessary CPU - * overhead while communicating with the external process. + * Extra care is taken to ensure minimal object creation or unnecessary CPU overhead while communicating with the + * external process. *

- * {@link Pattern}s used to split the responses from the process are explicitly - * compiled and reused, string concatenation is minimized, Tag name lookup is - * done via a static final {@link Map} shared by all instances and - * so on. + * {@link Pattern}s used to split the responses from the process are explicitly compiled and reused, string + * concatenation is minimized, Tag name lookup is done via a static final {@link Map} shared by all + * instances and so on. *

- * Additionally, extra care is taken to utilize the most optimal code paths when - * initiating and using the external process, for example, the - * {@link ProcessBuilder#command(List)} method is used to avoid the copying of - * array elements when {@link ProcessBuilder#command(String...)} is used and - * avoiding the (hidden) use of {@link StringTokenizer} when + * Additionally, extra care is taken to utilize the most optimal code paths when initiating and using the external + * process, for example, the {@link ProcessBuilder#command(List)} method is used to avoid the copying of array elements + * when {@link ProcessBuilder#command(String...)} is used and avoiding the (hidden) use of {@link StringTokenizer} when * {@link Runtime#exec(String)} is called. *

- * All of this effort was done to ensure that imgscalr and its supporting - * classes continue to provide best-of-breed performance and memory utilization - * in long running/high performance environments (e.g. web applications). + * All of this effort was done to ensure that imgscalr and its supporting classes continue to provide best-of-breed + * performance and memory utilization in long running/high performance environments (e.g. web applications). *

Thread Safety

- * Instances of this class are not Thread-safe. Both the - * instance of this class and external ExifTool process maintain state specific - * to the current operation. Use of instances of this class need to be - * synchronized using an external mechanism or in a highly threaded environment - * (e.g. web application), instances of this class can be used along with - * {@link ThreadLocal}s to ensure Thread-safe, highly parallel use. + * Instances of this class are not Thread-safe. Both the instance of this class and external ExifTool + * process maintain state specific to the current operation. Use of instances of this class need to be synchronized + * using an external mechanism or in a highly threaded environment (e.g. web application), instances of this class can + * be used along with {@link ThreadLocal}s to ensure Thread-safe, highly parallel use. *

Why ExifTool?

- * ExifTool is - * written in Perl and requires an external process call from Java to make use - * of. + * ExifTool is written in Perl and requires an external + * process call from Java to make use of. *

- * While this would normally preclude a piece of software from inclusion into - * the imgscalr library (more complex integration), there is no other image - * metadata piece of software available as robust, complete and well-tested as - * ExifTool. In addition, ExifTool already runs on all major platforms - * (including Windows), so there was not a lack of portability introduced by - * providing an integration for it. + * While this would normally preclude a piece of software from inclusion into the imgscalr library (more complex + * integration), there is no other image metadata piece of software available as robust, complete and well-tested as + * ExifTool. In addition, ExifTool already runs on all major platforms (including Windows), so there was not a lack of + * portability introduced by providing an integration for it. *

- * Allowing it to be used from Java is a boon to any Java project that needs the - * ability to read/write image-metadata from almost any image or - * video file format. + * Allowing it to be used from Java is a boon to any Java project that needs the ability to read/write image-metadata + * from almost any image or video file format. *

Alternatives

- * If integration with an external Perl process is something your app cannot do - * and you still need image metadata-extraction capability, Drew Noakes has - * written the 2nd most robust image metadata library I have come across: Metadata Extractor - * that you might want to look at. + * If integration with an external Perl process is something your app cannot do and you still need image + * metadata-extraction capability, Drew Noakes has written the 2nd most robust image metadata library I have come + * across: Metadata Extractor that you might want to look + * at. * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ -public class ExifTool { - - public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; - public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; - - /** - * Name used to identify the (optional) cleanup {@link Thread}. - *

- * This is only provided to make debugging and profiling easier for - * implementers making use of this class such that the resources this class - * creates and uses (i.e. Threads) are readily identifiable in a running VM. - *

- * Default value is "ExifTool Cleanup Thread". - */ - private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; - - /** - * Compiled {@link Pattern} of ": " used to split compact output from - * ExifTool evenly into name/value pairs. - */ - private static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); - private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - - private static Logger log = Logger.getLogger(ExifTool.class); - - /** - * The absolute path to the ExifTool executable on the host system running - * this class as defined by the "exiftool.path" system - * property. - *

- * If ExifTool is on your system path and running the command "exiftool" - * successfully executes it, leaving this value unchanged will work fine on - * any platform. If the ExifTool executable is named something else or not - * in the system path, then this property will need to be set to point at it - * before using this class. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.path=/path/to/exiftool - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * On Windows be sure to double-escape the path to the tool, for example: - * - * -Dexiftool.path=C:\\Tools\\exiftool.exe - * - *

- * Default value is "exiftool". - *

Relative Paths

- * Relative path values (e.g. "bin/tools/exiftool") are executed with - * relation to the base directory the VM process was started in. Essentially - * the directory that new File(".").getAbsolutePath() points at - * during runtime. - */ - private final String exifCmd; - - /** - * Interval (in milliseconds) of inactivity before the cleanup thread wakes - * up and cleans up the daemon ExifTool process and the read/write streams - * used to communicate with it when the {@link Feature#STAY_OPEN} feature is - * used. - *

- * Ever time a call to getImageMeta is processed, the timer - * keeping track of cleanup is reset; more specifically, this class has to - * experience no activity for this duration of time before the cleanup - * process is fired up and cleans up the host OS process and the stream - * resources. - *

- * Any subsequent calls to getImageMeta after a cleanup simply - * re-initializes the resources. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.processCleanupDelay=600000 - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * Setting this value to 0 disables the automatic cleanup thread completely - * and the caller will need to manually cleanup the external ExifTool - * process and read/write streams by calling {@link #close()}. - *

- * Default value is 600,000 (10 minutes). - */ - private final long processCleanupDelay; - - private final Map featureSupportedMap = new HashMap(); - private final Set featureSet = EnumSet.noneOf(Feature.class); - private final ReentrantLock lock = new ReentrantLock(); - private final VersionNumber exifVersion; - private final Timer cleanupTimer; - private TimerTask currentCleanupTask = null; - private AtomicBoolean shuttingDown = new AtomicBoolean(false); - private volatile ExifProcess process; - private int timeoutWhenKeepAlive = 0; - - public ExifTool(){ - this((Feature[]) null); - } - - /** - * In this constructor, exifToolPath and processCleanupDelay are gotten from system properties - * exiftool.path and exiftool.processCleanupDelay. processCleanupDelay is optional. If not found, - * the default is used. - */ - public ExifTool (Feature ... features){ - this( - System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), - Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, DEFAULT_PROCESS_CLEANUP_DELAY), - features - ); - } - - public ExifTool(String exifToolPath) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); - } - - public ExifTool(String exifToolPath, Feature ... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); - } - - public ExifTool(String exifCmd, long processCleanupDelay, Feature ... features) { - this.exifCmd = exifCmd; - this.processCleanupDelay = processCleanupDelay; - this.exifVersion = ExifProcess.readVersion(exifCmd); - if (features != null && features.length > 0) { - for (Feature feature : features) { - if ( ! feature.isSupported(exifVersion) ) { - throw new UnsupportedFeatureException(feature); - } - this.featureSet.add(feature); - this.featureSupportedMap.put(feature,true); - } - } - - /* - * Now that initialization is done, init the cleanup timer if we are - * using STAY_OPEN and the delay time set is non-zero. - */ - if (isFeatureEnabled(Feature.STAY_OPEN) ) { - cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - } else { - cleanupTimer = null; - } - } - - /** - * Limits the amount of time (in mills) an exif operation can take. Setting value to greater than 0 to enable. - */ - public ExifTool setRunTimeout(int mills) { - timeoutWhenKeepAlive = mills; - return this; - } - - /** +public class ExifTool +{ + + public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + + /** + * Name used to identify the (optional) cleanup {@link Thread}. + *

+ * This is only provided to make debugging and profiling easier for implementers making use of this class such that + * the resources this class creates and uses (i.e. Threads) are readily identifiable in a running VM. + *

+ * Default value is "ExifTool Cleanup Thread". + */ + private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; + + /** + * Compiled {@link Pattern} of ": " used to split compact output from + * ExifTool evenly into name/value pairs. + */ + private static final Pattern TAG_VALUE_PATTERN = Pattern.compile( "\\s*:\\s*"); + private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + + private static Logger log = Logger.getLogger( ExifTool.class); + + /** + * The absolute path to the ExifTool executable on the host system running + * this class as defined by the "exiftool.path" system + * property. + *

+ * If ExifTool is on your system path and running the command "exiftool" successfully executes it, leaving this + * value unchanged will work fine on any platform. If the ExifTool executable is named something else or not in the + * system path, then this property will need to be set to point at it before using this class. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.path=/path/to/exiftool + * or by calling {@link System#setProperty(String, String)} before this class is loaded. + *

+ * On Windows be sure to double-escape the path to the tool, for example: + * -Dexiftool.path=C:\\Tools\\exiftool.exe + * + *

+ * Default value is "exiftool". + *

Relative Paths

+ * Relative path values (e.g. "bin/tools/exiftool") are executed with relation to the base directory the VM process + * was started in. Essentially the directory that new File(".").getAbsolutePath() points at during + * runtime. + */ + private final String exifCmd; + + /** + * Interval (in milliseconds) of inactivity before the cleanup thread wakes + * up and cleans up the daemon ExifTool process and the read/write streams + * used to communicate with it when the {@link Feature#STAY_OPEN} feature is + * used. + *

+ * Ever time a call to getImageMeta is processed, the timer keeping track of cleanup is reset; more + * specifically, this class has to experience no activity for this duration of time before the cleanup process is + * fired up and cleans up the host OS process and the stream resources. + *

+ * Any subsequent calls to getImageMeta after a cleanup simply re-initializes the resources. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.processCleanupDelay=600000 + * or by calling {@link System#setProperty(String, String)} before this class is loaded. + *

+ * Setting this value to 0 disables the automatic cleanup thread completely and the caller will need to manually + * cleanup the external ExifTool process and read/write streams by calling {@link #close()}. + *

+ * Default value is 600,000 (10 minutes). + */ + private final long processCleanupDelay; + + private final Map featureSupportedMap = new HashMap(); + private final Set featureSet = EnumSet.noneOf( Feature.class); + private final ReentrantLock lock = new ReentrantLock(); + private final VersionNumber exifVersion; + private final Timer cleanupTimer; + private TimerTask currentCleanupTask = null; + private AtomicBoolean shuttingDown = new AtomicBoolean( false); + private volatile ExifProcess process; + private int timeoutWhenKeepAlive = 0; + + public ExifTool() + { + this( (Feature[])null); + } + + /** + * In this constructor, exifToolPath and processCleanupDelay are gotten from system properties + * exiftool.path and exiftool.processCleanupDelay. processCleanupDelay is optional. If not found, + * the default is used. + */ + public ExifTool(Feature... features) + { + this( System.getProperty( ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, + DEFAULT_PROCESS_CLEANUP_DELAY), features); + } + + public ExifTool(String exifToolPath) + { + this( exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[])null); + } + + public ExifTool(String exifToolPath, Feature... features) + { + this( exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); + } + + public ExifTool(String exifCmd, long processCleanupDelay, Feature... features) + { + this.exifCmd = exifCmd; + this.processCleanupDelay = processCleanupDelay; + this.exifVersion = ExifProcess.readVersion( exifCmd); + if( features != null && features.length > 0) + { + for( Feature feature : features) + { + if( !feature.isSupported( exifVersion)) { throw new UnsupportedFeatureException( feature); } + this.featureSet.add( feature); + this.featureSupportedMap.put( feature, true); + } + } + + /* + * Now that initialization is done, init the cleanup timer if we are + * using STAY_OPEN and the delay time set is non-zero. + */ + if( isFeatureEnabled( Feature.STAY_OPEN)) + { + cleanupTimer = new Timer( CLEANUP_THREAD_NAME, true); + } + else + { + cleanupTimer = null; + } + } + + /** + * Limits the amount of time (in mills) an exif operation can take. Setting value to greater than 0 to enable. + */ + public ExifTool setRunTimeout(int mills) + { + timeoutWhenKeepAlive = mills; + return this; + } + + /** * Used to determine if the given {@link Feature} is supported by the - * underlying native install of ExifTool pointed at by - * {@link #exifCmd}. + * underlying native install of ExifTool pointed at by {@link #exifCmd}. *

- * If support for the given feature has not been checked for yet, this - * method will automatically call out to ExifTool and ensure the requested - * feature is supported in the current local install. + * If support for the given feature has not been checked for yet, this method will automatically call out to + * ExifTool and ensure the requested feature is supported in the current local install. *

- * The external call to ExifTool to confirm feature support is only ever - * done once per JVM session and stored in a static final - * {@link Map} that all instances of this class share. + * The external call to ExifTool to confirm feature support is only ever done once per JVM session and stored in a + * static final {@link Map} that all instances of this class share. * * @param feature - * The feature to check support for in the underlying ExifTool - * install. + * The feature to check support for in the underlying ExifTool + * install. * * @return true if support for the given {@link Feature} was - * confirmed to work with the currently installed ExifTool or - * false if it is not supported. + * confirmed to work with the currently installed ExifTool or false if it is not supported. * * @throws IllegalArgumentException - * if feature is null. + * if feature is null. * @throws RuntimeException - * if any exception occurs while attempting to start the - * external ExifTool process to verify feature support. + * if any exception occurs while attempting to start the + * external ExifTool process to verify feature support. */ - public boolean isFeatureSupported(Feature feature) throws RuntimeException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); - } + public boolean isFeatureSupported(Feature feature) throws RuntimeException + { + if( feature == null) { throw new IllegalArgumentException( "feature cannot be null"); } - Boolean supported = featureSupportedMap.get(feature); + Boolean supported = featureSupportedMap.get( feature); /* * If there is no Boolean flag for the feature, support for it hasn't * been checked yet with the native ExifTool install, so we need to do * that. */ - if (supported == null) { - log.debug("Support for feature %s has not been checked yet, checking..."); - supported = feature.isSupported(exifVersion); - featureSupportedMap.put(feature,supported); + if( supported == null) + { + log.debug( "Support for feature %s has not been checked yet, checking..."); + supported = feature.isSupported( exifVersion); + featureSupportedMap.put( feature, supported); } return supported; } + /** + * Used to startup the external ExifTool process and open the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. This method has no effect if the stay open feature is not enabled. + */ + public void startup() + { + if( featureSet.contains( Feature.STAY_OPEN)) + { + shuttingDown.set( false); + ensureProcessRunning(); + } + } + private void ensureProcessRunning() + { + if( process == null || process.isClosed()) + { + synchronized( this) + { + if( process == null || process.isClosed()) + { + log.debug( "Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = ExifProcess.startup( exifCmd); + } + } + } + if( processCleanupDelay > 0) + { + synchronized( this) + { + if( currentCleanupTask != null) + { + currentCleanupTask.cancel(); + currentCleanupTask = null; + } + currentCleanupTask = new TimerTask() + { + @Override + public void run() + { + log.info( "Auto cleanup task running..."); + process.close(); + } + }; + cleanupTimer.schedule( currentCleanupTask, processCleanupDelay); + } + } + } + /** + * This is same as {@link #close()}, added for consistency with {@link #startup()} + */ + public void shutdown() + { + close(); + } - - /** - * Used to startup the external ExifTool process and open the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. This method has no effect if the stay open feature is not enabled. - */ - public void startup(){ - if (featureSet.contains(Feature.STAY_OPEN)){ - shuttingDown.set(false); - ensureProcessRunning(); - } - } - private void ensureProcessRunning(){ - if (process ==null || process.isClosed()) { - synchronized (this){ - if (process ==null || process.isClosed() ){ - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = ExifProcess.startup(exifCmd); - } - } - } - if ( processCleanupDelay > 0 ) { - synchronized (this) { - if ( currentCleanupTask != null ) { - currentCleanupTask.cancel(); - currentCleanupTask = null; - } - currentCleanupTask = new TimerTask() { - @Override - public void run() { - log.info("Auto cleanup task running..."); - process.close(); - } - }; - cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); - } - } - } - - /** - * This is same as {@link #close()}, added for consistency with {@link #startup()} - */ - public void shutdown(){ - close(); - } - - - /** + /** * Used to shutdown the external ExifTool process and close the read/write * streams used to communicate with it when {@link Feature#STAY_OPEN} is * enabled. *

- * NOTE: Calling this method does not preclude this - * instance of {@link ExifTool} from being re-used, it merely disposes of - * the native and internal resources until the next call to - * getImageMeta causes them to be re-instantiated. + * NOTE: Calling this method does not preclude this instance of {@link ExifTool} from being + * re-used, it merely disposes of the native and internal resources until the next call to getImageMeta + * causes them to be re-instantiated. *

- * The cleanup thread will automatically call this after an interval of - * inactivity defined by {@link #processCleanupDelay}. + * The cleanup thread will automatically call this after an interval of inactivity defined by + * {@link #processCleanupDelay}. *

- * Calling this method on an instance of this class without - * {@link Feature#STAY_OPEN} support enabled has no effect. + * Calling this method on an instance of this class without {@link Feature#STAY_OPEN} support enabled has no effect. */ - public synchronized void close() { - shuttingDown.set(true); - if ( process != null ) { - process.close(); - } - if(currentCleanupTask != null) { - currentCleanupTask.cancel(); - currentCleanupTask = null; - } + public synchronized void close() + { + shuttingDown.set( true); + if( process != null) + { + process.close(); + } + if( currentCleanupTask != null) + { + currentCleanupTask.cancel(); + currentCleanupTask = null; + } } - public boolean isStayOpen() { - return featureSet.contains(Feature.STAY_OPEN); - } + public boolean isStayOpen() + { + return featureSet.contains( Feature.STAY_OPEN); + } /** * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support * enabled, this method is used to determine if there is currently a running * ExifTool process associated with this class. *

- * Any dependent processes and streams can be shutdown using - * {@link #close()} and this class will automatically re-create them on the - * next call to getImageMeta if necessary. + * Any dependent processes and streams can be shutdown using {@link #close()} and this class will automatically + * re-create them on the next call to getImageMeta if necessary. * * @return true if there is an external ExifTool process in - * daemon mode associated with this class utilizing the - * {@link Feature#STAY_OPEN} feature, otherwise returns + * daemon mode associated with this class utilizing the {@link Feature#STAY_OPEN} feature, otherwise returns * false. */ - public boolean isRunning() { - return process != null && ! process.isClosed(); + public boolean isRunning() + { + return process != null && !process.isClosed(); } /** * Used to determine if the given {@link Feature} has been enabled for this * particular instance of {@link ExifTool}. *

- * This method is different from {@link #isFeatureSupported(Feature)}, which - * checks if the given feature is supported by the underlying ExifTool - * install where as this method tells the caller if the given feature has - * been enabled for use in this particular instance. + * This method is different from {@link #isFeatureSupported(Feature)}, which checks if the given feature is + * supported by the underlying ExifTool install where as this method tells the caller if the given feature has been + * enabled for use in this particular instance. * * @param feature - * The feature to check if it has been enabled for us or not on - * this instance. + * The feature to check if it has been enabled for us or not on + * this instance. * * @return true if the given {@link Feature} is currently - * enabled on this instance of {@link ExifTool}, otherwise returns - * false. + * enabled on this instance of {@link ExifTool}, otherwise returns false. * * @throws IllegalArgumentException - * if feature is null. + * if feature is null. */ - public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); - } - return featureSet.contains(feature); + public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException + { + if( feature == null) { throw new IllegalArgumentException( "feature cannot be null"); } + return featureSet.contains( feature); + } + + public Map getImageMeta(File image, Tag... tags) throws IllegalArgumentException, SecurityException, IOException + { + + return getImageMeta( image, Format.NUMERIC, tags); + } + + public Map getImageMeta(File image, Format format, Tag... tags) throws IllegalArgumentException, SecurityException, + IOException + { + + String[] stringTags = new String[tags.length]; + int i = 0; + for( Tag tag : tags) + { + stringTags[i++] = tag.getName(); + } + Map result = getImageMeta( image, format, true, stringTags); + return mapByTag( result); } - public Map getImageMeta(File image, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - - return getImageMeta(image, Format.NUMERIC, tags); - } - - public Map getImageMeta(File image, Format format, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - - String [] stringTags = new String[tags.length]; - int i=0; - for (Tag tag : tags){ - stringTags[i++] = tag.getName(); - } - Map result = getImageMeta(image, format, true, stringTags); - return mapByTag(result); - } - - public Map getImageMeta(File image, Format format, TagGroup... tags) - throws IllegalArgumentException, SecurityException, IOException { - String [] stringTags = new String[tags.length]; - int i=0; - for (TagGroup tag : tags){ - stringTags[i++] = tag.getValue(); - } - return getImageMeta(image, format, false, stringTags); - } - - private Map getImageMeta(final File image, final Format format, final boolean suppressDuplicates, final String... tags) - throws IllegalArgumentException, SecurityException, IOException { - - - //Validate input and create Arg Array - final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); - List args = new ArrayList(tags.length+4); - if (format == null){ - throw new IllegalArgumentException("format cannot be null"); - } else if (format == Format.NUMERIC){ - args.add("-n"); // numeric output - } - if (!suppressDuplicates){ - args.add("-a"); //suppress duplicates - } - args.add("-S"); // compact output - - if (tags == null || tags.length == 0){ - throw new IllegalArgumentException("tags cannot be null and must contain 1 or more Tag to query the image for."); - } - for (String tag : tags) { - args.add("-" + tag); - } - if (image == null){ - throw new IllegalArgumentException("image cannot be null and must be a valid stream of image data."); - } - if (!image.canRead()){ - throw new SecurityException("Unable to read the given image ["+image.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); - } - args.add(image.getAbsolutePath()); - - //start process + public Map getImageMeta(File image, Format format, TagGroup... tags) throws IllegalArgumentException, + SecurityException, IOException + { + String[] stringTags = new String[tags.length]; + int i = 0; + for( TagGroup tag : tags) + { + stringTags[i++] = tag.getValue(); + } + return getImageMeta( image, format, false, stringTags); + } + + private Map getImageMeta(final File image, final Format format, final boolean suppressDuplicates, final String... tags) + throws IllegalArgumentException, SecurityException, IOException + { + + // Validate input and create Arg Array + final boolean stayOpen = featureSet.contains( Feature.STAY_OPEN); + List args = new ArrayList( tags.length + 4); + if( format == null) + { + throw new IllegalArgumentException( "format cannot be null"); + } + else if( format == Format.NUMERIC) + { + args.add( "-n"); // numeric output + } + if( !suppressDuplicates) + { + args.add( "-a"); // suppress duplicates + } + args.add( "-S"); // compact output + + if( tags == null || tags.length == 0) { throw new IllegalArgumentException( + "tags cannot be null and must contain 1 or more Tag to query the image for."); } + for( String tag : tags) + { + args.add( "-" + tag); + } + if( image == null) { throw new IllegalArgumentException( "image cannot be null and must be a valid stream of image data."); } + if( !image.canRead()) { throw new SecurityException( "Unable to read the given image [" + image.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); } + args.add( image.getAbsolutePath()); + + // start process long startTime = System.currentTimeMillis(); - log.debug(String.format("Querying %d tags from image: %s", tags.length, image.getAbsolutePath())); + log.debug( String.format( "Querying %d tags from image: %s", tags.length, image.getAbsolutePath())); /* * Using ExifTool in daemon mode (-stay_open True) executes different * code paths below. So establish the flag for this once and it is * reused a multitude of times later in this method to figure out where * to branch to. */ - Map resultMap; - if (stayOpen) { - log.debug("Using ExifTool in daemon mode (-stay_open True)..."); - resultMap = processStayOpen(args); - } else { - log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd,args); + Map resultMap; + if( stayOpen) + { + log.debug( "Using ExifTool in daemon mode (-stay_open True)..."); + resultMap = processStayOpen( args); + } + else + { + log.debug( "Using ExifTool in non-daemon mode (-stay_open False)..."); + resultMap = ExifProcess.executeToResults( exifCmd, args); } // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()){ - log.debug(String.format("Image Meta Processed in %d ms [queried %d tags and found %d values]", - (System.currentTimeMillis() - startTime), tags.length, - resultMap.size())); - } + if( log.isDebugEnabled()) + { + log.debug( String.format( "Image Meta Processed in %d ms [queried %d tags and found %d values]", + (System.currentTimeMillis() - startTime), tags.length, resultMap.size())); + } return resultMap; } - /** - * Will attempt 3 times to use the running exif process, and if unable to complete successfully will throw IOException - */ - private Map processStayOpen(List args) throws IOException { - int attempts = 0; - while (attempts < 3 && ! shuttingDown.get()){ - attempts++; - //make sure process is started - ensureProcessRunning(); - TimerTask attemptTimer = null; - try { - if ( timeoutWhenKeepAlive > 0 ) { - attemptTimer = new TimerTask() { - public void run() { - log.warn("Process ran too long closing, max "+timeoutWhenKeepAlive+" mills"); - process.close(); - } - }; - cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); - } - log.debug("Streaming arguments to ExifTool process..."); - return process.sendArgs(args); - } catch (IOException ex){ - if ( STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) && ! shuttingDown.get() ){ - //only catch "Stream Closed" error (happens when process has died) - log.warn(String.format("Caught IOException(\"%s\"), will restart daemon",STREAM_CLOSED_MESSAGE)); - process.close(); - } else { - throw ex; - } - } finally { - if ( attemptTimer != null ) attemptTimer.cancel(); - } - } - if ( shuttingDown.get() ) { - throw new IOException("Shutting Down"); - } - throw new IOException("Ran out of attempts"); - } - - private static Map mapByTag(Map stringMap){ - Map tagMap = new HashMap(Tag.values().length); - for (Tag tag : Tag.values()){ - if (stringMap.containsKey(tag.getName())){ - tagMap.put(tag, stringMap.get(tag.getName())); - } - } - return tagMap; - } - - - //================================================================================ - /** - * Represents an Exif Process. - */ - public static class ExifProcess { - private final ReentrantLock closeLock = new ReentrantLock(false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; - private volatile boolean closed = false; - - public static VersionNumber readVersion(String exifCmd) { - ExifProcess process =_execute(false, Arrays.asList(exifCmd,"-ver")); - try { - return new VersionNumber(process.readLine()); - } catch (IOException ex) { - throw new RuntimeException(String.format("Unable to check version number of ExifTool: %s",exifCmd)); - } finally { - process.close(); - } - } - - public static Map executeToResults(String exifCmd, List args) throws IOException { - List newArgs = new ArrayList(args.size()+1); - newArgs.add(exifCmd); - newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); - try { - return process.readResponse(); - } finally { - process.close(); - } - } - - public static ExifProcess startup(String exifCmd) { - List args = Arrays.asList(exifCmd,"-stay_open", "True", "-@", "-"); - return _execute(true, args); - } - - public static ExifProcess _execute(boolean keepAlive, List args) { - log.debug(String.format("Attempting to start external ExifTool process using args: %s", args)); - try { - Process process = new ProcessBuilder(args).start(); - log.debug("\tSuccessful"); - return new ExifProcess(keepAlive,process); - } catch (Exception e) { - String message = "Unable to start external ExifTool process using the execution arguments: " - + args - + ". Ensure ExifTool is installed correctly and runs using the command path '" - + args.get(0) - + "' as specified by the 'exiftool.path' system property."; - - log.debug(message); - throw new RuntimeException(message, e); - } - } - - public ExifProcess(boolean keepAlive,Process process) { - this.keepAlive = keepAlive; - this.process = process; - this.reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream()); - } - - public synchronized Map sendArgs(List args) throws IOException { - StringBuilder builder = new StringBuilder(); - for(String arg : args) { - builder.append(arg).append("\n"); - } - builder.append("-execute\n"); - writeFlush(builder.toString()); - return readResponse(); - } - - - public synchronized void writeFlush(String message) throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - writer.write(message); - writer.flush(); - } - - public synchronized String readLine() throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - return reader.readLine(); - } - - public synchronized Map readResponse() throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - Map resultMap = new HashMap(500); - String line; - - while ((line = reader.readLine()) != null) { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - String[] pair = TAG_VALUE_PATTERN.split(line, 2); - - if (pair.length == 2) { - resultMap.put(pair[0], pair[1]); - log.debug(String.format("\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); - } - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need to - * look for it and break from this loop when we see it otherwise - * this process will hang indefinitely blocking on the input stream - * with no data to read. - */ - if (keepAlive && line.equals("{ready}")){ - break; - } - } - return resultMap; - } - - public boolean isClosed() { - return closed; - } - - public void close() { - if ( ! closed ) { - closeLock.lock(); - try { - if ( ! closed ) { - closed = true; - log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - try { - writer.write("-stay_open\nFalse\n"); - writer.flush(); - } catch (IOException ex) { - //log.error(ex,ex); - } - try { - log.debug("Closing Read stream..."); - reader.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log.debug("Closing Write stream..."); - writer.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - log.debug("Read/Write streams successfully closed."); - - try { - process.destroy(); - } catch (Exception e) { - // - } - //process = null; - - } - } finally { - closeLock.unlock(); - } - } - } - } - - //================================================================================ - /** - * Enum used to define the different kinds of features in the native - * ExifTool executable that this class can help you take advantage of. - *

- * These flags are different from {@link Tag}s in that a "feature" is - * determined to be a special functionality of the underlying ExifTool - * executable that requires a different code-path in this class to take - * advantage of; for example, -stay_open True support. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Feature { - /** - * Enum used to specify that you wish to launch the underlying ExifTool - * process with -stay_open True support turned on that this - * class can then take advantage of. - *

- * Required ExifTool version is 8.36 or higher. - */ - STAY_OPEN(8,36); - - - private VersionNumber requireVersion; - private Feature(int... numbers) { - this.requireVersion = new VersionNumber(numbers); - } - /** - * Used to get the version of ExifTool required by this feature in order - * to work. - * - * @return the version of ExifTool required by this feature in order to - * work. - */ - VersionNumber getVersion() { - return requireVersion; - } - - boolean isSupported(VersionNumber exifVersionNumber) { - return requireVersion.isBeforeOrEqualTo(exifVersionNumber); - } - } - - //================================================================================ - /** - * Version Number used to determine if one version is after another. - */ - static class VersionNumber { - private final int[] numbers; - - public VersionNumber(String str) { - String[] versionParts = str.trim().split("\\."); - this.numbers = new int[versionParts.length]; - for(int i=0; i other.numbers[i] ) { - return false; - } else if ( this.numbers[i] < other.numbers[i] ) { - return true; - } - } - //assume missing number as zero, so if the current process number is more digits it is a higher version - return this.numbers.length <= other.numbers.length; - } - - public String toString() { - StringBuilder builder = new StringBuilder(); - for(int i=0; i 0 ) { - builder.append("."); - } - builder.append(numbers[i]); - } - return builder.toString(); - } - } - - - //================================================================================ - /** - * Enum used to define the 2 different output formats that {@link Tag} - * values can be returned in: numeric or human-readable text. - *

- * ExifTool, via the -n command line arg, is capable of - * returning most values in their raw numeric form (e.g. - * Aperture="2.8010323841") as well as a more human-readable/friendly format - * (e.g. Aperture="2.8"). - *

- * While the {@link Tag}s defined on this class do provide a hint at the - * type of the result (see {@link Tag#getType()}), that hint only applies - * when the {@link Format#NUMERIC} form of the value is returned. - *

- * If the caller finds the human-readable format easier to process, - * {@link Format#HUMAN_READABLE} can be specified when calling - * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned - * {@link String} values processed manually by the caller. - *

- * In order to see the types of values that are returned when - * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive - * ExifTool Tag Guide. - *

- * This makes sense with some values like Aperture that in - * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high - * precision values that are near the intended value (e.g. - * "2.79999992203711" instead of just returning "2.8"). On the other hand, - * other values (like Orientation) are easier to parse when their numeric - * value (1-8) is returned instead of a much longer friendly name (e.g. - * "Mirror horizontal and rotate 270 CW"). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Format { - NUMERIC, HUMAN_READABLE - } - //================================================================================ - /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifTool. - *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default {@link Format#NUMERIC} value format - * is used. - *

- * All replies from ExifTool are parsed as {@link String}s and using the - * type hint from each {@link Tag} can easily be converted to the correct - * data format by using the provided {@link Tag#parseValue(String)} - * method. - *

- * This class does not make an attempt at converting the value automatically - * in case the caller decides they would prefer tag values returned in - * {@link Format#HUMAN_READABLE} format and to avoid any compatibility - * issues with future versions of ExifTool if a tag's return value is - * changed. This approach to leaving returned tag values as strings until - * the caller decides they want to parse them is a safer and more robust - * approach. - *

- * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. - *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. - *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. - *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Tag { - //single entry tags - APERTURE("ApertureValue", Double.class), - AUTHOR("XPAuthor", String.class), - COLOR_SPACE("ColorSpace", Integer.class), - COMMENT("XPComment", String.class), - CONTRAST("Contrast", Integer.class), - CREATE_DATE("CreateDate", String.class), - CREATION_DATE("CreationDate", String.class), - DATE_CREATED("DateCreated", String.class), - DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - FLASH("Flash", Integer.class), - FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), - FNUMBER("FNumber", String.class), - GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), - GPS_DATESTAMP("GPSDateStamp", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), - GPS_LONGITUDE("GPSLongitude", Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), - GPS_SPEED("GPSSpeed", Double.class), - GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), - IMAGE_WIDTH("ImageWidth", Integer.class), - ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), - LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), - MAKE("Make", String.class), - METERING_MODE("MeteringMode", Integer.class), - MODEL("Model", String.class), - ORIENTATION("Orientation", Integer.class), - OWNER_NAME("OwnerName", String.class), - RATING("Rating", Integer.class), - RATING_PERCENT("RatingPercent", Integer.class), - ROTATION("Rotation", Integer.class), - SATURATION("Saturation", Integer.class), - SENSING_METHOD("SensingMethod", Integer.class), - SHARPNESS("Sharpness", Integer.class), - SHUTTER_SPEED("ShutterSpeedValue", Double.class), - SOFTWARE("Software", String.class), - SUBJECT("XPSubject", String.class), - TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), - X_RESOLUTION("XResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), - ; - - /** - * Used to get the {@link Tag} identified by the given, case-sensitive, - * tag name. - * - * @param name - * The case-sensitive name of the tag that will be searched - * for. - * - * @return the {@link Tag} identified by the given, case-sensitive, tag - * name or null if one couldn't be found. - */ - public static Tag forName(String name) { - for (Tag tag : Tag.values()){ - if (tag.getName().equals(name)){ - return tag; - } - } - return null; - } - - /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifTool process) into the type described - * by the associated {@link Tag}. - * - * @param - * The type of the returned value. - * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. - * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). - * - * @throws IllegalArgumentException - * if tag is null. - * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). - * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. - */ - @SuppressWarnings("unchecked") - public T parseValue(String value) throws IllegalArgumentException { - - if (value != null) { - if (Boolean.class.isAssignableFrom(this.getType())){ - return (T) Boolean.valueOf(value); - } else if (Byte.class.isAssignableFrom(this.getType())){ - return (T) Byte.valueOf(Byte.parseByte(value)); - } else if (Integer.class.isAssignableFrom(this.getType())){ - return (T) Integer.valueOf(Integer.parseInt(value)); - } else if (Short.class.isAssignableFrom(this.getType())){ - return (T) Short.valueOf(Short.parseShort(value)); - } else if (Long.class.isAssignableFrom(this.getType())){ - return (T) Long.valueOf(Long.parseLong(value)); - } else if (Float.class.isAssignableFrom(this.getType())){ - return (T) Float.valueOf(Float.parseFloat(value)); - } else if (Double.class.isAssignableFrom(this.getType())){ - return (T) parseDouble(value); - } else if (Character.class.isAssignableFrom(this.getType())){ - return (T) Character.valueOf(value.charAt(0)); - } else if (String.class.isAssignableFrom(this.getType())){ - return (T) value; - } - } - return null; - } - - private Double parseDouble(String in) { - if (in.contains("/")) { - String[] enumeratorAndDivisor = in.split("/"); - return Double.parseDouble(enumeratorAndDivisor[0]) / Double.parseDouble(enumeratorAndDivisor[1]); - } else { - return Double.parseDouble(in); - } - } - - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ - public String getName() { - return name; - } - - /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifTool Tag Guide. - * - * @return a hint for the native type of this tag's value. - */ - public Class getType() { - return type; - } - - private String name; - private Class type; - - private Tag(String name, Class type) { - this.name = name; - this.type = type; - } - } - - //================================================================================ - public enum TagGroup { - EXIF("EXIF","exif:all"), - IPTC("IPTC", "iptc:all"), - XMP("XMP", "xmp:all"), - ALL("ALL", "all"); - - private final String name; - private final String value; - - private TagGroup(String name, String value) { - this.name = name; - this.value = value; - } - - public String getName() { - return name; - } - - public String getValue() { - return value; - } - } - - - //================================================================================ + /** + * Will attempt 3 times to use the running exif process, and if unable to complete successfully will throw + * IOException + */ + private Map processStayOpen(List args) throws IOException + { + int attempts = 0; + while( attempts < 3 && !shuttingDown.get()) + { + attempts++; + // make sure process is started + ensureProcessRunning(); + TimerTask attemptTimer = null; + try + { + if( timeoutWhenKeepAlive > 0) + { + attemptTimer = new TimerTask() + { + @Override + public void run() + { + log.warn( "Process ran too long closing, max " + timeoutWhenKeepAlive + " mills"); + process.close(); + } + }; + cleanupTimer.schedule( attemptTimer, timeoutWhenKeepAlive); + } + log.debug( "Streaming arguments to ExifTool process..."); + return process.sendArgs( args); + } + catch( IOException ex) + { + if( STREAM_CLOSED_MESSAGE.equals( ex.getMessage()) && !shuttingDown.get()) + { + // only catch "Stream Closed" error (happens when process has died) + log.warn( String.format( "Caught IOException(\"%s\"), will restart daemon", STREAM_CLOSED_MESSAGE)); + process.close(); + } + else + { + throw ex; + } + } + finally + { + if( attemptTimer != null) + attemptTimer.cancel(); + } + } + if( shuttingDown.get()) { throw new IOException( "Shutting Down"); } + throw new IOException( "Ran out of attempts"); + } + + private static Map mapByTag(Map stringMap) + { + Map tagMap = new HashMap( Tag.values().length); + for( Tag tag : Tag.values()) + { + if( stringMap.containsKey( tag.getName())) + { + tagMap.put( tag, stringMap.get( tag.getName())); + } + } + return tagMap; + } + + // ================================================================================ + /** + * Represents an Exif Process. + */ + public static class ExifProcess + { + private final ReentrantLock closeLock = new ReentrantLock( false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader reader; + private final OutputStreamWriter writer; + private volatile boolean closed = false; + + public static VersionNumber readVersion(String exifCmd) + { + ExifProcess process = _execute( false, Arrays.asList( exifCmd, "-ver")); + try + { + return new VersionNumber( process.readLine()); + } + catch( IOException ex) + { + throw new RuntimeException( String.format( "Unable to check version number of ExifTool: %s", exifCmd)); + } + finally + { + process.close(); + } + } + + public static Map executeToResults(String exifCmd, List args) throws IOException + { + List newArgs = new ArrayList( args.size() + 1); + newArgs.add( exifCmd); + newArgs.addAll( args); + ExifProcess process = _execute( false, newArgs); + try + { + return process.readResponse(); + } + finally + { + process.close(); + } + } + + public static ExifProcess startup(String exifCmd) + { + List args = Arrays.asList( exifCmd, "-stay_open", "True", "-@", "-"); + return _execute( true, args); + } + + public static ExifProcess _execute(boolean keepAlive, List args) + { + log.debug( String.format( "Attempting to start external ExifTool process using args: %s", args)); + try + { + Process process = new ProcessBuilder( args).start(); + log.debug( "\tSuccessful"); + return new ExifProcess( keepAlive, process); + } + catch( Exception e) + { + String message = "Unable to start external ExifTool process using the execution arguments: " + args + + ". Ensure ExifTool is installed correctly and runs using the command path '" + args.get( 0) + + "' as specified by the 'exiftool.path' system property."; + + log.debug( message); + throw new RuntimeException( message, e); + } + } + + public ExifProcess(boolean keepAlive, Process process) + { + this.keepAlive = keepAlive; + this.process = process; + this.reader = new BufferedReader( new InputStreamReader( process.getInputStream())); + this.writer = new OutputStreamWriter( process.getOutputStream()); + } + + public synchronized Map sendArgs(List args) throws IOException + { + StringBuilder builder = new StringBuilder(); + for( String arg : args) + { + builder.append( arg).append( "\n"); + } + builder.append( "-execute\n"); + writeFlush( builder.toString()); + return readResponse(); + } + + public synchronized void writeFlush(String message) throws IOException + { + if( closed) + throw new IOException( STREAM_CLOSED_MESSAGE); + writer.write( message); + writer.flush(); + } + + public synchronized String readLine() throws IOException + { + if( closed) + throw new IOException( STREAM_CLOSED_MESSAGE); + return reader.readLine(); + } + + public synchronized Map readResponse() throws IOException + { + if( closed) + throw new IOException( STREAM_CLOSED_MESSAGE); + log.debug( "Reading response back from ExifTool..."); + Map resultMap = new HashMap( 500); + String line; + + while( (line = reader.readLine()) != null) + { + if( closed) + throw new IOException( STREAM_CLOSED_MESSAGE); + String[] pair = TAG_VALUE_PATTERN.split( line, 2); + + if( pair.length == 2) + { + resultMap.put( pair[0], pair[1]); + log.debug( String.format( "\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); + } + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need to + * look for it and break from this loop when we see it otherwise + * this process will hang indefinitely blocking on the input stream + * with no data to read. + */ + if( keepAlive && line.equals( "{ready}")) + { + break; + } + } + return resultMap; + } + + public boolean isClosed() + { + return closed; + } + + public void close() + { + if( !closed) + { + closeLock.lock(); + try + { + if( !closed) + { + closed = true; + log.debug( "Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); + try + { + writer.write( "-stay_open\nFalse\n"); + writer.flush(); + } + catch( IOException ex) + { + // log.error(ex,ex); + } + try + { + log.debug( "Closing Read stream..."); + reader.close(); + log.debug( "\tSuccessful"); + } + catch( Exception e) + { + // no-op, just try to close it. + } + + try + { + log.debug( "Closing Write stream..."); + writer.close(); + log.debug( "\tSuccessful"); + } + catch( Exception e) + { + // no-op, just try to close it. + } + + log.debug( "Read/Write streams successfully closed."); + + try + { + process.destroy(); + } + catch( Exception e) + { + // + } + // process = null; + + } + } + finally + { + closeLock.unlock(); + } + } + } + } + + // ================================================================================ + /** + * Enum used to define the different kinds of features in the native + * ExifTool executable that this class can help you take advantage of. + *

+ * These flags are different from {@link Tag}s in that a "feature" is determined to be a special functionality of + * the underlying ExifTool executable that requires a different code-path in this class to take advantage of; for + * example, -stay_open True support. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Feature + { + /** + * Enum used to specify that you wish to launch the underlying ExifTool + * process with -stay_open True support turned on that this + * class can then take advantage of. + *

+ * Required ExifTool version is 8.36 or higher. + */ + STAY_OPEN( 8, 36); + + private VersionNumber requireVersion; + + private Feature(int... numbers) + { + this.requireVersion = new VersionNumber( numbers); + } + + /** + * Used to get the version of ExifTool required by this feature in order + * to work. + * + * @return the version of ExifTool required by this feature in order to + * work. + */ + VersionNumber getVersion() + { + return requireVersion; + } + + boolean isSupported(VersionNumber exifVersionNumber) + { + return requireVersion.isBeforeOrEqualTo( exifVersionNumber); + } + } + + // ================================================================================ + /** + * Version Number used to determine if one version is after another. + */ + static class VersionNumber + { + private final int[] numbers; + + public VersionNumber(String str) + { + String[] versionParts = str.trim().split( "\\."); + this.numbers = new int[versionParts.length]; + for( int i = 0; i < versionParts.length; i++) + { + numbers[i] = Integer.parseInt( versionParts[i]); + } + } + + public VersionNumber(int... numbers) + { + this.numbers = numbers; + } + + public boolean isBeforeOrEqualTo(VersionNumber other) + { + int max = Math.min( this.numbers.length, other.numbers.length); + for( int i = 0; i < max; i++) + { + if( this.numbers[i] > other.numbers[i]) + { + return false; + } + else if( this.numbers[i] < other.numbers[i]) { return true; } + } + // assume missing number as zero, so if the current process number is more digits it is a higher version + return this.numbers.length <= other.numbers.length; + } + + @Override + public String toString() + { + StringBuilder builder = new StringBuilder(); + for( int i = 0; i < numbers.length; i++) + { + if( builder.length() > 0) + { + builder.append( "."); + } + builder.append( numbers[i]); + } + return builder.toString(); + } + } + + // ================================================================================ + /** + * Enum used to define the 2 different output formats that {@link Tag} values can be returned in: numeric or + * human-readable text. + *

+ * ExifTool, via the -n command line arg, is capable of returning most values in their raw numeric form + * (e.g. Aperture="2.8010323841") as well as a more human-readable/friendly format (e.g. Aperture="2.8"). + *

+ * While the {@link Tag}s defined on this class do provide a hint at the type of the result (see + * {@link Tag#getType()}), that hint only applies when the {@link Format#NUMERIC} form of the value is returned. + *

+ * If the caller finds the human-readable format easier to process, {@link Format#HUMAN_READABLE} can be specified + * when calling {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned {@link String} values processed + * manually by the caller. + *

+ * In order to see the types of values that are returned when {@link Format#HUMAN_READABLE} is used, you can check + * the comprehensive ExifTool Tag + * Guide. + *

+ * This makes sense with some values like Aperture that in {@link Format#NUMERIC} format end up returning as + * 14-decimal-place, high precision values that are near the intended value (e.g. "2.79999992203711" instead of just + * returning "2.8"). On the other hand, other values (like Orientation) are easier to parse when their numeric value + * (1-8) is returned instead of a much longer friendly name (e.g. "Mirror horizontal and rotate 270 CW"). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Format + { + NUMERIC, HUMAN_READABLE + } + + // ================================================================================ + /** + * Enum used to pre-define a convenient list of tags that can be easily + * extracted from images using this class with an external install of + * ExifTool. + *

+ * Each tag defined also includes a type hint for the parsed value associated with it when the default + * {@link Format#NUMERIC} value format is used. + *

+ * All replies from ExifTool are parsed as {@link String}s and using the type hint from each {@link Tag} can easily + * be converted to the correct data format by using the provided {@link Tag#parseValue(String)} method. + *

+ * This class does not make an attempt at converting the value automatically in case the caller decides they would + * prefer tag values returned in {@link Format#HUMAN_READABLE} format and to avoid any compatibility issues with + * future versions of ExifTool if a tag's return value is changed. This approach to leaving returned tag values as + * strings until the caller decides they want to parse them is a safer and more robust approach. + *

+ * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; + * the caller is free to parse or process the returned {@link String} values any way they wish. + *

Tag Support

+ * ExifTool is capable of parsing almost every tag known to man (1000+), but this class makes an attempt at + * pre-defining a convenient list of the most common tags for use. + *

+ * This list was determined by looking at the common metadata tag values written to images by popular mobile devices + * (iPhone, Android) as well as cameras like simple point and shoots as well as DSLRs. As an additional source of + * input the list of supported/common EXIF formats that Flickr supports was also reviewed to ensure the most + * common/useful tags were being covered here. + *

+ * Please email me or file an issue if you think this + * list is missing a commonly used tag that should be added to it. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Tag + { + // single entry tags + APERTURE( "ApertureValue", Double.class), + AUTHOR( "XPAuthor", String.class), + COLOR_SPACE( "ColorSpace", Integer.class), + COMMENT( "XPComment", String.class), + CONTRAST( "Contrast", Integer.class), + CREATE_DATE( "CreateDate", String.class), + CREATION_DATE( "CreationDate", String.class), + DATE_CREATED( "DateCreated", String.class), + DATE_TIME_ORIGINAL( "DateTimeOriginal", String.class), + DIGITAL_ZOOM_RATIO( "DigitalZoomRatio", Double.class), + EXIF_VERSION( "ExifVersion", String.class), + EXPOSURE_COMPENSATION( "ExposureCompensation", Double.class), + EXPOSURE_PROGRAM( "ExposureProgram", Integer.class), + EXPOSURE_TIME( "ExposureTime", Double.class), + FLASH( "Flash", Integer.class), + FOCAL_LENGTH( "FocalLength", Double.class), + FOCAL_LENGTH_35MM( "FocalLengthIn35mmFormat", Integer.class), + FNUMBER( "FNumber", String.class), + GPS_ALTITUDE( "GPSAltitude", Double.class), + GPS_ALTITUDE_REF( "GPSAltitudeRef", Integer.class), + GPS_BEARING( "GPSDestBearing", Double.class), + GPS_BEARING_REF( "GPSDestBearingRef", String.class), + GPS_DATESTAMP( "GPSDateStamp", String.class), + GPS_LATITUDE( "GPSLatitude", Double.class), + GPS_LATITUDE_REF( "GPSLatitudeRef", String.class), + GPS_LONGITUDE( "GPSLongitude", Double.class), + GPS_LONGITUDE_REF( "GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD( "GPSProcessingMethod", String.class), + GPS_SPEED( "GPSSpeed", Double.class), + GPS_SPEED_REF( "GPSSpeedRef", String.class), + GPS_TIMESTAMP( "GPSTimeStamp", String.class), + IMAGE_HEIGHT( "ImageHeight", Integer.class), + IMAGE_WIDTH( "ImageWidth", Integer.class), + ISO( "ISO", Integer.class), + KEYWORDS( "XPKeywords", String.class), + LENS_MAKE( "LensMake", String.class), + LENS_MODEL( "LensModel", String.class), + MAKE( "Make", String.class), + METERING_MODE( "MeteringMode", Integer.class), + MODEL( "Model", String.class), + ORIENTATION( "Orientation", Integer.class), + OWNER_NAME( "OwnerName", String.class), + RATING( "Rating", Integer.class), + RATING_PERCENT( "RatingPercent", Integer.class), + ROTATION( "Rotation", Integer.class), + SATURATION( "Saturation", Integer.class), + SENSING_METHOD( "SensingMethod", Integer.class), + SHARPNESS( "Sharpness", Integer.class), + SHUTTER_SPEED( "ShutterSpeedValue", Double.class), + SOFTWARE( "Software", String.class), + SUBJECT( "XPSubject", String.class), + TITLE( "XPTitle", String.class), + WHITE_BALANCE( "WhiteBalance", Integer.class), + X_RESOLUTION( "XResolution", Double.class), + Y_RESOLUTION( "YResolution", Double.class), ; + + /** + * Used to get the {@link Tag} identified by the given, case-sensitive, + * tag name. + * + * @param name + * The case-sensitive name of the tag that will be searched + * for. + * + * @return the {@link Tag} identified by the given, case-sensitive, tag + * name or null if one couldn't be found. + */ + public static Tag forName(String name) + { + for( Tag tag : Tag.values()) + { + if( tag.getName().equals( name)) { return tag; } + } + return null; + } + + /** + * Convenience method used to convert the given string Tag value + * (returned from the external ExifTool process) into the type described + * by the associated {@link Tag}. + * + * @param + * The type of the returned value. + * @param value + * The {@link String} representation of the tag's value as + * parsed from the image. + * + * @return the given string value converted to a native Java type (e.g. + * Integer, Double, etc.). + * + * @throws IllegalArgumentException + * if tag is null. + * @throws NumberFormatException + * if any exception occurs while trying to parse the given value to any of the supported + * numeric types + * in Java via calls to the respective parseXXX methods defined on all the numeric wrapper + * classes (e.g. {@link Integer#parseInt(String)} , {@link Double#parseDouble(String)} and so on). + * @throws ClassCastException + * if the type defined by T is incompatible + * with the type defined by {@link Tag#getType()} returned + * by the tag argument passed in. This class + * performs an implicit/unchecked cast to the type T before returning the parsed result of + * the + * type indicated by {@link Tag#getType()}. If the types do + * not match, a ClassCastException will be + * generated by the VM. + */ + @SuppressWarnings("unchecked") + public T parseValue(String value) throws IllegalArgumentException + { + + if( value != null) + { + if( Boolean.class.isAssignableFrom( this.getType())) + { + return (T)Boolean.valueOf( value); + } + else if( Byte.class.isAssignableFrom( this.getType())) + { + return (T)Byte.valueOf( Byte.parseByte( value)); + } + else if( Integer.class.isAssignableFrom( this.getType())) + { + return (T)Integer.valueOf( Integer.parseInt( value)); + } + else if( Short.class.isAssignableFrom( this.getType())) + { + return (T)Short.valueOf( Short.parseShort( value)); + } + else if( Long.class.isAssignableFrom( this.getType())) + { + return (T)Long.valueOf( Long.parseLong( value)); + } + else if( Float.class.isAssignableFrom( this.getType())) + { + return (T)Float.valueOf( Float.parseFloat( value)); + } + else if( Double.class.isAssignableFrom( this.getType())) + { + return (T)parseDouble( value); + } + else if( Character.class.isAssignableFrom( this.getType())) + { + return (T)Character.valueOf( value.charAt( 0)); + } + else if( String.class.isAssignableFrom( this.getType())) { return (T)value; } + } + return null; + } + + private Double parseDouble(String in) + { + if( in.contains( "/")) + { + String[] enumeratorAndDivisor = in.split( "/"); + return Double.parseDouble( enumeratorAndDivisor[0]) / Double.parseDouble( enumeratorAndDivisor[1]); + } + else + { + return Double.parseDouble( in); + } + } + + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ + public String getName() + { + return name; + } + + /** + * Used to get a hint for the native type of this tag's value as + * specified by Phil Harvey's ExifTool Tag Guide. + * + * @return a hint for the native type of this tag's value. + */ + public Class getType() + { + return type; + } + + private String name; + private Class type; + + private Tag(String name, Class type) + { + this.name = name; + this.type = type; + } + } + + // ================================================================================ + public enum TagGroup + { + EXIF( "EXIF", "exif:all"), IPTC( "IPTC", "iptc:all"), XMP( "XMP", "xmp:all"), ALL( "ALL", "all"); + + private final String name; + private final String value; + + private TagGroup(String name, String value) + { + this.name = name; + this.value = value; + } + + public String getName() + { + return name; + } + + public String getValue() + { + return value; + } + } + + // ================================================================================ /** * Class used to define an exception that occurs when the caller attempts to * use a {@link Feature} that the underlying native ExifTool install does @@ -1216,16 +1271,18 @@ public String getValue() { * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ - public class UnsupportedFeatureException extends RuntimeException { - private static final long serialVersionUID = -1332725983656030770L; + public class UnsupportedFeatureException extends RuntimeException + { + private static final long serialVersionUID = -1332725983656030770L; - public UnsupportedFeatureException(Feature feature) { + public UnsupportedFeatureException(Feature feature) + { super( - "Use of feature [" - + feature.toString() - + "] requires version " - + feature.getVersion() - + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); + "Use of feature [" + + feature.toString() + + "] requires version " + + feature.getVersion() + + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); } } From 22361404e91829c03d562f25b4c2bada2617bb13 Mon Sep 17 00:00:00 2001 From: Chris Turchin Date: Thu, 23 Jan 2014 03:08:02 +0100 Subject: [PATCH 013/148] extract ICC profile, extract thumbnail, extract all metadata to xml and add more tags and tag groups new methods to extract ICC profile, embedded thumbnails, and extract all metadata to XML. in addition, added new tags and tag groups, mostly related to ICC profiles, thumbnails but also file group metadata --- .../com/thebuzzmedia/exiftool/ExifTool.java | 189 ++++++++++++++++-- 1 file changed, 173 insertions(+), 16 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 9fad81b3..8294cf61 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -11,13 +11,14 @@ * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and - * limitations under the License. + * limitations under the License. */ package com.thebuzzmedia.exiftool; import java.io.BufferedReader; import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; @@ -35,6 +36,7 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; +import org.apache.commons.io.FilenameUtils; import org.apache.log4j.Logger; @@ -262,9 +264,9 @@ public ExifTool() } /** - * In this constructor, exifToolPath and processCleanupDelay are gotten from system properties - * exiftool.path and exiftool.processCleanupDelay. processCleanupDelay is optional. If not found, - * the default is used. + * In this constructor, exifToolPath and processCleanupDelay are gotten from + * system properties exiftool.path and exiftool.processCleanupDelay. + * processCleanupDelay is optional. If not found, the default is used. */ public ExifTool(Feature... features) { @@ -312,7 +314,8 @@ public ExifTool(String exifCmd, long processCleanupDelay, Feature... features) } /** - * Limits the amount of time (in mills) an exif operation can take. Setting value to greater than 0 to enable. + * Limits the amount of time (in mills) an exif operation can take. Setting + * value to greater than 0 to enable. */ public ExifTool setRunTimeout(int mills) { @@ -367,7 +370,8 @@ public boolean isFeatureSupported(Feature feature) throws RuntimeException /** * Used to startup the external ExifTool process and open the read/write * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. This method has no effect if the stay open feature is not enabled. + * enabled. This method has no effect if the stay open feature is not + * enabled. */ public void startup() { @@ -592,8 +596,106 @@ else if( format == Format.NUMERIC) } /** - * Will attempt 3 times to use the running exif process, and if unable to complete successfully will throw - * IOException + * extract image metadata to exiftool's internal xml format. + * + * @param input + * the input file + * @return command output as xml string + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public String getImageMetadataXml(File input, boolean includeBinary) throws IOException + { + List args = new ArrayList(); + args.add( "-X"); + if( includeBinary) + args.add( "-b"); + args.add( input.getAbsolutePath()); + + return ExifProcess.executeToString( exifCmd, args); + } + + /** + * extract image metadata to exiftool's internal xml format. + * + * @param input + * the input file + * @param output + * the output file + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public void getImageMetadataXml(File input, File output, boolean includeBinary) throws IOException + { + + String result = getImageMetadataXml( input, includeBinary); + + try (FileWriter w = new FileWriter( output)) + { + w.write( result); + } + } + + /** + * output icc profile from input to output. + * + * @param input + * the input file + * @param output + * the output file for icc data + * @return the command result from standard output e.g. + * "1 output files created" + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public String extractImageIccProfile(File input, File output) throws IOException + { + + List args = new ArrayList(); + args.add( "-icc_profile"); + args.add( input.getAbsolutePath()); + + args.add( "-o"); + args.add( output.getAbsolutePath()); + + return ExifProcess.executeToString( exifCmd, args); + } + + /** + * Extract thumbnail from the given tag. + * + * @param input + * the input file + * @param tag + * the tag containing binary data PhotoshopThumbnail or ThumbnailImage + * @return the thumbnail file created. it is in the same folder as the input + * file because of the syntax of exiftool and has the suffix + * ".thumb.jpg" + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public File extractThumbnail(File input, Tag tag) throws IOException + { + + List args = new ArrayList(); + String suffix = ".thumb.jpg"; + String thumbname = FilenameUtils.getBaseName( input.getName()) + suffix; + + args.add( "-" + tag.getName()); + args.add( input.getAbsolutePath()); + args.add( "-b"); + args.add( "-w"); + args.add( suffix); + String result = ExifProcess.executeToString( exifCmd, args); + File thumbnail = new File( input.getParent() + File.separator + thumbname); + if( !thumbnail.exists()) + throw new IOException( "could not create thumbnail: " + result); + return thumbnail; + } + + /** + * Will attempt 3 times to use the running exif process, and if unable to + * complete successfully will throw IOException */ private Map processStayOpen(List args) throws IOException { @@ -626,7 +728,8 @@ public void run() { if( STREAM_CLOSED_MESSAGE.equals( ex.getMessage()) && !shuttingDown.get()) { - // only catch "Stream Closed" error (happens when process has died) + // only catch "Stream Closed" error (happens when process + // has died) log.warn( String.format( "Caught IOException(\"%s\"), will restart daemon", STREAM_CLOSED_MESSAGE)); process.close(); } @@ -704,6 +807,22 @@ public static Map executeToResults(String exifCmd, List } } + public static String executeToString(String exifCmd, List args) throws IOException + { + List newArgs = new ArrayList( args.size() + 1); + newArgs.add( exifCmd); + newArgs.addAll( args); + ExifProcess process = _execute( false, newArgs); + try + { + return process.readResponseString(); + } + finally + { + process.close(); + } + } + public static ExifProcess startup(String exifCmd) { List args = Arrays.asList( exifCmd, "-stay_open", "True", "-@", "-"); @@ -787,10 +906,10 @@ public synchronized Map readResponse() throws IOException /* * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need to - * look for it and break from this loop when we see it otherwise - * this process will hang indefinitely blocking on the input stream - * with no data to read. + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. */ if( keepAlive && line.equals( "{ready}")) { @@ -800,6 +919,35 @@ public synchronized Map readResponse() throws IOException return resultMap; } + public synchronized String readResponseString() throws IOException + { + if( closed) + throw new IOException( STREAM_CLOSED_MESSAGE); + log.debug( "Reading response back from ExifTool..."); + String line; + StringBuilder result = new StringBuilder(); + while( (line = reader.readLine()) != null) + { + if( closed) + throw new IOException( STREAM_CLOSED_MESSAGE); + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if( keepAlive && line.equals( "{ready}")) + { + break; + } + else + result.append( line); + } + return result.toString(); + } + public boolean isClosed() { return closed; @@ -951,7 +1099,8 @@ public boolean isBeforeOrEqualTo(VersionNumber other) } else if( this.numbers[i] < other.numbers[i]) { return true; } } - // assume missing number as zero, so if the current process number is more digits it is a higher version + // assume missing number as zero, so if the current process number + // is more digits it is a higher version return this.numbers.length <= other.numbers.length; } @@ -1095,7 +1244,14 @@ public enum Tag TITLE( "XPTitle", String.class), WHITE_BALANCE( "WhiteBalance", Integer.class), X_RESOLUTION( "XResolution", Double.class), - Y_RESOLUTION( "YResolution", Double.class), ; + Y_RESOLUTION( "YResolution", Double.class), + // select ICC metadata + ICC_DESCRIPTION( "ProfileDescription", String.class), + ICC_COLORSPACEDATA( "ColorSpaceData", String.class), + // actually binary data, but what are we doing to do here??? Just use to + // save to file... + THUMBNAIL_IMAGE( "ThumbnailImage", String.class), + THUMBNAIL_PHOTOSHOP( "PhotoshopThumbnail", String.class); /** * Used to get the {@link Tag} identified by the given, case-sensitive, @@ -1240,7 +1396,8 @@ private Tag(String name, Class type) // ================================================================================ public enum TagGroup { - EXIF( "EXIF", "exif:all"), IPTC( "IPTC", "iptc:all"), XMP( "XMP", "xmp:all"), ALL( "ALL", "all"); + EXIF( "EXIF", "exif:all"), IPTC( "IPTC", "iptc:all"), XMP( "XMP", "xmp:all"), ALL( "ALL", "all"), FILE( "FILE", "file:all"), ICC( + "ICC", "icc_profile:all"); private final String name; private final String value; From 45d44fb5ac72e79a98309cc5ef355ea092696b2f Mon Sep 17 00:00:00 2001 From: Sam Smoot Date: Fri, 14 Feb 2014 10:02:24 -0600 Subject: [PATCH 014/148] Added the following IPTC fields commonly used on Press photos: * IPTC_KEYWORDS (Keywords) * COPYRIGHT_NOTICE (CopyrightNotice) * CREATOR (Creator) * CAPTION_ABSTRACT (Caption-Abstract) * OBJECT_NAME (ObjectName) --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 5 ++++- 1 file changed, 4 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index e43d47a6..435e0597 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -748,7 +748,10 @@ public enum Tag { "GPSTimeStamp", String.class), ROTATION("Rotation",Integer.class), EXIF_VERSION("ExifVersion",String.class), LENS_ID("LensID",String.class), COPYRIGHT("Copyright", String.class), ARTIST("Artist", String.class), - SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class); + SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), + OBJECT_NAME("ObjectName", String.class), CAPTION_ABSTRACT("Caption-Abstract", + String.class), CREATOR("Creator", String.class), IPTC_KEYWORDS("Keywords", + String.class), COPYRIGHT_NOTICE("CopyrightNotice", String.class); private static final Map TAG_LOOKUP_MAP; From 615dde6fac07575681fc5df8ba90a0e4fb78def0 Mon Sep 17 00:00:00 2001 From: Matt Burns Date: Mon, 31 Mar 2014 11:06:04 +0100 Subject: [PATCH 015/148] Added serial number related tags. --- .../java/com/thebuzzmedia/exiftool/ExifTool.java | 16 +++++++++++++++- 1 file changed, 15 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index e43d47a6..f9568406 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -748,7 +748,21 @@ public enum Tag { "GPSTimeStamp", String.class), ROTATION("Rotation",Integer.class), EXIF_VERSION("ExifVersion",String.class), LENS_ID("LensID",String.class), COPYRIGHT("Copyright", String.class), ARTIST("Artist", String.class), - SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class); + SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), + SERIAL_NUMBER("SerialNumber", String.class), + INTERNAL_SERIAL_NUMBER("InternalSerialNumber", String.class), + BODY_SERIAL_NUMBER("BodySerialNumber", String.class), + CAMERA_SERIAL_NUMBER("CameraSerialNumber", String.class), + EXTENDER_SERIAL_NUMBER("ExtenderSerialNumber", String.class), + DEVICE_SERIAL_NUMBER("DeviceSerialNumber", String.class), + FLASH_SERIAL_NUMBER("FlashSerialNumber", String.class), + LENS_SERIAL_NUMBER("LensSerialNumber", String.class), + SCANNER_SERIAL_NUMBER("ScannerSerialNumber", String.class), + SOURCE_SERIAL_NUMBER("SourceSerialNumber", String.class), + CREATOR("Creator", String.class), + COPYRIGHT_NOTICE("CopyrightNotice", String.class), + IMAGE_UNIQUE_ID("ImageUniqueID", String.class), + LENS("Lens", String.class); private static final Map TAG_LOOKUP_MAP; From c56f9a66d623a30f96bfbaa53b50073d9bbf06dd Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 17:55:28 +0300 Subject: [PATCH 016/148] - remove duplicate items from integration --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 3 --- 1 file changed, 3 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 45d09da2..95f179e2 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -752,7 +752,6 @@ public enum Tag { OBJECT_NAME("ObjectName", String.class), CAPTION_ABSTRACT("Caption-Abstract", String.class), CREATOR("Creator", String.class), IPTC_KEYWORDS("Keywords", String.class), COPYRIGHT_NOTICE("CopyrightNotice", String.class), - SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), SERIAL_NUMBER("SerialNumber", String.class), INTERNAL_SERIAL_NUMBER("InternalSerialNumber", String.class), BODY_SERIAL_NUMBER("BodySerialNumber", String.class), @@ -763,8 +762,6 @@ public enum Tag { LENS_SERIAL_NUMBER("LensSerialNumber", String.class), SCANNER_SERIAL_NUMBER("ScannerSerialNumber", String.class), SOURCE_SERIAL_NUMBER("SourceSerialNumber", String.class), - CREATOR("Creator", String.class), - COPYRIGHT_NOTICE("CopyrightNotice", String.class), IMAGE_UNIQUE_ID("ImageUniqueID", String.class), LENS("Lens", String.class), ; From 6806bdb2010195e895e91213a72ba7cfc5556d25 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 18:25:22 +0300 Subject: [PATCH 017/148] - alphabeticaly sorted tags --- .../com/thebuzzmedia/exiftool/ExifTool.java | 125 ++++++++++-------- 1 file changed, 72 insertions(+), 53 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 95f179e2..108416f5 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -711,59 +711,78 @@ public enum Format { * @since 1.1 */ public enum Tag { - ISO("ISO", Integer.class), APERTURE("ApertureValue", Double.class), WHITE_BALANCE( - "WhiteBalance", Integer.class), CONTRAST("Contrast", - Integer.class), SATURATION("Saturation", Integer.class), SHARPNESS( - "Sharpness", Integer.class), SHUTTER_SPEED("ShutterSpeedValue", - Double.class), DIGITAL_ZOOM_RATIO("DigitalZoomRatio", - Double.class), IMAGE_WIDTH("ImageWidth", Integer.class), IMAGE_HEIGHT( - "ImageHeight", Integer.class), X_RESOLUTION("XResolution", - Double.class), Y_RESOLUTION("YResolution", Double.class), FLASH( - "Flash", Integer.class), METERING_MODE("MeteringMode", - Integer.class), FOCAL_LENGTH("FocalLength", Double.class), FOCAL_LENGTH_35MM( - "FocalLengthIn35mmFormat", Integer.class), EXPOSURE_TIME( - "ExposureTime", Double.class), EXPOSURE_COMPENSATION( - "ExposureCompensation", Double.class), EXPOSURE_PROGRAM( - "ExposureProgram", Integer.class), ORIENTATION("Orientation", - Integer.class), COLOR_SPACE("ColorSpace", Integer.class), SENSING_METHOD( - "SensingMethod", Integer.class), SOFTWARE("Software", - String.class), MAKE("Make", String.class), MODEL("Model", - String.class), LENS_MAKE("LensMake", String.class), LENS_MODEL( - "LensModel", String.class), OWNER_NAME("OwnerName", - String.class), TITLE("XPTitle", String.class), AUTHOR( - "XPAuthor", String.class), SUBJECT("XPSubject", String.class), KEYWORDS( - "XPKeywords", String.class), COMMENT("XPComment", String.class), RATING( - "Rating", Integer.class), RATING_PERCENT("RatingPercent", - Integer.class), DATE_TIME_ORIGINAL("DateTimeOriginal", - String.class), CREATION_DATE("CreationDate", String.class), GPS_LATITUDE( - "GPSLatitude", Double.class), GPS_LATITUDE_REF( - "GPSLatitudeRef", String.class), GPS_LONGITUDE("GPSLongitude", - Double.class), GPS_LONGITUDE_REF("GPSLongitudeRef", - String.class), GPS_ALTITUDE("GPSAltitude", Double.class), GPS_ALTITUDE_REF( - "GPSAltitudeRef", Integer.class), GPS_SPEED("GPSSpeed", - Double.class), GPS_SPEED_REF("GPSSpeedRef", String.class), GPS_PROCESS_METHOD( - "GPSProcessingMethod", String.class), GPS_BEARING( - "GPSDestBearing", Double.class), GPS_BEARING_REF( - "GPSDestBearingRef", String.class), GPS_TIMESTAMP( - "GPSTimeStamp", String.class), ROTATION("Rotation",Integer.class), - EXIF_VERSION("ExifVersion",String.class), LENS_ID("LensID",String.class), - COPYRIGHT("Copyright", String.class), ARTIST("Artist", String.class), - SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), - OBJECT_NAME("ObjectName", String.class), CAPTION_ABSTRACT("Caption-Abstract", - String.class), CREATOR("Creator", String.class), IPTC_KEYWORDS("Keywords", - String.class), COPYRIGHT_NOTICE("CopyrightNotice", String.class), - SERIAL_NUMBER("SerialNumber", String.class), - INTERNAL_SERIAL_NUMBER("InternalSerialNumber", String.class), - BODY_SERIAL_NUMBER("BodySerialNumber", String.class), - CAMERA_SERIAL_NUMBER("CameraSerialNumber", String.class), - EXTENDER_SERIAL_NUMBER("ExtenderSerialNumber", String.class), - DEVICE_SERIAL_NUMBER("DeviceSerialNumber", String.class), - FLASH_SERIAL_NUMBER("FlashSerialNumber", String.class), - LENS_SERIAL_NUMBER("LensSerialNumber", String.class), - SCANNER_SERIAL_NUMBER("ScannerSerialNumber", String.class), - SOURCE_SERIAL_NUMBER("SourceSerialNumber", String.class), - IMAGE_UNIQUE_ID("ImageUniqueID", String.class), - LENS("Lens", String.class), + APERTURE("ApertureValue", Double.class), + ARTIST("Artist", String.class), + AUTHOR("XPAuthor", String.class), + BODY_SERIAL_NUMBER("BodySerialNumber", String.class), + CAMERA_SERIAL_NUMBER("CameraSerialNumber", String.class), + CAPTION_ABSTRACT("Caption-Abstract", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast",Integer.class), + COPYRIGHT("Copyright", String.class), + COPYRIGHT_NOTICE("CopyrightNotice", String.class), + CREATION_DATE("CreationDate", String.class), + CREATOR("Creator", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal",String.class), + DEVICE_SERIAL_NUMBER("DeviceSerialNumber", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio",Double.class), + EXIF_VERSION("ExifVersion",String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + EXTENDER_SERIAL_NUMBER("ExtenderSerialNumber", String.class), + FLASH("Flash", Integer.class), + FLASH_SERIAL_NUMBER("FlashSerialNumber", String.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude",Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef",String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed",Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_UNIQUE_ID("ImageUniqueID", String.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + INTERNAL_SERIAL_NUMBER("InternalSerialNumber", String.class), + IPTC_KEYWORDS("Keywords", String.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS("Lens", String.class), + LENS_ID("LensID",String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + LENS_SERIAL_NUMBER("LensSerialNumber", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode",Integer.class), + MODEL("Model",String.class), + OBJECT_NAME("ObjectName", String.class), + ORIENTATION("Orientation",Integer.class), + OWNER_NAME("OwnerName",String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent",Integer.class), + ROTATION("Rotation",Integer.class), + SATURATION("Saturation", Integer.class), + SCANNER_SERIAL_NUMBER("ScannerSerialNumber", String.class), + SENSING_METHOD("SensingMethod", Integer.class), + SERIAL_NUMBER("SerialNumber", String.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue",Double.class), + SOFTWARE("Software",String.class), + SOURCE_SERIAL_NUMBER("SourceSerialNumber", String.class), + SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution",Double.class), + Y_RESOLUTION("YResolution", Double.class), ; private static final Map TAG_LOOKUP_MAP; From bb0cba60e96117ba1237d7d3d6f36b303f4306b6 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 18:31:47 +0300 Subject: [PATCH 018/148] - formatting --- .../com/thebuzzmedia/exiftool/ExifTool.java | 142 +++++++++--------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 108416f5..8bf9da5d 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -712,77 +712,77 @@ public enum Format { */ public enum Tag { APERTURE("ApertureValue", Double.class), - ARTIST("Artist", String.class), - AUTHOR("XPAuthor", String.class), - BODY_SERIAL_NUMBER("BodySerialNumber", String.class), - CAMERA_SERIAL_NUMBER("CameraSerialNumber", String.class), - CAPTION_ABSTRACT("Caption-Abstract", String.class), - COLOR_SPACE("ColorSpace", Integer.class), - COMMENT("XPComment", String.class), - CONTRAST("Contrast",Integer.class), - COPYRIGHT("Copyright", String.class), - COPYRIGHT_NOTICE("CopyrightNotice", String.class), - CREATION_DATE("CreationDate", String.class), - CREATOR("Creator", String.class), - DATE_TIME_ORIGINAL("DateTimeOriginal",String.class), - DEVICE_SERIAL_NUMBER("DeviceSerialNumber", String.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio",Double.class), - EXIF_VERSION("ExifVersion",String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - EXTENDER_SERIAL_NUMBER("ExtenderSerialNumber", String.class), - FLASH("Flash", Integer.class), - FLASH_SERIAL_NUMBER("FlashSerialNumber", String.class), - FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), - GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), - GPS_LONGITUDE("GPSLongitude",Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef",String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), - GPS_SPEED("GPSSpeed",Double.class), - GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), - IMAGE_UNIQUE_ID("ImageUniqueID", String.class), - IMAGE_WIDTH("ImageWidth", Integer.class), - INTERNAL_SERIAL_NUMBER("InternalSerialNumber", String.class), - IPTC_KEYWORDS("Keywords", String.class), - ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), - LENS("Lens", String.class), - LENS_ID("LensID",String.class), - LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), - LENS_SERIAL_NUMBER("LensSerialNumber", String.class), - MAKE("Make", String.class), - METERING_MODE("MeteringMode",Integer.class), - MODEL("Model",String.class), - OBJECT_NAME("ObjectName", String.class), - ORIENTATION("Orientation",Integer.class), - OWNER_NAME("OwnerName",String.class), - RATING("Rating", Integer.class), - RATING_PERCENT("RatingPercent",Integer.class), - ROTATION("Rotation",Integer.class), - SATURATION("Saturation", Integer.class), - SCANNER_SERIAL_NUMBER("ScannerSerialNumber", String.class), - SENSING_METHOD("SensingMethod", Integer.class), - SERIAL_NUMBER("SerialNumber", String.class), - SHARPNESS("Sharpness", Integer.class), - SHUTTER_SPEED("ShutterSpeedValue",Double.class), - SOFTWARE("Software",String.class), - SOURCE_SERIAL_NUMBER("SourceSerialNumber", String.class), - SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), - SUBJECT("XPSubject", String.class), - TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), - X_RESOLUTION("XResolution",Double.class), - Y_RESOLUTION("YResolution", Double.class), + ARTIST("Artist", String.class), + AUTHOR("XPAuthor", String.class), + BODY_SERIAL_NUMBER("BodySerialNumber", String.class), + CAMERA_SERIAL_NUMBER("CameraSerialNumber", String.class), + CAPTION_ABSTRACT("Caption-Abstract", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + COPYRIGHT("Copyright", String.class), + COPYRIGHT_NOTICE("CopyrightNotice", String.class), + CREATION_DATE("CreationDate", String.class), + CREATOR("Creator", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), + DEVICE_SERIAL_NUMBER("DeviceSerialNumber", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + EXTENDER_SERIAL_NUMBER("ExtenderSerialNumber", String.class), + FLASH("Flash", Integer.class), + FLASH_SERIAL_NUMBER("FlashSerialNumber", String.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_UNIQUE_ID("ImageUniqueID", String.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + INTERNAL_SERIAL_NUMBER("InternalSerialNumber", String.class), + IPTC_KEYWORDS("Keywords", String.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS("Lens", String.class), + LENS_ID("LensID", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + LENS_SERIAL_NUMBER("LensSerialNumber", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + OBJECT_NAME("ObjectName", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SCANNER_SERIAL_NUMBER("ScannerSerialNumber", String.class), + SENSING_METHOD("SensingMethod", Integer.class), + SERIAL_NUMBER("SerialNumber", String.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SOURCE_SERIAL_NUMBER("SourceSerialNumber", String.class), + SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), ; private static final Map TAG_LOOKUP_MAP; From be72be9a0192953a863ecec890f4efab227da69d Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 18:40:28 +0300 Subject: [PATCH 019/148] sorted --- .../com/thebuzzmedia/exiftool/ExifTool.java | 88 +++++++++++-------- 1 file changed, 52 insertions(+), 36 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 30ea9386..7a4d1772 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -711,42 +711,58 @@ public enum Format { * @since 1.1 */ public enum Tag { - ISO("ISO", Integer.class), APERTURE("ApertureValue", Double.class), WHITE_BALANCE( - "WhiteBalance", Integer.class), CONTRAST("Contrast", - Integer.class), SATURATION("Saturation", Integer.class), SHARPNESS( - "Sharpness", Integer.class), SHUTTER_SPEED("ShutterSpeedValue", - Double.class), DIGITAL_ZOOM_RATIO("DigitalZoomRatio", - Double.class), IMAGE_WIDTH("ImageWidth", Integer.class), IMAGE_HEIGHT( - "ImageHeight", Integer.class), X_RESOLUTION("XResolution", - Double.class), Y_RESOLUTION("YResolution", Double.class), FLASH( - "Flash", Integer.class), METERING_MODE("MeteringMode", - Integer.class), FOCAL_LENGTH("FocalLength", Double.class), FOCAL_LENGTH_35MM( - "FocalLengthIn35mmFormat", Integer.class), EXPOSURE_TIME( - "ExposureTime", Double.class), EXPOSURE_COMPENSATION( - "ExposureCompensation", Double.class), EXPOSURE_PROGRAM( - "ExposureProgram", Integer.class), ORIENTATION("Orientation", - Integer.class), COLOR_SPACE("ColorSpace", Integer.class), SENSING_METHOD( - "SensingMethod", Integer.class), SOFTWARE("Software", - String.class), MAKE("Make", String.class), MODEL("Model", - String.class), LENS_MAKE("LensMake", String.class), LENS_MODEL( - "LensModel", String.class), OWNER_NAME("OwnerName", - String.class), TITLE("XPTitle", String.class), AUTHOR( - "XPAuthor", String.class), SUBJECT("XPSubject", String.class), KEYWORDS( - "XPKeywords", String.class), COMMENT("XPComment", String.class), RATING( - "Rating", Integer.class), RATING_PERCENT("RatingPercent", - Integer.class), DATE_TIME_ORIGINAL("DateTimeOriginal", - String.class), CREATION_DATE("CreationDate", String.class), GPS_LATITUDE( - "GPSLatitude", Double.class), GPS_LATITUDE_REF( - "GPSLatitudeRef", String.class), GPS_LONGITUDE("GPSLongitude", - Double.class), GPS_LONGITUDE_REF("GPSLongitudeRef", - String.class), GPS_ALTITUDE("GPSAltitude", Double.class), GPS_ALTITUDE_REF( - "GPSAltitudeRef", Integer.class), GPS_SPEED("GPSSpeed", - Double.class), GPS_SPEED_REF("GPSSpeedRef", String.class), GPS_PROCESS_METHOD( - "GPSProcessingMethod", String.class), GPS_BEARING( - "GPSDestBearing", Double.class), GPS_BEARING_REF( - "GPSDestBearingRef", String.class), GPS_TIMESTAMP( - "GPSTimeStamp", String.class), ROTATION("Rotation",Integer.class), - EXIF_VERSION("ExifVersion",String.class); + APERTURE("ApertureValueDouble.class), + AUTHOR("XPAuthorString.class), + COLOR_SPACE("ColorSpaceInteger.class), + COMMENT("XPCommentString.class), + CONTRAST("Contrast",Integer.class), + CREATION_DATE("CreationDateString.class), + DATE_TIME_ORIGINAL("DateTimeOriginal",String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio",Double.class), + EXIF_VERSION("ExifVersion",String.class), + EXPOSURE_COMPENSATION("ExposureCompensationDouble.class), + EXPOSURE_PROGRAM("ExposureProgramInteger.class), + EXPOSURE_TIME("ExposureTimeDouble.class), + FLASH("FlashInteger.class), + FOCAL_LENGTH("FocalLengthDouble.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormatInteger.class), + GPS_ALTITUDE("GPSAltitudeDouble.class), + GPS_ALTITUDE_REF("GPSAltitudeRefInteger.class), + GPS_BEARING("GPSDestBearingDouble.class), + GPS_BEARING_REF("GPSDestBearingRefString.class), + GPS_LATITUDE("GPSLatitudeDouble.class), + GPS_LATITUDE_REF("GPSLatitudeRefString.class), + GPS_LONGITUDE("GPSLongitude",Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef",String.class), + GPS_PROCESS_METHOD("GPSProcessingMethodString.class), + GPS_SPEED("GPSSpeed",Double.class), + GPS_SPEED_REF("GPSSpeedRefString.class), + GPS_TIMESTAMP("GPSTimeStampString.class), + IMAGE_HEIGHT("ImageHeightInteger.class), + IMAGE_WIDTH("ImageWidthInteger.class), + ISO("ISOInteger.class), + KEYWORDS("XPKeywordsString.class), + LENS_MAKE("LensMakeString.class), + LENS_MODEL("LensModelString.class), + MAKE("MakeString.class), + METERING_MODE("MeteringMode",Integer.class), + MODEL("Model",String.class), + ORIENTATION("Orientation",Integer.class), + OWNER_NAME("OwnerName",String.class), + RATING("RatingInteger.class), + RATING_PERCENT("RatingPercent",Integer.class), + ROTATION("Rotation",Integer.class), + SATURATION("SaturationInteger.class), + SENSING_METHOD("SensingMethodInteger.class), + SHARPNESS("SharpnessInteger.class), + SHUTTER_SPEED("ShutterSpeedValue",Double.class), + SOFTWARE("Software",String.class), + SUBJECT("XPSubjectString.class), + TITLE("XPTitleString.class), + WHITE_BALANCE("WhiteBalanceInteger.class), + X_RESOLUTION("XResolution",Double.class), + Y_RESOLUTION("YResolutionDouble.class), + ; private static final Map TAG_LOOKUP_MAP; From 3ef01f5ee0dc1ae0bf3b4cb99f7fabd58bafb9c4 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 18:43:08 +0300 Subject: [PATCH 020/148] - format --- .../com/thebuzzmedia/exiftool/ExifTool.java | 102 +++++++++--------- 1 file changed, 51 insertions(+), 51 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 7a4d1772..94c2fe8d 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -711,57 +711,57 @@ public enum Format { * @since 1.1 */ public enum Tag { - APERTURE("ApertureValueDouble.class), - AUTHOR("XPAuthorString.class), - COLOR_SPACE("ColorSpaceInteger.class), - COMMENT("XPCommentString.class), - CONTRAST("Contrast",Integer.class), - CREATION_DATE("CreationDateString.class), - DATE_TIME_ORIGINAL("DateTimeOriginal",String.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio",Double.class), - EXIF_VERSION("ExifVersion",String.class), - EXPOSURE_COMPENSATION("ExposureCompensationDouble.class), - EXPOSURE_PROGRAM("ExposureProgramInteger.class), - EXPOSURE_TIME("ExposureTimeDouble.class), - FLASH("FlashInteger.class), - FOCAL_LENGTH("FocalLengthDouble.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormatInteger.class), - GPS_ALTITUDE("GPSAltitudeDouble.class), - GPS_ALTITUDE_REF("GPSAltitudeRefInteger.class), - GPS_BEARING("GPSDestBearingDouble.class), - GPS_BEARING_REF("GPSDestBearingRefString.class), - GPS_LATITUDE("GPSLatitudeDouble.class), - GPS_LATITUDE_REF("GPSLatitudeRefString.class), - GPS_LONGITUDE("GPSLongitude",Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef",String.class), - GPS_PROCESS_METHOD("GPSProcessingMethodString.class), - GPS_SPEED("GPSSpeed",Double.class), - GPS_SPEED_REF("GPSSpeedRefString.class), - GPS_TIMESTAMP("GPSTimeStampString.class), - IMAGE_HEIGHT("ImageHeightInteger.class), - IMAGE_WIDTH("ImageWidthInteger.class), - ISO("ISOInteger.class), - KEYWORDS("XPKeywordsString.class), - LENS_MAKE("LensMakeString.class), - LENS_MODEL("LensModelString.class), - MAKE("MakeString.class), - METERING_MODE("MeteringMode",Integer.class), - MODEL("Model",String.class), - ORIENTATION("Orientation",Integer.class), - OWNER_NAME("OwnerName",String.class), - RATING("RatingInteger.class), - RATING_PERCENT("RatingPercent",Integer.class), - ROTATION("Rotation",Integer.class), - SATURATION("SaturationInteger.class), - SENSING_METHOD("SensingMethodInteger.class), - SHARPNESS("SharpnessInteger.class), - SHUTTER_SPEED("ShutterSpeedValue",Double.class), - SOFTWARE("Software",String.class), - SUBJECT("XPSubjectString.class), - TITLE("XPTitleString.class), - WHITE_BALANCE("WhiteBalanceInteger.class), - X_RESOLUTION("XResolution",Double.class), - Y_RESOLUTION("YResolutionDouble.class), + APERTURE("ApertureValue", Double.class), + AUTHOR("XPAuthor", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATION_DATE("CreationDate", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class) + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + FLASH("Flash", Integer.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SENSING_METHOD("SensingMethod", Integer.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), ; private static final Map TAG_LOOKUP_MAP; From 7420b8ed52738c15a406bfac73e25ec57a9a8801 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 18:44:06 +0300 Subject: [PATCH 021/148] fix comma --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 94c2fe8d..7e1cfa0a 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -719,7 +719,7 @@ public enum Tag { CREATION_DATE("CreationDate", String.class), DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class) + EXIF_VERSION("ExifVersion", String.class), EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), EXPOSURE_PROGRAM("ExposureProgram", Integer.class), EXPOSURE_TIME("ExposureTime", Double.class), From 8253e6489877418503abff157874904da35463a8 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 18:45:53 +0300 Subject: [PATCH 022/148] format --- .../com/thebuzzmedia/exiftool/ExifTool.java | 142 +++++++++--------- 1 file changed, 71 insertions(+), 71 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 8bf9da5d..435d3dc6 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -712,77 +712,77 @@ public enum Format { */ public enum Tag { APERTURE("ApertureValue", Double.class), - ARTIST("Artist", String.class), - AUTHOR("XPAuthor", String.class), - BODY_SERIAL_NUMBER("BodySerialNumber", String.class), - CAMERA_SERIAL_NUMBER("CameraSerialNumber", String.class), - CAPTION_ABSTRACT("Caption-Abstract", String.class), - COLOR_SPACE("ColorSpace", Integer.class), - COMMENT("XPComment", String.class), - CONTRAST("Contrast", Integer.class), - COPYRIGHT("Copyright", String.class), - COPYRIGHT_NOTICE("CopyrightNotice", String.class), - CREATION_DATE("CreationDate", String.class), - CREATOR("Creator", String.class), - DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), - DEVICE_SERIAL_NUMBER("DeviceSerialNumber", String.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - EXTENDER_SERIAL_NUMBER("ExtenderSerialNumber", String.class), - FLASH("Flash", Integer.class), - FLASH_SERIAL_NUMBER("FlashSerialNumber", String.class), - FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), - GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), - GPS_LONGITUDE("GPSLongitude", Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), - GPS_SPEED("GPSSpeed", Double.class), - GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), - IMAGE_UNIQUE_ID("ImageUniqueID", String.class), - IMAGE_WIDTH("ImageWidth", Integer.class), - INTERNAL_SERIAL_NUMBER("InternalSerialNumber", String.class), - IPTC_KEYWORDS("Keywords", String.class), - ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), - LENS("Lens", String.class), - LENS_ID("LensID", String.class), - LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), - LENS_SERIAL_NUMBER("LensSerialNumber", String.class), - MAKE("Make", String.class), - METERING_MODE("MeteringMode", Integer.class), - MODEL("Model", String.class), - OBJECT_NAME("ObjectName", String.class), - ORIENTATION("Orientation", Integer.class), - OWNER_NAME("OwnerName", String.class), - RATING("Rating", Integer.class), - RATING_PERCENT("RatingPercent", Integer.class), - ROTATION("Rotation", Integer.class), - SATURATION("Saturation", Integer.class), - SCANNER_SERIAL_NUMBER("ScannerSerialNumber", String.class), - SENSING_METHOD("SensingMethod", Integer.class), - SERIAL_NUMBER("SerialNumber", String.class), - SHARPNESS("Sharpness", Integer.class), - SHUTTER_SPEED("ShutterSpeedValue", Double.class), - SOFTWARE("Software", String.class), - SOURCE_SERIAL_NUMBER("SourceSerialNumber", String.class), - SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), - SUBJECT("XPSubject", String.class), - TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), - X_RESOLUTION("XResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), + ARTIST("Artist", String.class), + AUTHOR("XPAuthor", String.class), + BODY_SERIAL_NUMBER("BodySerialNumber", String.class), + CAMERA_SERIAL_NUMBER("CameraSerialNumber", String.class), + CAPTION_ABSTRACT("Caption-Abstract", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + COPYRIGHT("Copyright", String.class), + COPYRIGHT_NOTICE("CopyrightNotice", String.class), + CREATION_DATE("CreationDate", String.class), + CREATOR("Creator", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), + DEVICE_SERIAL_NUMBER("DeviceSerialNumber", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + EXTENDER_SERIAL_NUMBER("ExtenderSerialNumber", String.class), + FLASH("Flash", Integer.class), + FLASH_SERIAL_NUMBER("FlashSerialNumber", String.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_UNIQUE_ID("ImageUniqueID", String.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + INTERNAL_SERIAL_NUMBER("InternalSerialNumber", String.class), + IPTC_KEYWORDS("Keywords", String.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS("Lens", String.class), + LENS_ID("LensID", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + LENS_SERIAL_NUMBER("LensSerialNumber", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + OBJECT_NAME("ObjectName", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SCANNER_SERIAL_NUMBER("ScannerSerialNumber", String.class), + SENSING_METHOD("SensingMethod", Integer.class), + SERIAL_NUMBER("SerialNumber", String.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SOURCE_SERIAL_NUMBER("SourceSerialNumber", String.class), + SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), ; private static final Map TAG_LOOKUP_MAP; From 19bf667806c92752b084886aff3222ae9804c10e Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 18:56:23 +0300 Subject: [PATCH 023/148] formatted --- .../com/thebuzzmedia/exiftool/ExifTool.java | 90 +++++++++++-------- 1 file changed, 53 insertions(+), 37 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index e79a2320..46cd6d00 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -711,43 +711,59 @@ public enum Format { * @since 1.1 */ public enum Tag { - ISO("ISO", Integer.class), APERTURE("ApertureValue", Double.class), WHITE_BALANCE( - "WhiteBalance", Integer.class), CONTRAST("Contrast", - Integer.class), SATURATION("Saturation", Integer.class), SHARPNESS( - "Sharpness", Integer.class), SHUTTER_SPEED("ShutterSpeedValue", - Double.class), DIGITAL_ZOOM_RATIO("DigitalZoomRatio", - Double.class), IMAGE_WIDTH("ImageWidth", Integer.class), IMAGE_HEIGHT( - "ImageHeight", Integer.class), X_RESOLUTION("XResolution", - Double.class), Y_RESOLUTION("YResolution", Double.class), FLASH( - "Flash", Integer.class), METERING_MODE("MeteringMode", - Integer.class), FOCAL_LENGTH("FocalLength", Double.class), FOCAL_LENGTH_35MM( - "FocalLengthIn35mmFormat", Integer.class), EXPOSURE_TIME( - "ExposureTime", Double.class), EXPOSURE_COMPENSATION( - "ExposureCompensation", Double.class), EXPOSURE_PROGRAM( - "ExposureProgram", Integer.class), ORIENTATION("Orientation", - Integer.class), COLOR_SPACE("ColorSpace", Integer.class), SENSING_METHOD( - "SensingMethod", Integer.class), SOFTWARE("Software", - String.class), MAKE("Make", String.class), MODEL("Model", - String.class), LENS_MAKE("LensMake", String.class), LENS_MODEL( - "LensModel", String.class), OWNER_NAME("OwnerName", - String.class), TITLE("XPTitle", String.class), AUTHOR( - "XPAuthor", String.class), SUBJECT("XPSubject", String.class), KEYWORDS( - "XPKeywords", String.class), COMMENT("XPComment", String.class), RATING( - "Rating", Integer.class), RATING_PERCENT("RatingPercent", - Integer.class), DATE_TIME_ORIGINAL("DateTimeOriginal", - String.class), CREATION_DATE("CreationDate", String.class), GPS_LATITUDE( - "GPSLatitude", Double.class), GPS_LATITUDE_REF( - "GPSLatitudeRef", String.class), GPS_LONGITUDE("GPSLongitude", - Double.class), GPS_LONGITUDE_REF("GPSLongitudeRef", - String.class), GPS_ALTITUDE("GPSAltitude", Double.class), GPS_ALTITUDE_REF( - "GPSAltitudeRef", Integer.class), GPS_SPEED("GPSSpeed", - Double.class), GPS_SPEED_REF("GPSSpeedRef", String.class), GPS_PROCESS_METHOD( - "GPSProcessingMethod", String.class), GPS_BEARING( - "GPSDestBearing", Double.class), GPS_BEARING_REF( - "GPSDestBearingRef", String.class), GPS_TIMESTAMP( - "GPSTimeStamp", String.class), ROTATION("Rotation",Integer.class), - EXIF_VERSION("ExifVersion",String.class), FILE_TYPE("FileType",String.class); - + APERTURE("ApertureValue", Double.class), + AUTHOR("XPAuthor", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATION_DATE("CreationDate", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + FILE_TYPE("FileType", String.class), + FLASH("Flash", Integer.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SENSING_METHOD("SensingMethod", Integer.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), + ; private static final Map TAG_LOOKUP_MAP; /** From c9bdebef8880c4be2f1d32f41f3b7d6ab57d239e Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 22:06:38 +0300 Subject: [PATCH 024/148] Merge branch 'matt-changes' into HEAD Conflicts: src/main/java/com/thebuzzmedia/exiftool/ExifTool.java --- .gitignore | 3 ++ pom.xml | 35 +++++++++++++++++++ .../com/thebuzzmedia/exiftool/ExifTool.java | 19 ++++++++-- 3 files changed, 54 insertions(+), 3 deletions(-) create mode 100644 .gitignore create mode 100644 pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..389dc77c --- /dev/null +++ b/.gitignore @@ -0,0 +1,3 @@ +target +dist +bin diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..d3d3c965 --- /dev/null +++ b/pom.xml @@ -0,0 +1,35 @@ + + 4.0.0 + + + com.thebuzzmedia.exiftool + exiftool-lib + jar + 2.1.2 + https://github.com/thebuzzmedia/exiftool + + + + Riyad Kalla + software@thebuzzmedia.com + + + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + 1.5 + 1.5 + + + + + \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 29e1cfea..f28fa2d5 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -467,9 +467,6 @@ protected static void checkFeatureSupport(Feature... features) try { // Read the single-line reply (version number) ver = streams.reader.readLine(); - - // Close r/w streams to exited process. - streams.close(); } catch (Exception e) { /* * no-op, while it is important to know that we COULD launch the @@ -489,6 +486,9 @@ protected static void checkFeatureSupport(Feature... features) * scenarios, so making this method easier to use is more * important that robust IOException handling right here. */ + } finally { + // Close r/w streams to exited process. + streams.close(); } // Ensure the version found is >= the required version. @@ -720,10 +720,12 @@ public enum Tag { COLOR_SPACE("ColorSpace", Integer.class), COMMENT("XPComment", String.class), CONTRAST("Contrast", Integer.class), + CREATE_DATE("CreateDate", String.class), COPYRIGHT("Copyright", String.class), COPYRIGHT_NOTICE("CopyrightNotice", String.class), CREATION_DATE("CreationDate", String.class), CREATOR("Creator", String.class), + DATE_CREATED("DateCreated", String.class), DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), DEVICE_SERIAL_NUMBER("DeviceSerialNumber", String.class), DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), @@ -741,6 +743,7 @@ public enum Tag { GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), GPS_BEARING("GPSDestBearing", Double.class), GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_DATESTAMP("GPSDateStamp", String.class), GPS_LATITUDE("GPSLatitude", Double.class), GPS_LATITUDE_REF("GPSLatitudeRef", String.class), GPS_LONGITUDE("GPSLongitude", Double.class), @@ -978,6 +981,16 @@ public ExifTool(Feature... features) throws UnsupportedFeatureException { } } + public void shutdownCleanupTask() { + if(currentCleanupTask != null) { + currentCleanupTask.cancel(); + } + currentCleanupTask = null; + if(cleanupTimer != null) { + cleanupTimer.cancel(); + } + } + /** * Used to shutdown the external ExifTool process and close the read/write * streams used to communicate with it when {@link Feature#STAY_OPEN} is From 84f035f59f260c12b8dceb21e4bf1c79d98b6dc4 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 22:33:46 +0300 Subject: [PATCH 025/148] ignore --- .gitignore | 2 ++ 1 file changed, 2 insertions(+) diff --git a/.gitignore b/.gitignore index 389dc77c..83850880 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ target dist bin + +/.project From 4727ab357aa4c21496362e925466971b80aee52c Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 22:39:01 +0300 Subject: [PATCH 026/148] fix --- .gitignore | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/.gitignore b/.gitignore index 83850880..885c8f15 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,7 @@ dist bin /.project + +/.settings + +/.classpath From cc46b7c285430871bd3143587c6049bd6ded58da Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 22:47:37 +0300 Subject: [PATCH 027/148] - fix pom file --- .gitignore | 9 ++---- README | 3 +- build.xml | 17 ++++------- pom.xml | 28 ++++++++++++++++-- .../com/thebuzzmedia/exiftool/ExifTool.java | 24 +++++++++++---- src/main/java/log4j.properties | 8 ----- src/main/lib/log4j.jar | Bin 391834 -> 0 bytes src/main/main.iml | 13 -------- .../com/thebuzzmedia/exiftool/Benchmark.java | 12 ++++---- .../com/thebuzzmedia/exiftool/Example.java | 6 ++-- .../thebuzzmedia/exiftool/TestExifTool.java | 13 ++++---- src/test/lib/junit.jar | Bin 121091 -> 0 bytes src/test/test.iml | 23 -------------- 13 files changed, 73 insertions(+), 83 deletions(-) delete mode 100644 src/main/java/log4j.properties delete mode 100644 src/main/lib/log4j.jar delete mode 100644 src/main/main.iml delete mode 100644 src/test/lib/junit.jar delete mode 100644 src/test/test.iml diff --git a/.gitignore b/.gitignore index 885c8f15..683b0b2c 100644 --- a/.gitignore +++ b/.gitignore @@ -1,9 +1,6 @@ -target -dist -bin - +target +dist +bin /.project - /.settings - /.classpath diff --git a/README b/README index fb1cf048..0868be33 100644 --- a/README +++ b/README @@ -11,6 +11,7 @@ Changelog --------- 1.2 (In progress...) * Added support for the "CreationDate" QuickTime tag to the Tag enum. + * Merged support for WRITING meta tags from Fabien Vauchelles 1.1 * Initial public release. @@ -209,4 +210,4 @@ imgscalr - http://www.thebuzzmedia.com/software/imgscalr-java-image-scaling-libr Contact ------- If you have questions, comments or bug reports for this software please contact -us at: software@thebuzzmedia.com \ No newline at end of file +us at: software@thebuzzmedia.com diff --git a/build.xml b/build.xml index ce942f45..1bd6c84a 100644 --- a/build.xml +++ b/build.xml @@ -15,13 +15,12 @@ limitations under the License. --> - - + @@ -36,18 +35,12 @@ limitations under the License. - - - - - - - + + - @@ -58,7 +51,7 @@ limitations under the License. + linksource="true" public="true" source="1.5" use="true"> @@ -79,4 +72,4 @@ limitations under the License. - + \ No newline at end of file diff --git a/pom.xml b/pom.xml index d3d3c965..d7b8bf6f 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib jar - 2.1.2 + 2.2.0 https://github.com/thebuzzmedia/exiftool @@ -32,4 +32,28 @@ - \ No newline at end of file + + + + org.slf4j + slf4j-api + 1.7.5 + compile + + + + junit + junit + 4.11 + test + + + + + org.slf4j + slf4j-simple + 1.7.5 + test + + + diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 829a2100..708f736b 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -15,14 +15,28 @@ */ package com.thebuzzmedia.exiftool; -import org.apache.log4j.Logger; - -import java.io.*; -import java.util.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * Class used to provide a Java-like interface to Phil Harvey's excellent, * Perl-based fNyjEB|~A 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 z≫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

sl*CtvD7j$_;?KD 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

{0o23%x0zG^lL-+)0hE&z$21eha>paa zqIxrg2H$s%e`Ux4S6MyPFNl)-&mhY3Pl#^Hq9`DK%4)Sc>0HDF?J)SGtsj~yw9MNn z4Vpoxqk8(b@tHTF)(0>;SNial`dt<=IzP)3{i+C%jCbmaho} z;s%ISWg>y>prFr5lvKAp1GxCcl!c`QZXhTr0DnIVOhAKh_b?p8>iv^Db-=*y=?O8I_{w)_wGs(!N*s(!*S~Uxb!87K3+&x2^1{ES^1ETT)1)fN7;TUBd z>BPSw6|6PVzU!EkLcyPd{(BOYU<*p}fmwB-Bi*XuTfDEBRS8YOflsKH*ZNQI-;tmC zzQ;f9eOKHb$@v*)l%DVRoJweJ-We*f@k?_cqlIn2LvR-AkIALC(2Cd@q8fZ0zaP`% zEri8oL2x=RG=UJ+CHoa3X8-26zYp=uG{!GkJ@f|{KOa5}RzFW}Q*b5j2zJ4oQOd@~#N{Z>)a2ObJS{H=&(iUg5(}dbQX^!?R<@w4wtl>8Yk0jZ=?W zXR*i`U`vq0PKNmGwGBc?Mv~3&*Pp%)Tz?plEy$qBqI@l&!b7JzGDadnuvc+o_OZd- z!}HRryB+K>WzQTwtuyzBiarwW?R0(}r2W*9&e{wlD3+XY!m2~td>uHI7g=_73u|m? z$C6?}E+_30-W=F1NYV2&UZV2mI001?pNx~DsLFFD<-em9>w!T zq0e=>Igk(cV7VwMU>`!cdedN&JK3XY11+QZWQ@lozW)b2ZL$SI{{c_p{~0{l{t3^o zH~v2fbWrGKY%u)NK||SV?nZIYOq1>Vn@=0xs?FwA{3gIJ$A}dhR(~%*pohRX)A3s` zX0BCTJ&U7B*Q?3YMfJ9T4{;P2Z3bqqG(7kfm4d=vSC|Gbqk_ofFKhj&9^L@19l;=u zf@nz0vM9-2HUl^U{YOFIw z8kP)37N`P=wr>EpCiUCswX#N(Y{V%Lbog&${0=6{hOoK74rl<3Z#R*m;a#r7-n}0zXcACP^b9Ij3lA zN4m90o!YbV;;&>VdTJ{e5nA<;0{z|rm9OXBM1R&lfD9CYj{w@87@fbr9M%|Nb6DIyaq5Oq|S{a_rVwNw+1RnDpF9h@@==a zNCNqc;O!2-t)gHm5%>~YwwJZzqJ$mmkx;i-{BdhsAIYCl`B!dO1_zzewqJR z-sn^497S*%@MX|nM+x~GUG)!thODcp1O;=N&FM69g+D^q+ik`G&wf6?xCEi=R92>= zcCT6hkX;_d%(P6vNMz~kGbp%QiXH{DJljhgeHc z`fF-Sf48o;!(M(D4CYLc?BM6cgt~-;?d+g-YaMTFc=f8c#?k)JqK%}g1I7sYqGs5YAOi#E$$<+2QCe5g!nH!(<xETZd53-r8&KIwU%Jas2j5>yS1*=}_N zi(uG~{$}8rM9XxfJ{$MG{sj3~IFK5Dw*G^yto~;WF~@(v;XgW(VBMw)nxLdTxQdi; z<2+jGa8ZE&4-^>%11N-{lvC!Wbt~7&tHeIJTZ|Vg1Ezo2aM#bim`0iwtGxXb=U8Pq z&g4qD);?OlX3&ch0z;6=?2WQdrKECDigQP4mRB_*f}jWyL6IuORA=A8RtGX7xXJIW z&vrp#jxAE!w7lazr}x3-4_S;qrf(piY&kc_xVZBnuH7N^yIoQy$`E!8uGClorhF-xEuw9M3~at~ger!}8wEJg9$`(3>w z3s<76>VsZvzwRI9h(2Y|*GF0myHRVW_FK(9hPe}2qC{pZ4R1>#(C-a>>E;(Xmql0u zCAMMD?^T9#x?QBJRurJxhcL7SDWI%kER(=G+oJmcoB7~fcz!4wdGp9Fm5PvAM2wzdQDC9xR+B@4Uxx(+d<>$iOJ1e~bx<&huoiXA$oJRSHT9%wR z9tl9KZQ5j;#1w}hw$^bN^Dlv`e=Mkg{tiX>OVR%HgCXo5O_jI+$tByRD_+VetAyd% z+o-_5!jmZ0j`r|t&lnT!zdL&WuWa@2;A~X${8}_d`@Ax8HFb5lBLv~5hGaEBzLU=; z6SP2%|7HVHht$?JX5_j8YvrclVJqucb9hs~R;;pej z7cr1njcm7E+arU35@sYKf_4m4PX+5 zd6fCm6g?%eBMXhO!;&l%r5L3lE7ds47NOX%s%>_}6_FsH$tvL|=L%rEL_8Fm(OD*_ z@vK=3>f4H{Wvu1Q=tQNZ7LqGXZdhj$^B4;$8ker7TqYa9Fv9_&$}$zIGFbxc(lLv9 zC77~CM4pQc!Z{Y}+)O4bWtamkzlYZrIs46{=PhDXHl;f}*zgtKB5fi9F<*I&7cA?t z>!cMeZ(rO{EO?svW|Pk=WgkyaI}eGbik4q3h->E-;FOx3qBa!iCu?=qM731U#*lfP zTe`pt>NiU{JX+hK3dE!|ybcY^pf&M|i-*#k=#a)++@#eqmMm9o#b*dq=+wq?B1Kr{ zr<6CcBsHsT7G1THSwd4Aaj`E>o*jNTszj z9lj zTM+m#H-#ao7pVS&4XhEnAt(pA0XgH2$ed9(un=S1-2)X_pQ%v>yHsKpZZawosvpTF zvh_+uqC;Pi5C4m@ci_%6T((8KW81cEr-LuH?Ju_79ox2T+crD4?T(W^**bTxeb?IK z-Z9>P@IF`v*_CJei5C+aAwb$+wX2ii0^O@7UtN&VU|;s+b!7L1V)k zw7xUJ05$hnl9n~;@5a!-q z2BTETTpCCfU_d!bZn<@AB&}h%Ok!FNxJjc?5GZ~~SDecZ3#|AecNX+HT!ZT6;zlj^ zbtzUP!LdpFUi#q?&!4yXdL17#rD_84OYt#1;V#2rwg$;4t>9Jhi3p`GO|1-D^2XHr zXv3}4DVBnw&E(4I;NQ`cK$-#u(lYY06fmXqBt?NHwiF6=NPXMey5WJZ(}IUo)w>#I zH2l5{Je?TqWy89y>eoufi+@&F+~o8;U&7WW{OJVOwa-#1v;OI4YiGi29MxJ)M(9an>FugjY;;yO`PTOg z7L`4zSK3?6sxI(RXeaa14X);ZH&1%Y)pIJcpZ!|?1WhX}(&u<_Xqxeq5<3^?Fj?w_ z^Id=kZrSCn0mYlh$SQt`+~HK)w&n79X)dRa)@#-MF6k%-`Q2fP+2}>UOB(jPa(PeX4yngBgAM+H-Gsnz5DP9Z%o@#)NRienY(jK4;6iZ zN9aWbSLHxsUoS%(pR%TJNcKE}Rpv*>kOZ3mHNU@iCxl|S{Q7Y20XKQEsg->2`W|&$ zP=CLHh{TdufN2L4Eu?O1=`sKEm-`sFw zfA~#~UY!q=%SIM>;G4OpnSrb*$Kd!n2AJk*8%=8yg?TcNDjLyy37i~{@P1=vk6(^y z=tq_pEDj>w@|8gp_x?yljt>2JR^ZyZ7ME-t<_&Bh4d;wXV;2~za7T1EYOoR=DhUPU zGQ%h-LJyy*JKldp)8G0wj<$_7PI}mYrjOGAp`duW88CkFTMZCivB1?bT%)ivgWGS- za3OCztv89TkoSzA^ckmTYX6zl(97-)V;`;%32FpW;>r$_UsM$w(RcebA zkYX57oPS_gsy}`3Q}RRLAmrgCJl6!}s6CXZjhG!4b#@>haN8_mlRk@zLnSj09e~>$Kv_Lp|+C8Y0a= zLEcv0U}a-w55V>t;-PHyM)dP?(RGH9F1qQFGx}Z14fKg4*S#T=_AnN?vPrsUboOMr z8iwCcROdn+0U;c{z z#ycKf>t~AM@x+3{1{;sanTskp+IU85FiV%S#Eq)UMw=@p>E=@}9~I}y7GwIu;e}{r zdKT%9M5QO2trOCsD)-`M-iz0`G{|w9ZoOk{@Los^CV7fpjFV&jgiT-2lZx?TNji;u zrIYn-?wt!JA_c)n(}XkK?N__}JyG)Ya1bA@W^$Bc|HEq9tHXw@F}&#Btv)ial6Bf? z1pKOX7XN&+ZVvnJ|2U1xpHYHJ_SM*~esM1}|EpC7z}>?6zblP{RIHT$?O>v|rLu6X zk|LNQ0fx0AuD4(>WMckrB^4~w=hi@Sc;$LI6!RB=uWH(NF|&sP)=#RD4#_$gs+ZcB z45yjwjwdofU*FGgj*VXJtl&-v<$>1djMgIM=jLd(t47kG4#|xL2SP+=zClv-GzlZ6 zl9#$@O84^Jw6(w$YWM{>o5Po5xGv!7D#g!{s&Xc)`R)eW|U=?P8EJ-zKxt5pVgk~r8U z?7FQ2x}PyK83q0_baw2LwQU%&UTlRwv8t<%;_8M5@)n7HnIf5PGDZ!(!;IpaDHDMT ze$Ff(-$m2SQeg|R8a71zTwNzYs*!Z7ANDDA`JX@@iGA|*B!akyzlc&G1(w)i^*0Eh<11zma$y4z}xxVqt1nhPk}Cg6NI`!zs6HY1zd6kpZ8 z+@;AQsW{KT0D=@QfHG^uz74!=6p4*=i6r(|QeI@Pmo6LkWB`_3hs_>i6E4fwg%wI- zWv9Hd14jx%Z!amh-j7=a?qLTcpk74a>uVJG>_vDvwZa%Qwj+$d5lM;@eZiIus+{3`knA+l)IhYpL_Rhqgd9B!%YWu z8h_coUhW!s6`TM{+jIRuVnjC~MCn+4DG0soYLYN;-Is`iN<^WI4JZvWdmkg8B!Hvj zUE7__zt^!LDCh_`|Cb1Uwx>{@JyEUeOwK~Ce9Mo<-*Ydtta_n4$CY9#@<`d(OTxPl z0GDDe6WFJyQ#=>?4GU^)GyuzzA_WS+pzR*D(b*C6(&lYeo2*0<_C!BLG+Saa_QE@H zmQ1KXX-Rd8F3bC7s|1 z9yw;-o4)el^?%GV=U+LPe|)h9Dqrmx=l>dO|8`mM>qw~*&=_dp3Unk>wsvu}|1U9I zlA4wJx)@TIm57N7GG!oV9u;)a@GKOL1mS@VoI@>f9W?zZZA51sAn;(EB~X9xICJ5L zoRgfq;8VzhS!0&&y?q~9pTJgD7poULYX|F{{@?dc$oyvzRs4Wdivi$9{D2L}Z+ z7thtcUvOfyW}%CDYQjKgaL7DK!ERi%E8WQ`Nr@qIFnQa4T`(o{0Xv$JMslw*JT0>~ zrDk`Gq3QrD{FksfPH0`CE&4_{IAYbMdyHN_P_3^;KioceS4YFOd;k^BSW}Qnv$OxQ zzE-D)t;u#3c;&9z4FrBDjonIl7{Zz{6bs{l(FwR5yAYctwyAslwP9&U447E5Dg6^CDpZBS zaS5-dZv-HNif;qF0Rida#=@RUG#u!zmt-UX$o)^7g$7F9fr*#emDZ)ssr3zD>~`8?>4<&=I~|$IG2Y z1#x;eR(|wHcxipp#ulv%&~R`AEcW2)@Nj*LHwk_@x3HR+!UTaPw!z(+D0!L(#LG7u z-$rmmw#()$YvIv|$?jo6$rG`wy_sSl@G4m&GkrtHt8xgQ{Q@8t2lOJQ^YD8dl^eF&ADDeSl$pfjdQaV-k@LRJZ8$5p z*+kH=mq1&}gNDr|BvH1MreE^rN!=g zljux5K~Kp%4mGw>r-sb(+wRI+rfubn=TEmzOaWPKzSyG015upVL&qJvv6Awts=IQS z)Q2lPuz`}$T#;tVU#4fOfw}?jq9>e@Gv@rl^B`3PY$FL?24i)cp=2Z5M6X)dzH<8> zMcHDww(;-iD2-=oWDb!=I*P-mA2ujrLl6~mli3A;OYc7z^!QaBTu%sVmUo<@ZpiB* z+OF1^uQ|_T;tB`!k#6St_}c?7x`S??AH1}jx*LEI1hK@8vIAdow}qu_{Kg7Ej?SXR z8)EJEur4uLqtyIsaQ5v1a(1)1q9fIZ{$U=Mf$9$lbqNqt2`^lJ6G73RxD>a)td-IJ z(&fPh7DH!=1Ru~H#SMt8wfwNg<{Kb2(jl9s9Bcrc`9DyvOI zkELSYkyfZ3zgfGQxP(n(@H1MZ+V zR52Tnirhf#$^z3Gjx-GshwdadL??sp)JoKSgpP)$LDSri@e9DLqp}00h=Nu9jRBIm zX5L$J=*z3Qb2zu~4p=gZ4`DM|-^!Z4EKROwWG*d7V00+ErdFN{Tq(fqH z?6`q#2!%F$2{*$kddasv{nu4+)q5LY7EiHWqjiGceH_pMpWGy*;dhgl4XG=1a z<-w5BCM^an5*vzSJ_s5mF)M-3MnaXUc7?{-%FWm+cw%_yLYoqcjU***Ip=8BW`!f_ zQe%;JR^l()a zDk4Si&I3DWF6N8%|E)1>o%m@Jt;+HSAiot;+T^i z%XjHe5pL{oMwkPhHM6_%6}${3Vz=4BPYy|WU#wKSs9X|%84q67)W#)C=L-c7LSK`WDWAFSOW%!(3Cvbi9XQkRtm=tWD3`D|#8y`$M zB`W|)Q_av#RIpuLjG=Kv!o(~i5H>?iBQrLC(kaNwBKDv*0-zOT^^CA>6-p|kCrWuW z7beYf%ai4fiVq*+AliqB<2xvyz5j72^pStcrjSttBXa_-Ctu7E=QC!7ZyDXO?>zY@ zlgnl9Q!T~RsRCAtKd)eLbAX2tO7VTJq23Mvd^>B4xG%lB%eMXQp}E}aVyFD zH=8}na8s@&pryDkOIBHOfA7*bP!r==V($>&pTjAmZ3F>?q@rOJ1O=o;4g{HOMt#S1 z9raSKa0zw+bJ$>L%bpcle)MO-dlt0Wuciya)5clgRc)qIWRw^>UL5JcaCr{FS2zUMfD9AkRj}t=y5zO;rto6-@LA@_;?O z-}nZ`pLVb;=44kHZZN4YByPRKp8Xu=ZY$D3oaef*0=Q=Cg=@n)`2lg>M{SNF zKX17b(5JjYI`FV(LDF}y!0MiiBt|A_8Tqgp;ll<4@)MbO*W;7II}egZgYgI+-Fev8 zPc3ho|Ft_%p*=h*PZr&ppftC_pZ-Bbh%=2okFqPU>I=2eyHu@l3DG3s)NW>*ewO!h zKQOfg+9|XW6`%a{qEF*mn&T3$0C(;e=CscDMIPBTz$4ELlwJbL7!w?yd`OaE7l5@> zXMJ$}a37HjJhqR$DLy?#5(Bm$TcLmf1k1|!gs5N55r(dEFFhThFD*#WONC!_U!Ns4 zenzSPs1`NpWYB{BF`$T-P(d8dE!LnuMwC4Q+XS_KAV91*yli0#ui-QCC^)OxvPeEShI$G(xz7bk-3dKHpNij|0-^2pOk+vuU1> zLYyOseF;WTpjq_0%J~;z(Di>)YW|ziCBqRQEbePg3H{a1{nJ*?)zHzxkWmz9>mg)q z{k3D^{9hGil%lMB{|}@r&2BKo8_=Gc+&ChvBFufE$YCf7iYNjm9X@)XGKQ736!EU0 z$816vY+53@B_4EucVp~`%0JNd;;^YT8oFhHcp_X94GgyIaH#w zWLFBLC)$&fDK}_@m(aF!XA+_}Z*(j&2B(t75j|57+e{tS7eO+$l-cK;g8KO9#3UYn zxoQ*Nazmn)^LIHb0a}9_oH9gg9+?LeTUOGa+aa{I7c;U^MU@_VsrW1%kkz zQ(htF!U{TAY2U1305-04b+6^gaUhAZ<;6>m>E^NyY`L*41b2U8l*`YSTljw*>44CU zZ7_d9H0BpXGygM){*NCkW@v3~WN2&!aCEeD{D<|KBsFa(WmU9KSH?DWG^$3833701 za%#~wYI-6INn#WwYw0%4L$Xy_IqorN%90@elSr2Rzc)jiW~p(%nD(FZr=NEce)g&7 zTvW6#2~c9jqtz{}rZn|5b-S#;9W3|c{QV_|*MI!|LZm+e5#;1Ye@Fx$C1`74A|h*N z8(wcn>K|jqqs~;sTu5kwYA}iVodH#W?xO)0jIEvBVobu9+EEM1>3H&vFVyzrQx6XyMortx0?8gjsSLwPL7>_t21C+CDnkIEEcNr$o zvM4rrsWX{_j5Y&%N@JET>#4eSV*1?VS)qcq0xnX{D!A`+n0}&>!F;GPFY`X7C`&~T z`U1~J)peR;g)nA!4}vo=u0?BjNu6DLI?;NQE?#^y9vhsbKyETvZ4z*7EzNjDfkSrd zgGsHmCj*&wGnC7b2;4_4YI!_ zqjPj50OUZ+mQ+N}(O~20$cHvzDv9Q3iQkSb`W?VHNhH-uI$P(?1qJ(c<`dG;m?l&a z4{c?BV@jyffISp7*LG{d^!T2o(F7;hBc-YWCWuaxgpq!(4vm7sPd0+M zOCuuIGx-bXOw6&x5(XQvq-yHMeIvncksN6BMI6~U@8RGXf~^}Y=|X3)crRwxIRZA< z_0>tZPJ?imr$y%B!ro&lbgKMl&SgB)%76GaUQVR^=0hm!)#&)NM&|AkzT{gm@(Q>0 znO3>hkz1p#`Z3k&)A$>V`ptSl6ZXQQE+IuMj6jls;$wk*V*CMS>N|Z#6mEU))rNG- zSeUwQ%uNO3oA(yW^<6+&uP*STTV=+^KL>uqRYp@D&$?-w;pCP4qRFIBC&@(!@kM*n zFtwZNjpzo$XR_A@{F8TQ+BwYpVUBxK0cXVAEzwlS$?chX&{)fPRvl@F5#Jt5H*_8f z3?J!ot5|afAI|}vkBnwG+uJYtTz+nKSyjlb5Cl=yM-PYQhCe{?9Ur78m-8KjKM+Ph z=ofk5x(X#e5y%ez#jxa^PiCpy+*PBaK`*fb{?2bjJmqe}FUK>*>O5wI7?eR=BcvuQ zxgA~gTNq@wxeG+`Vb?Gi&kR(Du=->rv3`WwqmUdvzB0JCv3=;E$As+?YI+%m;XEY$ zxv-S!r3#C+i^8x4)<-z)*XDM~SL`0Q?31hOBNuQV{e4QkKd83rF)IRBWoJ(b3|VmA zG58>v=bYwP4~=Bq;e^)1J*QB?pA)^gA-`!>G@BYLG#%Umi~^<=z`Y1uBJ4i7_2iF{ z%Ry>?;kSlowTex7W|?r>V{o3H>JJ*f`aR&a+(6DhCrp3(t622>7~_qwyA?p+6uErI zy_BnP)vQS}>QW2;qeZ>6sdPgV{MArm0>`V~91hhpg6nWRL^BEK2 zRaPoyJ&c=v5O?uZS7V9Jm$?maz259N&i1-WdY|d}*$u$KRG1MO!PLa-OTl4~-KqF; zDw!Kwo_8S+sd%Oc0q7)j+p*JGv`#BnyDgnf@n&Q#9i2IrxVkmC^eEf0W5Yxpdym3r z@D|S@@J%pdVpCXE??Y}tFSYR_!L@1UUxzUuipJz7TQw!UWlgEELa>i@=*}T(P17K@ zYr|Owc>9K~I*{rgr5|eap@_7r=$R>4+Q!`6!%rYj^-YxYpWl=;$2M*-v@ExoN%A_< z^d%p%s^C-%FZf# zaL1YSd9WO2Nu?!vkOWyu2jY~J1LwB%@0>vrJ4fG;HM6ZVh%d(;!s+l8y<9iTO|686L+ zbX)!r^%(dIRA*E>SaVUB;vy&s29EmNJhld!BMx}K?UlvhTi7a3TBEqX=&_W%hwlAe zrUZ@UtJB11-(H&@Tb^o4%MHvBHak-4GKeD_A*WRheJw zvF;6jX}P*k7f;xC9|9>oEBc?>B*EAt@B|yP@r9eBHD75?zM*9fl0}mQ@o7@mmk|A= zyzNU>kLrw_f>EE(%0@M)4|#Zxt)xX8GoMoZ{8m9#6ZcBr=_CAV4t@mnm&Gu^F(mF8 zinWo&J5ruXIA5m-%OhF+ukfp3du}5k4S3VXIe`iVU$+26LX3eJ8MeSs8I<)8{SLOO z```Zc0h6?NWptgvkFatou$CvI>KHUVq<#(PlKarD>*M3P2 zHnlP!4m&G89b}20ev3;Bgy1jcl}8{Z(Pl(VQIsT#UyDZG4HGTb2xa&yI;S*Z=>oa> zJIIZVLuGnfVPUI%`l$?=;P)BoNS{VU zxtFTSY0e!9vVx=xsWtk58S&Zi-|znz+ryRt@d{sY{TKdA!2hpnD1wFz*ea*ZHuWO!G)^l5S zp)ty9o|n0?7QSkM*TysFr`*pEF{3GviJ2Rb>(i+WJJaqoPWjHqo)o)$9LigLe1u{Z znTpYq(f;3U7pJX+-1zdn%MOHhI3U=tcd2CqbVtsU`&l$wMaGnlI9v4lUT0LkHNlj? z^*6Am4;%rac*L{Cm)Ovp`CCIi`UW!OVVfj<8VEKyY$WCuH zaa4hl-TV4yaF3V#U^5qQ=o#qI6n4IvecI>p;2H~eq2gs#Z`}b-Hg9FRpI_D)z(2e^ z7&p4;+sd~-;J+nl6=s=sUQQ8c&B(vpzamqv($BDN<}KC*3y3&Q58KEEn1E9n_}CM& zZjoT!`^A9dd++f?UvM`HRyBcb(ad6~66!&V^g8bmOV5=F6KnmxE0#n(MIwpK(N0{M zHNONE1+OKCtlSJ=_7)v--87 zvlUYwDt;X5p6imM4)|LJ;X00r`O@72E6k$`5^X8AhU;anF_})j zp368XX9!8yzKc#Rh*c}n0nGQT+A8Z-z=_pLZP7OUw&EeH_?xZG2_eH%B}e%;a7r3x zW#U^^r!1IgI}A7vp&WI4<-=K3rxG-CvxKy!vsv*@|D47*Jju6cs+vpxf;~tG-%tne zqe}yHJZj^0SWewq%6!@G>lYedlbsRwxn6Lc!_j+2Rw#|}LU04n_)7M_EnF$_%JGze42ags;ps&xJfj z$1@db5eMHSz;O1`n7vfofuM`Tea6-^u`T4OZc|(0DB`IGbYr_~_G=8y!1MjGMekv< zN3FqfM>=-bvsHG6agAD$oRQrOpHZ=&b-pV;2QLOrYhY6Xzp`k9VdH(HEsa3lRm$Q@ z^&Q-oNlLP8kD|Rn#v1F5_PgBUd$tRaA>xdLMh(o^&)D9IV8*iN0>9-ON>DRH&-<^&!irB^) zlfL27-)VChqfgMkD!2dc&X%n$P3@=&CNajSdKS`r*byaT= z{$}MorW3TgcgaZJX2cv@`h!%HO)(*zRgybMv%kLRi4Q5X1Hy#a2+X!c793!xz zqew)xR(TEfm^3F4-#4VfwcfPq!eT9`Sj+Mv`(50{rT9>>y}by^lYaj2<$iaHbJwPT z#_hcFkTood%==B{_saY)bTXP>a4J-rNH4t{+e~!g_3G(%ROu%amaC8FA^KWRw{M7{ zLJ8IVX%zTuc&mH^ar8Jap2UJQf87;tx?&ox}VVkSt%ke`z72 z9OFICHHkQ%FzITwID-XX!RQ{7H$nm{B+%NAb308(l~-&? zH?}f@hOYwPX$kLxL?a~gamz?o8Qn>k#P4qBTEg)@`*@8&AQ0@GK`j&J9l)G9phIsB z8*LSad9oQLp2vr%jkgaRG&#C)-mof1 zgS0awUA9vmbPGMY1T72$I|Y303WW>okh0EVU5VMFs5ABU^D-1c?9AR{5)!OhVXuGS z3ZnBcPshu#2xrVdpP7`hhgp24+|lLC-0SCH?gZ<&)X}&ZMfSu5Pa^CwFBJ+`5|9YW zNoTdDtZW`Qr=#;r;l?ZZ#wt)y-%lOOMJKH??<>V~#6D0QHGo?Nax8{;lzleTH6QFu^6On zrfL@Isma&v{Z5!P8?a{g(r`E_(!smRJJ@SF1X_RAvu4O2)TDQzX!g(Y&$fE}l*rI5 zv`<@&IPxwLx{-=q}N;KhHn>wR#x%wvXQ>m!8hM-+VyuV#=!1hGxH zkgC1Ow?_45B5uPmRD-Ar`iyVPT}fdQo#{f)6$Cedh!qScPUp>U1D6pK-N!CB&7BRe z4I(rEcR?KIEJt$|_YNAiD744qkCO`=)O?tqoDFfR8y6Rry3pC>T?BoIyd))0d7Bjw zQ7&&>LY$>+d5TL$m(|}xJw$C(QLS3?5zoh^BZ>kzdP*>0K-9sZR-_K%{CSV$@g(@O z=yrnpM5g|Mm0NuRPm1eiCdQsCxnJXg%fEIoQeFJJ#+5j(k|W*?Wel@y-LziGhA0Jf zEXAIiVrC@oEU1qEBr4~S-C+wa;zx~mt~j9<4kEc#S(KKYM0c*?Y^e}&K_Ti zZBq*~7e_;9JIDVRzhx`6LZS4wpJ?M}_Z!@L(bn=jZNND1^bfUyxm{7-k}5 zh3%MmAPMy$-V_X;G23DR_?%tTe|yznyq>;%B1={hNZVDQ;^t1pVa2)Fw^E|*{B&9PhLpX=gh)AksO7Rvg?ZmHyjH$#mL6)6i_ zs;j4N@0TfDaWY8H<3%X-#tF!$0PJZZ>wQ^M!x>bvYCpTylEB*m*yf6gd4EN2r^9_C zYS)JI)zQ`a;eiL)XkGnozddE!vLAgc!t0CA!&R$cn=efUzyhyoyoHB52ehsViwG8? zod*&Rv+G%>KY0ert5N|FS%EKtmwXYf&PYq24J^V8*-S`z*93{>^?1mpTG4;fg0VlT zEs*d8YX7WKJWts)Ox3px{GB**oN&uMge053itPlPQHZ(LU7CW$io>9u^s&7em`)lB zj&SB-`p9;D9S)Hv1Ubdx!$d97Pms;``D08pjS9hx#>t7tDz5iG*4cu@=-)-Z=mHjq zZ{LXi_1~3HRrt?;sIso~wO`4f@B?Eh=^L^TASxUOq;<>AT?8!(Ou^s$!D1!S&|y=T z5_j=V$?^sL^Vf`uq>*G&jhd!!!b(Ho_~@mdb+cP>$8qLWcJ|Ak<2OW6=3gT`TFkSN za(K%9DhvBKawq14lH_t0TvY|opt4*A-DWPC10L+{xq|@wfY!p@`e0g~HG9?XI?6^8 z11|Ujt$Di?A_3Q9zx;q$B*HA2W1jWqjyc*5{mz|xr`%52(is_?`VhkH8xDH1p3$T* zq|Kzk-ukWJ#E{rVDb~vf)l51PHqgWiys~|8Uf_L5Gi%jYjDi`+j^Q(0g%&fO7;eSr za8p*}!3IkV%+7X$Zf~EuFmyB%3}cD?UoKPUWx3Al^-kW|8P!meI;AAy1!M=Ev2E$n zW?9l%et6gpZj~DNR~Xcc($9XEZ6*s&dYW3oMZ@+64UsX_-#|A{m}_yp;G7Lp{E# zty`qAQ!L3R1cC@`mr2)lR94WLZK>HvB>q%4*fA5RCFThx>FOr;ZLyapNzJuC(@+H` z=R>g+V$q-#QYl)w{6<~Ugiw!@ot#vh;v}_#=|qPgh+fnZyj$rh7HH_d4WdiatdaN` zJnWxJz0hLZ#aAYmwwQiqeM&`BIqexeR)1bjim8Po{au|?Y_BKyR-ERoNJGV&LL8Jhzyj$XjMRQ*gjMw9NbT;qdXB3?K)0$8<#MOR`(Gna&dvn*pHZl4<%Ft=hdc~;n&Z(EU@}$~ zGjkT}e!+ZajGkF7ewc=2U3K!9x$nNd*PFiD{`>g|c{T^BKB5T6Rsb7d$yKroj?cJ9 zjt|dOLnea5Ks7eOL(*DGR%7n2Izq0ambwd7eS+0z4yNv+Gmsj6-ijmPvIi|oyrl4Ot0g`1!*=(j)2Vylzuj)V6 zo3bPvdJ}rG=0B?9KNZV!3JX`v*JG|lPAf<&J3@;vnHG_3r+qZ4MC7yVnE6D>Hxd`5 zxE_}xMShA=D1TTC+iV4i2|m2X`~1O}5Jv46Y*<4CuBF^eyO0!weQH*P9TIOoKJhgH zsqgoZrFw3x;dY~Ik+}EJgt49>?+P|h15!0(CRw#*SiCBQ-O)0PxSwq286VmVP&EKM z0DBLTHG9WJdvx}9l6eobHlQVjI9$Q|5ZQgyexzQDQUi&8%eTQwsT}qo%zn{b<)%9r zwzLNs5ORAKegPeUHM`M%Es0Mpx6!?~6?#Ys?A^>c&c<8$55~X_385Yc$1EW|qI}`8 z8wruVUxOVu;Si>V^{OnKa4Rqmi=#@CN1$I|h-y1Q93=_6O(zj6V4QS_ zRSI&{n}n1%Jv`ys*Zv5Xua5t*E|!{>#+?p~;}AtfU)Hq>Te7L5npH~dE4FSxxE5ML9lO>B9G@}sp_LC4ixOtw zrLi~PoLh3`t0M(A%u`GDSQmGa`~`^u=T_d`AlNReDQ&b#xl@{WqDfZXDsK2Xt29XO zr_9?~PLO+b^l3)<(lotuS8WH$5?N@)PYc$7+j7*veC-Z|*rM{;F3@wtTq@IzA5lQs zmwuvJ$?)D5*5&?k<5l9i&kkg@BOc+|lPk#B$G++=2%g85sTL;lQd3B|&=vBzb7PZv zQkiQFFGe@t5L;~aK!1gKq$iEPsxbNsien+fD1*g@TasqW=JfuHLh#^>G}~8(CkN>s zTk**rBgg35QydYE zxkw`bF;@RUU|K;-kpD9!y_{?1O(O2nXYq*={4GDE++05xxf;=_3PTl7GdMfk^?^_H z7*vUSm944Pb6c$xW=YtU(B=GMu#vwP=E8gE#A@j0EXhj`4+fneJhOHkq1%eCe~6>-1u4R2zKXQb{}0W`|C{(% z(Uo6N!1A45YGN7>@ecb1lRpbz=u4CfN|H}O@jLAYQyPWVxTLz$+Nz86JL=XwZ0Bka zh5sq3y1l=cWEl#;!A@2`q-as3-u#f zNY8X)J!7outj3>&sB#$IH({N+>F z;@kcsUJdEp$5lGe^2bnuTianMjf_=QSdw(K?Q^s2MNIhytWz4LNm2y$z#{g|Vx~`C za!aLDuN(G!hA(+7mue_kNV+r!qodMXfF8PqGj(gx9tVa>>4}=X_z;O0I$fE@urB)3 zk9StH3y1*??T!(}Dsrs@+b~EVzdj89_WDg14I)V?%BxtHHsZSTyRHSGq?=0mUkeD`duN;LE-K zQJ9zo)Q{r}T%4?zuuUdO-d$170!&UD2fCL=Vnw~E6|ghKe!!hVqCNVRT6hL7jzHAm z2{}?$!n0LI8S)itkv1YFHW=H)cf_DA$*;uYHXoE)_YVVf!rLBJ)WSQ-EM>(AvY6s6 zvDzZTo^QN_DJ?Q9juWMp;wy}Jyue_6%qOV zLOKH!<+?3g#L7jbrOIHu%j;=$QBggEzANsHU0{i5Uu;c!98Y>|Imz9fKRxA`?+PTh z-_$aRyoy0a=!V1MZL;WnI&>Y*+fk;(MZeB zemq+GYt0~#%z_CR6)aQAK)j8nSP4aW`wFk}Nzz*-HQE_=N`k9<=IenG8A2Q9(kC=4 z7COR;*SF>mJu=}6w223K{%?z2jueLp#bOkoe1)S_o^A+z2ohW;bE`#AbbaIj0%f0t zP-c~3tk&61TIKhy#mxXk+UE-!q8?hm1Ot!r(+HV(HQ`od(79k%>qWIv#H zP(k(5`Lt@4Fzw^yQuO4SR^DsC2Y@+&3kNwvBw5RFz90XCywOTLnYaGRm#$yM7x%w@6#(}y>5=W1T*c$x=PD-u=J)!K zuOv(5KTSRC)~hD~DzOnMB$k>%;NP3#VzH>=Ruq(K!vsP@9t(BrFKm--3gkZ#{su5o zkc3ePyza!XOw%!98E4y>4jG@y86rry|=6ONz5nqNHp- z6*DwRub7!C_NI#n4G97rF~Go z(*nAb{vS&zgIx0t%Lb3y5`X-*W2&QF)gt9xnfmo<(Un?6@Z@Q){2KukKU(}_kyR%= zRqYo1KO0X;+RER%s_@J0Y4bBiZEnuBK5_z96u?32an|Uu%i{^xRO)|qU$O_38xi?k z{Jk-2vx5j`HZp)xXX9gu1@6;STWB!Vh9djb-DeE6Nkb6qhxwJ@b=dpSfEQ1jIG|0{ zanem~eXVbEPMbUgBV^kS%8@G6i{Tn~3=*5aF1CAL3GatO#O8%nO1kW{@g;CxNX_Si z6E{U;VoMmHLA(;p%B#VFnjpHarbsGv^a-9hClb5EkkuqK$uRpj+7gJQ-jWV>i+U80 zy`4sUhe@pShg)J6OLjnsa*&BFKH4$GwFs&=DpWplM+_(M;EWTc7RC|?vn0IS=aWeKkS-E_Noiir zu-1@KE+~G!9`HDg`=D6F+m(TKEMB?|s>Jt5{X}4&6qzGf>KHxXHK8C4>l zqWhD!wY2foxhs7Q1pg^FV+(Xai3(f4NLI}zJGp0MxA!uA)U9ALO#etEG)L&Wv>))z%X=aLVgWGhN5oBW^PvkCji? ze_!r9pz={$Nb#nB=YsBAa@7QvEZ#H*GXfN%7%PUr**i*uov~1nO=4AHMFxtPDA;8H z3K5w&#q2r=q%|_8Y^hQ}3o5D?ba+=RIV@W+fXXPS{SxvliA2jR${Z z4eg;5PPY0mqp1BiPLkFzyTC6S{S@}j{M`(Hg}!=SKR9T%2}dRFkP3549v|{7y7o5j zyUI8R`nOnv1>gWxCPTXEbY|gzN8b_l#H53h^*G1;DtU|dTBgh^PrGV|GIvRlHj=#N zqX~fH1DMI>-D3__{Yv=;I))e|VXBEPqt5W_3>Z43 zUVB=@RIS_-CXKneY~b+d!ATuJpJ^$CtjfjfyFU}ZXgQ51O zwOH#Z`|u7_=jeRdinEPqw+Dl4HHRj1^k|!kDWYkLq7Hm;{_VeOTg!O$KEx&{cxhy4 zILxuIo5Ed(u|~^yH@c4q+7ol41>jEHzagGUxY$rdw3#ewew-y>r9` zu?nfXd_TlpRiOvrI~XEX#C@vq^S8~7NJI3^=%iR)0SEyV+daXyhTUM=|$FY-* zl3EBXb!I5McPgoJ+iJO#AF-zvM|$_wW|@qq9}v*&Ixs<5M0DYIp?bJuF+6W*--=DB@ckAzNJVq3?o)A@Hba0K{w0b*aBim#=eZZ zU2D!7)oq1FJdd>s?x4kbY|e*_GtAC}CLF})Sw*|)yE*!a33FJq?qE8Sd&U;*YvLWy zchE`IU4IWhzw(xQHdW{+Sm&HtKZKH;!gzH$^d z1^#JS8-m@z93+G!g#r`kIBv!fPznWC`tj`nYYzEP3^z$@dYJES&~uuL2;wa+odFPt`y27?-IcbChLFTD zlP||@3cvbDlw{GS7-(J1s+1~bnf=>>HtkFLqJF(mEV zIW46gv>_;K8X>$~OmZpDAPA2^sWgkDywdK(>#C!xf46Sp*qB^&^^_cr136@zE#V&ZsW3RLCd1k7R+7fzBDAI4oC#$dTf zX7Y0GO8Lf84!GgQJ>Vkzl<(NGbMX>jxkxc@6AK;U&LeL!e$=NXQ>U`Pi!`&6ORK=ltp~c*) zd=PjMP>Q$LB{iVA$h)^2o=qDhl)#cq#Gr0Z_hB;oCuD9?D9g|B1O^pt3i)bh4pS9) zYeeJqmKGczMH!(YU3A_dKZ1JyZ)M-VVWx}RWyiu7W`=)Z zCfz?P`~E3r{wMFIrfrRdF$kw`4MH^3uOMy=e-Gm`K4RBqu2h$(d97873(e<0&u?jLz+qR)XuJ zQ6*cIh7yi_VbJN$xTqQb4`2Tjommui>!Pu3r()Z-ZQHiL*tTukc2YsbHY&EA?D}=i z+NAfpV9JT1qklvNVm6v4JpLuGJv*57D!FnilgyV1C<7)&bw%Y9@ zq|45t5*QHTaj|-`axl4>Ud}_qYp3B1$6dXZT`6RhMn!U zxEvQ{R=%oJu~6N&Y%8cav^M)V$LUOGn6U`ZFq4&c_|u!f3b0)NJqi6$H1lrI#c&tu zXs-v65)q%6$nHB@)AAW3syW0#dC}>?pF_I3&Lk}`D*wgWa!jieqmEG)%3~y-9s(x5 zyijtcec$Vj^MMQp--t!5I-E(rDkpW9dSCR(DUMHLe zK3mtR$hdQ8DziK{s=jHU+6O5x#PuLBDE6cE+LmTI#Px^;JOIH1do8{j9xt_N_P{<% z$0%OPutOv@6Z_1yTb6#8C;QV4hcl!e_Z1?K#Svrn%yVaeh;)(nA9tZ3 zs;a<%z2!nW^${oRLY~}Q@1!IrYEq|~1|vs|smZu6b7IVCpwH@5%VQAExi=b2Pr_eJ zJFY0XZd9wPfJ0F!S^|DIQ+YJ|Xr_~dlB41JE!Xaw`$@Ja+F;Wj$Z0Er?=*BQo(pM^ z|J%jA!eR!d)kU`=7d5zBNGlGj?&aPtD&H{HN5dOiyQ}tUQcQFq9ht8!W=(8laYKxB zVLp0pmIn33X*&*VRcyo&1b5GvhIb2$FqikDnyWzQ@zC#jVSO;GnZ*@jKkwUMW`ScO z+l*ABXD5num16bwJ>@etfPlBQ#{r&qsb{JjSS&saa;V@&`G(Y?H9AF^PX=>#6&$5L z^E?T((tHnGda~R09YlME$o-pH8O~UwTWNI66+OE{ZQdI?dl9ZCl)`S6bVGx5!vShk zUGOqw=E>}n6o_A!v1%wutnHLM><6rV83nXH@L*fj>FD0??gH~S~ zN2K}#mXkS}{35ljSKzjzXF!OZPt{sq$kP5Zes8*?%a!}d!ZOW?)th|U3~&?vughWb zI)|i;_K3fBE&KRQ-}EeZCd^-`(hN%9CrhtXOkXjd{j)dI3=uEsFuoMXJ5x9~LyUCK zO?d<(5mBf6j71`^!bpkkkY)$G*%XtpY@Y(ehk&J7BB`x*UJSmDV)q9G@fM}G9+C(< zSLnOGwVhp}#t=Rqs;$=cD4jR|O%(2TW44LhtM=ra=EQ0Xl8uGsbFVJhX4@N*C8C)9 zdB#U6S4TZ^;PknuDY%c-o{xasR~>7BWNtjw3-a)5$k8)ZtN*OvcYwsL#Ks#g-4`_K zD@)#hf#E?trJ@IdzeWpOLXzLLh^$MDayGgU)5etwn3xj_Lh^{dTIqvP;B0c6gsRYq zCt-?^L+t>`{L9dgbVaiN61pO3i4UvoJaC@$2lR4KZ10^y*@1zZT^f`U=@2{aaAH=i z?3y_yk`>tf4V$*?Fs9Tzj^HE2FV!fU4Yz<8muabSR3iMR|2WF(gGh+@G*VL`r~|&< zE7@?Pr87x1YmV8ztPyvOSFUXssf?Q;B&{k)eT3&5C_}+s)H@mtu>;rnO$a zTJ=}H&&}4>fT7pJ$M%Qs3EPd2E=0`0(vyViW;jo-k5M7 z&ye(}Q<6{#QD13T(LZI;H+K%6GQNQhuB|( zx?31*4eFk%0F4J6rO^$*Tun0F1^Cu4Wxv5GT(4w2JhUxyt}?ZKb}ki-4!sH<-mSC! zgmi8pgh{%hf!Zb%^$wZ+h+oA)m(TZPc*z=D!_c8Vygh$p_LgO2feBClGkG}_kb&^4Nl zB5uBdd&1=P1F+RLxLG*hDyB-R^_uz=4YNg-T8lwKjHR*!gJ4;)B;}g8I5rxsP`o@Y zM^RbkfhRhSf0!SFxXIaEgdUpSQ-f^U;&fZK)|xiDSmsn!@H2=ra^kpKGw}G{T(+m$vN|?zIV??=5k3PS~d2((vQm)~^gro2@^loPbg;X+vvIX-8 z(lwlD<6-ri@~C+I!nvq`bBEO7d6LFsHjyzaC%9fQxtqi|T#EJ)_BK|dO_?+4n6%MX z!;GcKxaWQ{%#OqDu^SBOqr|y@0pS@lWhykts<4H2a|?e8eWsSjLW^sI7`5uTM;94 z-k3C`C2a_GrQjBEDtnMerz@hMZLI3zVJ6K#`Qp@{J zP?0mo%ihF^8yl>Z=})l=kwS}7U*TBR->CAS5T1vM!zZ$~#5U9)E)(H-3;{L5auc=s zDzUv*+ABb>Qn4Z*JX(rLXT>q6itqrnL>R(L02rsqX~iK|#`r2~x3{wSKg5OTqh3Wq zFZG;qjx{Y`d_5&NkYp2M)>*y(% za$O)+_nT(eE8Ha;*pN3M((RaI0-7PmA7#9SnfM4A@POqbfpE}P=@v8g6V#d$j1-k^#|9LU;EM4#xT$L%kAIwSZ3Y>YfYd-hjOFvJkt@fu zY9#?xj#uMI@)2N`KDq{-Uw$8vX3RgFyZ)K_6A1IB|3Cbw&r=6VLys$^f-r)NV2P1ze6QC~9UNE!0#Pd4uT z{rYME3%&%>+n5{l2O-Oerb&*5- zR9>FC=JYlWsu1z}(n(PEY6>i&MWC8Tm?lWNAk{cC;VM%c5XC~o0rKWg z3vv~fWUI`H$7xe>b7mHn%+yTP%1^uRxXJb?o2{{KwVmPi!?1~Dit0z1cXY$|%dmoFMj4wpOWUO=USukAb>Fk)^y z;eQMdWPRRG#C}GaqD=j?0GygvoPT)W=6DSMBVeIVA-)S_;Rhx>XM(~HsrC&lP~}{I z%lGWUf&#MqaVMC^ZQoWV9vxL)0c*)h~un&&s{9U#0{OY z+$_HslwoG1#A?0f=t(X`R1cEKWLJ3DhJP2b11_;*!errKoPym@1lj%X`E2v{c$enm z*6}f}r;fBNi^ono;kyo_}71j40|7Vw_gGMCjl?OJ2wIS3MQw4!0)&sh}?Um=<_13 z17U7G^S6^f3=66_B;E!lq88RMy%0NOSB&CvS=yj}(?bIGdlCn-kF%Zv(3C=*8OU-teNkI2kv%P$VTzdW z5HVElHi{FFfhwKp?O7wIQ~S1oo$?Jpa?MnUNbqtP5R1TCLxYM41SJ+w?mgb zy3w2U#b>u8)Sd@Q!{M<$ba|#>eY<-uZG|@JgC`2K{HwtmbV;vMW6$%y{JpXuUUvD` zI4{U2gHJF9T;g#)u^yk_s(kzA$&AXU|CZs6EHiDAznF-vSbtsX;~e;>z{Jn%!tHFk zvO_#!p-&`~6^>gr>}EYDlBZbV97~j|cEsO_f>h&NcEw%l!=-5#;qy== z%kjm?0nq1o6X1OjbG{05J}M0x=?1u*S-n>d0&2+;WcpHR({6&Gn%accobZc~ds$JM z6BQO8gI!mQsI?a*MmH*0W7D2kW9P?=^U9p8B1|`QAB<-Cacq!3R*iWqTkgn-Fg{xO z;&|@`a9O{AK0k#tpNO~#ar6S#G!YqYUOM10n&0mE%$cWhvCOVwl@M{<-&peYO~1iN z2WfwDBvB4wuD&;XX9^|_PN5!v1kAJy&ifY%*ylj zkGSyV{fxM<r)COyxHw z+LyNf@TA(?J&~c+mlsK1gxU9=^n1iWz*y8$vP_&de& z-ud)}hzavQ@pT1=`*uHqsb5fBXC|t{3VUWhqKf`em-m?fGHJ{D!Cm>@5eQ%a2eswcAk}vcQwXFJ~ruA!|6iOb&O; znei85AtD;!`G)wk^wLV?MRDv+=izMg&M!0dj`Wil$MQ-kkiK=eSN^UweY&Z=sZi@o zIY(vjz5SH&VoRj>GGYQ5KLQCi0DGus&)^%J4y&9B-M2lmAye9{;1mcGGzPOD+!vd+&58cQA&*xpn(#SGIwRm~V zzGcQr^aMe_6$M0oSYf3rp=-?9<_TlosahXfwZvJ>k=F%DS*XO!mgn+@+yCu!g*6at zf8gy3XDIsW30UZf$U7K)gj-##=MrRa1nnJ)bv!5c&dxql>C2#ShGqCmu0K=_|56bQ zyA4I)C-DQ$(l0MWdZg!=sX-Z%@*;4++{1dvoY5OV`dgDn-k(*M9D>@3z$p{+Y7&cm zkpQPgVxku}vp#-9<4fn`#l|dU-!c35u#jbG>X!*$n_ZDT9Y2KprRI&a$6-1+Q#|&CC}qX_8KUM?z;#LlU*^spLDnzGS{9 z8USeB=G;T#nH!PBEXXE!~&872_BA@~d@Ap5zrFYsO>Y z4ZxxI`(<9ZFF(sOU*xa3&R=s9xu}TQbz+5PQS}=2Gt){$&JuOoN&^us#+TXVjbYv& z%a)0+9&hle@PQK(1pRwk{d+}K1RRfk`;Q2fFD{Di2^Fm+0W@@~&0`h7<$6u_Pm&(Y z%Y^bLgfg!`4%N4{9y})_}5l2^QMd;1Vs4Z z$~)lDL&S)B%tSAJ;T0}Y{-jAoX;UELcP2)8pR;y)bgVKd)1t}`;_%m2^eW3BmE6t^>hFJ z$nrtD5q$zomA)x4u{yl0J?BL<4SKcC`-+WH#ax!AIk3#0BzLr~`@&7AE@E^H#l-j>47XRVLqDVkMWdHY-$p4=~j{R?9 zpst~{Nz;~50W}>8$q-ftCZ()WE_tjew~NW$8ns}%gl#~G&6mwuEIm=ZEzMo9^bVBAg`WF+6-TStlRGJ;v7|V{!OU_M>kN(Tn^3~7w zCyja`{%Wu%i~^0P_+a9%zMx{Erg-p1LT&tKBUyeFm?W6TU&@k@$RnOeZdmCkB7;s+ z3Y5RW8WFUCP?NImjV2`6BP@($LUTYUBFO)0n4nM`SxZlr1;0}Fk!u*FSEv93MEZCs zJa|g?T7phMU&~B;3-)w?0XzXWV7J>qeH0wuen1vMB?3?f;jf87gfy>_LHRJRF6sv% z*HASV0(ElMOe!A6!}QfE1@>EWc7Nn!6kspU+Am#Yr>rBL_|h5|AmhfJwMbSRN*BBM zN-Sz~_BEebTh+D1<@fk!^NdCz#^Wxa%V(#LbB)GVTA__Uu{9J5tSYr;Nrk#mu<6oa zQIVd3j4+YP;*Dm=l^&rho=BUVtu)O%`MtBkh0#2<(s4Gx;NXmj+(wA5;M36!~BrUnKK zft-2N86v#4CwI;VKJzB*twpRfD+n81U^qe0vh)kA?T-iqE#^{fId6iUPFqlZHD@%Y z8gEeg-(rPPV1V>!@GGm1=eqa_73D^!MJ$E`_=B%(!UVRdy55t%J0E_KOKFWrQAgQ{0_eN{)LQL>(@gVk4f9;eYT z2sg`6+-lm;L6g3PTYrT(9*;MbagFIurB8nGohvC!bAPBj3s z2u$6CaL?JGfPDy5P3{eDJ&R|%a9#i#ksoZgp%};)4A{AI#F?Mo@Eer>WBOM9`**jEq`f%f)IFFQ`;t8~VSt z9{XGu?B)K^={CT`3yUtI$Qet~Ffz%HA$FQ= z`*Y>3;@3=Jm#5DK+Yh$-BmkW$OMbn`W;Qzz2z3uOvS8B9Se662F{b-HO|h@V0dZ&bcaFG+pqYn%CGJ(QO=z zwombJa91%K0`FtNZLJv$AJDUEB(QwufC#%RT_M{c^lA!&-CP^DHp`A8!xSX9_UmJ7>nW=R&%Z2H!fqdEa?YZ1R3>AVz2qI~0BEU8a`=(B0e~ z#!mtHZoXq&KkOrE{ILTE6b0Cw@V|TD8r3un-$vHWOoFjQ;65Sn*LD>6earr9l7D&%AAsrvAYZfhLdt@Q^2 zfGxo^_CCcfXN2h=k~3s=Z}D2|-1ocxH-ASA$PV!j`_6DK@elowa72J+EW|vmd(<|8 zf#~ZFRhKB@Sp+9>9QvCSzeqL5>WsbY-2p4sHuM;WkQD^<0veZ9%n-3f(yI!9 zNAB|>C5Ol_>@_`-N8uBEA^H>B6I$T`)G`KJk{QyU@Ekk19(e1+fy8ou%Q zi}#5CxT4Op4OJ9>2uQQ-ukR_ygC)NgwqM+o+N@`YM#>LK9ODAUa)80AGZ20YfYxe)#kNm zRbg2@=h-K{MSgau+~2oCQlVwZ$3IYF?H?%d|0!<%&s~s}oujSUe<6nd zg%$qSKImU{V1lNB{vBq^oNOd*XeFi7AWJkyTGCBd+Cnxb2x{qyYMd6XqkYxT*^RxH zyFN1`Y)rVJUJ1jmO=xGgT($ICp)JTkqg3@=s`f+n)a}9EkWE|qG2F{?lIJq((dRPL z+f4ZVvS8M-FaJ3{V&dqEx0uMr1Z||8!_tWVFYeZOGJxivDjHAzlrlpzt|zc4hmY#< zNJR=EJ{wAL1vyJIHYzaLncvKCV+5{`k}Z$%_8$P@%4>HZ^V$^Y<~cT^%}W!0;tCKW zezm6fXT*zYFuV#65b5GH*{cD&lZ$-Pf#|bSKI9?SABg7ev)S{3=yTYE{MQ;xk?Rj4 z%Joo(uild23#{Cs!rN(4EIG$>)YJrlE5*)5tayltVrsdS<=c1MC)U)s&gDn?5 zHD`0Zbmij!Bv5*PAS^C62vD)Qmg*|Rs6~y7I?i#a7m()NH_PugpmyB%(#M3V*lUUG zDxZcV>%vHcDZA<_3}@{W!w)PN?RmcmK^GL)Jk|qg;8G#S);4XB>uH?XD_Ut56p1@> zuyL+&bc9!Pllni-mZ zm=g-gL?2EBYlXMuc#$~pa^F^7(e#z`M^rs(2zCk@7P92pw z{w8XTMb+^&u%>`Cb^?B%!XDcHZcqu3H?+qk~0 zrKT5KL9j}oBl%g6+b~r#llEDM7kL^+Xy`1F$-Z3<$!ElQ^^whfy{F3fF6}4& z4P)AcD=@CvT0I)Ml!RrsK4p-ypz~7MlQ!pMlW&UbD9Yk!P@D%{Pxy-)z;K@sYxPb6 zpHTZ1^BW)h)=9pKd<7AYX9n(GRabS>b~cAFhD&T-ls5TqeiVWv3&W6-Qrt`muFr>d zE-t=&B`Ght+a7oCmgb)polTy5S)f#lK&M;`rKJ{_{?lq1AB}SiZkS zxTqb)JCTGJ8@E~|ON_t|2?`Bo|C;_HRpQ{lVXuLshw&MFkqFs7&%$%#Ri3V?Ejv8j z$U!3OzYL?E?AyW6Q0@Fnj#=&eGq^*B>?f-;q3U76h>AX&>{g(@G1W9Ir5?F|E9uch zfdC<|&Z?&E9Y&#=xEcc$M8lDBK`~B(%kJ;wSh$ikdS8{`0R9{;k5W_>6KUl|QQLKH z6art8!7MGWhymywGvio*tI?N%plJn+z?atHA-8#!s@9)984$|zF* zB#&xSZ8UEgEXgJZRol`XrAv%e?NM8=`!j8#XI>DdFumW#RZ~Bd_qAJ!=CS6Ox7PJ` z=A9KH+ITqt6Ze90;XWcI%Q3Mg&Fr2S;u~|gxHQS69FNQ|F<~|K!pk4Yf~9o#LL#0E zN%@B6u_bl}waa!sa*JJp#$&-0#U#ddbHm+Q-a)_mtUECFP3_G|7t$ux*!TwOI(k!4 z$l-#VZ80w-h3=~xrQ#bJ)k&c~oK|fW=^`_iDsRDaX34?7nNY+B$X5LInyCbN2SH~R z74~j})e%vrWs65viHngydMf1|O+k`Ay^;2+r?&M4Gfl^4n;SZFmiI6jh>-kaPE47t z1wBAC$(%xPOc+mcdSJI6U)%v1pYSx>JWZf-Yb&f7_hfp3R0|#Uj#`BkZpk*-3-2}S zEGJA*+_n^j+Vre$O<;#j&dwhG+>RcFW#go!l1rYF&X(eq5EULNsA9@j)FW!wx>6ksMM3Ii?eO*C>j7q# z8Su@uzIA@fo?YD7`IfU{BC2%BqDWtstTlhhubJr~`%Ww<$G(T{`V-vm*OPPuWMRmi z$UUi?il88Ur<|H0svL|KOtKy{Au{=pd5S&kK`C)Zj4u#A%t4?T8A<5-P^f2PMPcoM zLMUrS+TSF|-1-QI=+MPRF;ZBFhs%uQq`Gj2t&HTMg)%7m>9-KW1lx|Cc0OrSEO3`7 zBBj}jxySTj#a4?mD&#L92%nG3I{513k0Mdzva_=C747u)z>Pbh;&aI5hWD~; zHsGA2>fD*@xe+MTjVbc7SD&bY6Rxmb$3$6U0F-CgZu)Y6)kv}>(JvPL)eh6Dvmq++ zphQFVgG!a{eFv8Rh+3DV=%2j`F)pDk2X{nZW3%w-9G5)e9joSz@vk1apamtWwfs_#5_ggl8$)Bo#&(2W zWN!LBF_)OkNMeHFbv_YBX*Lb*Pgmf~R$I!+%qBuE!Ml2|dq2I*g-uRN^xOuA8wZC; zAmY(Xuq+eIVmJCHF;kXexbVjTOr$YhdVBowryctnnI+nn7?OU)l~Q ze{XHJ7(z)b@kwsgYY;Sr2{NI`mnX9!m!c z-cE{r+zFjM&*NnCqYRbVYl=jJUp3l@ccW~!zOIVxg`|pbSymA>zG2vxO=2W4!@ii{rXFg0O5Jos{k^tJ?0Jz<60fq~~W;!Cl(WK6OFt zuX*Ys7V2jdtUL&qM~o3Dhtf@|A@EY}J~#{q9Z@abmWa6^2CQ-x;SuY3-@q06V|}gw=Tncsx+3!?JLq|{CHf+H#Wk37260@;=C46M%i$|TZa>_pYYKqT zKR3ihagBM5Q%i%PeYSNISSXW(m1?mGEk^()^7Xz`mk&SMs~hWk zM*v8Fa4n9rF_ z&s5)_+cTYg!{%$^R{+l?&z9NlAw$>CAHVx-XFT+b@*jL}#~9x20>2leS~!o&Sw7FP zo7-XGDTrJCyiu2>7G~a?_BU|X_t>&}nm;0tw}k(1ZRJ@(Z)_P15YRNn|BV>?PYKfh z{NMhY7}N0a#8X56k!zZ;XHRZ{ma~)&JPS^;Um&MLw~ii7DnY?P$tnqL5ze$H&!)@H zHFIaT0~6AZx~JtY2%!A6B9W*rmDLsyp-ezrL=02$>(%e>tBA zWvBCH%f;`+_odSVfiKROc5u^7GZ;6R6P9D*+#K6JabF$VKG{eEsr@jy>0LEpxZLbj z7TaNqsG8@<&;zO2F`du@(oq2^f3(+(6F>jq@WF2jQxyI>eIJ)Krh zy1Si3@Xk!>A__~g6wSo!N}HPvhx?;FUw?JCM(|2qVbGG)YD{)^ydDP@h1857OUEl{rN^)?rpcSJ@HXet{FmN+hpUA zRd11d&vH~Ii7JJ8xZIn4JmQ+FMRS-lOJaoBVmGUp=Mb74ejBP4Gpf1goORTCBKjtJ z5djZ?iir$Gy=T`M!@CU?e#o8rTDym*xVyHz*5jh&@eU!El(P@l5Q(m=?C7a)aQMy%u3quo(rM#~JeN)WY z?n@Q10(7^)c@8ew9G6|MnuaK>a4pGkT3)-zWSaR97qx|;-6r|;$4taA9mwwZne@fw2L>9j=9j&9#u@Cn;cp)Vaooz_I~@Fz zZ=qcLXgf|jwCYli`#_JIU*Qp3d(34(?Wl!OzTo2bqcfI&3EYpx2(RN)mkypf$w{n) zS&h`-;ke}bt*3~z^?q-?iQ?eI*{4OerPyydnSBq% zxO9_Ui0CIfhB4FarM!c*vitf6Wt~oy3UIOKo;88zc)R9sUDX4^QIC>^ms@(sGk0V? zz5_L>xqfHvn{|5CO)SXW;OrtSMppN=(uut+5$Y(Q46;y+;;CeO1w(1eVN`jlUsTB9 zmoSi%eMt$Kl;vY(jBC7W0Zz{Varv)^kCAQDhAH^05m%hc__#v~MU-bjD>(=`??T=?LuB~zu;P3^NDyq&$mC(Ygl>Zdp zhDJ#!5sRGpxw%Cft54pU+!}!$b>J;`fQ%nnPmjXC7AVUw4U2VX>NhXAF$Z1m#nX80 z_nlY<3BwoPhU1JOVToy3)+Mk`vg3j?&lcDPRGcmV}xE zO-R>NR;I2sO9u9kg5KA`{Z5qt&m3cma|TyW2qOsWN1EY*+3QK>^gun)8}Z_p8Q|mM z)bQri82UFyXq`ORI`*<-t30X^mOB19kQxfk3H&&Vg>>#wPBh|I&?mqa$H#urNDlAA z?fW9yrF@*jq9*THE($r+f4xHj@yq}`7s7nFaBBE`U%znf&TIx5b8%@92<6I}WHdq! z#+_5+)N_}_7A19WAWx@62E`}y*$HsHDoJ6pP++^{bcc8RU@0J|92d)Gj$_*>7!u`) zlK6Mf539ha(cP%ADAU1F0;c$y#hdOba%Js{R_Pn}7K^x25%9-q`i3jcY%+X+T1_~= zfy_~l2;kfZ#PxQ8rz`o5;9STAxzzH18^KZ3-Y16N=wo4Lap&XZUE;?Lt_6!FBb*#< zyu+9G_r~d%4obGOSQo-OsP7{1 zlgg9EPau3YsVWtS{g{#V5%0v83O+yF@?_n}1^XBV18%2K)HqeRrfgy2h5Hjp zt`W5GPkcejyJXp!)_ot0B)Kl<6;_Dqx#b7sH0_y9IO7d5_hV`m^YDW$gJc!Q8u=?3 z?6sP1WOYMqd1?&i{2=uz%^a5b99GNibJOkn%={DT_hxPwgzB{b<=XMhniBug((kd` zZ=R%ANcV&M4(W%)&3;F^?>`4Ggj>-bx4*uldq3g*6=|ND-nDb;F6ky5e>cAn=|*KV zy(FYFBQ*Y&Z!Q^Lw5-r)nsN5RDt~Fj%N?9nv|=7RPs!V*dB9SaD>;{nLAErzwGlei z<}$b8hN}g6(k9Dl$>gHi%n?FK$S22sYm}X&hl@3N>Wiz1-KFUJ1MMNDZC1iS#FGN6~i@_VVAfPL=dC{VKte0b4UyfG%ZzrYB6}7IdCXG-dyqZ z?eYBR4gS0uicsT_qCwrNpmCvQ@FVblH{i}I=Hu=BXC$Kie=-vJ&yl#Cs^b5Yx};41 zJq}N@lfe~28vn^2$?42{D$KI3ZLN&dC%zIx0vJ)D3sH(969XI6r5`ozZ^35EEIXJD zCaD(^4j_`v=!3$mNn+TWTeu&$H?w&BIDSA{0YYp{P-M6?Jxz?($8>72?qerJCFy*Uji}30NiB6!P^p-m@+B0=)u)?|7oZx@)Tlf!9f=^HVDG~(;=$-}$h~ob^%=urw z|9`hSTCj#HM^6G2a^8!N&*)aA#LA_DQiN0y6$6TtVpUc~7=uF@GK(@evMwe`AmHeP zuNn68C+wq@*(WZWm2tvX#B$*X&x!dGP4Rv?;#&=rVTp(;2#xU0I`DFYl(8! zS>SnV+3fNfYRnlJbvsTK>7e|`eJ4Mu4wO7?Q z9L1B)H&(>ilf`X7SoW-{XJGj80|jqS#%$8D?SA*juuP|1mf1p!OtbC?cXWvO{H`9;rt8Tppar-t<*c6aU6#E4G?Kpz1)F}+8**5-2Z3Onr^Bf@ z?KIAISpRz9yMh3wjM%$|q)jPZ#3$1n{84m`Fa}cOD@&j%{KW45#b&-EP4ay+On6?> zvT_g%D;grnkar@We^~%2M)WIJn;9FCljoFmrZmet!k`h6|YpS4y+UeM;#g9nkAfeWmo(*d^#QkQ$c(2I=G1BN!kztAUr@9@yLO&MKxo~`KFod6mY2&Eiw=! zYq(GdXTftt6wp`M$UxVf(EfpY9Z&8pc!5&D=&I#wMQ1T^mNHL$g=%Xg#|p%}OmZ`a zsnDEo>S9Xpd8b$r@mvcTsEFb!i5(M_+|gof7}dXQk0-H#LDC^zrec9;)UODl8#`21 zTw8O!SFy6NcJ;#s7i#v-ZBG;UN}C`P2jNyq_b(G^tgQQJc@xpN8fV#V9KBl|%%bDGOkgG{>twJoLcn`I?4wSOjdl^DEew5hgxk2b ziMIw7ceP|1o=8&>`R4Z>aQMT}f~bZ9J4tI;?aCV|f@*M=8m1v>x-#~vvDuU!jSn+O z|5RIBD_g!f($X_N`kcqz))x1WMbZ=X2Q$S=eDIa^uF%ysm&IMF8KdiQ$=R22g@Xvo z?IJibp^cY#)>w_b1EWy=OnaknfvrVk|3bAdkKeS42S=wYd92;_Y^=;|L)=A$xR3(v zyJnJOu0qcf*!?`m*x# zF_fS#Te8)&!%ej=5Yir*LI0G$MHm|Js4kn((xa$q#_Y*zL?MG)P5{R4aTyqaAsBFC%xg`tg@Q(S30d z^>`RY>I>`)E8_5hAqLydUjTPxwQs>OveV<)cmfpTGNBCdkSfo0wm5BV^A0-K6?xb= z?^yAQoxp-k{q2kDcOR5X!apeuw4d@3ArkAW$amtT00svSX?1w%8}v`g+20@y`^#;O zSE|(fV+*wJ%sF0I3LK9Gvkp;ef$>?I&!9<$1z$;RTW7E`b&|EEv%-XoR(lzNAl=-* zyo_48E3_xkkBPC!51FC+2Fh<{equ)&;FmTi^nH@;%xuGIIob&>YptC;sqa9 ziWJ`^9rJbz+u9G~9&akHrTlh_3&ACahi`2rm@}anoHX zTHCz?pH8guBzS;8tMI~s?KG!X>pV^5Y;B}lXD8*Eoeo$B5X+X)9G*EHt|_%xYLt`Cog>(}#}XmwD~iH>5zzKyAUPg-|GPF7n_ z%GWvKkSPO5gY6(n7yH*C^wQ7+^w@uC<$AjgaH+j#_*OYas3;HIa?q}t>A{TcbR;)v zx*2F{XW)qoX(cGbkbwD{Qlu(UI8ATU^4}0N6Zb@rIQ380EpJQ2s~)@?+q(H7b@Ey* z^b1j$=k%7HQApaz?VUD4B`5OvTvhrvv*9ObUeK{PnlFAR2pz=L{J1+>tNf)qurSs# z7jC*vrG7Yo-W6g5pQ!%#B#J0{ia%F~?6XC|w$(d~muIr^wQ8;Ntgh+-)(ux^#?sEM_Y0Rb5r~kQ8*fwvFMlaap9XU!sEXO* zGg38;8l8otoB_Y*0PB*9^=+)b{f!~;u0T+@FJ+PjD0gfsR4)H4JruE52@ybt%UI0_ ztRb41yUpXBF?enK(z0dZHBHs9Y5b4(X62^Sk$e$~pBqe6T9qy1dCeJ@`X7-cErE zn@rM2+4xFpPUk^MrU;Z4F3z$7WL1$=du+J{?viq*=>qBS7%Q3Eh4ERKbtJ!=iLnO^ zPWUbC>%6lLfSKI61y1q#m&(Dw8mk2tUd~tu066hkahWT-2UnMJy4b0RjC)RDSx2dm zr~K?9urpFY_rQi|)S?i%hPiewY(Amm99yN1SW~Sj?&Um0MN@CQkH#H~#wCr$1<$JJ z>%zQBN^yc)!hCA6 zG6UmRte=Nx`uWXpc8Epr49>L70?i}Vj zfh|`10_5Clv0fbj!0CXu6~TWIg#B#2`0R_%k$KJ7)1!~D1B955a&J!qOlv2kUgS*LYj+YX`S*j*2uC1d>*Q#XDe zS=(z6UfFX&CNAhnY!mFVW^6Y@X>e2lUT?H(Xa`J4f58iQQ-A2x@B$_A{Uu-ejXwxZ z3Kn6=^&~8`#0D0_gt{}}gpNnbQnFbNv%rbf_QJ1Bz4>oqAh$7`m!0r8k z8&!kbj>dUIon&w~qfzs8K(^>x12RAKcZ00vXyT8N|NZHX*gU1vi||3^G7Ae~!^>^J z{g?aCdaSie=EWQ9*%PcZJ3wb9Aw}<>u3ll8eUguDaz9+2X7tw@i1QVM!i0&n8 zrXxPDbsmp7Xn3nm_JB&*jM8rdL+dy#DF0DCd=6Z*kIGikg^4#F z66K*+aXI|&^w(k%_BCIi=uh@g9!Ein_#QM_NJXW>0+$pu>1gHpMjGwRTWlVqbZYVV zKJX&!%Z`=3Gx6l#d9DSk*B@~ee^7YlCVNFPV|Q~hA+dFVrF6kLDEUo;Tg*IQv}|0o z>|?PLh^lW5eH{dQAPl-Z!{^xkqQy}YOa>{m)MJ=bQ)n3C_h>Es&tZ&AQoO4v^A-)V zHZtjk>Pg}IuE-o#&B17ziHyXBdJ0^$B4r;fX395u08RfkH}Nwdh;A}{N`XW~iG}s* zV_}u~MHo_y7YbSQX*aYfH`R{vtQVyi&ZUOjR>|fSv=WP~CgjEow>h1(_eG#0HBJ%c zh~timt)}rlFAFKfd*FG3@=;+3^;BSJy(&vroe3f~Gh-TOY{rqo~FEBn7Bn zott09GAMS?q2p3JoI*}OA-5Ek8hbG%O#$Nhh!g6qt>vIo)6DF^#Uq(04Xw?9u+*l6 zt!=TCZQj^r336MK+#V;xp$=En$($iy6cA6&^6gop-%PF^Ujmprpv_)TBk-41?Tr{; zhV2olGd6uuM{CrxJ@?hg5zF|=Ea7!-%A1a77WbJfU(EJCK-Yk7u*rTX50=gmK|B(> zO)i+o82K(+#NDVQ52cv(`oB^S;LB?;wB5m~VG}^mEo&8$cyN1w3vOB{IR*Ga23oSY8eU3H`ZbGaW*&(re3UGeA87oIR z`a*`zDu9}bUkSkO5`#yU)g9G~?3$fk^yi*c-vbxb!9~Msve|1gHe|)^ z-!Z&{Or1#ffE`*;hU-R#ZtIFy&bIKLEw#IvRp7L2=tDe!wibZc30i`heaR_srDW_8 zyjsxv2bfq`wRiS`kU|>QRI1K*h#@b$yj5GO;Yjx<2;F-SQZnN?vT1|zlR279W+o1^ z-8y!MZzKa^byJKco|Kh^*tawwCg~x<&h1fF3K6WdPsm=M$`mXmr9FI4Tsx|Wyf4FEo1ul$IqI<9xh^_XIt~Fm1`5GnI zuwdrpRUea6`bmwgM5e|U+f4I{9#C-tmc$!TikKIyMISAmbA(LWJI?}%_xA1$Xf^}K zC7f2-eg+xKwWx$OmA9PEQ@{$I|DYl#cV#G;#A!ILUS*%XY(HM4{ps=j6u|>8ZB6YJ zMmOO}??+13t=z2(PzASwTZTlYcPYH07V1{wB}UmEMvrH}K9%s1sn(un5v4xNdLyun zxRt@kst(Bj^(yiT>>^+rN7tR}j`zW+K*!~eU-l)Z7e!jv`V$ydTgOR~=v-sbs5E~n zvGmSVAGkG6(Y3PVgFx*P!Bv@!9PTKv+76z*n>`$6G4aA>)9C!3=kZy*ku(>?GQ*uu z&m&_v-iHh?U$>{fFo4#Kd+EM9glBM~7Y*T5mW&@R@%E%9-rUv|P`9;J_mwg@?7M|P zmedHi0S`%?bYA*XIb1w(K+V&kRiJ2xko-NRi&ut&jf-u=-ypli&7`DZabEmPiCEdn zcf9_~p3vo4ChFnw2PPQ7kI7J{GvgEA*YJMEePpGUf8Yltb_0rWvIFP^p0q!F32h^M zV=Yi_JNv>u>?ZUL=uhEBI!P1p0Kk?i)P#Ik8-vF5x%)o=c>fV%)>{2pQHJ>i#^M10 zko|XmyOgZ*e`eVKS?GrJMma+L@m&kbG7br(K>z~L05KeGqFA?7q#CpzjTb@k7g&;G zOE4ZVHOop1`bS%(ab-|ZrKN4tM6RT5CE7-`T)~D{WoA>Qc2Tv|tXH*M(R?#C{TpnX zDf;YvbiZ}KY`^%9yliiH@pqn~z0Q(EQwVdrCgsDbKh$P~wL>GMw>a9#nLGX<_P(U<-DJ`GVfrb&~E~0emC(asw&DuqH1b z95=)9W=9SwOXbUADuD{k37SM8Nm7h`OO!~OeMNwhnS^OOH>t~}JCGVc$V8AIbXw2F z7js$DsT&p-+f9U0%3p*j_LH__hdss3qUqhgp_RJvQOcdt*OtL2>3 z__H0H$fmNTSBx^ST7K3Aj3;vV@TXFNgx@#hyNuKvT4H2)fb5sNR!G^^ z$*@@|PMc_Qu3v#%MrRHgLy??lG-*R7{^vHPjlxhjRVAssBi8aVY}4`nk?8J!i7agn z<`AV`Nr6;aMGeD3j2a`-^zG9>+a9FXhDy^-Sdf$5K7fO{YIPb%@kOEOnJEZMfVUP=O`b$FC5RbXEee#+HVua%^Dn7iJ$CzZY=HdjD! zFh*LR8}~A_e#nHK6ZKaWr(pg76so)SI*E+p>cQ3N7?t(KWWRU~4Ye1X={o}6q|yj- zNp9ZS!m>D@l%ZBoIs`nC)-qKGfetIuV9N9FUUnm15+gf*O-q7eMTAEIte zS!?JFEskOZN$3Te#JiA4Q_LTusCEqbD0FB4h0OI$yU|nqbWOQ*Yf-XW*UmAG2^9nR z@>J${WDhJ)u<8_7yqbL@bBhkrl&yPMDF*>eEY)j~Hkz%K5k+!w${|OQLghVKrfGEl z(O=&eq{Pn5-a~VDi1eaJePf8we1CC;ic3G8(EXqVP5`z!0^eTB9p)@9pAO~hd_PTO z@0%Fb7{wTwvU+^5VVD9^6iVY>(M9|EjLv#}d)42+jZcTDReOZzfa$=7nKZ)@|00>~ zi+fc<-a2jt(9XjV3ew@7B8Pb`ITTh{LKhQX z9ma-_Wm*c+svv4sWRhh78HV@bl-x6B3{wWzg;8Oi5Rpcd<#Q1fj~TY7A|kNXr&5}N z4q9sl4&nH{GcGA%>hI;rEFCJ0B}g*9EB?h7q$U{4cA4K$mSq!-+Bnwn9I52(5E%TI zp8IKGpH|FYe%xg#-_DPXuNJObh5>9^Ed5l((S)zAzB+_*?cU7wT@^mf>!!OX+`VMa z;^|Tas-5;J07R-haj8IIqUR>qOY;<~aT#q0>Z~;<3`IK9)s|XWw$XadfZ9C%5tz?S zJc&3a>jEl!Wk7v*SjS90?f^y}vgzPcA{C}~)cU84#0%NmBF?mWNw9I1nrKU86Ysu6 zU|_F{VfnOrpQ7|DlwuTg(Y>OfD7ef~<|>o%0^ZkbrHkF=-O-#qj z6WhOrqbcX~X*oH3B__Ny`TU667{vur<%mss1*s?Q22n)I3#=6h-*=0&P`jBjHC-AV z5Fl4eqReTIiSpK5Y^T{^R{-Qw{wKm+U#qLOh3t+?k1SrdjR#LJzNu{XRc05jWf_;{ z^fEdv<|IZeGevQME5fL*$0mqPLV$yFc!A42QAic633IUK{uqPDIjL!cJbYjl=s`wv zXbqu68Sd_G1AM7Xq-nzJtmMFQm?T<1b(kFboyb61>UiJ=bkda*k*F57o^wd!QS8te z*h8fKwnm6pTWpDWoaVaPhh%uD}D9m~$6WQhp=N}a;MX7<|KU?9ih zA`0-lrYOI_b{G6PiPGS&7~?r*a|IAgRTEvNFF|tvr-BCh?soY@1{EKlof7 z;6tPyq~sWWUL8smKft?RfIY0kX2kq0wdEP{&*2Q-aResVGpik_c{a4nS#@N2yMsG# zO3I(uTCQK`i5=_d{QIzny(X^)4?PgfcZZ1CN8}Mch;WCo+k<3;ln-afMtZnw)Ce>i za&VWU8G<$h)gu$34_|VZ%nVYmJk<;XFp!+(1@m@}fG3*|d;{t?tdf|ITNT3a9#of> zcgG&-oV{}2kaym2U^}}wq05=(uy&i5i3?c=tKYmMZSAJDY8Wyu8Rk*XoOP~1?E{o} zO|+?s9r~iW>I_!ulxy}H5Ym?aC`y&2a79px&++nTdIicuT@J_6iFbml`f6-Q7Z1w_iI9jzUhCREh&I4Fn4UtG@^7?%G(gHZ3OAI z!liG-6vWyou5p97>nQE@N~GNuhvnp zg$Km`$#6AY7lcUGh5N~_G|+}pbO8ByF~GcFgGwtw%#;~QMw#(ec5ZRhnTawTqM=7w zut%Ui2knByJNGC(dbQ2fu$dToL7GR%#{pCX4D&%=3`f8kMDgTN)u1UhOe-C>WCXS` z#9AM6CK-~!FhmO;vVOP0m_FN)tMNCA$KWJt+>z2Rg!Tettj1&E7{IUK!U|6%VLlm zs^6^<8p;v;$P=zKIJZg=Jtb-xO7ujnVkK3|bgT!bx@bLVJGgS1<>3F*Zq@|RS{}qP z$Gqn|&|wX#V-k`5&EeU_s^ONsBofrbSPVZtivyJ5AqPnjv!%6z!O5E5+b&VEmoS>FK|=f zo!8HM16yJg)|eSk5(RMH0Jv=uc~plTVG4QFtpCJmG1RWS{_`mr7?;`m| ztT?^HZ;{*+6#(FuKKlQjMt{c=WeZ!Y|22|issHbhWQ?pKO$Ndm!Wi@{RB(XInuMsz zPl>@FNV1Sjh`5RCa@rP*o%!ODMzU5-+6vy&q6z%Dmi@O3t&fegK=oYT^zwIyc6s|{ zYyF44A;Y>p;!*w8Ma9O-`fzIol|dCvjI6JcErZBXq5s!_S60&OX4#jR13>?V%n zRyB8*#i&ueEVX)A^~~>dC)~gH_!#OU1ErNoy4_WvkUyB;rDUw05fvoz|W@<18*SI7v?ErSdIs; zuhkcFLGcmCfTwbYAV=liipS`!(l?^wyn8^!=O-^UO$^0Xv=6k2JzR2hQ}FZ(!-qY5 zayW5PG>DGk%@|2f`Ra)A2lAjI{+ZR{er4b_nCCFVz*`#Y*(Pkvt^c)J>iFdla!36Z z7?dBSbc*Aw@eE4D3zvP%!Z>QMc1?1>{VS`B&nlpITx59kNQ-h73!?EIsH*v_>G~8K zqxSLw6z%Dn9S$Q4b3o4RS;E7%5*wqX%V41a2`CS7pdK{2@ro7^=T>Jz&Q7B%;}ehE z0*d8Xt9dO4f6c5tV7MEGGER@&z}OYLnsf(RBrYM6NmRwC)#5&#DwC+TSGtg{?viBZ zJqod0^ORGQnlS`r`b1_0E?Kjk@w`QM}hKz)8GbZGW!wBYdfAkk|+jL(z)8-b3T}yBMf?Yx9@dSKoTPFP`)1TJfJmV;O zO_@}rxHM((`wvIRm38um`pZR4vLn!fIUWCLm~$rNPJ@Wu8VY&qV;eIEjtcwRtzbKm|6}u%^KEcXZ)kB1S z4bQF7S<5y(ac6Q;X4>O14Et@Z!6(vT3f|Tv1-p!}{38cYK6!g79EH2;KodDM21VZ& zsijHW@W>6LtF~qjcm}LdasNtoSFnDS8d9)52{AiXufX4<4`3q=#ohBb4V_8tC#UR( zwDR=(g}d@t-;u&t-~P&tT2dCT)OhHv-qb6RS~@!xCQMw|UAD#znA8RmgU-}N%JTD! zPVHCj?VF|K55+u$77Qmg*SRi|VWUkPlS(-Wb{m+&6Qd~cY6DIV%7k+A%WW*brA+l( zc-Wso1JIxOTf0y3KIF|ATfbqC4^%=HMbdIq#CegZQWIHKb26-EBk-#Whx@d`o5)6O zp+a;^#%c&rWCKO=+DDcsLFDpMbdHlqUO{9mIm&!NWN48BGPH2fA^Q{+DFoNyYbj;} zE$~U>Ii#)eG3N(k306cz*>H`@FjLG9RNVK{I3t33Bqq}noR9rsF^Kg%UO;*OoQGd>!nTYytp~PSPE zu5{HE6+fB6hI?9J=KlKmBMB+#DeQYOvKC$&?&>w8QSEk4!DchKY5b(-PkE>9b8_5L zv>7I8Ri|f`&9*dESMS2X%Cs!`2?8US`+AI^emBcfY&l$6&d+QILvVgih zdSQIju^GUDLN*(u9?^n*=I)*#_HaF(^ap=^Im;1}TiAR5Y@-%F34SXpg!t$Pe$xq5 ziqgLI%GQAoxDn%&Wd$NtT%Sh;wg2MLb-(J?tFIMg&d#gDmPPuJOS%2u&8J8f3m_(T z-Yv|9uW+sM^N`I~nWI337tC?EqJzk5PeF*bnnvbOGz#pU#d9Ua z5+jYob2vnS%Wq})+z9$lxUgIh&+k}R_6=F`u%+t&C+fnkZN#{ncZD8fJ7BfXP8(V; zxVTb_1K4Mq9JpK&)bIIU(aE|XfAxe1&dBNp?7r9rM(`Gw0ju(`0X)8xN*Md)>ExKL z=@kewUTn{fs={fiI)8*GvIo8huX$p8aU|ao1*%WFJsp+mkU6ZdCW7Vk+d!)RBAMk3 zhF`Cn(+Z~dE0+^0rut87sgz4{hM*X(F$N{6a)dc`T;%VWZ=q;a%vOmlt)i%@?onWM zSVbRvN@zEl0#(G^Eh6w@=A!~SUd;8L*eZpzu1BD)uSxN*#}Uwrb_Rz{`ADrMjw%>} zkm2AL1<0g>kwy6ZeQXTkAdf99sXEP<2_LNrk;4fIGlfTNC>1AD#8^>IkkX}UTHBQV zDPz7M*DC*4s{;yQ1ZL0%g@6{BhOHkuG8)JA+{_=jirCnkBT~stqG*LKQe04D1Y|{q zc=PA?qqJhCxInQ3V4fcKS$c2Km9hqTujnBWA6cyrkbF{a5Q#myxG?B$uji@RJ4o-) zS1oRCLIH?DM@C&p(0aABzxvaqR)uiEd-M z05AXmyx%OH{lD9=s+d^+ent7uD4pbgyVwkDjem_I|7#bUr26KDtcvojm+m@mU`a^R z^bes?A|tsN!WLAqQnlP7qA_vEMdD9}pD~#n8Exxc_dz&CHH78d!SGx$(a7&vmz13^ z?9aX*!Ov}D!m6c!U*F_Qms^V4ja$mwRZUH|AgbB{aMnb%7G2A!Mws@=F56~xGB?X+ zSpirFOKNzR_DH$EzR*A|9Iz5Cv6Pj{UA$#o;yB*WY6S)*X^tAVc0fS^U>d@;(xR#~ z8;JZ|rV<9U0Z-sxuIB?=*q2jtaj~+UiakCP!h$`Yr$IjiJcUVcVRwnS5LTY@Jw`yA z%_g2RQ_%i9-s4ov2@f?YHWK9QgKG5D1bgcY@QFG~L*pWDvMoUJI(1JVSWsAP&pJOS zu%&Y^_N&%{ik_O94y)Rd9y zrd1bB4^8BHYUft(?wc;)$w{UlJ~8mLP@9-G#9ua@>}xErU^_Q(#W~h{6BE2Z($M^i zXS$lxcFnjbreIhaD_5=&^~m-~S~zA>VsS7ny%MSGhhl`&rFd=)-cs@I;fd@L23p z^4RQR;uv3>^$KD){IlCds$@kF77ydcB?g``Z16itTsyh*_d{R0CdFa8WrD-T7^DXK zom+q}?92RqIcL53X%c!F*qDmNU~`h2zYup!?S*Yb3$|OZZIuaapc8Q!wx!fal}B~y zEWHwJcWiOk&Vor67%n*yoAnRsqV)@Bzh_(Sy+dm*`ViuI7hHCxY?4sKiD;RMX^C+M zrYo#yOpa(b>irstQojlNw%*OOs~HZ{D?8LfFA!hP*b3Orn1V_tTe4cs0Z2dApNxLt~8h6UtT;nz0 zcHb8~!(3190;r&*aSSA{4%Ed;U-jZFM$Upi5nSWWqvNh+X#yu!lY#wdvnhC~%iT`} z^A|H7X_+Hj@uulTit$FtRGb&8j}1;x#Q7}PoE9!l?yWd$m2z;DGoL6BjZ%vq@E!0`;{Tss@iQhqiJXD6X z7g3A7;rBB6AL*AM62%Ao3uqU`SQGKMa2hv+v5*_xqO~M-CwmR}LhC|#(F5+t!*tKn^PdACx zgj;Hl?J3T17CYzpFW4JW+iqa$=q+MqE=Dd^crH;(9={}MSgAI~RPis@qH5cV7WvG# zXPQVwAjs)M1X?ynBKAF(_Ghq$d$KLx3^?4ODUM-5mrZyx;w(!;JuiD=;D|k;%|H%= zoCyULeW+8LA^XK@^uI6^BJ1+D|2}Ao2173>st)1N1#&*H@aQg&hvWxV$2j_xQ+Koh z^a02EjaGBz4r!F`8snO?#0I7*Gx2RFjT{tNVo3Ljc#a(a>v9+CAt$Y%>FM#bzMSzR zQ*x?c#kG0{!y#3sBzmH0hEKngWiAPawR)|o(d@rsH)Ax~@QpC}1hM%{Xnn=LB{!pI z2pPk=MhE&(Y`lf3OBkYSZVBWbUOrf9edIIv=g;9k*}o5sI-)s(4UlfI!)BTCTas46 zO4)N(%auIV=+gmv%;8cZOk?AJe{37beZq*8*ef==Aj!@xXh^!#We;XHYzR1C`%BUs z4wYv~m(22nt(!v*qk$UXeWHaxE*kE)4vy4aS2tpba#i(i?rCp^S$+DT(Nu{4YBT?9Er3T^$_e9_SV9T$|8t`M z|6bSrb0yPNMpno0ky|w;tri$c1Pa&6hXs^Hy%1N_lBxq45Qi<%@!GCA@!)rT82K~vCl?ldm&5^R zWn(T1n~YCJiM^PPJ)t$o0U4k4j*%>JhJ2i@Y%wQ2)w1N+6)DF+tL#B4U2-1|>MGGx zb}}s$okI;KQx;Qp<2#*P7?AqrgDLazQc6?}#4yRlZ%zmy+0k{)b=hPZT1uVGu{+W+ zV*Y?pkxtrIHu&ss*f2<>BZ3$Z5q)gy*}E+Z-E1j<=;k(adVX}OoKg~$b6S|&FPWWQ_Rz2XwANs+!Uz6x=aM~;3oa@&S0$;m_<_Nxp< zD!1xtZOc`r*+{B7r~beyOsLG6#$`pyjy53$sx}`BOYQf$R3QYqKHf8BqP1&qS&SiyLh6R$B1d!# z9uYY|W5&|p=+3M1YS$aPP0^$+A$~cnQ_-B>q90yI)Gqxz@SD`v&3@fXl5xN*R>j8J z(tq>kjFotQC{Fx-uJeOPy)E{$gG@GCZUO#izG4NC;c02~v7=d6)}w~((%Lrn*AjFO^EWNc;4zRFtJI+jfTy zs%O}#5C@)JkJtBOaM{)rCC{{@S?I`;@)MZV(cH3R1l?{&ez5JuwPWwBG6!Zm{c9KSKF&9)3IsUM0QiGqQw zN;40SWF=aFMdA)shA(XB$+O|i_(H8SW5_0wqwEeDq^rQ)9zb-o_RVj2tVL;vW)y%- z6+^#YoSAnF0YwYt6t{iA`mlL_Zisf`s5w}GMY|zXHjArxP%o`xm!@D#La+mYC)9?= zTgfVRYxeyEouK6v!#Dv;L}f-B5WlE`a%*3Ji_Mdyod`|ywCsudB4Dr|Nac!{{)8o-$23Nuy+af8*lB>I(Sd( zP@*-NTT>_>f(TF%1~6Z;7X%`1-g#Aq4LT#s*)_Rfy_~j+x3Ws9X?s7M9_+r;1*sXck{+sI%uR&P0Rh?%q0pp&C}|6ueYPI}Zm620X+ zk4~gsbdnErV0TqVA4#n5BLKYx$vafsKSL`lop`-v0NvFGP~O4=>@GA(-84fjK(DR< zJ9D?XWAD7U-1Zt!AKk(D5>Dp#@GhSazdR8mT>d_J;8#rm{uI3~LQWq-c3(i(NMa9o$yg6N4ma>}b2tZyP&4w|uVD&H^Ke?8LIzN1GufS=MMJ$E?( z-`KrB&YhIGkbNe9WrbypY?=gWZByDtDkC$(%uNz529f5HfDX#p*(xh^ciO9)tBadV zH%$HfL(ia4R@USi=P#Lvan(#Vqv^I(HO<5el7;bn=N+FlqI);vL?9=stm}z8Xj>!^ z<2F}JxDzQXK_jD6k5c6djeNV-NEyZ&D2|5rldva^L#(bNwGT1yn~;)`BdjrU(KI-e zRO_je>&oWN>k}APT%Qx#a%sgDhCTC*T#wpQZR%3|w@I2N4X@vGxN zH8eGA=ymOzsadgkOj)OReqkOw$P_Z9Q>DgqQ#WpcW=v9ubs~}P>W73}8Mu_@uG7un zyIdP*EL%F#tZ6ETh_l45`MhXJ24v|l-Rn;^@vfC*l|{nLf}*2Wp@=g?NZN>LY>`pq zq(>T@l5P$bK7$j}T$m*>g_GkcZS5QRSc2LjGP#wHm!J`@@25qLy`SEQV+lhA&spRQ zX0L()SJe&5Va+=3;#b`21hrI1Gr1ZHR1OOnmx;)AJf-A^YO+CzWnqfJ6unhIdCX-9 zscFbY+K5$6>%2rGb-1#xFp3nPV0?iWFrDz=AX4eL+=#HGDpG-$&j<~yOBSS?#zB5o zq-kMUGzoheI_Z{nEjW~Ca+-m4g;u1kxb?_{X`+O}=0y6vLLHx~#t^!%tc>dj!59P1 zGuje~WW!LCmTX4ViAU>%%tTqxX?cN7>>`Ke8bO4^VRz}N`k}e0qve&&$dJXEOJtZl z>9J>;_R)S2>o6j72BDIMOaq>3WBR)Vt#Pm&W30F);VL(*Necd1rT$;e2ys)m(I(Av zw=Jieu!r&AvT+kC!YI<4WXES1!4!R2>8YlnXNJLKrdWn()kf6oMA)K9QvR`iatxad zWi|Z^>Uoc<3V%dxp)gxPTd;^oJ|i2^Q~So@Or)0(8iq7vCm9EI`WACsg4G14mRzZ} z#V9rvX!f+^QiSyrUuB4F%-V1C3y-NcoHBw4(L#eNS(Rkg5yMH75S(U{p=N4Yx&ckL z|E~7h4uT8dc<$6`9d_jkvCjs|Sa_D|a&6mk6UrvehfB#OViM7GP2ZJGILE7nx+znf zRLAnkZYUzI$0sUnRJt;wx(TmMq)gKx8Nm$N&mtTd*7>>Rs)A*JC(R$kFSu2Cmk}@2 z&o%4Pv$8r=6HX&b7xq3J)h{AU41&Jhdn6dSX-0SSa9y-qVHk2w=;=_X)&7NhU&E7b zG`YR|w?=ohW3qc?ZlYY!FjeQylQ{m5ao$W;1=Ele?*4i-61@|GYCq0ZwvuU3)bJ^m zYpvA@-DpzVTZ5dKop@f~RZCdP-^AqRDZfmdwk4ZU!R?5%$mFeBsb_7;gj6H=$n12p z4K~tyLCR`ppJjJ_8?K`dqO?MGCA_>Mn%%jB_Y&)6^NCLUe3eR8OfX8;Dw39K$>LrQF$DsycmGg(xpr$wMhM zkv6&8ZH@~L-_-cUbR<$k7^%d9za~X)-I`O*b=Hu7?eMPl!?hYmA}ephu{6%^E>KEw zMVcw6Nq$-x8H{zYK0@>;7fYdOW@Ta07^gL&-Y5!(EWrvK9B=znor(Ve)V!2GEplGN zcey(XhuhmrHiQg~RGB*=ZD6dZ$pb0DXBwC7?-Bm%=Og3UIHcR5cu3QT;Q@_~w$oYi z(_|S>4r#p5(r>%GF#POIt_vQEwZpY2bU(<0>5|6D76-W5)NDSwM8_)O%#i?p%TyiS zzlUmv$NO25lQ!q>$+TZ3j3I73q=7L`{(wRF7dNaHzMY$D1~nxRwD!5U37883xaR&w zO>hJEba-2oooTq3@PKlN503R@+@dDG9eAGU1PEf?gq}M{*O_nwN6_3GBXrG&<+JV! z(P!TmUu!4XYA=cZxdj2z#0L`n3;6JqrWXT`Vj0F6SY;V5V&sd0{DNq{?LtSskU-@L z(TD+=O?mk1a8`-AzzB~i2)tRy9(ttuQ+GoGbM0UxmLxx(RwgoIc_v<3 z)VaD6vDTHEFuZxqep6oX`6h1R4cY$24_^>l_?ALA+7vadkt%{A1<}jY?hC2ABXDwY z=1sh{EnBi98f~?^AFvt`V}yS_;v>}#1;1~}qFAC*tQs9N0=JDaGJJ%K#)h*_*t z@PIT%lsAbNVvQuM&oy z%TIOBM`w}A$C+L&M_|mJ=Vs57zTyCZ?10at-#7*rU(tokcT0d&iIE?K2{o}W4a-gL z=uszs7!>zDWUkvM_!kY{SF9EfDx}>24~otXY!P{|J*Y&$q_``J~C~4;F3Q& z!vV;xAcb6hm*V{nD_hClmOz1>IsXImFF$9s30Nc2W0$r43bMvpsGLb3Uy)^WPEDe7 zLioM+d0SdlwLnvAKpI7loFLaQZ)@yIL>4D*_B=<5D0#HgIU6&OW4i=>B0 zId;)NtPqYeJzrn2&`Uzl6#t7mr$nORIvtT^FDIg zAXn@iKS9r&I~lKa?#R6G8p&W>yAMj^EXeavzZptQ%xKj3=~G3PjpmvUThPX>WD~Zr z%NP_^E5vng7ADLJ;Dt%{T~MO9`JC3{@>u53LXG}{{IzRTiUqO3mQ5(I~o`{i+I=?*jO0J3Yi$#{;x4V zO5H+zQw75Z2$QMsjHqd;Y*`L{!=N|XRT)v+uQ?oO$zN4!$<(wTAzgANTEiS!W@XSpyH6Daf$)9HE49WDn(e9IBF}^`0ak_AY;)! zNwMnWZk>rcj(q3{CE-IMg1c1Fe93{k*ieHzUG&L;yI`t2V{}SjR|;xp{;%gl9W^s9 z_xOXRO9yX0A~>+wPx7zSj7GceD2!LN1-fm*tP?!chbt)6ILjav$1ms z@z7?gMCxSnN+}7w?V6*b_g7Ell!Q0@zVYT9Yt2@gy>)4b*tc%L;$`qkQZDdQ^seS(>>QG5bF0a^i3Ix^}IR`^zmg-V~eqDkjzEG<+C zgdPU}_82YvEFo5kR32g(08hMj<^Gt1`0QcX7J{h~#AAWlgi;xNnVe!7+($ia9KdZ* zqUP0#k^5fUMqbHcWTzQfr9CG)`76Q~VqI8P)>)=l2Z%OREr+*N?y`c`EKJ!?Nv_(L z#T(h8bmr|&5wypyE<^Aa@M5@9*-mqqhZDwzoP*BWGvgt+Tk; z-u;hvR6$7|2?9-f9#h`Z9s9=ITwH6Q!(HCoGbgOaImFT(BSztBUPovK9E)!dql3VZ zj*_Edj~H;JnQLk+s8|=pNCf3b3k8aA`4*B-^)@Yd<}S#ep4B@@p4B_bjs<5ZHP}wn z*=?V$xVC#Jp}1D`_F)6nyJQci`-G*+YTkn@M7&h<#4SP4YMZY1Q_z1t4doyr2lq5_ z_Pa+OdOCJ!X(ZVOpiR$M**O3Y4we{AfknA=u=#hiWwf0GRuZ<38q$^Ci9Nt|rgG&Q z%(B?MZt;jrdrO~1bSMoXSr&OB39*XMqr!C66FMRb$~4Ep@o&(aIl17{H|}?l16v78B8BoC$j;_w>{ntqe)|ll9C3L{+eJ{D zy!SI4%ebSb6+hYF*)3O7?8RWOD9Pa{TL0CwG!N@)rOr+W4>yv->HVn2sM;V@Aj?wxkS0$Dg_8yr(A^e&YMYcU`7}}B9FD?hbtOe$NORk0P05&K~>tMX*#PucO4Jn@EWQl1W zJ3-74o;dZOu({K0EcW#qU!h6P3VHs(NlvIYtUcHl4|Vxo>~#A(GE`H`yH)2i0$OP; zl(NYgqFV4NqcDfsV9pKRBrP}E(0c!7dbZi)>-H`3(B%#>QrCWdji*=AS86=GB*^aO zc!IVWN%#Gnj~&pO_35TyNMFAi0`wA57<&86v?{1q_Y(Vuj8$w*yX~B;3A*Jjcm|-N zFG7{wMe_5!_>gZsrL?64Y7{q7ZPcY0E|!&0V3`hfl%|@CnqY7LJP(_WfN+oIy;XyJ z55Dp|egX0gsM^B6cYnQFg9{NF!RiiCdJu^g`ri-|BarL$&W?BE^#~=8u5d-l91w7% zL#+AMh=v%(*;nML;AWI!^>FAi+?n`m&WJ;&NT3|?39%c7!#znU{Zy+> z&TlUDz)wO_$Fmvl>S+@BUW6hEuG1;}9|C(Rrjel42Z= z@zFBkT#gVgYE6j{{{IMR8z)zW#Lz&Hd&+E>(X(`Fxk~wevBb>`K@VzbukrHw%n9-R z3Ef4;xmCv=>vqm#f1a4SWa|f2V4ciFVoem`#7l1g@%_li{x*v3)%__dm04#*6G$DW zmPx`YnKFWAIp@3nDE&VP-T$#1(i+y!F#R5byZpV#{=4N+*2LM|&REsf!tQ^sf=5c@9SV<>x{+`;HXES;fwi8jCxQf-*XU=Eg`3kUncIA@?x`e%tK;~o0ZdJ==>?(cVxMQ{5#+UX_DRz<$+{R z`{15VV;1La{6F|Q2jtXwr$&1Cmq|iZQCcdZ5thSG6JJlB2QE4N8R?r(k}aW`meoRMAb&&)+#GDVUWDzBPR&eT&TNY-yGDKjaiHVRD#)G*>?qOU3tFShpgUGe_&-6&j};Ky|4mG=Eu#^WR^}40JG+BFM~$qqVuJKGjiCpW~Ho3-VmTY z7M1j(84ZAnWvWzz22py!j5cDEG6h7bYN=?EX408*dP$$yucR|J2#an>cx6p$_e{E0 zdbAiPWy_fpZB5`a5H%)N@R+7idB9P#*no{r?S#cdUE;W+Q7|vba2Ak+$EGPG1NXZ* zl0MgzWFrVpr!WsPCp-?#rvNKyDRf&kX$jCMD}?`BHtzw@WYLO~lej0lCNGLTFM7LD zI7b0!s%X?GqJz^ZpECjI&;zFq;ph5FoRj5;X8I=RPEP=5;s1InmhQ zhZcEGC>JI$I$=bgqs6(C#^e2vZl;FFknAg-t0y)1M=hll>F1u#_DCNEA}u=%#8ok( zR_Th{(ZEDzQAXD!WolsCTsNR(hk<}_zm+9xpA{DdweX!tJP6}NuL%}g2YYg`z~rcZ zW%v{SkYlz-kz9+5Q88{W12*u5qYjjBP?QJfCJOgR_7%B^Mc_bTz|FJCrEY9k{>bJZ66)R zMoX|ET?oaDM3d$oA4dr6YMBVYtRvL9-l=Y|~<h=KKlp>7Kn;ob*rqz zO9;=?Rc8L`O&=!3Q{ehCv$l6CT(XLRI=X$GydB_QA?SAIjLpA?;a)GJ-a{Z^rH#gx zu7jmOiYiC#+#;)2DF?dRlfen6_J+Dh>U0;+EW3E75-FVE zbMr}VE1xh05iOs>dMcKboJa(@p5N24Bj|#pxQPY|5LlqCX5f}`6WLQO#GT)8iBIos zI*qlssO1q%)8iF@$!ct^Q!8_DFWm+6Zl@NH=?RC>zux$=vh&QuHYscL9lMNwkiLtK zHNruqG-;5D269E&bN=`_{`e>R!<`)Hx;}tA3ZVOrYinp-Q;M4Tiv^SFHQNNUHub`BvtjsZ!h)$}CuOrCKp3Rx!8Cfr@ZPxcelFd=D_JJg*d{ToV^g`{aW z$@4=a0~Z|eLe%@H<6rt}U&WJG?k?$?6X#6XP_TrwNqhLCR>-UkUVP7qZ|4TDB8&;H zcjKI79f0iUVDLJ3$$xQlO+qqhJk9q0-N4fMihI1L9Z1VcxnadPT^2W6M{7pf78@2G zy%toRxD(k36QumpRe8iv%8YkbO7gRvX=m24skSk^+BN=1*GEgF)}NgbF89#QB8q(R z%=!nns2|VVHLlGVt_bQ@>I_Bn=v)H1#NpMl`ML8kC&S#?13rW`b8;JrQ;yDMtnGAm zYUEg^u){nD;UIVYaHY(I(sbui&-RRRxOe3ejuW#Dr-Pcq{cNMAXz-OBZ1v=xlY1vm zrD46@8ZK%$qu~pV0`4x6o}KKXvX^+aidEyj$k8n<%6Z2z7?q-}exl^^d4ecu%1?;O zXu~v^W<59P*!Y^?h~p(+Qu|WLXxXSkdJU-mnFA&ZG43 zYB^W3Bq-sxH3!t1-?Q`+!f9?P5CQ+ZF=e{6`%fj;P?sUO8+g5fb96K&x~Mb1wS2V3 zYiC@>`bbgR&6w4t%~-{TCw~y^1%dJ+aC*^D zWGl^0Rpnt+t}8+tf^(F#ZXLH;f3U4TxsISMUiHv1l<+WA=ZblvuKxl~Zp~vY%7LK9 z9)&gS?jj}QIFR$mlmGJO=$!Bg1=B+wV?#L7>`rFtD^Fg4YNj6Hg?!%Vt4ZEQN`qW_ z!6Osq&R}r5G84&N@A234y8@G1Ix3PW@ox}Yf165y74yHygLSI(f!2~Fl9RBY+Uk*Pj80W_@lu{qnvK=v zaQI_oUMKx>ob%l2ODXa+n$_Y~9p|>+_FD|K_|fAV(yJ6s@8-Xrd%6qFo8^-Bra&0O z&VrLGsM&PRXnT;dh8+r%I=rpW=|ftSilZ_cR#A#D8i$5c31n9#LxRp>@OfITZB=x< z8C+Kt!oRl6btn&0?k?`a@)b?u6U5IXB+gs|21kFodIySf*tyyvPdjx?C!hlfy~=Gy z+7nVO13SiOgcm8f&8Hk(2Ut)RE-rvoR{Ayml6qrufL61d6y9P z7N)O(r%oVDt*`ZD31qlw2eQ~BneJ*s)Zrki`xmJPVVZ+1Kd#rMxmM%B zw)@_m&Fcgr63yFc5I(7 zd#e!jcoKx0aqtcf3Y8KGPf}8*o;)EHG;h{Cujac1q_$X?!CrnW0Qn>JO9NrYGzj%N zYPLAG_4c%OaQpk&V>17y+(_4Mx;5KHUtf>_(bAK>$Zxs2gMki6;YiZEW-J|jL8;+Q zsZlPa1D+GZP=WSL;B{a9pdh;xeU>$Y8>g?GVX`$c>*4Q(HzAHNvQO{5T`smAS+uV( z-e;iCo&KNVJv`W5*~kGK>LDWCyj#71cT>ieu8TiKo%3`n!$!JW*P0GDLH!+%5kh2A zZtURvp(Keg`Zi+nWdzU;p@jPEADGidsV?OMIX7TPe`WvPK5_Qb@&c8}qW5rWT(~D9 z+{3m5Gqwj8`up&#pdGI06Wz0`H$w)&rns;&BPcQ>a_UP&h0@I;a;7w0p~jK5r>F7N zJ2F=K>_jQncf2>Is(nia>hK$)H$$(-^$$LvYF6eDYajhBNBM!bK~N6aH@Uxne35Pa z4dd!3CK6Ovx*TiAG4# z`+*qyDxIds{yhd{b+@xB=M}`Da2=S?AD*bRZVt|W*O@92Jl?W})J1OCuF4*=$jY#m zF&TJ+7hh+{BOf)!&1L4yWt>s4351+R$d)3Cu(9%nu5m#ki3uJ^_{cyFt^l>Z-mJkm z{t%FLXN%l$i%$z|8x=8v4xzp(y-u51ZhLkU53xcvH8_TWM1~Ne|+l zlNAnK#!O3g$XTU9aExZi?2;}|AR-CUM8rCaGQN|t(8|Kt1w)z}%q8hS4JNS!gE~#XXJhq+=uf)}8sqgu^t17wNQmL>>>T=v%H4gVh#D*4Qs=K$D(_gb$mke43J!F>Kb)7cNlZWRr>Vk)%VN;F~u7(N8S093TrBVp4XUG2j zM*3S1hzBhLxnaed`j&K5tI(hH=mWwh$PE`Cd268NG8RU1`#|25%`tl~$;fVG)7fh4 zNP5q4^v-ClZ!SVdKp%J>GCOLD(DFJ#;%tI2$48CGue(x61ulM2I$*3t*VsU5q->RC ze$Y0QgqwasugvxRx~Wb5&owI1egqR5VLsT6@EeZh@&e)TLi_s(PqgDL8Rz_u>a}@E zui&_mJ4sV=$-}@D?|CteYu1vC4xG`hOq>{FRGXbdgyyQ+3-8Vt)#zK+k7OF(;jZE9 z)ocC(*`1iqv+2$=vY`Vb*>vByM;(xAXGVdbzB)u*h&wHo>tz1RcONpcOBz|XYnE$L zTs?pig>fLN&v=JMY3KBt@<h-43Vk`0n_^Rc`^5%kiHk(kw{xw}svp`5`X_xKp8 z1EE;Wb_1~7use;PQ`ZSdaIuy`XB1PnyK({R7nj>uSE>bEG|~D(yeVO`}E3 zWl4;x1Pu@_#z}0pD-jeUZL>bNccBsImRe zZI`rxhn>rRbJta*4(pC_?BOHOI2S1j?we$nHv>%o>4AMj@TW-kOD#XDgjP*>0(RiHm*4eZAGPLv^vtIi*Zyv5Zqw z)cjMFWzn;JE(Vw4>f9-sZNC7h>F*wg)ABqEd7SC4Tz5zXK&o3h23Y~?! z*X2xMDQumFxp)j^DLowa#JVcHddf957SHj1n%){+-Xa5Pi|y6 zck#JDR{sS1GTm^0G(l~HS`gmwyUlmjpQGD54R$)7-9$e5249G|Ka{$>^_V_WqKVC) z^P-7y)gy>$y?pX_dk`CUeG|WbR_vB=Z!O%i=;-${2-0f^b1CN0^XmW*%g~}S^DCs9 zD1#~4pgcjWjDQF>4aERD#fou7nPiK-<)W!x)y~pUHmK%(3Y{~Ll*9H)`6nyHd&xgz zCPnnir*padx_VLUZGO=s02%-EjnZ*T9b0C`Kx`L_g(8U*w&2R5^?KEG7YhZ1s`N&h zY*!P@5c;fi=UEqxlF`ZF$`mc>xAuD)D|*)()1!IOTm*0k81?_vBtTeouQpKfo*jO!+nF&`e4ehPs7ShZgqBYHmtVxbnn(83ngszmRc&MZszg_A+d^n7W8xZcLVzDXvkJ zthvJKDUq-x9;phYlE%z9nc5~F_o@Lsua%{!8x|m_s)&LUIyl@>NkhwO;3i_YzbV!Z zWw^iJ%-jkvoCGPFglc~?|2S6tJUey=HwLh9B zjnyvb4SUR4Rg+%7w{&n=?-4^HFXka1G5Y$Cu=W@d^e zE(zFoWk%k>PuChVm!zEmw&XIHDK#I=165?5xgWpD;F{CZUwi*_iyTpfT)kGk~>Ni*Z&Qk?q=5gLuLq&C5ncC!bvbEvE} z#4y!X^l=BPreD{Pd%q?mf5^{q)HO&P&>LF`y%?H6cyjyxv9<&V4jGLY1lk>s|O8!OgZqn$;q_$(SryPg$6rA5} zMO-MFg^T{$P%5TkZ8&3k<%Jb+Qm!<{WbvHPLs!W&qc%P>r0yd`Ymm@dLk}C?=4P1v zvJ;SYPEY+c2jaP8vXt)BL4wC;08CPXJ@MJ0-wN-i?S!Y|d z8jHP{Kd_YvmRV(hmd1?(PbXkKL?P)ja^CiJSLk+pwv1EM?QM6Xv*0Z~0-65(@PL#PkAqI>nE1ndT*h_kNDfnW)Y$F>Rd-2-) zm<>@;O9_)(7!5d9WE7-KSh)`_43SGbdUa;5O737HO${cmxuiDE)EUx;0xhqJS~E12 zk{dN{Wu9K2m`rB8a&bNU(;vl9<9C|b!imO7BUx4g4B#lsc-Y-Q6Bi@ap8SC=={f!1 zvc!^f=?q8Z6$v~z50AvjefC=>Z`S$kyGIBm(}UKqr*bqTj3oQ3m3C)?KhnHGC0+G; zwb&K)%LjzTol09GnQr&QD@~h;Zt!e4T+^8J^x|;5K@nkYv}8+IxP9$cz$^9i&S4O) z$I5?oNw=cq#p#~zZh$VOyTe{e;>(p;=Mg*}Bc zGXt?d5K|(h<2U-EJox!2Uh7p)=-mfWm_x>WZ z)N~lilE27%EW;#~C2ZHvm&M}d3NlLYpG-mi&v%PVq)bx2)7|!?Z>~gONsYQLAuoT&Ivbh%9X8)0gD57Ci zHTZIN!5z0TSO+#UsmZvKgQ&$+Su+KvMpH6cd-}7dla7F`=FzRJ;?<&*V6i_SI^t*2 zyZ%^s?NxbY84b_agk?`ZYl3g(4JwJOt zhYZQslyG|*l|i%7PFUrKTLU{@;Kuj*i*ec9S@GTkbx4D{bt1DQLA+En~w1mKK5z)AN z*==R?m7qU!jlFnu^T844{2{DzDz$vj`QwV@dCprdcBG#vBx7|BoX`OBhfus}^5jn& zoN@t`50T-#J56+-J1Q(|iB20oS|1M3Y|X ziv`e)QsPjJ8W3LPTHuRLt+(X;erFBp?_iei99d%fBTDMO;Z)w3BZ?Ck->f_%l^DSm zh0BL?&(b|A31O8X5qujMa`pU=cp&ve1_?AxXWMfi#=%tnn&ZQoe7kaPLH zZmiHRmMXTG_~G-$+@qo}EM)oNCn_^OI2n;NWZ6aa5Ec?dGH}~cQpLY#5+ZmR7FhEG?viatg+#UmeftPK9#Q} zViJX&WXl2Alq*abgN&@elrx>}^m`0wDz2L=PjjnC^N6~?kX4;fU6Q32c&&d~4Uy|$ zqj;u!b6so4{a04Xo;3*dIi#^sj%I+>qSLFHl*`8IIsf5tA9-T}`?=gw*63pN`+Li@ z!QazL2_J6c@;TU_gy=nfzedvPXlz6Ymv-E40)5R1RMOhK5!vBs(wFMFMcf z8-g`g1-oERY??KU(;p0#1DoV#2Wt!lCa?1=POvU##rg>vo$vR#nc2fL;=x{e!LL`D zifY?84UKCKJTF^~zE-JPKj8THYLSjtzY7Gs-cS{`iv89CadL!Y=ZH< zL7aV^>6_CI24)LA^Ir7*G!Yq&9WMt%Ej1>8%n`JSDTcF=b~(FMIvGKp2*jSu@)27- zwJ~U0$t01^85pWb5pfUePnK?*>htjawJ$4Ptpm*<8Co?Ppj=ZX2R>PqIG| zg1tixJn%`r@VEI0O9=E@J(G0%5hwhklAh0L_uCl%);ZL#;I}Zs*Z)UgwAMRP=2byk ze~yJWZRhTkRC&+3S8W5TBb2>Uk}t=^J*M8G{LkygAN)?_I=}MR^E0zK=S$>b{KB3G z-h=yIUVtc$*cDOIbg@)<{P_!{n^<#=a@_@gh}4yu0J;JpH#2moz;W{~rdUzXOIJ-ZX#dh}S9HsfU%1O@W|B;;Ha+L_q{bDx1lmGwzWbMq%{##%| z9oCz`%;i(Sq6jx?NNh>Xc>Hci)sT>O)HQS9E^efraC|oCa3oGfT(qNLk-I|21bG#S zEA!{Kkj!8dX-+T_9P{r~eYB7Uj*0AuMHF;hnaR2YOhxi@bB^d+Pm>oHm9DBwHSZeP zt1m~J*PmNoLf@h5?mM=`f*@IoXSKHs|7*Z=cJTE+G#*1w-Y(7*?Xv;q)ld)Zb6o3Z zh(EDa>5#|m4LagySPtA4$Kbwi*|VL)XIkr9%uvcFW{*$x4mMu$UT3&o_-hU88(t4; zk59#}n|lN?EF3C}JT82JW0E&sjWV@z*`7)gMv^k3RcSa|La}0#WV_&B<@B04FvQ75 z`JxEry9&;VInpF7tI~W5fA_Lhpwfw9kR_|O$T*vIF(%w1oC&Q;xsrL3;P)i@S$o7S zd5b1VD^}|QPlL6LFYOUqJ3^0&MU}pde5pbaC8F0&u;3&B5>g^UunN#r_C-qc#MbK; zAzpCnRL_a#ox(*`7gm%jh^fKvqO-B<{l}?mU05#jdHKdnHgP@DxOAgpzlg(DA1wMW+D_H)oCKK zWZknlLv%xA36ogDno>FBb!f6MF8U6?-=qkKkTj%buSiVN^y}TAcw)+cZw} zC=9uvsP&Ba7v|e_A{8Ub0ZT%iIWugi-!=kLm$L~`QK$4gz4JEZX3X`xWgu~()ROjH`z*YtIwa^O$Eo2!@ z!;p=$uEOnnkDq@L^?w!*A?$F`L=E-Yko1jth#?a)Ah(Qq8V9y>xV zbW~k>ay=fd+2Fy2Rj#D04um~jOmYt#2yCLu3 zD!HxM*X@j`HAN!R8}4u*hW0+nT)rjhRLd)s4LMQGg3p|ECyqw(`yh)P0Nz(ydcvY8-h*`^JBWC}LWdP^q_oH&@Bt~Xr zG(B?kGBps}4nPy{djm(LPwdJYE#UJKPNQe9GuV4t>t>V6B=`oh&yj_Zm zLPr{l0~`8VxED^d0>!&S_PUS z%SIqLX^(3t*lD0vY3;tO+IDRl*0Bvc_=}I$@!1J!Jd3dtPo}u=fZ&l1_omFSb9=}Y z1(1PH+k@Go$Jx#jXrGhoc6x7%S{uYdQnU~39-^~o!Hu8*3qc=MPc2x~Cik$T%#Myu zd)aKP@K-wyavd}@1%XpS2~VU3`uHcNppG8+_=NclsSF+G2lK%bIi5n&7ta?%?OPojL{I67gZUz;J zMIIayeABY>Y7G6>I`i)cRzTpsB1xI^Kb+s%d2%QBJPmbiSGPG3TVxtFnu5~6JBvMb^Es`f4ZMGi8h>?@D{ zL5PqMq1F-C;#J;^D%7%8-OE>~y1U}0Ph7@!Lq2~Vu+uTN5i!0kvf-H*4Og6;i;NN1ygSPxxBZ%XBZCj(8fOzpc{YsdOfwU0> z4xN$%ODuPx@HnHws5B zJy>646!v%GAo$Uii7+?YkQc*l`j;RI%&yJE9E^6()l*?HW(#{Pd^}#H)~M`|t(woC zNFeXQ^n=v;27hHzetMfxTwOJ*-8c@D=$dDXz#~7oukfvGBDJ!|&C&PcmoyN6A~v>c zPeZ|iJ6VQw$>U!L;4C?g3}!KBp}kKyL{vJHEC1pW)#bq-nN*4MPBWXhc?J5}OEDci z)DBa*%ta$!`5j0wiXT;E47jVR zB&(_F{@c9q8M?}69yQ`nl%pV*ayhjV={=i4eXKO@%)ridsBoV~Lp8JUtkr|uhJkse z^+jfc&lA=iY2>N0#I^aUvm>I|vBWb0U%q$0BJ7;!52LZ}l~oX5z?0{F#{q7{GmXDhS{H9EAzpKI^2WH)}5ah{x_!*?H# zWl)_OzX0`h`O1&FNU?7(_oe3+{GZ%@$TtrGZ}%u;Y4GND>B1%n*T6&;`N6I;gvR18 zRhEpPK!AsgjK;*YVIMBg`cBUo>ZACGMI9s^krU@hynk+D&16sKt&U8HUyFlZ2d9<` zt7bsR{k-gIEl9-=QkJ5tawi~8R&A0R5BtmliCM4jS!;1^<7W@XTL4X@l3y66@{745 z4!y?>MX;J=-Wu;j7EI~@cB9^-ZiJR~_*M>G3plmLTzL355d355pqiN7{Rs`q?jI}d zJ>%Ul|6YMT;F~gf!J7PtCL_KQPA|a{l|(y99`ouf2Q^Q6XFU^Yy8K~H8mt#?OZXmL zqsQY_YMCNVa=rAm(-Ps5x6w+Eil%8flAMnlipMj*kknA-DVDh8kMNuGltvR96wpB@%BQ3-nO@a z{nWpCBPyus%BWJ+4$Zs*OD#7BXSjxbc-D-^jN3FVW>$Y0>MPy({=R?zh^+}^*opAQ zE+*Fqk5yW}(902dl>pknCEK~9W(4p%Od3Y`o?E1sJs3ovla=lYmYL89S|v~n`biOX zgNj7&mX$c^cC|vxZh%@(nFz|b-H|NPaf5{>@Rxh~u5z}viW4t z$Cr^tsQBG4Jap1>hQsiaAD$LoP2!?hJaQbb_%>z-{ngn!w57T8eZcB{w~mIBul~l8 zIx}jjXU_^*pxC;^z3uGb-k%B=)P=mTtGe3?`M5m@?GSg6_m-z@Pytp*w^vA-kb*GLnvQuoTq4fG1 zBhSWVC-jEYOeS&?p6SdcB4C8P-Ru0GG;}dN&fH#F7>)-KyuA81)>axI%j2)uXW6nto?xj1fCQcAfQ$_ZZm; z%xmDBnw{-`CAfhgsS7c#nh#Vbt=5s+3CUt^wLcLp9rg|h@YvV(yQC2rUeAtFcC{G! z2zJ7dHs5TlJYX~A`ptJW&7W4yEo(||UqTvSvV<|4)H3~b_rGK&f~`8P0qNnu2_q6zMgvJqviGy=E@`(<2Kd7=LV^=7xUSjB8(H%%4`<*tNznDa>)W5a2Po(Z z-svLZJBVjgj&forhtI&ize;a>K9mDpQ30+9lbL_^f!CZR2XZ*PqWB~Ni^nWe|!S`ER)KHGT)zB@Wr>C|Gh&fg)3II2r{p2zVYT8;?V69hlI{+EYE|G zYPcVkUOL^zP4IlDcHSUgU!*E~Yg%>Q@vLs}OI)h-;UOU)8qc##wIc+E^~6iP;cGP5 zXKZZ+`!i@%J!t!M8tTBPm9ANbg43x`?ViH&pQzsU`y@7&#)qi1vc<|H&CGM$OK)$D z+6kuQ$6zm7(8#j;ZkHw?!N<}pG$M+u1R$>-ATihos(D2<& zzuEmV5CaF^?CK#yx;Dr!^n;=%+ND(w~ znwUmVprB#FOx z+x7i;yXPYqhH__Ay%!udN8(v~h?HoId}<7*KR!}SJ^3amk~5jx9-P*pa?CxFf#P6K zJz+NNg5uzoJh}v}J3g*gk>DH+&cXV**NmC{c0=tqs+dCYgB9-fjuz~;#B(-@V#7GX zJJ&i*#aeW+TB~GyS$TTHxXIN76Zu2>Q9BJ-A=ppJZ;C2T98Ky+$-^^Q6_z!uO~o1} zZ07|MRRy(X9++3S+(On{wFuYWJ@9cijYCZ@(acW9aIvPBC+V)N&9&I#$sL=k7unf{ zZ+e6b7AkP)2lQD)40GY24yrdFSVKyM0Tc-&n|Pgu_F_)=V_S3CMQOp^kFi!*G%Swu z>nH;SI$785!I#&A+E<->NCUCoF3O8dElh0VwNy^9LHr~InA4R^2*=Lr%A4&)s!~T% zN&M0-L9SR*Ytd#rR5$9eYKk}(_BuBN1AytM<`MJtE5hImGmg9F7VG6IMY7}OO$mWC z8CBf9zn*lJLE5$F(Nigi0;BaKMnlW7Hv#^{OfpHI0&0ngO5$5sxfI=me+Y(M$<5)K zb7{r%4g`WJ>><~4vpXJ$EEI1@;t^VwJyz}cuAt+r!6*pAP3u6@1(f=wo4*O@YBf!jnFZH9U2_KW`=wUl zXj{`KJ~yk@D7@<0%my02mKn_hQ%9FE%T?z{bV=w8rulYvO)=DKDK4mShHL#}>=Smm z6~-YJnEM@qOHG6aF{KSO`{m#WTEE|A;u^I&j?sxzM%|<#8N@c*P>DMVQR8C{`w&Vu zXdi9ix#j=rLbiI+QmZRuIwlG5w#XZ^9taLTY6~jff_XM z2?_&i&C@qDb&b>W=3!r{fghgmERz?quP)V)Px@|bzz*LJ2j8tyl_?gVVl;pE zau0}x`%a0lYfhH$dQavijmRJTU?`$YqO^a-ez4wPOB6I>#r!yo zMr9z%H@c)d02P5#@1GhuW1*)Y&pyCc3*T&PpA<(Kk;AyN3GkDAe+(VF@6>o+=d zYjX~NFZAnycptOsEPi~4oEysto#eus#l^4m6X_XWsCju<9+49sXR&P&KhljKr|@%k z;Ay1o^Cy&1u>a_8Qo$x;MM20v5a`3rQps($&+#-`shA}Oq$`N+vuAu9(Tv3O1(ZhO z_MX4zhnRorkkd#KeT6=lNN~}zU&XP=GM;Y3VksE|)+7*`~0c4 z_YV~+{CegSiYcDJ;D+$vw?eQeF@jUR_utQN|NGSHxh2MwL;V_8fN$Rz|6fx}+``1s zz|qLuisBwb+})&O_Caq zA+pA^tf4m*Q+FL=+XZJGx)_udWHOWN-cP}cOmdq!_O1+em-(Y|FYe#h8LO+ama3&y zzUHQ8|8+e1)IEJH;Jr_G^Aqty*zeQ-GkHe{_9OSl55P_z7$niJn7}PVcN};M;9duL zUgb|%&*wb#UyxFv*eX7ml>5%z)3Nr&U=1?q8gT#Y*+1Kb^Tr8^vuXEvA;~+H`xSA= zjWZdH+Q1H5|A;Uo+Q%Ubo7~gN`$d@GB-aTJQNUsBD<(HbLei<(LzbgKVbu31_5*MO zm?LTALn0zZZ_dyv`!u^3Bw7{yXjhU{;3`F8A}d~eaP^jMQpQ(1X^lG-hnj$ofaY%9 zAs6QA6o-I7e3MSiA**LC@GpLgAqtIMqE*8WYoi}wS+Z57-xRln#-0yr#61g)r&h#o za|K|4kKd)!Pl%>l(@XTRMQ;=Wmer~>gm1h-v2Tkjpy;2~8shOd=1#W#bbCnI{9yXg zq$e7cMgBqGOhs;>E~+zR3u*Y)EH<=-7HMz&4?}#H&O2;uWtx4+nAMm-p91m_YePRr!UPeE%1u-N1U<2@=wD7W391{YKRe-?IX&0Ojs5MWb`vLI?2P@?At|@&!`}&|>U+t1mJxE|YS!WvnN)Bv6K5?MK&0~NW|I4%{ zjN9B7Os=t%BzXqAzN5^HR<&N#;7qE}AEiJSXFmULRFiF^kV^1&J&S^OEnE>E3>6ODPb z6r9k7CLBIK&rTg;Ml@9B!ygVFC$xg6!k!7q)T+TND@DS!3*_nmnB>O?WV+3Cg;i(9 z;s-H7Qc{=(0t>Y2dJjTqqfuQxTv!r}su&RIXjCDed>ee29VEbtMEuc(G{5iZ zmguN@+zTZEz?<3A{4|bT>4V^=81@G_(-E)_SPYt}=#xg%Qo*fnEsCAtQj&x4(d}jv3b$dZOz9Vm2FO_Lf*4ZC}f;#Mt5wUI3i5g z%j`W3Ea9L4e_=-`j$lL#1BU1l-?38WR(O~oy#8X!%jOp2rafBwTQx@j;l46@==1Sq z?({)jL)7fH=xAGJ!Hd!0g8;i<$L4}#)a*)_NR|rqvg4tQRT&a9wm3L5Mh1M{96mWhRr#QnE{>R6}<}$_iy5)7of3DR9~Ww0Y|DVaS|{jthYNTCW8fTKWc zfmWn4@WQ$gQizsj`&>xDYE^|hQkl0*7G=mJ>b^51g_V@--gFOT?P_OwD1v?od7XTZ%W*ru?!PjRiud zaUZ4fjtu z$nIS(>o~|^hmlvxK<0!d19ZY)&#E)|74cz8iT-=IFr74T5?M+(GFQHy%}2b=#%SOQ z#agNK$*y}Rp&OEQJ^fGzNM?2C&w3j~Q$z6jT(&^NdtRHt&jX^F56q5C<9Cp2C8UEs&cLFV3LmTP7;2vLWZDL8)LBA{A~xLH5$_M#Fe z^(@{--yJ(ZAtGdj^t@C8?ol3;_1}b-@6b=<-|ItG8=z2ozCW)xXO!8KtGv?>nExk zd=-E-8+|PS@iYaLhj~v{=8F@PqA2~b(te_Ni6N5wd&OTiEA9AakQ?38JJzqBG3JnP zkB5dP=YppSGETTS>nsthXMAbOp%t{6iq&#bO{WP)!fBh`oBw zb^LRyfhuZ(vHFC`f!fpl5A;m!R?^uhI8(S;-jo)jml^MDTILiGpO*?0SP4Sp4 z9^!4QXc;_&_LMw8XIf?J#W&CCjcZ;R`KrWKR^YIJ1_{)~@@Ie#BCb!O#Nc z7Bn#dCIDLg0@1mfr_W-3nw>c_6O|W1Lae*_vu~2jzd)i>i`3}w@ zP6?Q-DA~omU0XX>WOYbPAJ}SCj)&eR6wWj2!r9LZQ)T)9QD} zo31w8U_&QWH$-XI^iqw4XZO8tllfZIJ>d=?|C}6PxKF^g77L_^impLG%CYe3Km;~c&M?1 zjisvQD*wprI_ySR==O0!CS$7)q6P@9UXWW{$$@t2F<%B!?vpTB^KOB6(5={F7@<=R z!rU0YK&E>VQ-!MTR}w+Eds?yArRJpjsN4`KHLK(X|AcTb0f*YJshk(G0X*>I3yp93 zqydBo&QnRke{;~}$&1}`@Q+jHxenfRl!N0E?hts~`_REGSFf>vGH3V8msLN<@N1Xa z7Tf+@F|V>I{H3Mh2)ROM6LTk6o{B^J+;>gi7U1Av?5%IUk5*NjtNMDrSQj%qPYrXi zShvq+HRaWrp>qee%bZ>dLu4aU-rDqgv5q`38QQ&2SSG25@7P#TWW?lNlEt02zrmwc zaI+bGqMF3GoE2u8dGN3kcsIxvK4D7Drsx!ah+KsH&4F^*DlEYR6L{Z64a$`dXiGf2 zD{^NG=DDAH=pD~~7w%*q;Dwlr=ub~F8|I!4nm^Ncx-dLWaAH#7eNw#QO~}~FyNk+B zDE$P8=@BXcFUZhm>kUa3%J3sfR=r*P$5!PO+K2jeQB5xPRYCBKoCXZl8OSL z?cl0Vd{W=)K4w4%@DBbxw~#x^jJkxy*^Cla2UTChP-iJt@o_T|A^W#=WNU8Sl!L1M z`9j?lQ<7t|G~q8T(LJ-XqR{k*6DS9m2mub5>cY7cWhQOBC$e;xD2p#ffqgB-vf{d+ zh(j(f(X>~ZF4J-y>-1@blOlc3nloBXsZ{I5UZ`C{iep~M`4hk4fD=EDMOcCD$LyXb z`O~pIQ_}vBE7o~NNY*Tfx0F)-RroX=MY5(c2#!>N`8ScjDex$pdXZ;p$moKjko;p$A$8Xf0zuk4>)hZn)YuT)V|pK zL^2;hU!%9sP%$3M7r&3n#?Q|6{oSuBdmieGqQZa<1|O^D3+7WzJOR3Bwv+6D-;dRK zw#pa-qId`oXXd9nzpW^FK_{uv`DK3?wPD`JAxsaTlaXSULrE(m(jzfrhq@m#aRG8NQ$EuyLR`@xi-1HA#8L@@xt}Me4!Pxuf1C;+>k&wEl$r= z5Kb@~I4Fg$^jZv)!cD#@16F(I1l}#zV0-hyKT^0}vw>XRt#O|aiF|4FT66#0pb{Bl z_CL|?*9v96S#Bo!c$oYRgq5|)+)CVHd9p3~;Kia;n`0pmV>ZBmZ;Il3!8}hXIR{!% zXbry_SZ0y5$CV=2N1)B7av%`9(dKZX9rDdB`E2RWx+rAi<^ z_p+dFSw?Fbq)nV&q4pY;94WFrl+c_N8*2eo9L zWNV3ex3PAHks1;He!2kEddKqycZZE-rj2ChV?E2&M%}mTb+VP!{@gCgK)dRR*NNv> z@95D-CM}LAh=!3Sc%IA+?a=2c_H#K zeKGn}1)&L2g&^KVZI8e7%(2eSh+-q4p`VVE_Dme1)4h z#|?bx_w)j%4Yh;$5)S`n_OlHkd(hrXSleS4}Iyz$ta=k^#Xi|R|9$|n|}P%bH!`UB<)M~)-+P{EEX=P%FCHO8P$+Q^fF z(?^_6L{}(1WCUWM#A^gXfE`l~IOpl)Wl5T{4SPIZTn7rc=vY|yZ&4#z!ED`3IP)*| z+;m76(p2@(>znCNq6AJJ7oxE(y|j{%+iYfSpx`oF%*{TWUVqXf$ZdW1Sinw?+HWUJktS9EI&6@X)8*JPIQdDk)bX5_tDrSc z4f~)(EEn=g*0UKjrncCUXvSY-=pxoPHC*3m11+FfSyg=q+#3NMJs4NB$g{R)NSUlAyJ(m8d}5Fr_7rI+@0RGH zzOsTWk=`51D`_-_XNV^ZlpL0bsM$3wz0;;K0*;(~5tmoV*(pPnO0jAEP)G&o*(t(4 z=#Bt2Rw|vRLOgq8;HZv1x&i>{(y2O)hF5VU$tOU#tt}@F4zTQ!? znxiRRSkoNRds_e+U5L%685AUn}z z9i$ZBJc{UPj>@blI+aH0;q$HcQQ6XWtnTeIMu9{SsMmsu>kX-Bftzl}~z_M?-D7##=&d}1Lqd8-bSaE^W zJyN0l@F%O`n&yo#X{=iEuqj5qpf$fS-gwDWkE~3etZ`i^cRT)~{)(p<9HkZ92{cKh zNbxh=AAgiiV^@-9NjDQlR(mB=BDKPykVRg()%hX4LHK%oL7om3cjCGDIq@VZUkaDI zfxTphAenSPkg+HBzG14~j&sKlKZF|~-Ey33ht$66fNU9u*{Qca8#Ou>A5UMz~+jV>|va1p*GMT`oWemG?(8p%`8 zlCP%ukb_Ha98leCAE-@}&e5x-7XAFMDjm~9T%x9;L;TKzTmx;xXv~9URhtQ+Onn5C zT7y^{lLVsv!kUG+(ryN8WA))>*wdE~)%Y9A_~=zwJxu~9Uo(iiNlpKLx5Y1Eom^D(P zaN^ZTn1EB-c`j=8h*-^rC@7r4d_StzLu&_&DcXYqsuVj?S;a+&7mEEAmKmmA$VkLqO_ zY^qG*m=6TiZICWpB>?X`FTquN(oVtqK-UdJ+R$MT$Hjh6m1etUh-mZ=IAA1Y-UGfi zT`W7RGIh2sZXJ#0hmUP%N!Lvr!=;g{_hwm*%3_ZwW*aY8giE6#mYPmVTda0HIth~p z)^lFsc=k4Kr%xOimg{(Kkw#O#Lw=$-Max|#VW+=Pj{weP&um;sCN<@zRT$_TORBXq z6%c>*IA5%GU6^E3uxWDuWSEe|*XxD{xWgENwn)Nd)6(wj4^7iF%nJ2w)=f(N=^l5A z!O?sHP&Q?W6(ZvN+7iY&ySv0xA+Oc;+tPz=4C&+bIO;^MlWcpsPiQkbBC=4rhz8A;$ghz})E*7b2%1ig)!! zC{;r+n?NwmdZ=VC2b*6nhjoCTv53*`4mR|%G5E*hIc7Olk;miXV_bjfX6b|?IaiT< zy>WCLfLU0vgPD}0`U)k57wO$xae{4ueR@D$JYosh0wzjM!3Cse^DBN;o`LH^r48I$ zB*1^FZvLzAw;6v-8X+19a^keb{`hygQD!GidN_<0~!Cc;PgL$RF8E<0LCfPV&X7%$F{ikYRH{8Wupb9<;{Wqh($}^6j|RFQ;gfD5+IyQM#kt zA{TJ`d6oQGIC9@BmB^!Z(=(^?TAF>%+ta0Wd%pvwN$dB}-A%GaeK48bkQ&*Xr-%3H zNOv{()G;Y8Qnarup7bI-UNPL*~_%|-h?&2!PQCI<+=NqT|PvMzj^28O1 zIdF(Y+hXWaK%@rm4L>wB6O=4pDt&oFVmm)_3s`)FBLn_YrJNS}9V;VGdOP>H%ihfuVz`hy1{9zSwE;9}CPi^aoDrfUwXA2Kz8&=EhW9Tw?P!|@5 za<5Q(RLHcvrK=2&<%GJ0=ut*nLTT2H*`+g^Yuz2PMc2f6?LF&$aq!4p^yMhUIVpbz zvACyruD#fiqo~ebux0W~Cp|{66^QXl51D<9ER=hnta5 zRjO|bz1WAi7hsbX z@)*Tg2e3Kq2u7bb8+x`W3QYo=S$YscoyLFgQHBJyXaspI#!SF~9IX(@k{;qxK5UU5 z1H%Bstq_XMfcQ6gJxmgfyd4tE2o`oii>r_JG4#lSi(nNa_2&R(GQctH3`GlLRLyQ> zue#LWMT(3~#rkTyu=D1$vhX2p{v`4Vl|lVX&@rM`}62_slqgI)L%A z&Tv|bK5Jm8{%|kYJashpGPyaa^X0vwb#jN%8l!UWu$V;(e*-(HdHZUwH6jDPTx_Ot z!3&1A?>h#&Z?7m1o!t9$m8#^ks7VZ)OEhwGm+JP)j!e!F(eqlU(E9~T-fVf9@2Sci z>WWmS0h0{KAyP{4JyWyDrCW$kmT%Y-2uq?P3pK9VO4q$|t~q)$Tq`;YO}KO&ode-1 zTeb?N_Dn@A%=T;;VN zz{_|FV3ich5c!jS=MGN)s#e}xO_W=jj*C2%4)PM|v;EpFV+lW}XQKQt#fGCJaeH-BYmsAiQ?-w?8QvE`mPOSJb!W{c zq_r+Lx`aE=1`4cc7Ib5dzrqXdz$w9;^`sgW(y`dADF7RAmIK+~d?<9=P<%Cc5zB|=Zj@=pIIt?m0q?dH2BW@?HNoe5SJdtXA0>BB6AG$;X+n_ za&}F~C+2yac1>(&s9R`L5eKdZZ+F-}7T1&uKl&wakhOB>{BP;suC-UnS%$GVZ)6pYSJ8wv2Yv-R*&}f zKng51)qYDl0ac64RVX`uT=V2;u8B(Hgc)%$z(se>6_^{^it!tz?vu_Ua~dTZ>518q z`}By&S$|2t-LhH;0Kq_LKI%tQr4w|3J2K3hO_a|A0Re0OJ46nqlietMLD4 z?HW5s>)ZXOt4!6?^M|?RBg-&uLlPJc74Cy)gm$k4o(b@B!xnZgh94Eer@Dx zx2|q#3V&mBwcHutDs0WHv%$l^`CHQRJ#^y!0rLUzL9^^HJ7c;P3nh{4(-ga@&&g+Z z@5TD(U)S#!$mr8SQjY6T^nM{=bZm7sj#g4TEYM=D3*bky);7?p1?1uf7VDD^N}i;#8X5AD;7Axi8nv!V ztXgR|tBu;{yX92&EOcG_sg4x}?~r0!qp~SH+$S3u0jD=F3$Cn5mxo3I0XOOro5!q% zXf)0yZXqVQ@x~#CM6#mP*~~gxw7@bmQd=hhEiW2!4(KdW${LraOit9JNlg-dDVQdwdt!Ke*Jq;=yWDaOk%-}Kjuw5P7AKy&Z|g^(j~C#o?o0H93s zNBC0or_^)$^t7{xk5;O~h0z;_5(CbbhNif@GaNA%by}oY6L%FKs9YDO)EH=3cs+qJ ztP($Bm&T{jUU%g+Q7(R%LVS-);yfOsck9s?we+Do#^>!E>4JxnrS(>5^-M*rcI~b4rBO+y!f`+7r6< z_eHvm_x;jI8Jq^3ylBD!;yy(_t!g$eV_+xW#@^&jZMHx1r@kcw)#*p~M;7%w@CRAH z!ItLPu-&85iP%#HsukZRpM$tKz4X~#|D0I=jM?m+TL&GnXA4+`>GEg&L{tTb!)Crz zf?Ri-zy0G)ae&4`6TZ%p<43lK z%5k;8xWi;QJn5)!ipfew*-iS3{J1y8WN7vuh{?yI3y#VGPN#~B!0YlsNBeT!mc$U4 z#_@z=M|UWx<2P8Ei zWVA0rdxr8nd*7Zk?YV=Lo|+#j;}gYC~V?6&xL z06j>ue$oqBx-8-(u1M)&-nC^n@D@L~Wc9(i9N`=uUMcZ#3@UP#TZ6yTOL;GBy6UO!eR?7z<`teGWDGeaB-Q5j!*J^wNCTBv3eZUq zn^W|P&YwQOf#SzCZnq`Y{gB6GfBCxp+HLvWgW{Ie7YgwaNwL@RyR911&Gy#^jd9U1 zkU->)G{1RvOp@TKuiIcX+`TMtbOpW`t_?JrDm-(JE%8_yl zV67qX-;(7nqCak#^zNbRt|>g6rEbLK@&|6LpET-lLC|1y1$UkP2V_UY-%ewXwfrKm z5;5FRY!1uWHd|HBX5PBqe#zrKu-1AxkBb>;Z(rX9DYv0O_QZ?qaW zGRrH3sQVD_W}s(mU}r>%w;9{)dkUP7@_p}AmwGGc3h+nxu^{P0##QdDm3s^UYIv2P z?wNCU$V&w2CyH{0Sr zwXrOU3?k~MCU*b)$o@@jlr^w0Hgx(w74kpIBj=;-Di5d$s5YpK3#f|=D69x*Owvc* zQdiOvfe0uwOm5XsgV1NzP?wYUcTv^SA%dkeQT|>+!Bm%%r3h%v-p4}0p;GHqmXZjl zewaiUez~v*-eVNB#H;YxTR2GgIC}XT`|BBr`rE7UTNwp9I`CYzp`nqUk)FXX01*_C zJVA9nDo_=?@u5D@e|aLmiU@M9ADjUZ;J-om{#1J*V-tO6tABZ!*pRa#%qZp87TR4i{`>>=50W? zWLbPcJ&w!RVzd^_zRer)^7*qE3%A$2S_1Xep(BZ?6f6punl8VgB*q45^dTmLrhVCn zlt!L^vyeb6PU33gFO=)METr8)SKY&@;T`@mda0wYfsBG>M?BfOraWbD&-tS!WmZY0 zVF;b1fKY<&e+z9Q3KYXWy0x_f#UQ&2bQi8i3BRg1Acj@QKrz149;EvT_+NtS9|!*( zU4IHY(63+DAphpF{?98=GIKE2HxhNQb+-GTD=S(_T^3Ou>B}aaK@gokURmp0r$`Q! zMLk(qNK%+zE-XW`Jqh2b1ieIPC)&2BG92zLfS#uej(OhfVHvkLXHlN2g}&sB+p(vS z_SxtCYoBpqF68xhhMmSJI<~1`P!@|_jJYT{fD^{4!N#;$tpEMg!}+P^7M&v~msnIKa~={ibF zi?E2~n&@bw%8B~e*FU4xpc<-a2%8l-5j|Z?zMh$MxgNuDYi%l`@^GQ;!ibSIsk=z) z=m`Q%GG-PcD{M&hC?u*{oD;dTrL7`CM^_Sn>8d>?n*dXP-Zx;Nn${#01S8TZq;Yc6 z{VxD5@thnUtyloIJD?|O#1PewFQvc6P!1h7)VseAFkM)B%ZRiw%}};gYU>z}^xH9l^UrHE0-M6b8tPX)WokM!J>b09 zZC0dcFSiPJaToBTP#%kdgJ6Z2zQRtf1NCTg*YpR=;sBE<$=80f0tvUJU^JV0CS;kM z3rn@unS9clSU9nMD2%Z3$Wcimu_GZ*JX$9!H%qf)Yzt#m5%hPFsoF)MLNPXH?irUU z$9Jq0%2`p}Eb5-32`7MSJBR4k)-&8qtQd zq51a#wX}vvLT-N(x(Q*((ubTBH3r*vm1vGlV-|rDpEh6(+FR%|=j;Q^C|qiAi2zf7 z^caAYlBJA9e=Hk)MJ!Ct+?&syV7x>8&pr4D856?y=LmHCxk>ZC`q6*(prif|>&(f? z!Q8;v$=LB{c_o2@5FfwNR*NP|zDkm$90E|i08(J;3j_6{@pyw| zi{>EQjqJ@iRPBpG0Ex&!Ca(l{Be9toqIX)lV-Mp=reh{9FRwR00?1UUJ~_J zP?Rg7zZE2V`C+kvcsX7%1o`?x{|bHiK}-xesP)X_wwXV^xd|&;Qn8*QofcVVkDB$R zlF&no>?=a%bb^F<NaK2Mp0mR<_MJXWHL^#&j`{1_71T=)@QlEAb^wwZh(lw?VUa|TV{oz+{6*RXgqaNDD;V#41?S+Go z5=sxE^)MqJ^UBLLO?r8)i6`Yor=!Lz5Yc1Q+AXLvn%iuJ&SGuw=^joWU$t|7=uP?96xXNk{)yu zc-jXkhrZ4iCc=A}kI3C4d{XIatymRGOg=*rQgIQ9q=v{O87^I_{PTP=RXLcLX1507 zn`C9&d`!Fqo{GnD<|#-20`+D02&|8HYsM+h6stZ~&Pe<3(xhT=2cjc#6{x|7Wl=i* zGU<1sh_nI-a)Wdd6Byzy;-&y}HYP5HR^vOIL4q2+-x&2>1HbKw##&-3+eBVr4j|}Z z6_`a%pU9SllF@UO1SJgH;8E{Pu-2=0|L0 zH#Pp3m8>i+r>TteMFYIU7zAiOL||d)3)F?+JEsD;mXeE+0Ze3GzZMXCh@c~NmqSa7 zw3H0xdcD==V2Wz90aML!aN2gUlkGVgEoq8{J>s}CDM^S&IC!{qpY7Q5zU?VvgY(z> zoqNL`02j<22N9A4SqcOqUGA1-b5h%E5E)rjS*kKko_?|~E5g!h_fJw$gu6>kW1>R5 z32C8${}n-?ZKaw4=}(B{FpP^$g__BGOoXPDDpFVFAD7>*brbHERc6xto{&x;7l7G_ zBFlCqz#E2wtRR4kCj5{OMNt(~OOzK2GiMjZ0t4iXwW+q}E&V<~&}^9^(t2dZ8^dij zXRp%ew3);83R_JF#S+vxDa{!=Nsg&rO5(c<2gcnRQM6U5Mmyrr z&3x*kEEU2P@J-7QtaVonGo_7h!D?5N;mEF8B6gwN*E zH9W6;dJ~v}bxw7ui(VtJIi9_FWE*P%fufcE9%~4Mdoz6BLoFw*U(EBS!>As1_32rC zg*D*RRgeWb6~p=A1uGP)FAnxamcQqRBpgqOzvfDBTo?@p-t3+d(Ng^ zk1#%uL$D^}Cc9A@j#OGNAmKgB8{MsKAevo0LvIzR$}Cqnc6)BozFE7iW>eZklJQ&+D1V%_Hi}#0UmVG z^i%uJMfUKKZ9&FShR6^e=%i=bnFXqc3_ShFULxr~p+=Y+1j$uk>_&N9CCySvN^!oyX&-+_4o zMGu-h=tXEb8Ffv1b}zYnw|EI6wVR~T%7|sV{X_sRpp)f*6DUQ2^OwGs$KiimZe)+m zxFTDzSTzRmo*v%5=snChXm?->sq^@PorV{EjW5iuqyq{Yo4Fb-Ph9X1E!d!iwW9&~ zR+75V2kT7v`$!U z26&2laFN~Qx%UK8Op$ARk^1+(MA~HOb$`StCgE+0!n3c4beUe=ysCzzUf>0*4NJWv z-gBH;G89O+0W_UlfqoIH!MaC)R4}OJK{pK}3=LXc=k2QZE!E z>?BVrPV(Lr&o8Ey^aBms9Fai;?{p-aL@dn$3Psgnvs;73!g0&H*-oEVOF3dW5xb{# z{C?m5`H-KBs@vm(SZp?0{X_Ju?qiX9r$;>83FN1tQL=l-Pw!U7u}vHuYsl#9txBOmYesGZiv112?{9e$w&j*MAUJ67! z#2Y-+wmgKVxiEW<0A4yxy3l*|crANSK3?)8qr#`*cs)U+#;-|JIk0~wUnD?Gb(6bm z!^eo-Z=Kz}24ijCZleU0y(}iehMgzZa>q8+oe9yP4J)-WHGo?o8) zKR#n74)fD!v65w~iczSac^m3BMvGzSz(#T)fkEm~z3$-WT4{e@S_uAwCE6%I z%x=PcJisF4MR*Xq;m|+|dP{YDI8F;9HOh+PoR630psStAprw6m2qhjqOz_NZE;c5j zs0(zO{vr!`R=qW3=GhIJHe_Px4I1i7(Eb@LsWXc1OHl~_l!Y5gC)$uAHb%~%Id9IY z9kMC9@3|AlWF;AWa1K$&XWF728nl>oJc54XnyCq5ys2$lKQi@!A7>c z(8P5i0;{m6CkRsFv&I=aAy*{0kZU2)@4WaW|dkaWn-k@G7_$A z#-(FUC}n+aZGtXY7eg1JlE;|Xc=4P@Q$6UL2bjkU^dlD0WtyX`>Wx=T{=}AfvDtB{ zI%=OSSFV%9jF&>x)7aN=J*)%Ml`~VpPms8#h=cI1oaw;8xEezG7vXJ*=qri zohWWC^BAV$ zYVa;bu5=?_HB4#$#1hXmR63y- zfg-izj?EWe%{6I9)24;(Y~S5;;}1zwB*YCz{+j+M%}jV3@K5^d0MQ-*lHj0({+3% zzW$D}^%=bRM3Mj4fl?1s5VfCT`57-Cv4v*Tc=eY`kbd!k{7pKbpv&_gZYTBr633U zO|Btos`e2KGTl>OUzhhi$w*tPHrH8JsLms&rERaO>bOa*6vFc3epI9OsLWzho#?aJ z)QS_FfXjvCQ{-PNlc4B$O|~dLYb?QJn&ZM5(#JW|I%i<>IaT`N{Esy*tCBpq z!BI8C1opctl=u3NtsgZ ze+Pv8qnCCq{_ySpsMmj{waovUf;F_YF)=r#{SmTu#tu&IipEYq@=4gu(AduD|Kfm? z<0owp>5)QwO&#({y5pMU1lpVY(ue}`%P1o{Ad~=Mz{!cBT(0#^~x%JYn&X^hrnt|e@jE~;0R(W@@fVD%=3!AUP?Mcv62Dt6< z0)&d}>lm5dg4d)ENdzBbB$Bra0DTJzY@;O(rl0)sw-#s1e0h}0y_j}(lTAjO8JGmH zA1IZ($Nuq&eUxtB;_hs1;g(TO;A)}RQoc~tFh)=uM@o|JVpD5twqm@;X6%k|L0Pp7u^rP~_Z_gEr&jEW zV~n$m!N2Z#pr;Mv!>dj>&yJHe^^$iwA@hPzEZ6`%dOwEbU1*w~$wYmSP*0nLcO{xs zIJX7sT-~q8Be-TcHZU-nI6pffrKtd4ZNeR>OtZ<=HbEj?Vdc-Ac>6eyr{}fyFw|d+ zmU8s&2uWsPuoJ&j`n@D7D=pv~v0Qo!=H21`LdkR-6-st`ygc+URobbqm@Oj!{6*RON5U%#mSpV!QPNbTewri{`u@|UfNd*XOtAD7c(=7Sb9caKaP zC65PxivUWNav&w}YJf(M5yKVS&BDbDTf;R-DM1%E5?G)b@L&;1RRV{>boDRf@Wz8$ zp158Kv6+y@eRJK)QppKe^vW>j-30*vAwt*{f?W-G5MaGBp!-+62uc>AUM*9Gv;S5G zpIB{lE9-guw1%Nvstmfc#tjxVLfl`70`3)*JlQV{9CZt9bqgHz4Wl3pz-sdE^G7wQ z)Sh;re6^vl5O}1HA<$RRD4|R{yzO0AXWpWSz!lsf&akxns^--Zm zwLe{cGL8hW>hIco%m}JWv*hkgjaf>qS!uLQGimnt<7Yg*kHsa);kcq#PVg zdRcWFG)w4|{o993x6Ju&ojCIdI~xHWVO-0A?14Ut7CF8}*Hfj`Z2e`$hE{OqR}9w( z7{{CTitQ7=SSg6iDnknF20j~GDD*T5;%#1J+}moVOHI0Z78pQ<$VMbdHgks7B8^jH zbtv;2tbZXV={#FZ$mlas^l#f0E5=Vq6tJC&wS3e)tj4IBLDDk*Y9_(BSMeuK4#3=bK^dxhfs~`!4r!Euz(u;o+D|1+$mk zA^FQ$|HPAYQ{ZV12IY$@5hRlh_vfWM4xjM)@WI~c{I8|z-HF*Jj zPnAW+q35STgy2Khy$_OvPgJ5;H-eJlHE{wy&QW_5{|iX*=cS6G1iY4@q~Z?|y)^uy zGQHrGQn2h40vhXjh;~o4mF8v`rC2MU2ASR$35* zspN;t4ahMsuo^E5NmK>&RwQ--k#|R2)4I_)qWgv<8qW)vlr#t?RVbdU?wiv@QeRlk zG?u`VU)^Ybu9e2=FpvpO*=OunDG!@7XpX@Ag{@E{nFv8k02DX*bWpB}d)E2kVAFPp!c`hPT-7vIh{Y~iM$1QL3c-tuo}n5(m%z8wN~*HKV3#QDB;% zB$ExXOV%OO83Z7Bznr-iiLlpAAN!x--aB;97SOUgSsH8ipTA{g-_9b@}2YMNig z99B5-02~ba+sxa0XpaFOC>@)`(6>~(@e^be7dksbJqz$YcCl}VgY7USPw~A>qWlW64xD92t|?W2*S`lc|wQ%_Iw&jxNs|QQ91g3a7NNEPQ8;6 z6pxeInw0Ao(c%6H!%F(J!H^AsvpYFQ?=E@?PL(JQEa+Sa#u6tNrHcB1_>y^wVJG>GQAnmH0cG4tnr7Akj>hnh3B4KcEmmxZXWDPC}h5h={oPGdl zl|40!jRBl|O~cf_Cj5PL`Xp)eD@@IFD*W|M=YedrO_GudQ!#bUjK>i+e@9RO?2+Im zcXd#|7MxBNg>=SY-U`>t41brFeZD3x449^n!_bPbc^VkZbvm@)@5dn>%z_;b!TP}J zFG>a=jUCKGNVQ8u3s2LTGbGPJ8Ss}2qZM}<9zNMj1cH_iu-S{nhL0H$jjIb^@drKQ z_y<^w2ve1eAkIkb0rSW*k{3qG9Vn5a4-fOCtn7&z!-&IFUmZ2TdMCIiY>uPl(Xy#s z`*?GJX|~lra_*W9%YM7RmBQ#Yc4?s74h3Z!#+Y@t!47}5zRsSybOqArz6fuZM19Ll zlq_F5N2=*)IC;+9QQ%}_pfm5Ge>wItW1zs>4r(hp3+F3nBbFYi@EM~bQmn-2%XMUgr#lw1xmWZG|_8I*mE?@j$f0g9Hz0QvlMj$}~|H+nYT zofAI43w1b*z{El$la43zKwos=ki$XJbo6?(2vmT+-OLBK1X^I91$%)mS`tYR4G$;f=XDDtnNqMpvRlcjf8f5<}-|4;(3k(*aj|CW#$xNh*66Y{S&4 zNbo9sjZw#E0MAqx>`YGKtQ)rQ=S?zucg&f0n)30@)Dy=WUFqh)U!Ox)$ret?ZrIvJ zIMQdV?)o}7M=)%%LjAl0*b(yB_zYn-Nb?5;49$>P#sO4A?jFCZwjdhqiI29Z7#*1z z+DzEmLLlU{(AoH1@iXV7vw{{Z2VE)lPAA%AWKKo9OR2v7ycEeB;Q^Avuq?k%!U^`5 z%M9LM?=~K6vEd6~zSg(DP>2(Y`Xr+4a|V=J+TQdOj!6@X+rUbZQ6}?}AM%Q(a+0`- z$vgcb51*)-gu0$O>&kE=jUB2-(xvhifE9wFSM*MwuMaS*)QbyxM&&WPbKo_gg-i@kUFHc8p@60aic_vU?KkjgFO1TsQUjkZ=tUenCy2W1)-LMiM~{qWaF9~T&pcEV zw%#~)8YQlcw}~Iw!RTC>ju*jZrG0n^%@x}Z9VKdt$Muxlt{9}AfXb}u+_N9O)w+wp z+EeItjA<)iuSzbGgYKxR`Uc%lX!WE4zaDSwu1JaA)3l!Rz@H89VfD~q75)HBK+B!; zFCE~otPV<5h}t3ke~f(tb0$!lZfx6D$F^;=V|Q#P9e=TH+qP}n>e%k+W_EV(-JP0S zwSVE%srQ`sA;H0w!JD=Ty>FevkwUI$*GztnlJ#r1`Vwbe&%KlL4&9bkZ@a=5eM~wo^5El1eA!@uRU-&57J&Fm>ed zU)m|3=&Me_QGJsnLNorJATjr}J&$1Cn)!%(dG(aD-N;U z_&(p6=$HQJ#ZFrW;1W>GZu8iH()nrg4=;!u2z1Z>q>h zD@QyCa<5{$V_{F;N6bH>!lERwC_g&gEy&eBB;4Q6GcPw?jxs|C0uyJ5m z0I*P|YJ5~ugCBe&7NY|xnh_ofD0F2}T&MU&c?H|5#U=~iNg9C#s%J@v*I_@{UeL-z z%VF22l8rzE%|yQ*2*dU1)a37DFYoRVZ}W$ouir1o!mCjkOy8U(&a@SyQK~4vxFa!u zwGbzqDUopr0d>J<)wxhgRQ<`Nbaf?6nrVD=MWz!mP-LeO1`I3j@{7w~4 zX!Q~X&;aL_=X4e0zS=Y_(8*@K!vuR!nuwp?t5>QTFBfEewr2Obnq6h`uVz`ZIEat? zfvf)G{^783vO@%f*vs)}F3YcqCgID)xKdbo>49>yWI2MkrA}jYoeg3uH$ChNHR~>E zscWefrmFbfVTvIFD(04~%!bV$r|BO4_}#geiJnp6aXIl_rX3G2&ezZ*jra>$sG%1e zbPIe`wOnl&CTEF)FSWX{Ah`9#j^ zcFYH9lZQ4Hzmjo2@e`_PlI-XbD55w*3{nqD)f(HddAKuD&{rDisC6~sZFM(Q`veI6 zUI;Fqs;4g$6Q~7Rv+wB~)pz~P>{JS(DNuw*L6Su@6IzP->NXQj(dOzggf;7#*m`93uOfg5%njVQtgl7Mo!<$36$c1iI>T02-=#)!ZZY9~m+Jg_ zEM7XIeRo~(jXBHqa=5pZyAg;A4s1FL4s<(5h#=8013QdT)RJ3G63tEe=_#mPI4s`M z!`BYn1Ew^~uoS5wydSu;hkoEkj9<9mUmrljbFeNtUnsphKsfXw?)za5`X?2y)V13| zUA#sfhi5scg+cui+ZgkJ%pbeH{V~#g!7+x_#YbPER&baVr8+CMgXfH)8LKqDJmpLt zh%l1eD_xuR$2FY(S-tthkHsT|eiL2LjH{~gpm-y^)stw2{ z)YNE-2%Zho?jt~FZS`ZSCUOEW5It+Cj;K~)Hm1CX?{E>}y7*+ss zuF+iI{EYXL7;eKgEv`?#`*a@Y=UhQLiiY8mNmm+vij(RiCX_e9P4^S4k65cwf*35s zE87&;U>l_mYFsx?Be`fy$(w*+Mlbx}ybs6h@2EFAto>EFjNB^5s;4|D9^4@U3{asW$_SiK83-O6upm3q7q_AMr)5kfCV54_SAsN*W zlYU0+rk2nIQ!+{Ge&=`b)5hh?M|s`n1#Zk=lRnL5*e`Wn&fzq}0S@*QkhFT!oOyKy zeAotS%4aT^M?M0pZW#sEG3%ND*?p3{cTC)GXhj0sI5FOSHdURLt#ucN2;A6qM}iC~ zvF_w#7@uxO=_wTp?!X)8)d)s>BZiGEzqgz%dA6h%qPCn37_#$aM!5b^v51$Ua)y|{ z2pD297;nOkU{x4`WsKfK(d=bnrqXI`aVm`A1vaJld!?`cw74a=bRUM@@FuOfkE)$o z8Ng6~HsQ;tx$6kNUlY4{2gBudqucWjJ6~<{gZe>RyIsLq8w&ZcWE|l>s$Yb0%jMf- zj4VZ-c1NC&ZK8bH1x(lJXMa*9&L_@`H{+G<^5%-mIWupp_Ne4ivRuI@p^v6v?g_o$ zbwL+IQOfC!TJ`nB8q8M{=pvyxHgl`3#KR;sGsmf4;!u3$+rL3c_rOqCV_d<_lP{$o zkUs7CqHi$mhgIgYxJhX7_TS=R{_#8}S>&(lLjwWjeyaxlt-S1CP;f;@3)^oP{J-AE z@0#o*?BA4LlV&VB#6&VAxnlKeIz*}l&_yF9x@?h*Yi6t0ZVF zo0be{#QGYOn+?V&B(0htHN95XmzVXPY%hK07xv#~CT)f5^LTyk4s))*zU;QIKYGq{ zeD-=21V9nXZ#|J@Zl;Nn_mYLBTgF#$gI3ZuDF7QoH}p)K#H!bD`_$i2wpT=Gn<%{< zL-%|}trBo=0jd68L-zVe#G4Fy9(G8GyL}{`h}W0{BFqE``H*izHgNiDnj1Mzwi+A5z~O0p&UPqyacTiZlHPTN^{WWOM)IOuxCbJWQntfoIsu%gx{Q) z`56viQ4&Sl8@elGWEw5T62Z!Z`mvU>YLs}`s^u&(C(%WmelRSIeA1Td63wG?KX_v9lDro+ewKc(JCh(e~+=P&%JWL#ypr!mfg zvQ3SxX&231XNG>{iP4MW6d>>(qhvMm2vWj%+^L*;C@k0$aSW`MJZypM#trM!WobaH zb<*d_jK{(XbH9cUY|Vniw~`b&V77A)R+_C>epZQj1dwkUH(LvE$XB-q33{zFW^zVb za4dv1TZ>C+qIV;`-&eQVK_h%t7cN&{o0(mxMzKzTYlkGxRC-$^Gt?XgHBaR6m<~S8 zJ9~9pe&^|wQak&)2T}f6qo{#5<6bM*t%?Al#a1_9+Xn}?nj-@oqw7SW zgN-l9qg9Fq23QT&!bHKS8%G74*U9%`-tvwena_-uYutczlK~iLUSPJ%cPreL`c`gS zz!~;%VN|i0yUTX9-L-~W(7hpRsJ_|x5oTQSU=wfsKE#{)0K$DW=-69Qip|oc{N0h4 zu%O$4AJi{pxeJj~FznE$<}X}cX&;Vq%~+OTeL(^GyD4xQQ47lCXsT00`332$audYE zl}^cUUOxv87}RfQI*WH#+{OCAFgvQ`S{}06m*n8T_Fb1GE&6360(N#=n17EvTbjJ< z^%34kfcy66pkEBqWBV%IXuQh}hKHKpxPgE53Xmu28wgARo;KSPZW)jld|_9=LJhaL zx*g;7`rp4yO@hskZOmM8RNxE5Y_^1I<7A{oNb<;y0qN3fZYr9Gbv0X(CEO>-BhM)1 z^rexGF3LEzoHMq)%uZ2LvnUP~1I-&me|19AD>1jSfS86EtF_KU1{+y3kB7(E8s@#V zE0%&RdwBdc>%MOjJfSmjK1lmVvr!Y1xvQvbOE7tU*Wb;fM;Vyvydzp}iD? zYMN-;s0(r-1C&aRNa7qU;ObSkfS@uDg{y5$Ql&Ii3YG9u0wXx9z_mYVF}boX#{o~y zVP`+>KlOb0ONINk>E_@48#scM-pbig3cS%-xxy54D%3_;T&L?}r*9j(Bu5Y_bv5y`=QPQ?47V|8h+Z;MmQ`yg; z$7{HsW#(WG2GG{W!l*o?Xlr-di^yW(uLpOiBrkLAXC%V0HQjI8^)y*Tgza6avhJb$ zCSeE+I=Z>_%4)&rrL3WP^N4yo6f+g@(74qS^BaoXlYz zB>zU*>9ndaWpKMOL2=YX_I4F+SS&qepkb{e%7g_gr!T00i{iI-$8>Wcr(Jt;=YF%Z z(sgmOfzpUE+8ctAEV(~Lbd3N|&T*)@Lz?DqxCNSt!87YRI~iESu#XLx!tI6{&zM7N zc?t=}Z1Tt>R_5#x^TfExY**$Fd;Ap`YqK?{6+_tO^}beq%(X_`$UDg+AZg}QR==@| z3i(}lzOtl# z(webK94$zOyi?kTfyv7Yg#{hL(O(+=HMuD+z4#T;l$Jq~MC{AnnZnd*Fi2xlrotHASmY3Wv-zySE6u36sH$dPZjyVNl-tob|2zBWE#R$ zz#MUiDY*nPmeQmwadR{zRmDo0)lM5V_1EBpCB{a!=yf30Kt$XOkMm znQX*U&>UDcD>XKFdD7q23Or)CCssTp^B&3_XxkahH?O)$73`4E2*R;(yVW0`5d|u0 zW&D?+&&Snhj0CWjs^SCRZ zuI(06W&kUAyxt5u(JVb9NVUa9Nl4_R5Zw!B(-5r;y!qrln!TP zJp$`6jha;2ydt=+@zf!?tyz;Gct*>yj!;NzxUFp#I6tX((-4OxPMk|ki)qnScq1%$ zV(q=McH}~C8&7Wc6M&UN*4o1#`AtX%@sH>xO0z29$QGsec`*{aG5YtV_hWc75eUK| zu3H~-u{&9(tl^Ps*N@iqCO5BI2PgiiPWjPWW1aG>Hyym3A9`X5s<{}*RoQNI4ICNe z-XP;DVY*ObRr$~w9>LODuiUsWI%nuiXf(_}`Dc0HsxAkOFwco_YK!TJYS`ASgs5$_ z7y@NIu%#pDY>R^bmMobyXHacQA+MWI<_&p+l{bWdaxss1%ZtQzP_B8J=i=5Zv)N_n zV=YAGv!CN%fQ+i9+jq2YAcG(N{{v*$Iy16-=174^=TuD?6qf?O8vJ-BiHWH5I{DL+-Jz{wCK6d1gZY+YqBUBB!QuC-l z{Yc=D@&z+K^GZwH1Tvz$>MHx{nrG+LcI)lA$Cpn6O814{e~L4q7b7#u$weNH)CenT zZ-8o=5(%AB+g=FjH`>q;82z3j93iDWxJE&1vLM|wg*|?{W>lCOy}!eWQK}?SjFf`` z)CaCns&wz5Gn_gIJB-q1WWN$p7kio3L2@OMyz+-&{lND`N1x=;?cyexD~!7t01f5n@X5h_ksWE(>{h*23g{x^d|Bo!M#@ zYd8#deRIOhFK{}JGILp;9UoHTwzR#uPwXwn2G>u?yj<;rc9D)p{3Pq3ttY<^gE2Ya z<@)tXUB@GbrXMRXI4S5VwJf9S8;V{UqSsYOFb8Tqk|kfR@(is2n>YnB^K~&~SGr>y zmh_68WJ)-jCJN&c0|~#4p@29;_xnaVk;^rvR2h|)*8I=*38A%^6JZ^p4H(9>qkT;a z;l5#*!h)hO=(HuZWG_02b&riSHKYti+9}qn**te8H;HiOGMu(yQURv*$mMgU?Fm*X8ZJ^^g?SW&7L42I!D?To zmThv7oAV};?yRELDNisk`n5p|R&&K_I0kyvYH>dNMyg*WRCB+Niq){l za8%AQD6mC2G%Q{^-A7F`&M`dmx|Z{RNYFqbjq|_ zNm~doKWV@)r^Sn%RoraOqa-8cxu58+Ny_PFG2I52990UUDIA-dK&+HGVB1yDmZoxk zfsE8yu)RKU-&KuXS!xy!t(BoRvs5|Mxrt@rsD7U2PB^?)Ya1WZWlYsmAtWK|Sf;fZ z5&oqP;w`}(?ApY3R~e+rG^I;}NndS9+KyluXH(D2bb#An(%FVYULmOMG&5rv*4Yp# z0hNId#~flR-r-F%<#V!1vamYPGM=2v)N-9S<1gKP(u8&B|C1{Jp7Ux~ z1F>HRxUMjt>RypRX3RAjdRh=*_dxG#U*zd{A{yV&E1AUP8K!h(SQx;#O)lOtxVk%* z#55>vuR`{-J<>J&7jam!G-Tf8x5PPYd4G)VyWQ;%eEDQ;>C9m-1r@gT|LOGbb?8%n%HIjPL4}yJPid`x>7b5we zY_dn(4|%{Nvq1;6xu~)uKuv&Bx8%D4=Rd4}9RSfe3AQc?W(-+d0}lXj!<{}M0rl^mrwI^^^)xT z;b#HqopkT7mK)sG$y=Cbwrm|Smg=}m7o5>ou~}L8y&R(XE7Vg%XirhSILRhKPry$z z<0-{-vi&ly$}EvB@Ve}Q_MEw~tj7UehS~YYPD;G9utkZpfu212Ej7Y5QZhpEM2WAi zeAN#;c082rpn0cXtGqE$HO37g$iNg@Y#fR)KU`bJ+S4esBF5^aDtgNs(h5-)TvNUZ zucaj9=cnMd)<&cw73-0&ozRPIX`WcRh_SQL&;S>7hOK^`Ty2j z%yh`H-|P|otJy`6xl(y!xgSHm^msr*kDMbTFtM#7pORG3-@`EXZV_jeR8poI)N$hW%866}L5XHYE z6O`?&tu1WLzgdItxERC#1OS3nb*<69{bkdit}P4owCF|P?E&Mi(jA&gv7bawkQgaO zzslxBr)s^n5b({|J5+LivBnL)1S$!Mfg1~=(HQ|5R$wJj!t=lEXV`V$4kv^u3_4v~ zw^Y%!k99d+aqWCeUvKH#>3$&pZrr=2GLjUlg*q>E_Dw8`rXuM5OGPj!;u)0Hds3>cGGe| zN5k=PGtm&_$D@Q4DTOMmTWr(L2j*LE8bsG6A59m*TucWs@_dOrWM~{SlwF?Zve%0n#vXBXM9@M@NZJKt8{hC z)lJH5N9#E*nG(EEdFhO z_!JUDzzk{lGC6zo8uTeUt_b#YUp7Wd)(B+>iN`FHJ(yT7!x2FzNWS$(y@^USCoHm7 z`N{-k>&jI2VWM@qdMoyr$rhU7JVlF@LK0S3+N`|c+l+r%AB+VD)U6j{lQ&#>i-`mA zgUpV$m@mAkZL~=2G)3qo=6o4xVCWIS4cBbFB3T+y!3i)Z&CTT8NQfcxbpPTc^1Gs- ze62_eFUaO=N040KNUpLh|7|nfO}2kD`C1HhNIPKhOVcj5gJ~4BYmNHdj2bZ3Xj#59 zdgMMMlXbx|b8Ey8mpT-`VJ>^&eFaTCoG8$|sYI;WgzXrS8Id1JdE5jC{X38eh@aJn zX@A##vCQAi7Uo(=Z+)vR3tMHsWjFL@pcl^5r%7j@GENx(zAk?vVuc_ncY$Ct(~e`T4yi$*Jnrxmt8bHH(hGch($7jFc$a#1)@ z7>3x8%B9jPPG@78h;s15#EqOZ6HKA{?WSp6YxPkh`H_=j2KhlPw)al6}! z-?*d?2-(F2qjOA$r+ljq{KKc5dbx=9sr-Xh56Ig^37kTN2WUP4EY2{;C#>{yB`?v_ zyEs08oKq*A5{4TdpD=-6D8BPto4Gai3DXA*e{p;lz&Gwdv>>nWGd4#eY()Vyd{DNI z`PStbiZ9S2iiBC_?|ha|rRbS0TH>IpvB|dQE50|L8NTDqe^wjfI#gCb z87U8;75khFuz|Bs^QI<7tQ59Y&v(*K!CROWwUzB-*wVO*1QR+rGBKFL&Tqz16d5RS z%TsHj*xQ-1fP9oWlBX=TJj!lMVobEvO&#t}t^EKtwLQu@dVOmF8|?J+ZPqDI_Z*Ww zA4=bY$c1vYK0|y^;@+g3qP2y7C_XGOQDQiXcjI7>ij-15cFt2}G(SNlkcV|Qo6r); zrBtKBmT9VjFR0JALxX>H)TfgFq}jV)?Vb)2Itpid2TgPWgtkc#Axzr2aCg5vpfdM1 zgBu!Y@egCz^3+}vlZr-&G_2lbq1rIZL_|M>&Y3pj1a?1xx8i)`dvkS!~B^G z1D{sGsP4Ii>Bnk5d?xA#g$gJLUE9Tdh!X;p*yZ--F)E45r0__(f5gZG&bTmkBDdal z$yl+uU4&4uSxFi(3==kNRD6Akq3rUo+fO0WKT-|Hky!q^L{l0b?uDCLRRxO+zR zcW=4RDE&+5*n8^ZJKD-knoA~BLAH6wx51Upg~gTcNR~iJlSK;#^UHWj*}FgKK>=@J zgZTR|suzjhOUUQPfUz~;R29rUKns+kvV%!Gm2y!~vnr&Y@HIN`67~SQ8P{%NOqSk` z(oCQ7-oI*T*_^H@GL?(w;MYLesLAcAv4Q)JJN}Z4dCUX&$o{TIkmekLb*3U-OhmGj z#^L zM&n=Sh-@k}xyN^~L)P~!A^mrAM8(3!-r7{w(8JE`^NL0_l_E1mNC(QkGi zGt>B3%+1_<-{1e@JD}Aj3kjITw`K~#HCSX0p_}SX?c!9M8xWNk@CS1pr70|21>7CR zYfAQ;%)WPt2ODm3@5@^(I7rlq!`$*##5VQR8D*vJ6IT(jyaeyagEc#z(JO z;$1=8gk&(6E9baEZUmogd^nkz-ZbeK@%GlO0fnme8~*35}OY^ z`*+GbuQHmwEnm?^iVxX4>)lC`tWFAVz|~Yokm}(IN)!~uFkRpb6i47`DI8Qr=xE6u zv`6r1&s!tBRDZQIRvmQr(`cHuzN~mKMT+fjg_>EH8%w{D)CL(tssYk`U1wtJmp+S2 znPhR=PCEOs;4Mf{)}9K_$96*P5UI zI*cE7MtuPoc6kaP$3G<-W37oFh5M}At(1rsngsS_SFDA;W-EB4lKj;QYsHtAEpQMe zhak3^L-La6T)Uz%OtVJ7l|?iVQ@G3jh{$3$J^MZwXPr>}=e_y(4aHzy~((s-fZpc#o6iG)YPb4v|b z$bdY28zw zRAO9#he4PMV&atT+q1PdMgY|VmuNKvGLCc>VJ|@JJ#c50?wf;&R+>Eq=u9d((E5&) zx%2vtbliev=I)Dr{%H%FCj-BK%{Ukap*>VW{zBss`h31^gG-{~T!TkF#o|RSX?38^ zF5DmU{=wbR?5i&YrbcVu5dh7FPj;7#9O|5Dvf@8=SJYfn!}-b zOKg5K1M*p>?m#@DTVV8^VQ3$Rd+v}J4o}Tq-kOSTUmPxj^+;R1Ubw4_p3-(}ty8_v zMP03UtHa+{)BhIP6t877-4As3zL0NF5pHA42^&bAJ+gEEN;&AIeha7#M+V>6at9Vy zi!8&^s1q4lqShM?wNllo*cY4p8nV?1*->%m3g6MVfu#PNg-7lT@})n@nNaQ28KQAt zNust@bRe~RLAE-iMz2x7#R2$E3al{CQ=oHHxZ|@p@F{Hf7T~INN)6?dx;KPtYra=e zeNK69N55YPw()!f5@X>E8Fu72&mj1Q@fVCw}d~Jx-%?v#9&^TqYLy3 z^eEn>z+4F`7I<1QV#HL7jaKo`^sMX8BO?N&|GXL7IDC!A^5Yu{Qq8ZIOC0~rI6xl8 z)yEHOPJY?=n6mMNuF7)Old9y?RL+VN+o+$Iz@a%_TIQ%Kt*FV=cEJc3;UqdlY)NJv zEa-#(;I_$RBH6%7Vo~7^=~~M_lucyA z{IF=fM?j-|WrMUX_krTi61p|KM5??kO4@MquS4Mlg}RlWN9kr=d<2m}7B&VAhsL&y zg)1)_$VO(`iZOo+rfjShU=ovI!OVG}rKz#f(Wr|rgtDrN>}gLw)u8l1$+3RyiB$Ao z;@?8F4YJ$F|03szQrFxhiynwS=%X;wj7g!bu1S`pAO^7znK9ibV&F^ZoZGS;5M47X zp~chOkKt&E3$j?{4s_!N^&C}@9$*!y@lp_Q_-r-6~01j&lXEl1*a92SMssbO`h?puob447@KlB^%dy z%l1>Ne!-+{cWnL6;B1>$HmY4y;KnhKvMH~={PJC|n`D%*l+>>ZDI_fW&65)?%Qq(7 zTu3=3%<3d9TATr1X^9+he+BkDtP~Y@|7d?h(zb!b9@jzhhQgk-^SjM4c+w<5&@~shnvz)ty zg|;M?=Ijw&ty($yq-OrE8M8}`=XFgnl>{oIdz{}M#YHRjVnz@8hzjglH77~EdDA(! z+ob^z5BQn;?u_6G`?g>{r3XIT{nitytB*vhVr<^DtRQ#g97B!I*wA=O_X=LH?6^k- zt}SnvI|CS>N|U7eM%dojKE?Y)a0tvEO{50*{krQ5)CMSTq{?H56Z@>e8Hgrzl9}5! zF(Y3=xPviFS@;w$wDCwC;zyA|*g6X7l}A->DgzX(Uf}pE_MBcieQIfKVY+koA|~aV znXFQ{;r07>s9)*a6nfu6oj=fdXI$P!1Fq{`zkuv4 zZ+P6L0ueQ5+MLRmBAZU3MdDpTC!SM-nH~onaje8hE4)>I`M`Y259}NeqInbM-JC=l z+Ubbfnuo5OM>CZR#f%(<72m&2dRjq&BKC`*eVJ?;4YUqHpqF0{@xe3!V9Iemk-toG z36Iu=lNN|fveheh|HBur)W;De(zIC~oIR+TZz3lbx`P4->D_t8Qb>BxBAQ=OND}U& z#zgqM(7g`c!1m7ayRt9kCJEr%r-1fe0m#`m$N7X8C`s@N$-P8Pb{v)eCg+Fcrk2U& zeh2GYy|}%L5BTm1u)U!1H?*X~i!`QQIaxd!J>tRRUtY#hy&m+izH|Jx8WGO-Lk&Z| z|JV}@y-YGwnj~X6a0HvZ;dw`F!c2BR{l%{wX@}?Hda&AiQ6hl`oGut00qmkmg`E=@ zy4-uz4I6mNo^t__*4i?|ECY$D9FH!Hie0F<*Sl3XYf1m;j701(h!Q+$&>HoZ9OkDS zr&dz5y#!SdV_u!ywPC-RZ>n5}atlesZ8+OrKL=ahZiVRh9XO#23Pv)8DvUrJv=`f+ z8390>S&J?xhQ`p(g=iSv>W0p{B#d@)cGh2>+CY8EBxuv28}@@KM_}-_X_;~(RItwG zX9UR<)sVQ$N^S(`a0Ut^hE^0BYp0 zq%|}2h2b=y$lh#AGvsk@;FnP>maNpwd;xLk%&$J9WC7wI#3k|ljPoRqCLYLiWiHBg zyv{KVPfD{;%I!Cbmlz_V-?YKdECI1*#~tt4;({6m24fr5+U=?ldCG;JE;x2*DpR_I zTLpoB>4?#%I*8*PMUfYc!=c)kwinetVl3=YQCH(=gt8MA%0c&dEdu#b!GqdZQx<~q z0W!@}q*Ppk9HJ6k;1PiZQuDFo!5@-jaa-J(R~ir2IMoI>_6On-}#3REp^dJ-gvoBp8f=L4A>Mg9O!Wieol zLo031fvYAL&{1S23I^a#rW6{gGfR48Va1!JFJ>iXACn0vsy-6t4sVtFGEM$){6v$( z^2y%PcZy0;KxN`FI|Mg1!x6*3?@Ebe_KQ@`SqzGjwL(8PH1&I(Zc1iDI^d|2^6B&T_;n|vm z9BPj)<{LRME!oqSc(*X5TAW3UjPVhJSh0-j;~Op`_ZC;Wg-ZX>lJK(FrG*LwyCABZ z&VHAgW32NR9RE|XGG&@JMrYhre_g@5h@CkMA&ak`_Vm@l=*uwf!mF5a^eNtb!UQoE zC<#8$(4%f?;zP%$tvU5{LQ9Fu{FXP}vZ;jXwmQ6Wc|w@DVkG<))r+-teAXua9%qp> z_vn5;-1s-m-yVoo;YnNzV}nFdSY@2XpY^iI6L^Fv^no}rvXx9lOZoA0(}2>UI0&kOWzI1-{aeP12hAzQ4WMu^nL%%bY7BIz0Ir3$=J2I`A|IUXT@R3gG~11J;!n8tKa%w9`PtN!!Q z#~(=XJ2Hl#I%4LzfwHAD38rl9w5ZuesAZ692HzzEG!k0J<}3A#D49mi=jvN+N&oK_dXA z)Ul4%Ii$JYb9iB!(lwqgt8`qzF=1&4n!c zZhuW!l=+Cq*~(B2lGL3IT(px?rFg8T+ht8iOwR#5=r9zv!#Nk~yQZ8|v>DR_XvpGB zgaHD(MV|TwDPXcY)AN~h8Ousx?@$kUBLgysP&rVwSNtJsQcQf9BLS%<9uL%=;z2B7 z{wsU%W81*)3vdN60lGm=RlOqJdYUTESO7Hl@WUIV((HX(syrd}xB^@Xw}CM5>>rKl zX9hhbv*WpIbg^2kn8nJ$TxGeq^7JmASs}ZF!Zl8qvgZJmr~b0ZT4a?HB`RdcAId0c z*-(|(ui$8`Ecao-T8^9>PTVv6U}?IF$+2zO`A|0)%6nC4s4a1mEdz?3f%`^0k$pLR zqMb4Od%sh|5Cyre{J>jb&u)Y`A>9T%F8~wv4Az4odq2IwYT+_lVI+9Xp*N(AXP1=c>ifBN_ zQOm|BmC?(z%I7y%^^?=H>1EUkP0GR-Y1zQ#{gvm>HOJK&PCK&i=FllR;|^2hxFUKo zBtbbA-o?k&aJ@{+1`><1{pMcCB8N)GU}hA}JcH}!t?XgCg_eJ39r}Qp9XKfhW)j%+ z3MU_6v<}(ErR{pr8@v6xaV>07r?w;yGAwLqeC+yK_UOGwrj=Pt2=*fz`|#RwC#RLQ zr?{q-H*BnIQ;=gEO-##d%#v|r=J~;|)t_X8b%j-_2y4p__m?74mqkv#xz{#g%)z- z8{r=8^4@VkWb?=%jG#HX#;W1&H4c@wT z%2C{IhX{at*%?GwBV(qK+>O?%K|sGzVtZ&UR&VSYB6m-3H#k*C0G?sSvGHe!WP6)PM20&#ve*uIdzG7Xo&?QeOd8FifmUD^?}8G5 z`J`j4y&-x@Q|73=;AKv7@nzZ+d`z;sV1H$E?m+|0*8*kcBSD0d+=LrZp^z6|k10~i z2T?PD;|!{563YYBnc%qxf7sV?qO*rC7&K4?ZwxxO>QDOFGNB@bYuRf~0#Zb|I!UMt zqkc+OBoKoTj>E0Mlt^!N~GV}ju o_YU{k;`P+S<@UkP$6d*NQooCN;be6CYJ^W=ObW5h!u`O z%pV$UBw!AJ?Y}#nj-6Ylt*kNE1TskK3rF)OW?vLlf6}SQ==W;?9)y#+Pz>^hPN=n; z8Dlc}8m9R}Sv|6{pZM&B$|4}=N9^+Bh@Y1(qUNf0SH}W1%Z%cpSeS|^nG_&rDvPmh zb*Ln?Tch1^Lgz8Yv8+nrPl61CRkxO1gt?^Q+i^TNL4jg6p}25QD!VWRVCCU*94@8S`ucs>LF zs5WOG0kbmm`H2%^69^XgN+a&hg#aLDPw244R4gv_Z|tyvclzCmH6qFJ?nJDoDcSUf zb<<|%7mn0_wD+s4%pq9aN;}2UIH8Q&Ugdkz8Le6ulYU%__fkZI3=Z(m7hX-DX* zC#kVw*o-}ax0B^E1gxkTIM8Q(QCJPxmj8}#FDuOrX)N=yZGN(ra>qOhtPAFP|A zdD5IHE528+haiP4EMct!xBbdIa z4ApO1l8wW`9!vh0qxuHS3t2M!yA2HpNki2w!NRD+DYa;>3ASlDkB=s3Crm81EW z$rPW{mG?2vjMvA3zz)9<<*>s>pcOwDQf%BRNf|%jC8J<_sLL) zaFz=xUE&XaPX*fRx7fbSl$1)vd@#@*!Q)1lpxl6(pT#&X5#XGoV_!?A6@!8KS59*Jh zH7AY(BR!`!LVgs5~Q zB#I5O_xXADN-^CP7h@52=#+sf@uqT|nUf+Er($;Wsmxy)!YL%($kTWMe#a$}H%E`{ zN~&h66~+t?yP5XA_^>uXtkA@RgUr->=$Y}1kt#ubPoxy~9?(LW$&3NS(3tj0!oU$I z)4Q~W5BB77wLysFo8OHArqC(1BzqXs(l1cQ&;wrrg5Ie=fu>Vpkvq|u?I1;#3`()! zwqTGeVn!m{Bp>hN ziO7PzuV^{WH@#?l25*)5r@|V@50{cLl(?HRx?#ER4(#jcF(L8*g6D5VB_hXZ&Fw%` z({@`+@?mlP10&!#aAifS%hR;KG>){wBh+CRx{p$NHa#xDfM+{xn~Nwl*&Rfcyd}gc83J#A^1y~ zowvmj{w9V?D}^2&oQZm}H$}qM=V{+BpRV@D9k(3`wx72tP_D$<5n1lC!KmW&!nL>n zN}&=p*>X-)A-a0xAP4ryGAM$P`0`8F>c=AlA}9WF#TRGkH7gk-DD}|M|Y-e z-eN-{BMjdqhhj)u z39G|%N?$C%He%rq$lH2oQ#AVB)vju!iu6({rz_k^BXh>CVGTR6hqbAHSMS?^KRdfT zJ0nm6zcW>vRen_-K zLU?wx-@CC{D7Yy{xLgwAV@jp8597r(IRUJA%prrNQZK1ilWVh_JF=G&u;*;oPw@{f z+bZYy6#>!^G*4K`d;EpD?G_uz;CZcC`D1Pra54`bs0IDl^Ad8zMH^CEy!kwUcLYCT z4&y^KYpRr#+671#83ouM2UnT)6Tvj@rKip4bS=7;xYOwFV(l|zV#{n;+~96S!7}hv zKK|%i^Nm5q(n_WXu>*cKkUD6U6`~nEWdDbuqNZ+R;?Fox{LBh1yZQ#jbpFNbiWi0=iLt@@2-FF-1qEyB)rVxuq z!P&4baQYY6@61y1OVhHX(o^a-{i?w3oLVZ)RreIx;NRXgS|%e$g4cFX~LXweI{tgwS(sDv2Y>GVQ? zn!VkzubMeCr7y~`i?mde*^y(=@BvY4$-~Z-$;C7Hc+tT&x#_)CYY@Zs)cspG`OYY~ zwZBK^(ZPa-5)@2h1`M^Ilj(r+eHOWI)Gmd3Mwkf>7Zvs@yl@n%8K>F)L&|6*<+YGk zcLT#Z@nxvb7m^ki>hSG7c*lE!gqt=Ip3JkhSD+*riypX50*-WN79)^TJNj_m-97+U zDz!C`=5wYxp3^*ljAdN}dYie_yH#OpAP=Lb{W^ofw7n_@Lsc?0UM~-4gMl^s&;}cH z5}M1i##z3>M>!KBTX$M2y0_7RIAM~Bj7S=clx+SrjsyQ;gx5ZcNu_^f6LGdynbC+H zc5UgA$NrBumEL=(CAnK7JIxx6RcGfj?5$FL>p=ZCrRBI<=R%g#(5GbcJw0*tILBm1 z?lpAAV&KBTr2NPjlRL|(mpggZA+xh;;i{T`mMR_4h%6fKK4oO^R7$gn;J`zcDjr%i zIjSc2%0iS!EWqlBsqAfPN+$%FN86gn;fUIppWF&eg%~O5H?0OA3%9^ zqK49H2zRur=^ZIg;%`f^A|#@o1yn7{tqroR?eE(O(MjMhdUW>WHY0JP;CL#0+8L*J zy@hhaGQB8Y`x5-tQF|9qa|Qzu?k{HV??r>iE>11MJ-lnBvb9-TctNV_wEYQoVWz-? z_)DhfB+mg}GU$a4!~?gK+364(aswO;?l)Y}P44ZpNsM1PkF(1+jG~mv9j?`PnzDcAOO7C|=xLFhr_CO+NJa5=MNcJme_9ZFURfMXsqdF1ki+gfWAW|`4QaEsf$|UL5 z-9DXV6Y5XZqsvZyI1kRy*@qt09!AQ|=1%RLUbW^3x#UP$K-X5p7yjRI!BAVB;GO(E z$)7w2mv3^x_jHM8Qt{OkWUp)zpMzgTkHiyH(VtK|TZtHqQ7zJ0BMDXQW|)_y4WItf z#V6iS!>r^?Yw2sgNb_smn{`572y{cN5^McyrX7DMa0*g6m`7Tt_IhIFjm%-QjI=%; zL926yKZs}+-T8f&T$Y+a*x4GKP&d=drx_lsEueM8tg2(mF3t1$#W00xnoYp)y8TaL zGuKA3tW4_sRj@@THBeko6hD)Y)OEGi0Vx zNKL1Mpr3I=DPoB~5)JyX061n4atTS(Nm8~NxsG@0?@I33*?IW4W@8@|sJDymS*KF$ zVQ}}=d0=lE2dq3Qy96v zL3pnbreARXTCWhS%EA8w<1_qyqW&N26=h{1p?~R*RJZ>jApP1VCMK|b6{o-}k*Bm2 zf{MXgR;@6{$}c1+fv*Tz=_F2@UZ|h6W>vq4mgDUCJ&cAkf}!VgU*IZ5ndoVA9+wAnzac0R0A+>NFCT_Xg;uMtsQq?!^}Qyf!vOA46@GrZFY#5YpQ;oh}rM)Pw-Q>j&_ElMISA z(;J)zS72oLsUezARkSQiTNsSSO+H!=?WVIrY3w$=GWts<8u{H!MRe4ZNS5amomfFz zqEe1cEMlO7XD>r-;}lE{!zDu&Oa&0-McIs78#{?>vOARt<+zPbmKOk)=hj^_@j6SB zKt33Y3yK$+nRFA%<4ZHu#f}}$oJF?jC|Q=+67Cmqjt!|mItB~Psw!M<4JXL=NAn_+ z3o|Ut_{r+}{;tzlg~fEq$B8n{xW|A^F@}yX5$Q6D_`wPAM2TFbq|h;ruoj*+eK}~en{@B ze6&&I-wkJ@3<0uVGmKtjD!t4}J{JSkEZ)s6!##LezA&#grF5dp|E^xe;P$)%9+wJ0+QJ#9wL`>vs=1+Z~k;tLi2b`xJnF-`N``uO3Fs z5z*6Z@8CmkRu`;@Gul`zi-(TS#FkmrnWb_P&}gKm9yeAhG*4>H;8-#RG7c^_<6+|@emTDKkr98B42_$Q9|9>)G9dqxmyI_N{V<%{76fWux?NKx*omE4?FN^vtTemA7z$U zqku)ey*CTpxXGp=Qb=u^Ukarr7T0cbd2CZx#Cz2m%YHE^>&)RWjHiE&G*&6!$nyn( zlY{X}B4Q}+ifX>2YFBKvR#W7;`)`cd`Toym_+g*s!=IfEB5`$+F&iTs@8MEw{V4C! zd>Fm?{$ccYRFp3;Zg*U~!+0-1ad#x2Lu~HRw|8g-@7KI_@c`S)&a~c%!ho zgBoQYrx%CluA>NdQwMoIO%O|F_nk)F_jv!Bv7#EWPME(ns_Nfai}gQsSVDHTPIlHN z|2)tnR`PIiHn9>mkvH9$wqEb9(nZ3?NYT|W$xz%Iy-_3eF4Oaq){?x z5@}R=^c759r$bwc^R?sV>s<&l!#s#?G6)i%Ki-79?J7%AKlTOis zm?3Z%W~sd&CY5`>0SX)o_kaa(C-7GmXI{H!Y>W?32Xy%Mm!Bmrj@ne(Qqitn|`R!HIhJlz6SytI$dv zxN7?_^w7mkE;{q{Z|D@KQu#P1OR=Miu)L091 zN>&&2HN|^nF@cj!&J%h%8HG#}6fS73uP&_VWG3iMCfLw^ee~$b5QlYcaaF_gn9A5= z*BFHG)_pxRI}p@5OS6VrY|K z5m6*=YeptaBMoy7IYsdBDV847lun%|luXbZL=;(HYCfiFRfkTHo9)b}@qKrRS}37m zY)5lRW5D{exGPMS9q{x&06qV>xnKb+v10xIk3%^Z=YNeu8M|-!bm(qOPCH8|>H@0x zB4R%O#$0FfF^J$C1hEu?2-HLg+2}TLEjHH!I3C|GSb>8+NMaCi`yY^>(1t4xTT7IJ zFZE1s7dd9GD^F#+cDn)toUY2!`wz^udzFzW+DZ;MY{IH2la+y)fmzTYU9DDO&*;S$ zmQez=Uf|gVr3PK^4oh}UUlr@F;vB1Y)Qc7wJv2`dCT@DHE5$gDznSw3LX z_BuDKI7|@i7_FGOyUWu77Ju4r+_!Utx^FrHPVc~je!9W6_a+K#8H{PgqRA(Dk46OI z4xjemMEbb+sbQylUm?A9L0=4_q2dLzBA`?=ksH%P8zcZ^!=k}VVBO9E%j&9Gx<^{? z2{fkZli9|HbKa(w>7kYSLP4=Ipl!^^!@g33*eAn^h?9+hHlfpBIWeA*xSiMM#W1l) z2kNX(3km3^M#~J_wY)$P9fk1*Jq%BL_cqUG2a#lB&?OC$MqyigI~@;o81eyvyGia) z`UkG&JR)5-k_JV)=T4G8TioNu4+N>bv&oGu z3>attInJuOL~Oyy*B=@5dZh4@k@;%kumSCI3hreP3Rr?Oj6I6WZRrj44(V66GQsV@gLhLRTY6Vi0PMSRW;RE;( z>$*JV;ksT~1zuJW*tCNSDAPmFzgcI&O!8mL_8EAp5fNBc{^eQOKWz>saR%PiK4Q{0+QGi{Mrd z(k((GpVz(dlO!hFW3jy1CQW5W!qUx>B8&ofq8O;h*@wi^UjHg!Q+ey8I3Tqhv`_cr zjoOQeveh~yc3J;MUoplWZZS1(m=Ue_ik%jP?m%ZHX*PM%mb0Ek1w@}h_-F+(8fgq< zFuJUw*mCG^I7t3~vcNx}_UH*7}KZV|t-Y@szt>fD2;i$bw9hpR2ckg%14_VjT;6AjjZE4MmM^3uz- zAM12TVX-%D?s0$~l8A1kJS|8eOK1OE(6yby&0cCj1~0Wy@S;u9!{l*-AA|8=Nv?0? zn1XPSx(0({=D$EoAqg}Ya5dR!ln~{Z(CN9t9!)yF_4W6ZIBN9fr~-#6FIxz9|$H0;KmCk)Q>8P0top9Rjbb)>IEe&O}-YY z!a<2G)=x|;epc(VHa;){wwPc`S)Y(L=cnbub{*JJTMOBesM&(k63AM($4hF6ubyTg zhNd&1_!zs!a205EQ$d`M8P2F2)7V;88wJy??+LPBfWLn=xpCn<9ZkO0UmGY_|NI4) zMn)ehhr-<_1RA#{-PCt6$xobJ{R?tJJ>sk?iu~H-22#nr6~$SFGu!`ZL+~!21FZY! z#_&g=Z6_1Qr0Y=fO(dE#%WTWdX*|8NJbw;VIZKP%R+E&(WuCQCy2pNdMRQIO-2BF$ zE>6t3N&=>?R+7eCInnXNKHZMq*${)!9Kt`3B|ypM%k4o*`$sAGuxj`NKDa}c$L|LV zLkd!e4UWIDd9*0-t`qlutE!&knG3`HW%vPEH%}?($0M#oSDCX>0~@H5BG@Z z=_7QGu?mV9V`5gRH{ShXHAH`8=nQIy54xS%mk~5*ek8~gV}NnKt}!TwK}A>&jSROC z8KUCwgv4pr9(F^_Nhj2)-2;(;nZ5Nd zBTpX#H}N>G%Ka4;*;$b#+zX&K`R$$T0$dO4q$5sYg=St+c$K%4`I@7X;wynrm!j|# za%9aZnR`?+*I30ntn?%Fup~!SHwQv>sh}IB64;#dE#2~q16B#?&!LoMWnK8z>Jsqo z9%|39j<;G#0xqv0S?}27FcgR?&;i4QL!)Z!EyXAt^97%(0R@3-uxR$Rm-{l_3B<>k zk^|KHquj8?*w?>Nry;rLwSIncDJn7kmo`~kSw{MQw#g}Kklx747+<~XGOmf#tCI4< z_UfQQu&4xv5~<1c62$ey3>xA3G&$C$a9dZkTu6e&nwy$&o?3ECiYUWff$(>NHK?~m zEnzD6J-1D*t%ALFPh+I(BAL5%b~|si&)c_~WKUa7NT|vY3x?E#uOfH*K)STe`-O(; z4h(p{gOenTw8yt5jI?G`C;;v8Uk)^bo;x}uhnAnZ-@;mvHUC|dMMoN;+9U@aJXX|0 zuq|?lwSm4a^mdgIRt#Y24xJI$&mEm;FMGPE z?l`yS$+hu4aAWSV-7w>KfssK*-2Fv7lPgNnZakA?yrlc~Xfk7NibDzvxk-1?ktW96 zqG?K-* z)3|SgwSy3kMr)$dQ%SjF!cIZxlg&i84yE&yoY6@r4{U`LY}i;JYa zdx|qlOo((w5RddjjlI{SwQX@^kdaA+qA+_t**8o7#@t~#s#s;y5r6ywZV-;MguvEe zT|nf)b@edn$Ct3u780~{+A$=8BU9m{&I=cK3-94K(s;|C>5PAnUi`4szI+Nn%-rB{ zH)W&|_(?(p%g&poTVlywE0V#mGRjc3%E1W4H0cPJx9#wkx5cR1OJ>BUgo0xigwZJ5S<}9r>pRviR5E;vq3WzR z*>(}SseHC^5z(*1k{@E(LvMKRtD(17YeC(tmBIwU!cQH*$%&DCs1YP5TyR-TW;*~5 zr)(EigN9#K5Rz{8m7~ZD;+LG2vK0?pAEKZmU;WMhHsL{ zH_-j+g?Y$`!-YenSFQ|DKE|c!HfToa=H96f6ncz*)JGcd#y->Ym0O);M-_nYnM*hUp0l zV4+ph)7zcu;b7|M^SL&qR8@)?b+$2WGdPhd$O;&TDUrts+jf@5NsFcG=9#m>EJ0uD zIpLZHJY91Bs_!gQRe_{Fi*$KbqXa|CX`E?h&3_6e`e1>2z7#K!rBprFB*Y$b1bZbs zj#L7%jEQfomHLy1E4Ovz#r(2RMSv35u!cmy3N>+s+v4X0SYI^V?wfw=t!Y5k=(8G zs`{F=U&rZP4G?F@9hidc+p)Vvo*C3_x+#O>yGMA^)Dp@X9PY<3ivo zXi6TaIs=j}&&#){wbiuPV`LCW@H!pHw$x+Sfb@ZQjxQ0JI1ZfqZ#4{_2D|y#d zSA#d^f@&?O-)e+ubqoW*h-Ar(lP!4CLs_^aMh_|kTG;1fL!mCz{zMp9OKO}CB7b31 zg}z_vb|Drhv@>`mPUIqQSPOQ|_Xi9hk`h-aBD%XFY7F+SAkHZ@YM)?`lkY-p+F&Sz zklwvei$F0(qMzXuh!4XrCPspUlckF#(D-nkL0+$yI*bToI0`7$*iEe@J zo6#Gw87-$l=kaHVZD=NL14b9KB1>Y&KGzvm#jXcFZ26h&YRbSx3T;+}-WR}SKeu3A z7!h24Bn690*~8d9PBpD;s3>_uphfTTL#ehH+3ciTsP%@V#`>!| zjOB0F4mJrU+xjC{MGWBHVqOo<(miPD(RK3?j-{lTk{M52*+EeDUuXxU+QHN9=(Br> z0Dq}_R@%X`c5Mi40#T#x^x&!?W^J0-5thQASVNB5RLgFAW%72Ve`VWfHgY2K6#nFqe}wrNSx+$)Hsu@*B9Y9+`f z6p0n9VLk={(mgyFl&y_kIQA-Qr=^Z(qB8Q(l+w^12Lb7z9t?jx7=Aq(a(ghqcre5` zccRHO^O^pL!k+ekd^AEm9gcR7WlSgWVAuhqmv}JHbZp)pK?_*vuCxNuwRIS)=tLMI zR?sYLyR7DAQ9#^;Vr@$Rx5 zTug1*QYNEC^Mwc@&R1UuT4HbFQDo^pr(BKha2fzK+e#C-Kdb!?)(V)DxLWtBwcJgZ0CxBn&!>U8rLp8fgF zjs9jK{zpiHtgsNVu!Vt{t(}vzh0*uG#@WREpAHL(|K+fdl!dfvv4{xOtPK==pk4l5 zQ3QZ%6A*+v$SX&T#&kL0bX<5apuQ)%0oVY${{< z^X2s##A8cnG&rIKic+1;e%YA1OM7wN#m3frk=}l?&t_o29x-&*I1xe*QS~p;y(D{q zd{0x>NWeoI#K?Z0^SMBN;BN#24=(tg$VBG5E%A~E7s>iuN)jVBWC=o~0U@v4D!kzy zqLBfvcvf&%f zww8Hqz_W~~4a(J%rwdd2&!K=NB73;$qgZ(>ZmvRLRnp? z*3Hn(kXWZk0_7hhzP#uXaRq>yFuI6)^-3SX=V&$SX#pl4?xoJ_PckjpA`HRu%|{n) z1wJVb%y&QO9~`{gjK3>Qb6=|TtH*Pk~=^IcCNI&LU3uW!eCxkU@!P=+Za zTSkyY!-6O##K?O@G}KUgjo;DMY72&jZsqfz%jdwA&xu&ik!}{vmN<6P|MZDen@W0S zpiUG@MIXEC&8*etkL(<2gR(V%Jfi*UHlwL92DT4+CS^Pi&$?54oepSn8X-R}5;)i@2+ae1t6mw96KM{L9Uad0^Eva4)d-k$O zTGEkH>J|!atQRvHF`1TT+$a5M;{5!1afa4w@!o9)H`!Rt^z+GQ<_$3W=yh|e;rq3_ z`;JQMY$zgt-XQ7RFE1a~1jT7T6V@&$D=0vd=qMrKs>$mk8US7jmmyhRPfSLYGW&K{ zy){(47eYzBSE$Wgkx{AC|CnYOQyBi=ABL2aW|Ag%Ro4%95I|UTu>lUMeM_qhRQsD^QzyU7koZN> z`cSm3tT-@Gzc^*(Fd55YyjR$Ht05RpRb27ZYklfUAp;M#+%%szEBD5(SefOCOBJ0} zrso1?Tk{!5KuwK}$j>$D36DYtoubWLXB*{55KG45^no*jF%sP|XT^$Uh<%(yR=nclhS5?RiOKYbUm$T>} zhRYX{)`M*=QxhbitmzyL^*{JG7+*N__?t*b|CFaNdYsLmqghO+$d+_ST>j;dP#6F1 zTbfQ8>m%38`K{K2Z?~5OnfE!%=;p4QNu&CPNPbI;X05V?s*OdjIwQ)b%-0}X2PP4? zUB)+G%OSIW3eC4KvQM~ET8aKC3cZ5h`#4MNqvQ>+MFGEykGwr#K?!P~3MH>diIgi) z8-9jYx%Z*2Y!6&jdH-Qo&K@fg;PZ@D7RlxyI!sJRi913B)KW68dXKvEv>!%UD|u&y z2xx8Yq4Xt&^NY?aS09jDUn`;DOw7qjdR)dfXlkBIL*+8i1enm8w5qd8PD-Hg4bG~( z16fn8R-~$S^v*1_xKzB5gnGZEMCu&|L&2n}NRPMY^<(@TE2gPRPrX8LcG8}J=GyGk zR%IP>vOb|6JQ)*vTuh6rbH<0#>8@*Ef9M3?WNljGwT^P=GUIt-PbEYJ(K)A{=2HcG z_NBqd2oT=TtRH;@!E&U&~2i@A*G zY;r1kgvimGGT{V*yS9YMz>~W&EzO>od5ZUot!ma-!fWEi@!MBPYmt|c@2m?S}u|D zA<{k>ub}z8qAMU0PJZ$asy0Wv-Cz@Sst3Mx{g0!`Ym>m9z#4ay6n4e>T{#FyymruA z`#12rHl)6`8*zBs+9>Th`odL(=}q%#3bvecBA{?~d3(#b2y%0xontAN4j%B{-xVM( z8JAEBcJQa$giHKC|B&Ol$;Z)yMQBRl0l)G`XmYgNSny8p$$tqg?Zt^yRMG6g7>@O0 zIRUI44{C`r9YKF4R&L7gin#Cw4S#+{T;@f5pfMlRiG1GlA;Esq6T*J_2kAAXg08v< zg4d?;f5u$yW(4}tgMLv5Ry%5|9(AXMA*WTGliacn_WpW?8h1W&W0ODRW%_`%d|%yz z+17BlpI>f@+&Ir#W0cOo4lK&KHK@`@;mY)0t)ksyi_EQiA0w=j@CG(=>;^nJTDY3NuaIqor*f z26r@vyg8u_i`yE&eIRdilho{J>l_eNDS`wuvKYyhfg!feoSn9?KK*O=a)&3mBSgfs zPEA>_{DM3i3#Q7_3jI;{GkWj&1@eG z_SalLzdFDo+aCHoiY?|!ItGlepbMf#Fvk{+ZJx6c3QlSVb^j`6A~E#nM<}PGd7kEg z&=y5hxgMGxmj%SJ57xMl%bhfCwVW-R8Jc0VtZW}$uAsd1!aT(l;%I}ObdgeaU(o@v z=kTJtcJ=_$0rN=kdu0B4KlX__NCOhtJu`xvgP`2H$t4NjELKs-;u8{Zk{+%2c5>qW zB#>puTm59m_ql7@`A&rvM2$5-Y8VLF0do0(<6;K?;!IXi&2n|K;xJ@uYz$a!ACASg zM`;)<`dMZvvQ3_Br}eOW*2-wb*RGu+?RgfidrxodzRnZ{hg$TMt2`d5_a@))S9&pO z-idY5qx&51ey=?AossRfPI|~^&o0!=-dWaer zeH#&Z{P!2HC?hw(kDMJMSW<{Tkv25sj=;PYv?EW4j+g`nhmII0r88-0A)&$iNyU?3 ze(=40!_fQH51j74?qTO<>dI=@+q27uAclhi40&}nh813rUsPUHTr?HWotCSd27PZ? zGnvow;ng4CP)xRwWFQC91~^@ioq4diarM9-^zEsr=)q=MqUN)g<~?xLORv4nhMA(e z?<1?VbR@y%bGLBNLSROJ5c(wFI9Pwc5d&G>QFoXnt@2#Pyd$&i+;W>kg<#8SGDV z=T3C`3Zd=2xYxN7Dyo=|{*j3}P`^}C&Pie%98pBErsZrsXDQr_I6k3XM#)2jU<=P^ zO~}O7p09`CsDu~3jU$KPr;|=hG_PwcpPq06W{@(h>g+~)VE6C)(x8fYW}a{L$m@6A z^&d5F!WK^U2F^z2|4*Z@Y@>vvhU{yL*hp**TA?^!h>R?RC{9zTS`Hs3wT@i6SOy!G_zfzgJ#BxAheG?#~N*5jt* z`I*o66~+KMA5n}f)Q~;wk~&mlD}0~Sw!t;3*LUimH86qQ5Z!Wwye_Z)9@fgJI%YIs zSQy)lVcbwsAeQD?eJhSA4xG9a1sQn?B3M-l$Om+j#*A5Pk&4l1I*l^1zV!ucIEM`s?~Dhz0*iB6Ls*R_;LlC zFHRjb{JizpB9ufY;ASLx{i3u4uebQNjvEIZ6sWcp%O?ZCW9=dvdE*^tXQVgLT#KUdk@i|%~WA9F-v=q zwK=*%<5>DLJf_0V<=j2g#-V&GK9y{4Q@!v4JtI(u7E9G5GUvtoN*NfxfEn7n;h{enF(%y?Fj1#1i0C@hL*HV#sX4G1;Dfm>X4@ zd!#UujGA{aG0+4h&q$;njk4!RQ;&ee{{Dqj#T#az6-q}yAw*b0B;$}4Td0zMQ(+|} zl8Pm>AZj#^4n|$YGbvNME#gbuFaxeAL>f+K&=tlmDaM0Ul!Z?iKZpE1DLUa3OsNlU zzAm|ht*Qp;*$gqp_Gs>EJwUc+8F;tJj!KZ6HqW>mvYMi%QSH8r>WfYHM0K@Twh5`l zdY0V5OO7Sz$smxzJ_JA4xHP#;lSPe5ruWD8!qgYwVo9IhtiLsfJu zO~rNz(`LNJB6qYXTX$H_4?>80W}!WwJG!C6t2*Yho{*7j$BSHOmSEvAJQ2I7?ogf~ z0#+Kq>=|O+2QTM>NaCufNXp({z?cGfl=qQg3cyS47tuWD#9USZfUdsQ3ZH)Xbg1W3 zf>>#qh3kJog5eMatV zl696oHe_21C0(w>*D-8Nn?YJd=U_T+_->!vL}kFE80p}bs%PvF;pgv{e9ys8PcdWV zIm=_$dwP9yT6fDAFNhNdO|3uOXOrx*HE&>2Z_7UzDsa&S#%h4o9`?pb$yo_~zKsuk zUMph&3)S4x0$wI)^{t$ojMOIw1V|G!Ia2oN>0k7bN(inkwztPtlLI4fLftai@|$> zE~%ETc$07z;hrgjF9dcd{zN2)4N@5|NVqGS<#$3VedN3(ZN2|9Ct7?y(s~hl^*hqYzm-9R|0&Y`S%OHJ{CD{gqO2u{B!K)` z+GewwBGut8RIZ+nb`C_S+W!kx-l!%59?@GX)ugNV>cF)s{>AGq1e|WGFye1<1mA?a zX={KYz3XDew$se_mFsRs#;#wFw-EfGJK-T%D9I6VIin~&Ws--qD3H0uIzs@cjh4o_vZ>?p7}iQJdV z`1=y2MpK5fHe-pkokPQ6>f1q1;1PP!p)D6f3;G&H929pp;H1sE&e}b720o+Fda`Ir zr(%&~F>0uMuUdX!rO*VcWaDq+KCSsAO8@+P%S7Rc=6jbdw1-L6#GDqfYUQjXO7#+$ zsxSeiCBj(0a%N-%dYzSK$;Qy(@Iz*SSJJs!@Re-WiG<08uI3e0KfS#wf*Cpd8aByC zCJxDHmXqbv#8s*7_wz`;jSSxwPzO-IJcRI&-$8wI@k80{QOElXBO?i)o;hQCit7=`r9XCN0*Qv4t^FJ zKXLp zMW~MWI-Yrf1zrtT|DpGGFkENgfHT@WN-#lZ5GnnNyy$0nG;ph#lz`>TnwYfN%?W*uBt87yT^dSHi3o z;?VMYRs8WM3|_S0XqfSXfdwz&qE*SOdGg{V$n9Tp+rClbzxU|80dgaE6kFx{q~~_2 z$8uu#7+Z*gX7?TRwkavIlM`r1ztKuMI0Vz_Lhg^zWA~^SUn|33G?Cl(pU`_^?ZlnJ zLb;9~6fAC_4sXbB`qQzo(^9fnu%irlVxwe{7(3Y_-|Txs?LzPUL%~_Ni}$sl8j20D zK16q}xZ1v*rZ4>&44aLktt(4bTNl=qs{(KE#4WGifrkFQS2Iz!N_rQn$G_xHdw=rmYv6$(tAKN1&=OO?AiM z%CtHiE08~yI0UOSMY5orh8XUWR~>RC%cQfUevVpu>I6!HN;1J^MFh%VSz(&qMA=4q zxhUPAZ?7(Uup7X7AyA%TZUzf8B)5f?PX+evOQ3i#Ug#B(osu$k0M-%m`vyW2vEgA( z=63exJ40ET?n(v%NQA%{L*Dhf#A4}j7S1`(vaU#o7CJX}2nu2q>TqU1uzQo4f9x&p3uxpJz-_?gAapDTp#YQh2fjON5@^gQ^MgJ%pXYfCg@VV(x7^(-kvsv z^Q+x-){f;x_!AtPXCyyLcPG{OP04Un?VgLUUJ-c1&dduC&>u#~WI=q-|Agy<-5kTDa1dr@$>^Dy z5=m;zNj{%K4J}UZ;Luib3_^v*e7(swaW%zG3183=3|nnt)PjL6d&E%;!Jywxu4dmH zBV{Ulr>@g7+mpYvj+ozVd3SxaBBPK ze0DQ6p}yotguo6FLb&Vwp#qOn3Q1qOSRUt5@lQOy#riEozVTBM5?*KkGkhHN7#CgD_sCG!17D&v`8V#*7>{`)=!C|y z)Iw{u`4Cm=Q}E*q`L$?z!3XpoS8bjjtaYbYd%taVvSS(cqJOG@`p^@$`$LP)Nm_qEjI2c0AGt27lyk}@bw*pt_C(#9#f1Pg> zfKm+DHrWfU>xkX)#Lx_JrMzjt8qhs3nIcu%p|I>(RJy=U`EhB*Ae{@cx&`5$+@W-Z zhZvuv$V)37upgf$^|2pCu4;?1({tfC0OQr3CKwHLb5ya9$)#(uA zVxs;FqLM8v6Hm0*11L&-XfEgme}_4i4clc7Rq-_>_dO|STF7veb6#`@y}=jERyr>M{JLod{PO(kN1gdX8p{n2f>b1=|!iX2`!$>WQ#AR z-}Bd3w$9PFD3?Kt_cAw%l^xf>KNhv)M7WP-0xcg~ogs7=G1m&#Jy^>PJBqAcc%PIL z;Caq2Ysx=JCXZ#NH=_sYx8XpI1mtK&iQW=xg(n0ZXT;mffO-JQd@%kaZp8yr8l&I{ zc$n!xvo<0(E0`1LgC13qEx>bL)NOPUuh0U|WH(y-8@B3!$LFMiO7^V3k)=sdAoCb38?;IDF9k%yB~NYQJ88Xf`!2YqbI+jftL zw1()89UbAuu0n{P{b`jG@BE7XPekc3 z#+^#XGnJXg+Hn(SeyT)zoI{!2m!G>Yi|doRphQi!k%kJ8X_-Osl~5oZ1K{Ef_3b}o zaQQXPp3Xs3SOT(4KBt+PR=Pdrh=woRi zB~?qzbrh}|T$C++_!A`c5+sdzL>x;RCZZZx;jIp-)dz7`3KrBg8CFaUTV?`HJk&kb zm~j1vAAWRD$98ZqtYV?^{J5Z&T#NOnjM+EOJN`+2=YlLjL?Wc1fE}4bBIIB(K6yNx zHcR30YCk@yd4JqZLKkO8cBM0sHRwu$4m`g&74$OY)@SyZ@-{C9Ga-;}DG()Zrn z_nXbf^q(3T0VfYzqkmRw-&=GiBLhccB^MhTgMSWIQya!<3pZaxlgPkZshM3`C1U+l5VHeWqL?>hYp;GVJXea~Vj<%XVYd1fDqqwAIw)!K5NR3Z;& zGudkdDR=WGO0x4r7#hJs*GRM9?73Y_g3EZ;g1=XIp`|c1Zf82KRumS{-Ptt>92WIj zbl(V(o0{E(9k!oN(~k1!`)xrXRks|j&E{BggL9c{@>g{)vqn8WPg|4f3Np*iUBX1H zS(#XS)Ixhvp-+pG^u9HguD;q(WHe3PMEz#+IQHKBykY)W!MKB)F&mfdU~cW=wI|_> zjnzv_OB-ER|BWZCybe8%mfMv5RZ-E&DQr`DsUodZ6W%H9SH(URj!Jcf`f5W!9mdS3 z-8M8Dq>=>YqJiK2GhWMbR4ZBJ~Q6WjL0wmq?J>x-=~wkNie zxjFTpbMF2BgSuVaU0q#!ckimMu3GzDYd^1#&!@({`@4OQw!Ym;76QSFvg&PY9A3HX zel{&Ge6)kB?b2-_enI!-0Wa{HZ3>>Ra!4|qIrnxG)quJ?gEe-)_qkXlR|Xl5R^Tr^Msvyi4cpp<`T-tBn<96Y`T9;A z46s$T)>HBbBj1F8bw07NdVdPX3EHsTrW@KVbgp9E6t~ZfovJl!B<=ML(r%_}k2~TV zuSa;pNJ4Ime(2BBUUIrl)`ve}MbcS?*L=-3l+e3kUP#s5H|S($M>Nhtl%R_b3_n3v z1<{|-M%G;9>cOTGK3#FcJe(kDK9dK{P`#|cQ2%U?q+l=6(4KfuZUp7|WAHqM|O zrd)?H_x6*&V=P{9O*QNwvCJT0pFqV}uxwa#D~ii5$r#x_Sd`~(g5D7nPG1^z1C>=k zb!>=6&!Fb`LJum;jQ`*!MCls(aK8e6#!xOc2(e6l@sb;tFd1WBo5Y1MH|EJ2&m@aW z%r6Ggc_Oj>S4kcEj8BvOTWIL|o>?*d|N2M&v%sz)FNbb{?ceKQ;qhbvF23AJjgH}_ z?V&Ah<0gKIsjP`rFY;Ma1GoYS228n|W6rOaTJd|^2Za-Q?=29@g``meODRh$!YSpg zz0V4uuH~~lD;A!!L;GP-dVH^+d;ST{@^$qI{@Ww;mD+1!#&u*4!A6WcsOR2Bk>m{W zn8z7JafL}OLctd;i#Z6&MT)1D&M$8d(R&<49=e)>x^=53qb#%MmEVIF@l&LR?>33E z`^}ObjA{9?60d~{d6%AZi}8x5FkMHdS(1U0M9^lD)~PPVCU@h+>5st+UarY0eQ`lSs#2M`_tky=5UT!<32tI`m^c;(>^alE~D7j0AN zhGrdG=a<)Avn5=f50pgnk4vkqALp)X>~s-T6(jrwL${?03F8baJ+Fp-n(U%33_mpU z4YlGl$S12R6%aMl?GS=5bhI}#D%L$ejK7AP5t|tSWMw9m%9xJ7h#d4oRum?gr3!xJ zy&b*$P<6>S*U~iWhQ4rb)gb$M%SXR^guF|Ye z?e3m9et`=sO>!G+*7Lj3S!TvwsC(TriqH_u@|vW5%vuXYI&C%U4U|nn4*muH=gX)v zc%-XR={ukN`%8Z-9aht~?$L{Q(Rk!kGsFmtd?~U9B4T0RJ7syfs2L!}^S8y2E_dVf zk*DWV3=efDkiuOqkSa;_hQfFOy;#f|_KPoX+Pxq+pj~7ipX5puAzf+qGvXFxpL|F4 zHbjFQ^qP{@Xj}epuqS(LvTs!Z9aS z#^)2GV30Xj9X|6XJ##Q_7z{gk(O0%V<#r3akkKRi@`L=$mp+X4s8WO8xjuFJ+fuM} z2%Gbnuw3sS-w5}ef|0|XxGclJUH6V$&Ftipv2yPw&DoILNIcdu-X z*I$GVaweYy*7gkk17y})WFN=#-!8j~k%Gg&36JQzE*$yIM4iZ>9K`y>{jLPqlUib(6p?JPj_P6>kNo@zZy-16`LRa^}o?}P{ z9{%9*URYoIlD8p50HF_Vb1$s>`(*ktAFYs+%)u^gg6l^^CtTsp!h*7fWDr*{s(QFf zHF>b!0sBtrmt^AlaC^Z8->|m&bXsMpXS)lud?T9^;^8&i3(2tlL8ty;Gbne@x#MP# zvV?#a2e&9v&X51X@z81dod6F90wRR4n7Lm z8Cg6ZRt7=3-x9TE4_4!Ef?QH;cCMSdXvBI{ehZ<%%}AG4tX+)=N1zl2g+`T~9nibE z#ahv(r6s(_7USQ}lz9^#XTZl8U*B`@KaajO3nA}Amf}L4k{6};8r<4Pl5gs%QusN$ z-nD2JUx#oO-gkvkRyK$2J;~x$mw1*g$7boCJCURJ~AS<<1%_+A>*OHt(T?kLntHVwAGPdyzccQNEq;x!f?&O$x}Shz^~YmY$2 z>Ln)iY`X8`sRl3+oEkRB0f116y4*oaqpQ(sxU+;Voxz6NN8jdP9TEaqo}g|40YD+c);0rwn^FVG zM(;j<=jA)v-Yg|F307Xjx`ndN`q&#YzPoh1w&xUq<#Bq~OR#&ktokRSN&;m5fF0%1 zcGrwWVU1{^G<2K3uK3FdMzV;wvJ@s_UJq!tAw#*sJqI&4aiH$EVU0OeSUti{X5Tr& zW)9NlpzE|-JSA=+tY43f*n#DQY|<=|H>C?3~`(|saCmJ(k3YV z`3yCk*1P>!+9QHJ3GAk*pQ!(2jc4>G-SRi4=2Hq=zxi43CkGNV#?H$-QVLsgB&`sG z0v9utzb2$0_({B!(hm$9tR`;@6aC7ftg4D`}I(N^OnsLxeIJxaHo_-(BZL=ueEv!|JmUL z$d3d7sV3^D4QzrlskPl*S=_6cGeI7ba&E+Y^X^&{Vq78NB@{59(?^Dz%DU&*5cry^ zYlrkFMnaNkEQ}k{TZI>*s^)Ihe^mi3+Oj7<6jmub=k-74&-u54%oQ$N3E;p=fgPIx2WU7F0Kzo9<#N+IQs=!;z5uh@Uk$Z=nE60bi!nSR-ePsA8%vyPa3ZaqXb`U8jx zyeD`Wy66||(qhvC8Y9$~$3qCO@~ZZJ^M1u6x!L~g3yXKXC`*v@kD3>-lKb2KQ)~lT z$7_Lc!m#l3`igR8U zP*dlknwJfy$1gaOeSUscjSOcxA7bn9%qtpdGMTIfmp;kOAwHwPp4a_{mzUD?+HyF# zGl9=36%s}V<@X85B&cfCZ~pFx?w;9Jnkg+x*(L7_ilfB-1A&I7+9`Rb*^p}RbW*7+ zzBfT+(?*$G+@wx7W7Io9cmFv*6m?M9=$&epr2N^U*z~`<&3e1&0jh+_?vAFRKc|Xm=&W zPB}~%Q`#md!5=0#&dZu&KA5N$e;%j*ZsZ8Ydo&m{e$rbwBnBJ*JBrd*!thC0Xoaf~ zy>ZMKDe!>S5hvtCAn6I3#KFiTd1+4{7x07D#=t-#vw>dIo3Ppl-sIH2xlv4x)gRjk z{UAYiRN2KDLI3-lpAa5>SB7{1{arqhQDh{CH{$Byf2aU;)nSW88f}NfuO^9z!4g|I z+ke6wEnbIu;<7V{YJTdHxhSs}G3kU-J21>0U*@XGTummxZO#z`y9L+~xF~}eYd!W` zP)95(wsuAS%b;Ea^zld%DXJ_@u!b$=?TMz|;qk)pV4^ByTHx2@-i&Jht{dAlU5Z1z zQyl{Sy_3%zoLzMlkw)S9;|yepS+G<43y|s~D2eop(;_!tCRd|9-{(@4p8Ai*6v)CYm<%JrP?r^4Dk6h?FKG>(grTE|n zCzvaoiOdqSVwE_VV5f%W*=fmWs7EghH4a;ml`9M!WOR+`Uijgb_%OHCIAd93dTm`A zUqi>q4xb4hqWgGVy$E|kJ=b9w`9?Qa&Kt+R$pe(je{yiB#~$SP<6VvP=;;n<_Cw|T z4v5d$2EMCvXI*OG2ikbu@unPjPXS`NLEHAlHp5gMp{$*#6af1030+>30?m`eZoi2> z4}>3#pcn^==-1;D7X?*flg_lAeUs2lx@?eTQSXx_qZAFEynbdNyI zocpeH53~(t$Mq-{L2W`YbDB`?K_RPlO&@15`!Y*%W-drgk;--{w({ z`h+#qcbw5oRpJhmp&v2q?TUq_ol!Y1aGnC=4~kLfRj@bznU|PgDjr!jjIu*JYp)GX4TXP5IVkML4DpcrM(js}$3Nd=254YcZVjV3I z$`h)h1-m%`PZ6n9iZaP|#xX(_h-Qza8fk=kX=5jGRZX-_XkE18574k!qC4Pia(IXb z(w%-^@Yc~+-f=fuu{8UZ6XIWvs~0^JA+8@px)aXlF~h9O7V_Au!rQ5%+sT}Xl}GRA zmk#9{;L?eo7ar3oFz?VD*!Qtn3*WZ?2%?dao2X1POefU^?m?>)jaGAy*xnb&^d|ur zLC@fwZA9X%B^sXkkED_kkjEQ^}0!q|!TQ-s`83r)LuA z<=IMw_HkgpaKU~}j7C;%)R7~&?}*)OBnK!CXy!iIXkE2S!GaYdP7?P~t~AKVzhnRB z+6nQ$#zU~*6yIKC5D?n`ot&ZaA7c7X-nx8)CKn#Be*0n8qQ9)@r^1u>b z*EM==>sRE$2IN<0TPYG~h>bH-Hfc;wzR4@wZ-{|fN+m|0C5uYSGHsf%u1=G1y`Lq+ zlh>QiJ5kCP%wu@#lK@+`{Fr^hvGi4s%Ph~e*EP>cUgpPRpXR>+=jws$&vqy>jD$ab zex$zOCb4R<7K?exg}G9&*7uCP?TwaWjegFt>;p2Us7$}_U%%dRE49P=us@W-us+EhN21exJ=elD!C%yg4A4s0 z3jH-QKE~pS4)iDtMnm{}_oycCjbG51wjcHxLLtaTR-ZfvFQSFaY0LFt)i>9yhvLjt zx5hzTVzRejy%+GCp0y)GIIK%C_@9T9ow`&D_}kwCf|kt?<~n(C6|;OA$v(}!`{w`b zD(Ejo;Y5N-@G{Q6%1;xTf( zXDJ_qq_*%CO2#OYB{3(7CJOS&FUA1|N0S|gV5jeOXkQ@zQd-4uvqw8Z8*`(3egR;= z>`YkL%tmX-Gu!?Ng@hf_Cs)@i(tctpi$3=h;_HYPfIm*gOg^}Tdx|$p@F6A-2v)zuda_}&fA3z=8-(+|I z8Vc(8t8|s%1RkZ9fDpxz3vArWuL_``7 zmnV*?^d><1AlbJq7>nGz8InLlEjndW9HtC8S=1=8X;vy_jz2k!Q~9VzZknsyN-g2y z7M|D@nJ>6+WjCs6`9r<&`~OLmAD!|omtFGes$Xzo;{5x>`b7=XyM zy}TB@tqhITfzOFX!*h;r6gkXItU=mnIJcQL zbeXh8_eeJS&_2qXeIky4X$`0Bo{z3>VQ>{8C#H#9W-FSy(r*aXxSI$JI@v@aA}IWZ>p4r_-eg^f6|{pppKAMRjbhrrMYX_U4k zu|vfun2`2l4+37-F;Uf^t(wI6}c-Xi|?x6*+X$;f#uKo-tYL$eRiau>=Vdx#H&ajP-q!3^t^JW z!!3sE3y}f(tNP50bl5gTGc1JkR`|IJ4r?cyM_xp_!%EBCyO%WYQ(Rocqn7qXsh+GS{HrYGJP}nz z?(k!n7w)agRVy&OW=MG-sDm0bZf$twwhYl=PON+jLW>aZ=6t-|<4qBkOP%vH$N7=a zN&cy$g&Ea#EUaG7r0v<61HTb3_7u^d&0_SXS7XBGc&q5BaIwKd_jEk;eF3T2Emrrb z_HqRARoru(+Fe0)Nor*#+Jch{G;?0l!A(<4MRFxe?YyBFXN8@$f@TDrKxfEF9>JLn zwDEGy3O=k$?l+RPj&TOjusFLHHMiA zNV)P@?mFI^()EFV8j!cGGQ0YzgFe>Wv+R_PZvJ zNWS}Omu;`VbqTK3kTz6!da8#A9~$j{4bilgAk0Oe_8VLrSd&$EKZNK2Hr6JSw=>dY z{7!88B;{}D7ogI{v1GoU`eyic_wW&0TI8VIVXJg0=SauxOw74759=h@zUiwD*&8Td zL$wbyuU|L}?E~94SSRqgLw3R(h)Ic-p>RDU^gFsUJ@9CtHw1+;b+3$sG=?3yvuHXKaa>sElnq}z zNNL@I;OENNUeyGf7&T`~*{(2sP7r&j`TvZ|1^+V3*YnK$Xkn|pP8(DRFy7FxcetyWbJ)f_}cO(MlqIfpA=CW|9e z0Ey?djQp=jOe!3VaKLv&k@M{fK=!|jDE@b$#Jdl=CXT-%Ygf}6JPZuDHgWyW=KjoqHR&=nT-CAEE#lb-6f)6ROUsi? zpI8q}N<_c!Zr^973>v%g{gQHAj&rW>{8wD=u72BZiU}+q)ER9ewSnp;9_+y*sq*L8 z^`miPl>(`}UevHpZmlpB@19g?1<}GFxk6^|K3t*y9K7C>_y(R>;NH^b!RA2f82CyKd#L*| z#bEc&0+2l0rvONqPZ$_Nutjinth4ObAKW2ywEn0gelIi*21oKqPgzlaU_vBonmb&a z7p98AhnxbD9q?HxO84V*wFA}tTG`T= zDPt3z*b-YuIdf$$7=qXd2J1;Q=tiYDDY#6i<%qG$OaNkXPLOf%>VW{UN(!0E-MF6BK3( zlZ485C9HsFBKD_dcXsAP)0kC5)&~13yuoO}aVn;3!x=m)DguY#q}1co%pun+&7~se zFyZp5#U)d%!>cmajbJeYS&K8iRp>IE`9xw!QOrf=uL|Klw7m-u)TJtFb+DN@c00^$hJA{8#SjzU&x#{c8%1k6^ z9*a8YjUv*r30hdSSJ+jQeb_srofjAhF6VCOHq~xh!#wJf3+pFmN>o*9PKTU->?53sowlS`B3@yE4Gb(8L} z5Jt6szU$*rsfz+TsEWiII-?35IUU#KvKg~`>RB_}UHCB76U=$zE-%1vQuY!6XM|pU8#_^c~*n?NDo34EvPW5&;`Gy(#T z3z}X(vux`|O3JAeaW25ND36Q8wxdX5^<+{_f$?9Y~@Ux=AQ1?ig*YNH8q)!$TC zA&^l2a)?O`HzS_smz||(EBnA*1^ENf2aXV49ni@~ZD{>W;ao;@rMi{bpYytf8N$1` z1S>{Zv6INf4e4Tb5?~cpr1Q~IQ>+)G_Pq1_%HQlJ_NJ_ORH~|un1Dmzb+ttNEOEI< zYa5MSApcU*G6(d$XJOcKvR0_%T%csh(`6pyFTT3dg~SNg!4>%hPq%;^WhTuFO!3-P z7SIQ2s(AsbM52epU&UypQU4qcAK$XeAwFFZPOX9jg)7-mJFhCJMdGmvMx*Br1Rq|R zkzSdf7YVa577lVJ=tU^tjmG^jX$6k8HJ6I$&R{XzLVfj*aNnF(XH&>r2XkU?`Ee1? zat}k2k|@0%;9t+QjeTn6lueYC$s$iFjdEa!lB2*O9hb2F*Q1wgTbL z%8V&p4&Cl#j89wE&^c+KuI&vShAnNV?VmeFVK53q@)BEVXyy zOKlJf3cHO)#THik|I%QaR7v|)*jVIWUrFAqj`<)Ybt*)Y_K(!#vrEp?McK3I;v3M4 zP1X_sNgI&l21;@TlJbr%K>Ct<*#dE<7By9(8_F$7GvlN%2xM29(={cnwMwTvY|xlJ zAWVdx+S@L8iPEl?g)E)VhMytfME@f$N$9N-Ti(`?=s`+rM#gV@60a3aPzdHHGKzvSDm@?BtQGG< z8hCFEmWPUW+q@bBXAH*}RpY76A23N8Y1M$BDb7_JNjMdCnSsW46X&Va>6;Sdn1pY; zKr80wOgB=VSaJBYg&j_DexSiZ+;)gSe;DQCk*oLkf;Gp0!x&oa4O(^@2fh2Fb*_h5 zSVe|FYp<>K4|b1#k@ftE*pvo!2!>gYfD7h{ii z#Q;j@C-ZCP?BTR1JxnmAA!YW6@P?o8X{kD@4NLgriJ$*v?bDFV$Xe2Oj#3Zv|4<|% zW@KgS^?#98{(HLe!rY@tj+lNA`UDas2|*e;a2Z4y8U{R>UIav#MZukFyx*MbN+Ce& z!sxO@pk}@BsTotbvM?dP)mnFW*&4X4<51Jux?Hrp-J1HPW-A0XP{ZEv83wS6Yq;Z-?>P>*T4&1^+b z$cIbnI*gR_J@iY0$^MQk08HeOfTUeJOV{+h#sL4p1QyZLDVs>usfN96a*AZldo^Ad zetZ*U%{Ls$1M}N!bS3=y)rsrscF%yQmuZXWVD6kDDLeh07)q6FVSQxRP+rR zKlzFP{mG}Acl^sOHDNNq{}?bky6dz_ruR>z)?Xy+m&|=JlH%)4Gtz7X`>f1;PJ+Po zFq~lbDWFa)>07|jW_)iU>KmXF{8*0P*;8lozaF-MHQ4~1^A5@rT%H5)G+Wte%gsag z!^HT_{yNzt6P|PFjlLY1hBdZy*qQhg!F|xgjLX%+IOs8{$_%ubi_5BxR$}Oy>gDgw zCYYM*0kS!{IP+*!?I9R^JlkvhVy7^Y=qq(cc()p3O!Y|S8ufQ7Rz@B?JuV^XtVX)h zX=4<{y<;qYPepKMvXIq23$xq$Y}KJUh1^js84J)Po(L8f9x?y{t7`c=<=yK6YpP7RuS-2F%~$&e6u>tfHO zRpKJYa?fLmGb5arwrpCmdq$SUa`;nu?Pq74qb)LVxN5u`Rg^oV2euL-l05aIak$ps zeE4EbyS8!I#Gb^&;_ViaOJmrQ?W;!RXw+hl?NaSWAX(v~3^X1d6QxBn_=}9$y`lvZ zPTSJrmak87_7>2Z{$flhc%lo>r8b54Ie847Hpz)ZIm+TJ)0SydX&m+qZ={!CZwMI6 zT8Wzp(#I^4eIw{X_AboqZSob-DY|cR9w^zA>3H|Tk_4}s7a-ZlN;!TmM45N+BTGL# zJ?csXFBUeV=ogW5{2=?02(d|1p8Q24mMd+aGzunGFn22Zz2pp68|IpwyJT#62w!)4 zFQ;@&zaf7I)F!@!sshG6Nup9{ByL@%zU+-}@mM`0d$hGeu&I?|eoI~f*8|sSa=B(w z4tp?OjymUo(EXN`cDs!pbrNK`k7WK&47Pl$xkV1NBL`_#7`8XfYi30CS8rL=soi2*U(3Sj{&@BZx|y~|3%?Lkgc}nr$W2q3WKJhAS~352O8GlPzBkr<0m7yNX(J%<3B^7>EoOc zW;KN&;|iDR@>Aggp@O{mX}8+fwoDQobqoeCtQ{X{7o``H-raFV5R<0fnaFWKQJt#7 zQ<}I&JeWg9gZ%(`ydtt$L90%D?w+X&YJtx4_!Bi1B1iKnny=lJQmXzO5(m}|B4$;Y zGV>8$F(~W@1J%JAYRjHLE%{ioe6>j2x{3gHG&Pz}0WEzZ(_%}~hjBqO>Ge2T$lKM% z#Hz@4J=J7rISy@k<&1>U#lPy!odHEb4Tk>pvhgJ`6T|?&7(bqD%8zDlCBuxGy;KkN zOig*7KUhnX~d zVyt`1UqU?QRp8`&y3K1wGqQGLiKx*l>ybYxFSxJf*#hnTdvjQySFwQIx_ z(ybgl{yOqIN;oNMma>%@n^q)nZM{^Bb=D~f%4}92b6zkThf!#_mleHKD;En$#Plmj zcOU&4bY{&=a7E$Zedlq%UZD7!3V&~k1y)!&(h6jl##=tLCL5*2sjeQ=bd4!Rr-&c7 z6wt4co9S9qh?)9nw{}Ns^9WOf(fZ^$X8Lf*!gxy6ElK|Ac;ZerI5cEiy4F}{R2>O( zrjU?{OCTnDZ}poTWzm#8P0Fk>b#&FPw3=PVtBi`4l9ilk193BtxRoxh4kKh{$Le4_ zf-~GD7~wb+XRI_nF9|9`w{4w5oO(9Nq_l@BbCtp^x8``BdM$??r#Os&m3jTAiVJUz zmXk3P&vrfaiKYmh&6U$fsikO!*(Wc}mJ{aaIl%z}ejDEi9?$k6w!`s@?WiZ*s4l^Q z3%B43%l1gPS-_T%(7ibY@h{Az_e(C9rcd*@wjH^9+cK%@la1LXE&cjf7gtc&H85*Y zQKf>P14iv4lDkiM;mX*ZaCr=(H-usFTcqxv;VhJ5xR?2UPC=J)o@?8nTu*nWpBVw! z+#YbWPRJbXXnuOY1)?CX+(%GWCr^ga(n5ugZnL<69D>PVB= zkqBo!+PIN5vN|O>_0{wUeKVedJBpXzunAq}SGJL~H|CoiXSy-fqmJRT*dpUa(ltXZ z$IV)7V9fEEG?`kS5(W>>@u0)3pvVAWi$hjQ>BQFIKq!AIkVG&*AhXH(lBI7~Bz(7% z!y{!h&v&x`FqnhLG?96O4Usn6M`tzYKDk+$Q=R`t}HVw zuZNk%86lm62Y5d0VisSP4O3c{*{@i7WXC}==KWP-9Pt{Q!4i@goH0Bu431RfOEkgO z9JppRk^BNXC5?tZFb?q6mO=@jsu(Xr?qAG^vrr1PXaJctV#ynI?hY{Tma^;?gX@l= zyNP1(Oc-RyzY?0y6Nj5y10}Fe1tYRZ`UyR$Uf7$_*R;6_8=OdX1+L*vh- z6d&xlO71G(r-jl$UnJ8h~nszE7tgGuSwYW!saO-^n(f5$?jk+Uk+Fc z{Pv-eCxVS%j>J@M1S3ghx7bybhK;ntavGUbO=EiHltl{i12XDiKx7Odo zA>vtZKwI7Y#}qRXjeQgNYWrTS{R7uM5y*S(7x3WP@IYhK#}#2kcvj!vQE$lco5}O@ zT4#qUkS1v`@H6R7;r;0t*1WKlqWqI&3Jfxy{qFk|fzMlk&se*=mYV2gGp~kll1Jc+ z`#p|CjFqDDM-vz4;^mxXg)RCBU$Y)6P zs0~ydljT>k2s89oSfiW)jdN-hM1ysr>UF~8t$AjYE%J41e(KeT$#Cq_0wa8YnctS1 zx9!%$Xq5=pVGG3DmgninmN0AY5q61im8Le|A5}i%isy43p7P)H|g7O zP%c*jmoQOfx6*sX#h@RoT1sSwMp!lSHNwTfiYCP8XF%1uyMdp?tZmnFyUi)6uR%?{VotF!O8>nt zJcWjXUo1h#cPY~5Cygh<>IzK*bZ{|QEx@zpbk2g^oqS^4qy2Od1|x50iddSXQ6 zB9d+FZ?8$TZly_qJVzRMQR%1@<{F`>yeqm&>oKJ|AeG<6vzlYNjDf(}X*ORX+r~5h z@oyQR?qPuJv~jp75f98l84%G3kH)r_Fwk%2$uG-Jbl^3R=7h=|TC-N$GiFV$#IT0~ z!P`7#M5k-1Fy`xiXBR&{VdEp{gQv8&&{6Z5>o`X!v-Y>2arI<<0?VZ4|HzMnfV6?( zaD9K>|G6Q3U&)KB2{TA5NHEzMxtrPl&uQQP+8E=1ZEWjc!EXJ3>4Nuv>hhmELW6LA zoAOj5LQH3UkH}U0KcENyWnll&iw0-O zKo|V3+gu`?NvrIRa41p|7|vf%2}wYOulLIz#4v&n^%qmc=~g-@{elfz7mNWq?7@eHV#7d>m@e1Vg{&0u8hJ)=qJtKfNqOYmFs6u-6U{2+3qDv8?ecHOi7D)ft>I8zd0< z`3P5}@I%*C3J1jSG5{9A-TB|gu1Tbo!xcbP6(IV2@qnbGn^ZC#%R#YDk%?*dJOtms zm;4`hkLP<3^Bk&@(R1X_t3dHMTvI_gGkXpmuV&bfG?@FB3?E`O_VLq@L}`8#QjsF5 z4Csy_?UeqU9Z)`KuSz*dP6}tzf`2XW(G1>0OBMl{i5fD87)(rug{~7_lY$( z_b%_lub#tU%bb!|59`gztu2A)w)-X$kg(=avdlthkd(uB6^^{&JY#DxW79Qg;9Pc3 z=UUI2+f~U9LBQ4nVAUe9;V@8S&V$a5+mdvjp63xtnBU87!{c7@qLB2+P%V*~W(-7l=Y_g>G?hZ#Z|o~g_n{>1scGZ_MM zeJhJlx*U^V3n2^L`Xc8YL{+{6%LHEkpx=chX+esOjS<{W9a(btxzbgu5)4;wzcV}l z4bGX?;DQ_YSdhFZm)xs2mJ%AwwRY%12;O|11-WRKr~+LqkV^(;s_djY_8?$jx4Jey z{*@CNDer7iCgO~#U>G2e+P6iH7nnX~c1>gD)Bx)ewrGBM9;q zVx@)j5&C)|gI2Lpb(ir1Ii2k<$l##@ep5656~)Rnfgx(8l&TX@HlfVij1g|o;r?6B zF`d%}UFc5}uX(9H)`;QM0<%C3_M~Xk0JoL{OM-Qnu&`Bn0VjNr(;dz*9Nq~jdgHw&*w;je8SGXEf8KgwI|SUCgq3XvVJbx?awQk*yT*AIrU}Ck(MGeDLccmubpA& z0sAdRAU?PjAl9SlRJ$(>j5Y;eaZR zL5Xne`3Xzj8vL|HoXEzWn{4wo=7h%d(l#57~g?<41kLFBKnS~PP9K6)EG*#ZjE8FYiqv`EuuEBRu z_hM8tVToxh2^h)CheH$SR+8%_H+_KMf$i0F@qzq{&d0EU4f_fdIQxE|YIG8TN6Vpo zD*}BRNVHn6*f;E_p9?yP7%U7fnsevqN4<#@LGgrKJxei#fIu^$YT5|%akAXp#Gw(A zd1!uNTfks2y$g#J4t;9xhGkozBc!-@p~~pD%Vn{y)%ni=v9|<`&0Ns{{(fTAxu>nd z;StJfPgW`M5ktb8GRUxY$}!*O3xao_0GDbEo6<-4*hAd8V5&@I4CIPHkT(3&o?RAl zt7y*lpoWq;Np>?dr3v>rs)RK{N*F+n6(2mZ%lWFK>amNB zj1Sm(u9R_Ot!i;ILRgZa?@?{dFD`_)%y1|#5i+g7B(_OAzLybxhwx(piysHw5ONsF zi`+MDqY%s2y*>Qj9*ISArA}HeyO+pbxRELi?;FTq+JjOAI~RNUSUUG*JJ73=O8x#He~e=4!J9Y| zZMZO=5k}0Xgm?rx^aQ}pl?fR5q3d@{4{kfx^x`ME1D@5!E)$0bd%D*#UoL^;d#&~H zARNa{KL8UqjK&pwdQva-D?qSQ$qFB*8qSfXODAHqi6(mCdex6sRNGV*j)SXSU4(P4 zh&vYLuySQvoFkJ20*gTtF!eHyzA7*kT1xs*P#?dQk8Qn#+}Pswk`36oUm6?zjVeQ< z%s8UCM6F9)XQJzq4!rZhnX`+n`8uW!fn&FX2P9ijjf8*ygh}VacE~htb0~tP5&dX> zvWuauTlxJN&SUK)cl%EjtVw-+2i@av)Ob!m@6%m3f;z)Jw8Mr&15x|i2#^GWox!ZW zOg9XDb*2!=Idzqpj?=2PU+HlK6HV+ai(~ahI*RlIyrl>OPuZ@3Qq{2lEW<8ddhPxP zEk$sMKG%8fCXpBoF~pz4l>p6l=p(ShT!r>Tr-ZcrU;GgQr!spTuoYE5pr8tKYY8is zdtsJfYSV&ipNQgS#nZuuy>jd?Q9WpKP)Z5rIC`p(LDJoJgPb5%%+uuA+fY1W`09$@ z-;g%DbFAAR;4f+gav<*{^)!|mko2~n+@E^%bg-wjgmqAwzcGUZ zVZS{!A=P6?LoK<+Rgw&8#Pn4HG%!d6moQP7cM8wKu(tz$IG_*U$=@VuR3M|iz_}Ym zCMx!072e0Xoj}A$xRpfSM5Z1$1(aO;leFo~(xR6COCOC$bah9Y#VT00q>^sA;xY$Z zjUBaVkA`nlg0{Aa`w>6qEQ!*)WabdpqNWL&@%#5lxBJt>b>3SIN{6geCLl>`2#Ew5 z0Q|-8;ThYv1T%CVq$Wy((8v}gNrQxnYIp?%jrm&1yO$xd9f*&G0bEU3M6Cj()9arU zp&e@!4b2@)%pYLXW8*2ZRS7ubXMPB(@H4GppVOaG1mVG2!G!cyQ&hEKgVsXQA=1hv zn9h*257?Q%OhOExVGokIkl1^=DxmTjF+GGbImi^j1b?N(lzW8pp;C|ulR3Qge?nL1 zZ-&!;?&7mXs8Ib6aSjJY0hv77OmQJU>pA*oCN*r+_Cdkkq1(Bsv zcmVRB$dI)gC!2`vBA$V7w4Z8@p%QfBz=`f$B6hyTT>SY*^3Q*p z0urk=$Z6AUoI7AU_^Q~iK}{Mj#1K^|drVV5=Y7QMi^0IbCGXiAGxV+g_a({&6LeNU zUHlK}v@T0o#w~)xL zrPhOVOJ`HkaFV2GN9rVOwv86Oml}#2T|BppH*!&?smMQrsxt}|bkZ?+QuTke>d?AB zS{|8_`&Dk~EFwuP{U1}8IIrAheXtcu7}AxS0@Oq`d@IASkT&v-}4HfwU0 zD}OnwoC6^k7@_T~)ls<=#pE}(BOGyH@}ojJYQ-M*=lN3Cp6Mh3)V(wkX#vf2G1^Gm z?Rt-7!}?-r`vO^=<2YX>n_T%WYaDI7v_Sz=^|Ko1GQ+G1A!!2x)0{S)-LOBOdo+7y zoBfcXQF)rfKG)a=xZqou9g6b@S0y;>v5Ic(=&awEK_-cL-tMf6Oy?$PA|^bi@m6EOp@a_p&s(d`Kjg4Uf2=hTN@i8>enibXH!LK z@+~I;NX!vwDQ>}XZe~H9FpATgQ=1c9*W&8=_;sqUz>u>L~RLb@Xl{rPM3=24QR{59mtkrIUVA? zK}Wsx1eUuGtccRumaUx_tebGTW)%rBWVg5L;>o%8@{RP5@hdRwyo!WBLxda}VR-s@ z1^EQ=3Hv@KJxpaNa9A)C(d(K`_kkba2sDJZYXPjDw~U~XRl5L_D; z@jGobzH`s>1RkS5o}4hh9HG@0{Yw9HdwP`>n&Hqe(1fIEF{=l&wl__kz1!6Ar~UWM zg)8@mNk|+4Z(fL$>w)*>9qJ!n8BVAPwedr;LZ2 zPwl~da>FM;`>XHvLS?*Fbh>lId`ljM27nV7#JMpd_n9+p3>n`UY(=lSlCv(#ct74U za~*|-5$&i@_6ED)kG7+1#B?PbJoEo0477er4&7vmVY=T^fZ_K+^M98F{@cvn@jtXC zD>D~Wcg1O01{r#3d1a|ewHtYQ+35onL$4(=6cq~W>ywuM>iN{W>#kA z6IxjY+L@`@CXOYx1vd608Kwy)h8wwt>2XD_@qHP3+VTIVwJQN{s@TGT0;NEaU3Llt zT6T(*z0e(6y4kc8>Vj!=+Xm94Wa)wkL_}Fc*%t+6$peZD+e1MRWZy+Z1XPM3vWUO~ zeE2|~ynmA1l*ygBNy@w5msfqC_y5nFIp@sGnR90nhbMNoVk0|sc$KP+{BY|k9{02e z4nlA~^%OTF$v?Vs5f!i1RFI}^ENa^3Bm4(7kUYbwbgsu{C22I*Ye|vG@o}-L^zKP< z6$lDN6w)59SMU!wSk(Ct;%dM&81s-{sSwru4YcHmH#$1sP#3Ck0y6a?x%OE6Ps!i< zu74p^DfEkCdZvQc{dJNIay;bqiLBR=pplh;hSN*_{L28XODABxAkIvK+gmEHi3)Fdni2`(25II1+0&uhkz#Qk1;zCKG&R}$t z)g8K{h-`25I#19Bz5P5|+8o^5PiyiP4>QLOCfjgw6N=*@nhf#dXwqWV`eGihuy9O; zT3JzW;pY>g%ws|13p(Vr<-3w@(GeC*PQF^JH>rzd#lh$OPl!_$&MvXBBDGPgmIa}` zrY{RbFPMFR7{h`XQ&1ucQ4#7$Cof|`7-)xcH{zzEF6>5pf`edE%gaHdRL3bc5|u)Z zF$MA+Ors2Bp?G2Vv`)scQ1tR0gW9Sm3}h7x!G6MN#eh)LK7>4s^*?ULo6GSdDSh#= zS#M&T;bt(`$>7RVwb3L*=9skxy<;!Uo#Ww*%kM6R?86~Dxpqu^Y}RMGc*zmU zM$XiBn?4iB?Ip-}Flu=veJ?h0Y2ou*?g6mV!qIN4V0qUe zb;VqOSYKi`2N!-q@7%gun{sIPw#_iIDbRD>MN`9HoAo&j2Q!gu{>AFeT61ZdU^3{6 zc;0ew`uDrO23Bjx97bU;&f{Qb=#4^-Ay2OzFKA+QLV=(+a~+aQWtPs=z5Fi%4T=bg zVp~3gg3K%FsT>Ayyjouf?!YMpMh76TZIVqU`g(+{H0f3KrZ^l~+X z^n1cMc?xvD;{u#8+u$e&U@qk!OL!K%TWD| z(@=3}AdbqSSP#ywBx^FviA}aB%zFMuxLsRh2xzhg3oA*Msy64d$*yKS)D@#2zeYfh zqFNTZw31}bpvmU@@R9$DSbq>njJ4(mmEGA$A?KZ+tlQ6?eqZ+yC zAC)8(9TTA_4a0>|gAXyefnmZoGlnlfq}zeHZW6^mzpRq{k=Z7*5to2PW2lJLXmJ@B zyXjr^->vV9z72svxlwPZBsI~ugOaaxG6P~3# ze{cmu`OG#7MJyE+_aA#|QYj^wD#cG5Sn@OMwg9wP6}ldqweC52O2qkeb+%53Ht2BY zH5G3$N(mY6zJu!sH>_^wMH!JSj{czvP8?3kbPf@XsYTg%HpLl!hN&B@D^ zq2YwdTpSEcf=7M0lpD>J%Fu8EW8$*9UBX~omoRU8a=*i7?RUKrH0+)^Rkm_Mb+qMe zs0`T$*JHEpx#f{0%4irX7?TWoGGE|z%DlsSHk-lF2on~Xq1hcD894os-SA}acVIXs zVYqP5M+Qz;1l)Y>U?w!Q4Kq!;4b}hjk%2QHU3qzVLn};oH`+lneEQHw2F~cC?Nqk8 zIncYoYH0@RBOe(!L(Pm0AM5IaVTgp`=HEUtaK@D%GJoCI6Aa@d45?MBNE2L7*9m)8bGq=X{4wyzW%x3@$JR`On*qSU9BV(XPWv-!Ex^HbHmCvgCa;u(cD)Gj&~27*M1DUFV460 zk)jvJyEiPD@YV*jqMf7_2V1s)qO+8u zov#!e@9w;2f6HT_$dXW8SNcl9@$QCy%;NY(&0t?CINsek<(UUs1dz8RF)E;wuM`~b zKGx#wt!tnlDM>mE?(gC&1;@MZFKVqT0!1GQg`$VA6ddnP&CPvhAt<&;C=Q4EO2P5& z`~Q3;??X^Dkx*>v?IXo=9Phr}`}*Tupa_sq*!ucP!SU{MZC|^P01CatqCOkoD+R~9 zzhC*^cMrk!_Q3U0U5g5`npB1RNZ~$n%hc*MhGP512`foSCMTIwFI`-Y-K+=G+;@Ve zV?FIlgk;aJrk*+B-vIqn8!Iz<)1Y*`M|}ITUn#Et6SXF@3Y&HI-E;CUf}WLiCav0? z6}@#y01_&V-1lJbO!AJE-I_Ih$9;4abtC@$+&3J*oi2~-s3fr%g&r0404M@TQtMGu zW@NKv{8iX)D_YUDq5Fp8v)Blh>zfL;q_hljPN6K%jacDSGWur=v_-F;gE6wn@i;Q? zf=28jnY>1W!>2pH2{X@!H-%DWe&lm`lEk<$Rk2o|mx0A$z1|jKyRo8`|=QTl`^K)LLjsnwIg~ zEzg85aAtq(g)H*fpVi^li@PG;Bq9w!_juL4m7rm3?W;GAKG+SC7m*2|hsr5Pc*>cT zXijN{V)=cJoL${7m7rs$qhsjw(xM|CDV*v`G^jP`A-V1ByR*tlNpa*N1Ts1wkb9g% z@uecD%^G@^kC-SF2|705t>*s0$Q&r<;YZgDOu6U*&|_AW2)ub-zdmn6%I)}d z7Nx~soAtX(e0=#GKr$9|ITE<_HP}ZMltCw+*Z#u6wO6S+>kVYoOwb!Ix_Ryp%wkkM z_poNVCWjt_oivA9WJB|mbKg!P^(G5If%-4kW3$ea^Gi?&4INaasth!#Rk9d!1R0easgd2O5YX=eI)svXm!CJ#Y=KR+7rwd(p4|_A zNRN9KWNc)0;mj6u3tvb-4sQ^nno|?j4fu|f&@a^Gz+*fWuU=(~oVa*I`F+^N8!)`C z6lTw7IhZ0~oK~;ap?r%oqdB^CRO%t1mO>%4G76hsOeF)Jl+~vjwRxD1f*}^C zf|z5A)H;irTi_5>>-INSQCG31z2o?p3Ia<94gmzu6Vau{M}~pqksp;m2GU6=hIa53 zVH{A=_#(|_d;mkX3fa)R=dM0g3nRhTus%BG-RQ%CPR}+e}w9qU{MqJYqLfTSb7HSl>3uIJHWX}wQhnG4YG@S`J5cp3+^!mS*M2;M;SX58G4&r1O?hX}* zkImXP%M)US9@zb*S{7-GM%yD{v$SbF^D+QF_gpI+U%iJ|Gw3-aw3{U0?w| zvtue?1X4u?qa5g}Dp%f1f}C?8C%v$X$l-uG=OYyw;9COm+>CXN_u1;>cq>e#+K4K~ zUz_!UhQT23v1=Btx9-OPW<#=u2Kx#LV~Gw@jamaV%88~+!uDSCgEHR;#C8}Z*`8M! zU@|Mi@F~x|<`3I^0blVXg6GIxbxAfN^R zX|@c(^A@dO=2w6z-vn`j1`pdove$wHFp zv(y|&OdJptw)S~Isvs$?)#IPYK#~=){D(G8u5|wV517Gn0Mk>?yiGE|C>}>Z)MG5e zXExl>c(>KvTqse|13nl0fGZGW^j_%yPgI!2DMIlTff}-n;{U%AA6$6?R+^Nu{ zm}u|V#=mejjBLj3K;vR5ws&@W%_goTyra~Q&UkhKD9@pRQ55A{_;Aw81}3Xf5$+w| zUR>Wv=C6N)FOK4yaL{YMXdM>6gw#9E3u~^9RDhFg2GeS-dc=E9*i0T)QQlEjDTr&l z909H;24^~PA{_IUk{y^vr3Md1hD7lbVhBA~P5Ds<*^yy1W5vy0W0IKH>GeCB0(f%) z;A!a1=VhR=G8WX>_{mZ0lGKH4saKxfc#rIx>_!*Rsn@X=WS|{`lV52cdrA;vt_QO?uJT4>b(=*hQW_r!>>q`!rP{Um4bV|RvGUx=>8^zZ= zwBff`(YME-qh3__Y~DZyJ{q%M;`_3mL?)B3Y&@Qy2v4$sgI-ts+K7QKPTZwdLcs2R z{D+!+LE#Tgx1xmAH(`MBmZ$`(l?cAUBT)(&VT z0MgSVVUGcF$oAY~j9|vKLMArySN(4vSr46)3eJvHM}`fSLr%g`Ev(`JqKB@nLLQ~n z!Stk=dvYZt!V{)cN-{S2Ptmu%h_*+dq=F8WI}+s(9ZgSFD{?-4Wht?0Z_Tu{p(A`-+oCj{r6~G=s)osPh_| zQ**iClm9eCHc-)8g5A&HH8!W%Qvbn_X#~5S1pCZ5udzAXR;mBaDn*ru!Yqk;Mfkt? zQG@DBPI;wL_90s`KAgmZcUmB^?@%CQ-S*!3AXms0H#{X#U@wm@j6hrxqsaf_{>h|gB}ttui^sQ)46GC zeV!mE>jJ;cDpIufU%;bC)b-e`hgNf;v7~U6REf8T!0}xtAW6-H=zD5hw@2ixkY1Rf z1-V#AmVEVEF3+%xR5se>@)IZh;Wm?@WhI3c^06Em`&sq~>$JZ=LQ z(XL{T=CH?_@Z1Tgm~8EJqJ*8fnF~$Uu;LVzt%I!j*S^(3;v(pQu8do;g$o;7Lb8qU z68n{o$eUwW=hG1X{`Zpd?|(w4rNNkK1JP_{(2z6gREC_ff_a!FTSQi>1S6u9v)V=4 z9KvHszPbGrcxHfyo=+~`jCnRM;^SxY*t#|F(W?cDXh57y zh=GRQ2JweoO2TPHH;PJ7!pHUY?KU>S_2pmAT8#zaF&qy^Tlv-By&_=4ey}Qh5XyV) zpRLfa-~GvhO-fI7NzJMH4}WRIzo#Qla~D(hV5;-Jd*B5uTh_z<=FcLZJCP5C=q16* zI@Q=ZcJ4LGl;IEy-Y|Cb85LG918`hkM@rfySU58~FCj@K>VPfmkF$sN7>E8EkGT>Y z!}Zv#JzMZGRa*U6Hr~;ln(k9zyR9K7J(IcEfrFPW=wN4}m`Z2ZkUO7mkSf8{6js~` z>m%A4wsrN2gf08fhV>hUW1g`Bwo6+>(@+kqyvLD%w#$EpdJh!R8H+7?L+HIh3{Y}1 zr+Ds6OsQU7pv_5&64ad25V~b=I?)TJ_B(#GMU+Kzz>@@XzCn|r=him`#P{ph5%O@C71YqIt-GwV-)5k@kfpK`G(SUX+BsNnRUp!%+dE4cXgG{jtm9|y z6%fd^Z-)fDjn;pOUx-VUWD2-$6&o@odkjV#5tuFL)oEa7xqUSC+AYqM)mj~Y*@#3$xx%gQplH>KwoOyB484vHNmiGGni7wh9;-w zqV&o2{O2;@F6Sz7SakJ;$t6x}4`5b>E3ADVRF)Y`plsZjMFMBP*e zUfsZe#^RtzYeKkTPk0Do?WmJsHz8;})I8BvR=SCS=%{KCgAUssE{wSpfv*)5r1R*V zhO+Gp$QQhGT5rMDDP;fZMko+^I+C=j#I zfN%R2hfgOAKVPT1P4%TCGEIqneX>sU9%v!@`?Wz1iq00~6&0Y=tH+4(L#dfI*Jq zZcpL7c!PnXvM&kbN_Fn~znOXr^S=Ke^FdEko7`dmx(v$WD!*jbOEWQJQlz8BN=ni$ z)v8PT$GPV&C+Z(tPRt$$v^5BsFylIt_z($k}( z<)oXrsl}Dv=owO^L~r4cuc9UPh$R&EGhGXACAPuMLIILhj*ofRy&qQNA7lG4Ii@xB znj^(xmg6wbS)yx$kgsU3wHGK7IDHhj3i zC|@OwP8sxDybgX^4LfYKltZEzc=i+Y6JnyGI3aJJRPUeDfF3juZ~(pXrRxE`BT^9lpeIq=En4T&0pn>BuGFL0M4aMOdlUfh;nm^92o6<3s@%}x LL+IIXJH`J1EdB>a diff --git a/src/main/main.iml b/src/main/main.iml deleted file mode 100644 index 65af2187..00000000 --- a/src/main/main.iml +++ /dev/null @@ -1,13 +0,0 @@ - - - - - - - - - - - - - diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index e286a732..91b99e39 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -1,16 +1,18 @@ package com.thebuzzmedia.exiftool; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Tag; -import org.apache.log4j.Logger; - import java.io.File; import java.io.IOException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.thebuzzmedia.exiftool.ExifTool.Feature; +import com.thebuzzmedia.exiftool.ExifTool.Tag; + public class Benchmark { public static final int ITERATIONS = 25; - private static Logger log = Logger.getLogger(Benchmark.class); + private static Logger log = LoggerFactory.getLogger(Benchmark.class); public static void main(String[] args) throws IOException, InterruptedException { diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index 145018a5..acd5b04b 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -4,13 +4,15 @@ import java.io.IOException; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.thebuzzmedia.exiftool.ExifTool.Feature; import com.thebuzzmedia.exiftool.ExifTool.Format; -import org.apache.log4j.Logger; public class Example { - private static Logger log = Logger.getLogger(Example.class); + private static Logger log = LoggerFactory.getLogger(Example.class); private static final String TEST_FILES_PATH = "src/test/resources"; public static void main(String[] args) throws IOException, InterruptedException { diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index ec60bb1d..b5588f3f 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -1,8 +1,5 @@ package com.thebuzzmedia.exiftool; -import junit.framework.TestCase; -import org.apache.log4j.Logger; - import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -10,6 +7,11 @@ import java.util.Map; import java.util.Set; +import junit.framework.TestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** * TestMetadata

* @@ -19,7 +21,7 @@ public class TestExifTool extends TestCase { private static final String TEST_FILES_PATH = "src/test/resources"; - private static Logger log = Logger.getLogger(TestExifTool.class); + private static Logger log = LoggerFactory.getLogger(TestExifTool.class); public void testSingleTool() throws Exception { @@ -63,7 +65,7 @@ public void run() { runTests(tool,getName()); log.info(getName() + ": finished"); } catch (IOException e) { - log.error(e,e); + log.error("",e); fail(e.getMessage()); } finally { tool.shutdown(); @@ -87,7 +89,6 @@ public void testManyThreadsOneTool() throws Exception { for(int i=0; i < threads.length; i++) { final String label = "run "+i; threads[i] = new Thread(new Runnable() { - @Override public void run() { try { for(int j=0; j<5; j++) { diff --git a/src/test/lib/junit.jar b/src/test/lib/junit.jar deleted file mode 100644 index 666f5bb76058e25f02806dd8823b392280149fe1..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 121091 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–_-Kxp1ubW;4LQjeiwi(KZ#V7QV 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 LjhjzE-$3wx(YFCI diff --git a/src/test/test.iml b/src/test/test.iml deleted file mode 100644 index cc684a0c..00000000 --- a/src/test/test.iml +++ /dev/null @@ -1,23 +0,0 @@ - - - - - - - - - - - - - - - - - - - - - - - From 33995b911d097976f51ead64dac30f7c812cddee Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 22:59:46 +0300 Subject: [PATCH 028/148] integrate --- pom.xml | 7 +- .../com/thebuzzmedia/exiftool/ExifTool.java | 148 +++++++++++++++++- 2 files changed, 152 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index d7b8bf6f..ab9c0c34 100644 --- a/pom.xml +++ b/pom.xml @@ -26,7 +26,7 @@ maven-compiler-plugin 3.0 - 1.5 + 1.7 1.5 @@ -34,6 +34,11 @@ + + commons-io + commons-io + 2.2 + org.slf4j slf4j-api diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 708f736b..b4ba9208 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -20,6 +20,7 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; +import java.io.FileWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; @@ -33,7 +34,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; - +import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -627,6 +628,103 @@ private Map getImageMeta(final File image, final Format format, return resultMap; } + /** + * extract image metadata to exiftool's internal xml format. + * + * @param input + * the input file + * @return command output as xml string + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public String getImageMetadataXml(File input, boolean includeBinary) + throws IOException { + List args = new ArrayList(); + args.add("-X"); + if (includeBinary) + args.add("-b"); + args.add(input.getAbsolutePath()); + + return ExifProcess.executeToString(exifCmd, args); + } + + /** + * extract image metadata to exiftool's internal xml format. + * + * @param input + * the input file + * @param output + * the output file + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public void getImageMetadataXml(File input, File output, + boolean includeBinary) throws IOException { + + String result = getImageMetadataXml(input, includeBinary); + + try (FileWriter w = new FileWriter(output)) { + w.write(result); + } + } + + /** + * output icc profile from input to output. + * + * @param input + * the input file + * @param output + * the output file for icc data + * @return the command result from standard output e.g. + * "1 output files created" + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public String getImageIccProfile(File input, File output) + throws IOException { + + List args = new ArrayList(); + args.add("-icc_profile"); + args.add(input.getAbsolutePath()); + + args.add("-o"); + args.add(output.getAbsolutePath()); + + return ExifProcess.executeToString(exifCmd, args); + } + + /** + * Extract thumbnail from the given tag. + * + * @param input + * the input file + * @param tag + * the tag containing binary data + * @return the thumbnail file created. it is in the same folder as the input + * file because of the syntax of exiftool and has the suffix + * ".thumb.jpg" + * @throws IOException + * Signals that an I/O exception has occurred. + */ + public File extractThumbnail(File input, Tag tag) throws IOException { + + List args = new ArrayList(); + String suffix = ".thumb.jpg"; + String thumbname = FilenameUtils.getBaseName(input.getName()) + suffix; + + args.add("-" + tag.getName()); + args.add(input.getAbsolutePath()); + args.add("-b"); + args.add("-w"); + args.add(suffix); + String result = ExifProcess.executeToString(exifCmd, args); + File thumbnail = new File(input.getParent() + File.separator + + thumbname); + if (!thumbnail.exists()) + throw new IOException("could not create thumbnail: " + result); + return thumbnail; + } + /** * Will attempt 3 times to use the running exif process, and if unable to complete successfully will throw IOException */ @@ -712,6 +810,18 @@ public static Map executeToResults(String exifCmd, List a process.close(); } } + public static String executeToString(String exifCmd, List args) + throws IOException { + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { + return process.readResponseString(); + } finally { + process.close(); + } + } public static ExifProcess startup(String exifCmd) { List args = Arrays.asList(exifCmd,"-stay_open", "True", "-@", "-"); @@ -797,6 +907,30 @@ public synchronized Map readResponse() throws IOException { public boolean isClosed() { return closed; } + public synchronized String readResponseString() throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + log.debug("Reading response back from ExifTool..."); + String line; + StringBuilder result = new StringBuilder(); + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } else + result.append(line); + } + return result.toString(); + } public void close() { if ( ! closed ) { @@ -1075,6 +1209,14 @@ public enum Tag { WHITE_BALANCE("WhiteBalance", Integer.class), X_RESOLUTION("XResolution", Double.class), Y_RESOLUTION("YResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), + // select ICC metadata + ICC_DESCRIPTION("ProfileDescription", String.class), + ICC_COLORSPACEDATA( "ColorSpaceData", String.class), + // actually binary data, but what are we doing to do here??? Just use to + // save to file... + THUMBNAIL_IMAGE("ThumbnailImage", String.class), + THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class), ; /** @@ -1201,7 +1343,9 @@ public enum TagGroup { EXIF("EXIF","exif:all"), IPTC("IPTC", "iptc:all"), XMP("XMP", "xmp:all"), - ALL("ALL", "all"); + ALL("ALL", "all"), + FILE("FILE", "file:all"), + ICC("ICC", "icc_profile:all"); private final String name; private final String value; From edd06867f716b585dda3d665638c025a26a047f1 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 23:01:36 +0300 Subject: [PATCH 029/148] fix --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index b4ba9208..57fc450e 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -1209,7 +1209,6 @@ public enum Tag { WHITE_BALANCE("WhiteBalance", Integer.class), X_RESOLUTION("XResolution", Double.class), Y_RESOLUTION("YResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), // select ICC metadata ICC_DESCRIPTION("ProfileDescription", String.class), ICC_COLORSPACEDATA( "ColorSpaceData", String.class), From 0a1f82a1cd100c222d4833cd43311e656461cfa7 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 23:07:52 +0300 Subject: [PATCH 030/148] - formatted --- .../com/thebuzzmedia/exiftool/ExifTool.java | 1895 +++++++++-------- .../com/thebuzzmedia/exiftool/Benchmark.java | 39 +- .../com/thebuzzmedia/exiftool/Example.java | 72 +- .../thebuzzmedia/exiftool/TestExifTool.java | 392 ++-- 4 files changed, 1227 insertions(+), 1171 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 57fc450e..145ec7c6 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -17,10 +17,10 @@ import java.io.BufferedReader; import java.io.File; +import java.io.FileWriter; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; -import java.io.FileWriter; import java.util.ArrayList; import java.util.Arrays; import java.util.EnumSet; @@ -34,6 +34,7 @@ import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; + import org.apache.commons.io.FilenameUtils; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -83,10 +84,10 @@ * {@link Format#NUMERIC} and it is ultimately up to the caller to decide how * best to parse or convert the returned values. *

- * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} - * convenience method for parsing given String values according to - * the Tag hint automatically for you if that is what you plan on doing, - * otherwise feel free to handle the return values anyway you want. + * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} convenience + * method for parsing given String values according to the Tag hint + * automatically for you if that is what you plan on doing, otherwise feel free + * to handle the return values anyway you want. *

ExifTool -stay_open Support

* ExifTool * Because this feature requires ExifTool 8.36 or later, this class will * actually verify support for the feature in the version of ExifTool pointed at - * by {@link #exifCmd} before successfully instantiating the class and - * will notify you via an {@link UnsupportedFeatureException} if the native - * ExifTool doesn't support the requested feature. + * by {@link #exifCmd} before successfully instantiating the class and will + * notify you via an {@link UnsupportedFeatureException} if the native ExifTool + * doesn't support the requested feature. *

* In the event of an {@link UnsupportedFeatureException}, the caller can either * upgrade the native ExifTool upgrade to the version required or simply avoid @@ -214,162 +215,162 @@ */ public class ExifTool { - public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; - public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; - - /** - * Name used to identify the (optional) cleanup {@link Thread}. - *

- * This is only provided to make debugging and profiling easier for - * implementers making use of this class such that the resources this class - * creates and uses (i.e. Threads) are readily identifiable in a running VM. - *

- * Default value is "ExifTool Cleanup Thread". - */ - private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; - - /** - * Compiled {@link Pattern} of ": " used to split compact output from - * ExifTool evenly into name/value pairs. - */ - private static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); - private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - - private static Logger log = LoggerFactory.getLogger(ExifTool.class); - - /** - * The absolute path to the ExifTool executable on the host system running - * this class as defined by the "exiftool.path" system - * property. - *

- * If ExifTool is on your system path and running the command "exiftool" - * successfully executes it, leaving this value unchanged will work fine on - * any platform. If the ExifTool executable is named something else or not - * in the system path, then this property will need to be set to point at it - * before using this class. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.path=/path/to/exiftool - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * On Windows be sure to double-escape the path to the tool, for example: - * - * -Dexiftool.path=C:\\Tools\\exiftool.exe - * - *

- * Default value is "exiftool". - *

Relative Paths

- * Relative path values (e.g. "bin/tools/exiftool") are executed with - * relation to the base directory the VM process was started in. Essentially - * the directory that new File(".").getAbsolutePath() points at - * during runtime. - */ - private final String exifCmd; - - /** - * Interval (in milliseconds) of inactivity before the cleanup thread wakes - * up and cleans up the daemon ExifTool process and the read/write streams - * used to communicate with it when the {@link Feature#STAY_OPEN} feature is - * used. - *

- * Ever time a call to getImageMeta is processed, the timer - * keeping track of cleanup is reset; more specifically, this class has to - * experience no activity for this duration of time before the cleanup - * process is fired up and cleans up the host OS process and the stream - * resources. - *

- * Any subsequent calls to getImageMeta after a cleanup simply - * re-initializes the resources. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.processCleanupDelay=600000 - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * Setting this value to 0 disables the automatic cleanup thread completely - * and the caller will need to manually cleanup the external ExifTool - * process and read/write streams by calling {@link #close()}. - *

- * Default value is 600,000 (10 minutes). - */ - private final long processCleanupDelay; - - private final Map featureSupportedMap = new HashMap(); - private final Set featureSet = EnumSet.noneOf(Feature.class); - private final ReentrantLock lock = new ReentrantLock(); - private final VersionNumber exifVersion; - private final Timer cleanupTimer; - private TimerTask currentCleanupTask = null; - private AtomicBoolean shuttingDown = new AtomicBoolean(false); - private volatile ExifProcess process; - private int timeoutWhenKeepAlive = 0; - - public ExifTool(){ - this((Feature[]) null); - } - - /** - * In this constructor, exifToolPath and processCleanupDelay are gotten from system properties - * exiftool.path and exiftool.processCleanupDelay. processCleanupDelay is optional. If not found, - * the default is used. - */ - public ExifTool (Feature ... features){ - this( - System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), - Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, DEFAULT_PROCESS_CLEANUP_DELAY), - features - ); - } - - public ExifTool(String exifToolPath) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); - } - - public ExifTool(String exifToolPath, Feature ... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); - } - - public ExifTool(String exifCmd, long processCleanupDelay, Feature ... features) { - this.exifCmd = exifCmd; - this.processCleanupDelay = processCleanupDelay; - this.exifVersion = ExifProcess.readVersion(exifCmd); - if (features != null && features.length > 0) { - for (Feature feature : features) { - if ( ! feature.isSupported(exifVersion) ) { - throw new UnsupportedFeatureException(feature); - } - this.featureSet.add(feature); - this.featureSupportedMap.put(feature,true); - } - } - - /* - * Now that initialization is done, init the cleanup timer if we are - * using STAY_OPEN and the delay time set is non-zero. - */ - if (isFeatureEnabled(Feature.STAY_OPEN) ) { - cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - } else { - cleanupTimer = null; - } - } - - /** - * Limits the amount of time (in mills) an exif operation can take. Setting value to greater than 0 to enable. - */ - public ExifTool setRunTimeout(int mills) { - timeoutWhenKeepAlive = mills; - return this; - } - - /** + public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + + /** + * Name used to identify the (optional) cleanup {@link Thread}. + *

+ * This is only provided to make debugging and profiling easier for + * implementers making use of this class such that the resources this class + * creates and uses (i.e. Threads) are readily identifiable in a running VM. + *

+ * Default value is "ExifTool Cleanup Thread". + */ + private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; + + /** + * Compiled {@link Pattern} of ": " used to split compact output from + * ExifTool evenly into name/value pairs. + */ + private static final Pattern TAG_VALUE_PATTERN = Pattern + .compile("\\s*:\\s*"); + private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + + private static Logger log = LoggerFactory.getLogger(ExifTool.class); + + /** + * The absolute path to the ExifTool executable on the host system running + * this class as defined by the "exiftool.path" system + * property. + *

+ * If ExifTool is on your system path and running the command "exiftool" + * successfully executes it, leaving this value unchanged will work fine on + * any platform. If the ExifTool executable is named something else or not + * in the system path, then this property will need to be set to point at it + * before using this class. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.path=/path/to/exiftool + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * On Windows be sure to double-escape the path to the tool, for example: + * + * -Dexiftool.path=C:\\Tools\\exiftool.exe + * + *

+ * Default value is "exiftool". + *

Relative Paths

+ * Relative path values (e.g. "bin/tools/exiftool") are executed with + * relation to the base directory the VM process was started in. Essentially + * the directory that new File(".").getAbsolutePath() points at + * during runtime. + */ + private final String exifCmd; + + /** + * Interval (in milliseconds) of inactivity before the cleanup thread wakes + * up and cleans up the daemon ExifTool process and the read/write streams + * used to communicate with it when the {@link Feature#STAY_OPEN} feature is + * used. + *

+ * Ever time a call to getImageMeta is processed, the timer + * keeping track of cleanup is reset; more specifically, this class has to + * experience no activity for this duration of time before the cleanup + * process is fired up and cleans up the host OS process and the stream + * resources. + *

+ * Any subsequent calls to getImageMeta after a cleanup simply + * re-initializes the resources. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.processCleanupDelay=600000 + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * Setting this value to 0 disables the automatic cleanup thread completely + * and the caller will need to manually cleanup the external ExifTool + * process and read/write streams by calling {@link #close()}. + *

+ * Default value is 600,000 (10 minutes). + */ + private final long processCleanupDelay; + + private final Map featureSupportedMap = new HashMap(); + private final Set featureSet = EnumSet.noneOf(Feature.class); + private final ReentrantLock lock = new ReentrantLock(); + private final VersionNumber exifVersion; + private final Timer cleanupTimer; + private TimerTask currentCleanupTask = null; + private AtomicBoolean shuttingDown = new AtomicBoolean(false); + private volatile ExifProcess process; + private int timeoutWhenKeepAlive = 0; + + public ExifTool() { + this((Feature[]) null); + } + + /** + * In this constructor, exifToolPath and processCleanupDelay are gotten from + * system properties exiftool.path and exiftool.processCleanupDelay. + * processCleanupDelay is optional. If not found, the default is used. + */ + public ExifTool(Feature... features) { + this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( + ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, + DEFAULT_PROCESS_CLEANUP_DELAY), features); + } + + public ExifTool(String exifToolPath) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); + } + + public ExifTool(String exifToolPath, Feature... features) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); + } + + public ExifTool(String exifCmd, long processCleanupDelay, + Feature... features) { + this.exifCmd = exifCmd; + this.processCleanupDelay = processCleanupDelay; + this.exifVersion = ExifProcess.readVersion(exifCmd); + if (features != null && features.length > 0) { + for (Feature feature : features) { + if (!feature.isSupported(exifVersion)) { + throw new UnsupportedFeatureException(feature); + } + this.featureSet.add(feature); + this.featureSupportedMap.put(feature, true); + } + } + + /* + * Now that initialization is done, init the cleanup timer if we are + * using STAY_OPEN and the delay time set is non-zero. + */ + if (isFeatureEnabled(Feature.STAY_OPEN)) { + cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); + } else { + cleanupTimer = null; + } + } + + /** + * Limits the amount of time (in mills) an exif operation can take. Setting + * value to greater than 0 to enable. + */ + public ExifTool setRunTimeout(int mills) { + timeoutWhenKeepAlive = mills; + return this; + } + + /** * Used to determine if the given {@link Feature} is supported by the - * underlying native install of ExifTool pointed at by - * {@link #exifCmd}. + * underlying native install of ExifTool pointed at by {@link #exifCmd}. *

* If support for the given feature has not been checked for yet, this * method will automatically call out to ExifTool and ensure the requested @@ -394,9 +395,9 @@ public ExifTool setRunTimeout(int mills) { * external ExifTool process to verify feature support. */ public boolean isFeatureSupported(Feature feature) throws RuntimeException { - if (feature == null){ + if (feature == null) { throw new IllegalArgumentException("feature cannot be null"); - } + } Boolean supported = featureSupportedMap.get(feature); @@ -407,64 +408,62 @@ public boolean isFeatureSupported(Feature feature) throws RuntimeException { */ if (supported == null) { log.debug("Support for feature %s has not been checked yet, checking..."); - supported = feature.isSupported(exifVersion); - featureSupportedMap.put(feature,supported); + supported = feature.isSupported(exifVersion); + featureSupportedMap.put(feature, supported); } return supported; } + /** + * Used to startup the external ExifTool process and open the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. This method has no effect if the stay open feature is not + * enabled. + */ + public void startup() { + if (featureSet.contains(Feature.STAY_OPEN)) { + shuttingDown.set(false); + ensureProcessRunning(); + } + } + private void ensureProcessRunning() { + if (process == null || process.isClosed()) { + synchronized (this) { + if (process == null || process.isClosed()) { + log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = ExifProcess.startup(exifCmd); + } + } + } + if (processCleanupDelay > 0) { + synchronized (this) { + if (currentCleanupTask != null) { + currentCleanupTask.cancel(); + currentCleanupTask = null; + } + currentCleanupTask = new TimerTask() { + @Override + public void run() { + log.info("Auto cleanup task running..."); + process.close(); + } + }; + cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); + } + } + } + /** + * This is same as {@link #close()}, added for consistency with + * {@link #startup()} + */ + public void shutdown() { + close(); + } - - /** - * Used to startup the external ExifTool process and open the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. This method has no effect if the stay open feature is not enabled. - */ - public void startup(){ - if (featureSet.contains(Feature.STAY_OPEN)){ - shuttingDown.set(false); - ensureProcessRunning(); - } - } - private void ensureProcessRunning(){ - if (process ==null || process.isClosed()) { - synchronized (this){ - if (process ==null || process.isClosed() ){ - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = ExifProcess.startup(exifCmd); - } - } - } - if ( processCleanupDelay > 0 ) { - synchronized (this) { - if ( currentCleanupTask != null ) { - currentCleanupTask.cancel(); - currentCleanupTask = null; - } - currentCleanupTask = new TimerTask() { - @Override - public void run() { - log.info("Auto cleanup task running..."); - process.close(); - } - }; - cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); - } - } - } - - /** - * This is same as {@link #close()}, added for consistency with {@link #startup()} - */ - public void shutdown(){ - close(); - } - - - /** + /** * Used to shutdown the external ExifTool process and close the read/write * streams used to communicate with it when {@link Feature#STAY_OPEN} is * enabled. @@ -481,19 +480,19 @@ public void shutdown(){ * {@link Feature#STAY_OPEN} support enabled has no effect. */ public synchronized void close() { - shuttingDown.set(true); - if ( process != null ) { - process.close(); - } - if(currentCleanupTask != null) { - currentCleanupTask.cancel(); - currentCleanupTask = null; - } + shuttingDown.set(true); + if (process != null) { + process.close(); + } + if (currentCleanupTask != null) { + currentCleanupTask.cancel(); + currentCleanupTask = null; + } } - public boolean isStayOpen() { - return featureSet.contains(Feature.STAY_OPEN); - } + public boolean isStayOpen() { + return featureSet.contains(Feature.STAY_OPEN); + } /** * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support @@ -510,7 +509,7 @@ public boolean isStayOpen() { * false. */ public boolean isRunning() { - return process != null && ! process.isClosed(); + return process != null && !process.isClosed(); } /** @@ -533,97 +532,107 @@ public boolean isRunning() { * @throws IllegalArgumentException * if feature is null. */ - public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException { - if (feature == null){ + public boolean isFeatureEnabled(Feature feature) + throws IllegalArgumentException { + if (feature == null) { throw new IllegalArgumentException("feature cannot be null"); - } + } return featureSet.contains(feature); } - public Map getImageMeta(File image, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - - return getImageMeta(image, Format.NUMERIC, tags); - } - - public Map getImageMeta(File image, Format format, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - - String [] stringTags = new String[tags.length]; - int i=0; - for (Tag tag : tags){ - stringTags[i++] = tag.getName(); - } - Map result = getImageMeta(image, format, true, stringTags); - return mapByTag(result); - } - - public Map getImageMeta(File image, Format format, TagGroup... tags) - throws IllegalArgumentException, SecurityException, IOException { - String [] stringTags = new String[tags.length]; - int i=0; - for (TagGroup tag : tags){ - stringTags[i++] = tag.getValue(); - } - return getImageMeta(image, format, false, stringTags); - } - - private Map getImageMeta(final File image, final Format format, final boolean suppressDuplicates, final String... tags) - throws IllegalArgumentException, SecurityException, IOException { - - - //Validate input and create Arg Array - final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); - List args = new ArrayList(tags.length+4); - if (format == null){ - throw new IllegalArgumentException("format cannot be null"); - } else if (format == Format.NUMERIC){ - args.add("-n"); // numeric output - } - if (!suppressDuplicates){ - args.add("-a"); //suppress duplicates - } - args.add("-S"); // compact output - - if (tags == null || tags.length == 0){ - throw new IllegalArgumentException("tags cannot be null and must contain 1 or more Tag to query the image for."); - } - for (String tag : tags) { - args.add("-" + tag); - } - if (image == null){ - throw new IllegalArgumentException("image cannot be null and must be a valid stream of image data."); - } - if (!image.canRead()){ - throw new SecurityException("Unable to read the given image ["+image.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); - } - args.add(image.getAbsolutePath()); - - //start process + public Map getImageMeta(File image, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { + + return getImageMeta(image, Format.NUMERIC, tags); + } + + public Map getImageMeta(File image, Format format, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { + + String[] stringTags = new String[tags.length]; + int i = 0; + for (Tag tag : tags) { + stringTags[i++] = tag.getName(); + } + Map result = getImageMeta(image, format, true, + stringTags); + return mapByTag(result); + } + + public Map getImageMeta(File image, Format format, + TagGroup... tags) throws IllegalArgumentException, + SecurityException, IOException { + String[] stringTags = new String[tags.length]; + int i = 0; + for (TagGroup tag : tags) { + stringTags[i++] = tag.getValue(); + } + return getImageMeta(image, format, false, stringTags); + } + + private Map getImageMeta(final File image, + final Format format, final boolean suppressDuplicates, + final String... tags) throws IllegalArgumentException, + SecurityException, IOException { + + // Validate input and create Arg Array + final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + List args = new ArrayList(tags.length + 4); + if (format == null) { + throw new IllegalArgumentException("format cannot be null"); + } else if (format == Format.NUMERIC) { + args.add("-n"); // numeric output + } + if (!suppressDuplicates) { + args.add("-a"); // suppress duplicates + } + args.add("-S"); // compact output + + if (tags == null || tags.length == 0) { + throw new IllegalArgumentException( + "tags cannot be null and must contain 1 or more Tag to query the image for."); + } + for (String tag : tags) { + args.add("-" + tag); + } + if (image == null) { + throw new IllegalArgumentException( + "image cannot be null and must be a valid stream of image data."); + } + if (!image.canRead()) { + throw new SecurityException( + "Unable to read the given image [" + + image.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + } + args.add(image.getAbsolutePath()); + + // start process long startTime = System.currentTimeMillis(); - log.debug(String.format("Querying %d tags from image: %s", tags.length, image.getAbsolutePath())); + log.debug(String.format("Querying %d tags from image: %s", tags.length, + image.getAbsolutePath())); /* * Using ExifTool in daemon mode (-stay_open True) executes different * code paths below. So establish the flag for this once and it is * reused a multitude of times later in this method to figure out where * to branch to. */ - Map resultMap; - if (stayOpen) { + Map resultMap; + if (stayOpen) { log.debug("Using ExifTool in daemon mode (-stay_open True)..."); - resultMap = processStayOpen(args); - } else { + resultMap = processStayOpen(args); + } else { log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd,args); + resultMap = ExifProcess.executeToResults(exifCmd, args); } // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()){ - log.debug(String.format("Image Meta Processed in %d ms [queried %d tags and found %d values]", - (System.currentTimeMillis() - startTime), tags.length, - resultMap.size())); - } + if (log.isDebugEnabled()) { + log.debug(String + .format("Image Meta Processed in %d ms [queried %d tags and found %d values]", + (System.currentTimeMillis() - startTime), + tags.length, resultMap.size())); + } return resultMap; } @@ -659,14 +668,14 @@ public String getImageMetadataXml(File input, boolean includeBinary) * Signals that an I/O exception has occurred. */ public void getImageMetadataXml(File input, File output, - boolean includeBinary) throws IOException { + boolean includeBinary) throws IOException { - String result = getImageMetadataXml(input, includeBinary); + String result = getImageMetadataXml(input, includeBinary); - try (FileWriter w = new FileWriter(output)) { - w.write(result); + try (FileWriter w = new FileWriter(output)) { + w.write(result); + } } - } /** * output icc profile from input to output. @@ -725,646 +734,672 @@ public File extractThumbnail(File input, Tag tag) throws IOException { return thumbnail; } - /** - * Will attempt 3 times to use the running exif process, and if unable to complete successfully will throw IOException - */ - private Map processStayOpen(List args) throws IOException { - int attempts = 0; - while (attempts < 3 && ! shuttingDown.get()){ - attempts++; - //make sure process is started - ensureProcessRunning(); - TimerTask attemptTimer = null; - try { - if ( timeoutWhenKeepAlive > 0 ) { - attemptTimer = new TimerTask() { - public void run() { - log.warn("Process ran too long closing, max "+timeoutWhenKeepAlive+" mills"); - process.close(); - } - }; - cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); - } - log.debug("Streaming arguments to ExifTool process..."); - return process.sendArgs(args); - } catch (IOException ex){ - if ( STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) && ! shuttingDown.get() ){ - //only catch "Stream Closed" error (happens when process has died) - log.warn(String.format("Caught IOException(\"%s\"), will restart daemon",STREAM_CLOSED_MESSAGE)); - process.close(); - } else { - throw ex; - } - } finally { - if ( attemptTimer != null ) attemptTimer.cancel(); - } - } - if ( shuttingDown.get() ) { - throw new IOException("Shutting Down"); - } - throw new IOException("Ran out of attempts"); - } - - private static Map mapByTag(Map stringMap){ - Map tagMap = new HashMap(Tag.values().length); - for (Tag tag : Tag.values()){ - if (stringMap.containsKey(tag.getName())){ - tagMap.put(tag, stringMap.get(tag.getName())); - } - } - return tagMap; - } - - - //================================================================================ - /** - * Represents an Exif Process. - */ - public static class ExifProcess { - private final ReentrantLock closeLock = new ReentrantLock(false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; - private volatile boolean closed = false; - - public static VersionNumber readVersion(String exifCmd) { - ExifProcess process =_execute(false, Arrays.asList(exifCmd,"-ver")); - try { - return new VersionNumber(process.readLine()); - } catch (IOException ex) { - throw new RuntimeException(String.format("Unable to check version number of ExifTool: %s",exifCmd)); - } finally { - process.close(); - } - } - - public static Map executeToResults(String exifCmd, List args) throws IOException { - List newArgs = new ArrayList(args.size()+1); - newArgs.add(exifCmd); - newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); - try { - return process.readResponse(); - } finally { - process.close(); - } - } + /** + * Will attempt 3 times to use the running exif process, and if unable to + * complete successfully will throw IOException + */ + private Map processStayOpen(List args) + throws IOException { + int attempts = 0; + while (attempts < 3 && !shuttingDown.get()) { + attempts++; + // make sure process is started + ensureProcessRunning(); + TimerTask attemptTimer = null; + try { + if (timeoutWhenKeepAlive > 0) { + attemptTimer = new TimerTask() { + @Override + public void run() { + log.warn("Process ran too long closing, max " + + timeoutWhenKeepAlive + " mills"); + process.close(); + } + }; + cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); + } + log.debug("Streaming arguments to ExifTool process..."); + return process.sendArgs(args); + } catch (IOException ex) { + if (STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) + && !shuttingDown.get()) { + // only catch "Stream Closed" error (happens when process + // has died) + log.warn(String.format( + "Caught IOException(\"%s\"), will restart daemon", + STREAM_CLOSED_MESSAGE)); + process.close(); + } else { + throw ex; + } + } finally { + if (attemptTimer != null) + attemptTimer.cancel(); + } + } + if (shuttingDown.get()) { + throw new IOException("Shutting Down"); + } + throw new IOException("Ran out of attempts"); + } + + private static Map mapByTag(Map stringMap) { + Map tagMap = new HashMap(Tag.values().length); + for (Tag tag : Tag.values()) { + if (stringMap.containsKey(tag.getName())) { + tagMap.put(tag, stringMap.get(tag.getName())); + } + } + return tagMap; + } + + // ================================================================================ + /** + * Represents an Exif Process. + */ + public static class ExifProcess { + private final ReentrantLock closeLock = new ReentrantLock(false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader reader; + private final OutputStreamWriter writer; + private volatile boolean closed = false; + + public static VersionNumber readVersion(String exifCmd) { + ExifProcess process = _execute(false, + Arrays.asList(exifCmd, "-ver")); + try { + return new VersionNumber(process.readLine()); + } catch (IOException ex) { + throw new RuntimeException(String.format( + "Unable to check version number of ExifTool: %s", + exifCmd)); + } finally { + process.close(); + } + } + + public static Map executeToResults(String exifCmd, + List args) throws IOException { + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { + return process.readResponse(); + } finally { + process.close(); + } + } + public static String executeToString(String exifCmd, List args) throws IOException { - List newArgs = new ArrayList(args.size() + 1); - newArgs.add(exifCmd); - newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); - try { - return process.readResponseString(); - } finally { - process.close(); - } + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { + return process.readResponseString(); + } finally { + process.close(); + } + } + + public static ExifProcess startup(String exifCmd) { + List args = Arrays.asList(exifCmd, "-stay_open", "True", + "-@", "-"); + return _execute(true, args); + } + + public static ExifProcess _execute(boolean keepAlive, List args) { + log.debug(String + .format("Attempting to start external ExifTool process using args: %s", + args)); + try { + Process process = new ProcessBuilder(args).start(); + log.debug("\tSuccessful"); + return new ExifProcess(keepAlive, process); + } catch (Exception e) { + String message = "Unable to start external ExifTool process using the execution arguments: " + + args + + ". Ensure ExifTool is installed correctly and runs using the command path '" + + args.get(0) + + "' as specified by the 'exiftool.path' system property."; + + log.debug(message); + throw new RuntimeException(message, e); + } + } + + public ExifProcess(boolean keepAlive, Process process) { + this.keepAlive = keepAlive; + this.process = process; + this.reader = new BufferedReader(new InputStreamReader( + process.getInputStream())); + this.writer = new OutputStreamWriter(process.getOutputStream()); + } + + public synchronized Map sendArgs(List args) + throws IOException { + StringBuilder builder = new StringBuilder(); + for (String arg : args) { + builder.append(arg).append("\n"); + } + builder.append("-execute\n"); + writeFlush(builder.toString()); + return readResponse(); + } + + public synchronized void writeFlush(String message) throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + writer.write(message); + writer.flush(); + } + + public synchronized String readLine() throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + return reader.readLine(); + } + + public synchronized Map readResponse() + throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + log.debug("Reading response back from ExifTool..."); + Map resultMap = new HashMap(500); + String line; + + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + String[] pair = TAG_VALUE_PATTERN.split(line, 2); + + if (pair.length == 2) { + resultMap.put(pair[0], pair[1]); + log.debug(String.format("\tRead Tag [name=%s, value=%s]", + pair[0], pair[1])); + } + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } } + return resultMap; + } + + public boolean isClosed() { + return closed; + } - public static ExifProcess startup(String exifCmd) { - List args = Arrays.asList(exifCmd,"-stay_open", "True", "-@", "-"); - return _execute(true, args); - } - - public static ExifProcess _execute(boolean keepAlive, List args) { - log.debug(String.format("Attempting to start external ExifTool process using args: %s", args)); - try { - Process process = new ProcessBuilder(args).start(); - log.debug("\tSuccessful"); - return new ExifProcess(keepAlive,process); - } catch (Exception e) { - String message = "Unable to start external ExifTool process using the execution arguments: " - + args - + ". Ensure ExifTool is installed correctly and runs using the command path '" - + args.get(0) - + "' as specified by the 'exiftool.path' system property."; - - log.debug(message); - throw new RuntimeException(message, e); - } - } - - public ExifProcess(boolean keepAlive,Process process) { - this.keepAlive = keepAlive; - this.process = process; - this.reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream()); - } - - public synchronized Map sendArgs(List args) throws IOException { - StringBuilder builder = new StringBuilder(); - for(String arg : args) { - builder.append(arg).append("\n"); - } - builder.append("-execute\n"); - writeFlush(builder.toString()); - return readResponse(); - } - - - public synchronized void writeFlush(String message) throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - writer.write(message); - writer.flush(); - } - - public synchronized String readLine() throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - return reader.readLine(); - } - - public synchronized Map readResponse() throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - Map resultMap = new HashMap(500); - String line; - - while ((line = reader.readLine()) != null) { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - String[] pair = TAG_VALUE_PATTERN.split(line, 2); - - if (pair.length == 2) { - resultMap.put(pair[0], pair[1]); - log.debug(String.format("\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); - } - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need to - * look for it and break from this loop when we see it otherwise - * this process will hang indefinitely blocking on the input stream - * with no data to read. - */ - if (keepAlive && line.equals("{ready}")){ - break; - } - } - return resultMap; - } - - public boolean isClosed() { - return closed; - } public synchronized String readResponseString() throws IOException { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - String line; - StringBuilder result = new StringBuilder(); - while ((line = reader.readLine()) != null) { if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need - * to look for it and break from this loop when we see it - * otherwise this process will hang indefinitely blocking on the - * input stream with no data to read. - */ - if (keepAlive && line.equals("{ready}")) { - break; - } else - result.append(line); - } - return result.toString(); + throw new IOException(STREAM_CLOSED_MESSAGE); + log.debug("Reading response back from ExifTool..."); + String line; + StringBuilder result = new StringBuilder(); + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } else + result.append(line); + } + return result.toString(); + } + + public void close() { + if (!closed) { + closeLock.lock(); + try { + if (!closed) { + closed = true; + log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); + try { + writer.write("-stay_open\nFalse\n"); + writer.flush(); + } catch (IOException ex) { + // log.error(ex,ex); + } + try { + log.debug("Closing Read stream..."); + reader.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + log.debug("Closing Write stream..."); + writer.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + log.debug("Read/Write streams successfully closed."); + + try { + process.destroy(); + } catch (Exception e) { + // + } + // process = null; + + } + } finally { + closeLock.unlock(); + } + } + } + } + + // ================================================================================ + /** + * Enum used to define the different kinds of features in the native + * ExifTool executable that this class can help you take advantage of. + *

+ * These flags are different from {@link Tag}s in that a "feature" is + * determined to be a special functionality of the underlying ExifTool + * executable that requires a different code-path in this class to take + * advantage of; for example, -stay_open True support. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Feature { + /** + * Enum used to specify that you wish to launch the underlying ExifTool + * process with -stay_open True support turned on that this + * class can then take advantage of. + *

+ * Required ExifTool version is 8.36 or higher. + */ + STAY_OPEN(8, 36); + + private VersionNumber requireVersion; + + private Feature(int... numbers) { + this.requireVersion = new VersionNumber(numbers); } - public void close() { - if ( ! closed ) { - closeLock.lock(); - try { - if ( ! closed ) { - closed = true; - log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - try { - writer.write("-stay_open\nFalse\n"); - writer.flush(); - } catch (IOException ex) { - //log.error(ex,ex); - } - try { - log.debug("Closing Read stream..."); - reader.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log.debug("Closing Write stream..."); - writer.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - log.debug("Read/Write streams successfully closed."); - - try { - process.destroy(); - } catch (Exception e) { - // - } - //process = null; - - } - } finally { - closeLock.unlock(); - } - } - } - } - - //================================================================================ - /** - * Enum used to define the different kinds of features in the native - * ExifTool executable that this class can help you take advantage of. - *

- * These flags are different from {@link Tag}s in that a "feature" is - * determined to be a special functionality of the underlying ExifTool - * executable that requires a different code-path in this class to take - * advantage of; for example, -stay_open True support. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Feature { - /** - * Enum used to specify that you wish to launch the underlying ExifTool - * process with -stay_open True support turned on that this - * class can then take advantage of. - *

- * Required ExifTool version is 8.36 or higher. - */ - STAY_OPEN(8,36); - - - private VersionNumber requireVersion; - private Feature(int... numbers) { - this.requireVersion = new VersionNumber(numbers); - } - /** - * Used to get the version of ExifTool required by this feature in order - * to work. - * - * @return the version of ExifTool required by this feature in order to - * work. - */ - VersionNumber getVersion() { - return requireVersion; - } - - boolean isSupported(VersionNumber exifVersionNumber) { - return requireVersion.isBeforeOrEqualTo(exifVersionNumber); - } - } - - //================================================================================ - /** - * Version Number used to determine if one version is after another. - */ - static class VersionNumber { - private final int[] numbers; - - public VersionNumber(String str) { - String[] versionParts = str.trim().split("\\."); - this.numbers = new int[versionParts.length]; - for(int i=0; i other.numbers[i] ) { - return false; - } else if ( this.numbers[i] < other.numbers[i] ) { - return true; - } - } - //assume missing number as zero, so if the current process number is more digits it is a higher version - return this.numbers.length <= other.numbers.length; - } - - public String toString() { - StringBuilder builder = new StringBuilder(); - for(int i=0; i 0 ) { - builder.append("."); - } - builder.append(numbers[i]); - } - return builder.toString(); - } - } - - - //================================================================================ - /** - * Enum used to define the 2 different output formats that {@link Tag} - * values can be returned in: numeric or human-readable text. - *

- * ExifTool, via the -n command line arg, is capable of - * returning most values in their raw numeric form (e.g. - * Aperture="2.8010323841") as well as a more human-readable/friendly format - * (e.g. Aperture="2.8"). - *

- * While the {@link Tag}s defined on this class do provide a hint at the - * type of the result (see {@link Tag#getType()}), that hint only applies - * when the {@link Format#NUMERIC} form of the value is returned. - *

- * If the caller finds the human-readable format easier to process, - * {@link Format#HUMAN_READABLE} can be specified when calling - * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned - * {@link String} values processed manually by the caller. - *

- * In order to see the types of values that are returned when - * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive - * ExifTool Tag Guide. - *

- * This makes sense with some values like Aperture that in - * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high - * precision values that are near the intended value (e.g. - * "2.79999992203711" instead of just returning "2.8"). On the other hand, - * other values (like Orientation) are easier to parse when their numeric - * value (1-8) is returned instead of a much longer friendly name (e.g. - * "Mirror horizontal and rotate 270 CW"). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Format { - NUMERIC, HUMAN_READABLE - } - //================================================================================ - /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifTool. - *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default {@link Format#NUMERIC} value format - * is used. - *

- * All replies from ExifTool are parsed as {@link String}s and using the - * type hint from each {@link Tag} can easily be converted to the correct - * data format by using the provided {@link Tag#parseValue(String)} - * method. - *

- * This class does not make an attempt at converting the value automatically - * in case the caller decides they would prefer tag values returned in - * {@link Format#HUMAN_READABLE} format and to avoid any compatibility - * issues with future versions of ExifTool if a tag's return value is - * changed. This approach to leaving returned tag values as strings until - * the caller decides they want to parse them is a safer and more robust - * approach. - *

- * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. - *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. - *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. - *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Tag { - //single entry tags - APERTURE("ApertureValue", Double.class), - AUTHOR("XPAuthor", String.class), - COLOR_SPACE("ColorSpace", Integer.class), - COMMENT("XPComment", String.class), - CONTRAST("Contrast", Integer.class), - CREATE_DATE("CreateDate", String.class), - CREATION_DATE("CreationDate", String.class), - DATE_CREATED("DateCreated", String.class), - DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - FLASH("Flash", Integer.class), - FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), - FNUMBER("FNumber", String.class), - GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), - GPS_DATESTAMP("GPSDateStamp", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), - GPS_LONGITUDE("GPSLongitude", Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), - GPS_SPEED("GPSSpeed", Double.class), - GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), - IMAGE_WIDTH("ImageWidth", Integer.class), - ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), - LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), - MAKE("Make", String.class), - METERING_MODE("MeteringMode", Integer.class), - MODEL("Model", String.class), - ORIENTATION("Orientation", Integer.class), - OWNER_NAME("OwnerName", String.class), - RATING("Rating", Integer.class), - RATING_PERCENT("RatingPercent", Integer.class), - ROTATION("Rotation", Integer.class), - SATURATION("Saturation", Integer.class), - SENSING_METHOD("SensingMethod", Integer.class), - SHARPNESS("Sharpness", Integer.class), - SHUTTER_SPEED("ShutterSpeedValue", Double.class), - SOFTWARE("Software", String.class), - SUBJECT("XPSubject", String.class), - TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), - X_RESOLUTION("XResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), + /** + * Used to get the version of ExifTool required by this feature in order + * to work. + * + * @return the version of ExifTool required by this feature in order to + * work. + */ + VersionNumber getVersion() { + return requireVersion; + } + + boolean isSupported(VersionNumber exifVersionNumber) { + return requireVersion.isBeforeOrEqualTo(exifVersionNumber); + } + } + + // ================================================================================ + /** + * Version Number used to determine if one version is after another. + */ + static class VersionNumber { + private final int[] numbers; + + public VersionNumber(String str) { + String[] versionParts = str.trim().split("\\."); + this.numbers = new int[versionParts.length]; + for (int i = 0; i < versionParts.length; i++) { + numbers[i] = Integer.parseInt(versionParts[i]); + } + } + + public VersionNumber(int... numbers) { + this.numbers = numbers; + } + + public boolean isBeforeOrEqualTo(VersionNumber other) { + int max = Math.min(this.numbers.length, other.numbers.length); + for (int i = 0; i < max; i++) { + if (this.numbers[i] > other.numbers[i]) { + return false; + } else if (this.numbers[i] < other.numbers[i]) { + return true; + } + } + // assume missing number as zero, so if the current process number + // is more digits it is a higher version + return this.numbers.length <= other.numbers.length; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < numbers.length; i++) { + if (builder.length() > 0) { + builder.append("."); + } + builder.append(numbers[i]); + } + return builder.toString(); + } + } + + // ================================================================================ + /** + * Enum used to define the 2 different output formats that {@link Tag} + * values can be returned in: numeric or human-readable text. + *

+ * ExifTool, via the -n command line arg, is capable of + * returning most values in their raw numeric form (e.g. + * Aperture="2.8010323841") as well as a more human-readable/friendly format + * (e.g. Aperture="2.8"). + *

+ * While the {@link Tag}s defined on this class do provide a hint at the + * type of the result (see {@link Tag#getType()}), that hint only applies + * when the {@link Format#NUMERIC} form of the value is returned. + *

+ * If the caller finds the human-readable format easier to process, + * {@link Format#HUMAN_READABLE} can be specified when calling + * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned + * {@link String} values processed manually by the caller. + *

+ * In order to see the types of values that are returned when + * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive + * ExifTool Tag Guide. + *

+ * This makes sense with some values like Aperture that in + * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high + * precision values that are near the intended value (e.g. + * "2.79999992203711" instead of just returning "2.8"). On the other hand, + * other values (like Orientation) are easier to parse when their numeric + * value (1-8) is returned instead of a much longer friendly name (e.g. + * "Mirror horizontal and rotate 270 CW"). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Format { + NUMERIC, + HUMAN_READABLE + } + + // ================================================================================ + /** + * Enum used to pre-define a convenient list of tags that can be easily + * extracted from images using this class with an external install of + * ExifTool. + *

+ * Each tag defined also includes a type hint for the parsed value + * associated with it when the default {@link Format#NUMERIC} value format + * is used. + *

+ * All replies from ExifTool are parsed as {@link String}s and using the + * type hint from each {@link Tag} can easily be converted to the correct + * data format by using the provided {@link Tag#parseValue(String)} method. + *

+ * This class does not make an attempt at converting the value automatically + * in case the caller decides they would prefer tag values returned in + * {@link Format#HUMAN_READABLE} format and to avoid any compatibility + * issues with future versions of ExifTool if a tag's return value is + * changed. This approach to leaving returned tag values as strings until + * the caller decides they want to parse them is a safer and more robust + * approach. + *

+ * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or + * process the returned {@link String} values any way they wish. + *

Tag Support

+ * ExifTool is capable of parsing almost every tag known to man (1000+), but + * this class makes an attempt at pre-defining a convenient list of the most + * common tags for use. + *

+ * This list was determined by looking at the common metadata tag values + * written to images by popular mobile devices (iPhone, Android) as well as + * cameras like simple point and shoots as well as DSLRs. As an additional + * source of input the list of supported/common EXIF formats that Flickr + * supports was also reviewed to ensure the most common/useful tags were + * being covered here. + *

+ * Please email me or file an issue + * if you think this list is missing a commonly used tag that should be + * added to it. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Tag { + // single entry tags + APERTURE("ApertureValue", Double.class), + AUTHOR("XPAuthor", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATE_DATE("CreateDate", String.class), + CREATION_DATE("CreationDate", String.class), + DATE_CREATED("DateCreated", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + FLASH("Flash", Integer.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + FNUMBER("FNumber", String.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_DATESTAMP("GPSDateStamp", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SENSING_METHOD("SensingMethod", Integer.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), // select ICC metadata - ICC_DESCRIPTION("ProfileDescription", String.class), - ICC_COLORSPACEDATA( "ColorSpaceData", String.class), + ICC_DESCRIPTION("ProfileDescription", String.class), + ICC_COLORSPACEDATA("ColorSpaceData", String.class), // actually binary data, but what are we doing to do here??? Just use to // save to file... - THUMBNAIL_IMAGE("ThumbnailImage", String.class), - THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class), - ; - - /** - * Used to get the {@link Tag} identified by the given, case-sensitive, - * tag name. - * - * @param name - * The case-sensitive name of the tag that will be searched - * for. - * - * @return the {@link Tag} identified by the given, case-sensitive, tag - * name or null if one couldn't be found. - */ - public static Tag forName(String name) { - for (Tag tag : Tag.values()){ - if (tag.getName().equals(name)){ - return tag; - } - } - return null; - } - - /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifTool process) into the type described - * by the associated {@link Tag}. - * - * @param - * The type of the returned value. - * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. - * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). - * - * @throws IllegalArgumentException - * if tag is null. - * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). - * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. - */ - @SuppressWarnings("unchecked") - public T parseValue(String value) throws IllegalArgumentException { - - if (value != null) { - if (Boolean.class.isAssignableFrom(this.getType())){ - return (T) Boolean.valueOf(value); - } else if (Byte.class.isAssignableFrom(this.getType())){ - return (T) Byte.valueOf(Byte.parseByte(value)); - } else if (Integer.class.isAssignableFrom(this.getType())){ - return (T) Integer.valueOf(Integer.parseInt(value)); - } else if (Short.class.isAssignableFrom(this.getType())){ - return (T) Short.valueOf(Short.parseShort(value)); - } else if (Long.class.isAssignableFrom(this.getType())){ - return (T) Long.valueOf(Long.parseLong(value)); - } else if (Float.class.isAssignableFrom(this.getType())){ - return (T) Float.valueOf(Float.parseFloat(value)); - } else if (Double.class.isAssignableFrom(this.getType())){ - return (T) parseDouble(value); - } else if (Character.class.isAssignableFrom(this.getType())){ - return (T) Character.valueOf(value.charAt(0)); - } else if (String.class.isAssignableFrom(this.getType())){ - return (T) value; - } - } - return null; - } - - private Double parseDouble(String in) { - if (in.contains("/")) { - String[] enumeratorAndDivisor = in.split("/"); - return Double.parseDouble(enumeratorAndDivisor[0]) / Double.parseDouble(enumeratorAndDivisor[1]); - } else { - return Double.parseDouble(in); - } - } - - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ - public String getName() { - return name; - } - - /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifTool Tag Guide. - * - * @return a hint for the native type of this tag's value. - */ - public Class getType() { - return type; - } - - private String name; - private Class type; - - private Tag(String name, Class type) { - this.name = name; - this.type = type; - } - } - - //================================================================================ - public enum TagGroup { - EXIF("EXIF","exif:all"), - IPTC("IPTC", "iptc:all"), - XMP("XMP", "xmp:all"), - ALL("ALL", "all"), - FILE("FILE", "file:all"), - ICC("ICC", "icc_profile:all"); + THUMBNAIL_IMAGE("ThumbnailImage", String.class), + THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class), ; + + /** + * Used to get the {@link Tag} identified by the given, case-sensitive, + * tag name. + * + * @param name + * The case-sensitive name of the tag that will be searched + * for. + * + * @return the {@link Tag} identified by the given, case-sensitive, tag + * name or null if one couldn't be found. + */ + public static Tag forName(String name) { + for (Tag tag : Tag.values()) { + if (tag.getName().equals(name)) { + return tag; + } + } + return null; + } - private final String name; - private final String value; + /** + * Convenience method used to convert the given string Tag value + * (returned from the external ExifTool process) into the type described + * by the associated {@link Tag}. + * + * @param + * The type of the returned value. + * @param value + * The {@link String} representation of the tag's value as + * parsed from the image. + * + * @return the given string value converted to a native Java type (e.g. + * Integer, Double, etc.). + * + * @throws IllegalArgumentException + * if tag is null. + * @throws NumberFormatException + * if any exception occurs while trying to parse the given + * value to any of the supported numeric types + * in Java via calls to the respective parseXXX + * methods defined on all the numeric wrapper classes (e.g. + * {@link Integer#parseInt(String)} , + * {@link Double#parseDouble(String)} and so on). + * @throws ClassCastException + * if the type defined by T is incompatible + * with the type defined by {@link Tag#getType()} returned + * by the tag argument passed in. This class + * performs an implicit/unchecked cast to the type + * T before returning the parsed result of the + * type indicated by {@link Tag#getType()}. If the types do + * not match, a ClassCastException will be + * generated by the VM. + */ + @SuppressWarnings("unchecked") + public T parseValue(String value) throws IllegalArgumentException { + + if (value != null) { + if (Boolean.class.isAssignableFrom(this.getType())) { + return (T) Boolean.valueOf(value); + } else if (Byte.class.isAssignableFrom(this.getType())) { + return (T) Byte.valueOf(Byte.parseByte(value)); + } else if (Integer.class.isAssignableFrom(this.getType())) { + return (T) Integer.valueOf(Integer.parseInt(value)); + } else if (Short.class.isAssignableFrom(this.getType())) { + return (T) Short.valueOf(Short.parseShort(value)); + } else if (Long.class.isAssignableFrom(this.getType())) { + return (T) Long.valueOf(Long.parseLong(value)); + } else if (Float.class.isAssignableFrom(this.getType())) { + return (T) Float.valueOf(Float.parseFloat(value)); + } else if (Double.class.isAssignableFrom(this.getType())) { + return (T) parseDouble(value); + } else if (Character.class.isAssignableFrom(this.getType())) { + return (T) Character.valueOf(value.charAt(0)); + } else if (String.class.isAssignableFrom(this.getType())) { + return (T) value; + } + } + return null; + } - private TagGroup(String name, String value) { - this.name = name; - this.value = value; - } + private Double parseDouble(String in) { + if (in.contains("/")) { + String[] enumeratorAndDivisor = in.split("/"); + return Double.parseDouble(enumeratorAndDivisor[0]) + / Double.parseDouble(enumeratorAndDivisor[1]); + } else { + return Double.parseDouble(in); + } + } - public String getName() { - return name; - } + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ + public String getName() { + return name; + } - public String getValue() { - return value; - } - } + /** + * Used to get a hint for the native type of this tag's value as + * specified by Phil Harvey's ExifTool Tag Guide. + * + * @return a hint for the native type of this tag's value. + */ + public Class getType() { + return type; + } + private String name; + private Class type; + + private Tag(String name, Class type) { + this.name = name; + this.type = type; + } + } + + // ================================================================================ + public enum TagGroup { + EXIF("EXIF", "exif:all"), + IPTC("IPTC", "iptc:all"), + XMP("XMP", "xmp:all"), + ALL("ALL", "all"), + FILE("FILE", "file:all"), + ICC("ICC", "icc_profile:all"); + + private final String name; + private final String value; + + private TagGroup(String name, String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + } - //================================================================================ + // ================================================================================ /** * Class used to define an exception that occurs when the caller attempts to * use a {@link Feature} that the underlying native ExifTool install does diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index 91b99e39..8ec7233b 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -12,19 +12,20 @@ public class Benchmark { public static final int ITERATIONS = 25; - private static Logger log = LoggerFactory.getLogger(Benchmark.class); + private static Logger log = LoggerFactory.getLogger(Benchmark.class); + public static void main(String[] args) throws IOException, + InterruptedException { - public static void main(String[] args) throws IOException, InterruptedException { + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); + final Tag[] tags = Tag.values(); + final File[] images = new File("src/test/resources").listFiles(); - final Tag[] tags = Tag.values(); - final File[] images = new File("src/test/resources").listFiles(); - - log.info("Benchmark [tags=" + tags.length + ", images=" - + images.length + ", iterations=" + ITERATIONS + "]"); - log.info("\t" + (images.length * ITERATIONS) + log.info("Benchmark [tags=" + tags.length + ", images=" + images.length + + ", iterations=" + ITERATIONS + "]"); + log.info("\t" + (images.length * ITERATIONS) + " ExifTool process calls, " + (tags.length * images.length * ITERATIONS) + " total operations.\n"); @@ -38,13 +39,13 @@ public static void main(String[] args) throws IOException, InterruptedException log.info("\t[-stay_open False]"); long elapsedTime = 0; - for (int i = 1; i <= ITERATIONS; i++){ - log.info(String.format("iteration %s of %s", i, ITERATIONS)); + for (int i = 1; i <= ITERATIONS; i++) { + log.info(String.format("iteration %s of %s", i, ITERATIONS)); elapsedTime += run(tool, images, tags); - } + } log.info("\t\tElapsed Time: " + elapsedTime + " ms (" - + ((double) elapsedTime / 1000) + " secs)"); + + ((double) elapsedTime / 1000) + " secs)"); /* * -stay_open True */ @@ -52,13 +53,13 @@ public static void main(String[] args) throws IOException, InterruptedException long elapsedTimeSO = 0; for (int i = 1; i <= ITERATIONS; i++) { - log.info(String.format("iteration %s of %s", i, ITERATIONS)); + log.info(String.format("iteration %s of %s", i, ITERATIONS)); elapsedTimeSO += run(toolSO, images, tags); } log.info("\t\tElapsed Time: " + elapsedTimeSO + " ms (" - + ((double) elapsedTimeSO / 1000) + " secs - " - + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); + + ((double) elapsedTimeSO / 1000) + " secs - " + + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); // Shut down the running exiftool proc. toolSO.close(); @@ -68,9 +69,9 @@ private static long run(ExifTool tool, File[] images, Tag[] tags) throws IllegalArgumentException, SecurityException, IOException { long startTime = System.currentTimeMillis(); - for (File image : images){ - tool.getImageMeta(image, tags); - } + for (File image : images) { + tool.getImageMeta(image, tags); + } return (System.currentTimeMillis() - startTime); } diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index acd5b04b..d6f1bc27 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -12,36 +12,44 @@ public class Example { - private static Logger log = LoggerFactory.getLogger(Example.class); - private static final String TEST_FILES_PATH = "src/test/resources"; - - public static void main(String[] args) throws IOException, InterruptedException { - - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); - ExifTool tool = new ExifTool(Feature.STAY_OPEN); - - File[] images = new File(TEST_FILES_PATH).listFiles(); - - //list all first-class tags - for (File f : images) { - log.info("\n[" + f.getName() + "]"); - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, ExifTool.Tag.values()); - for (ExifTool.Tag key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key.getName(), metadata.get(key))); - } - } - - log.info("\n\n** GET TAGS BY GROUP"); - //list all XMP, IPTC and XMP tags - File f = new File(TEST_FILES_PATH + "/kureckjones_jett_075_02-cropped.tif"); - for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] {ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, ExifTool.TagGroup.XMP}){ - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, tagGroup); - log.info(tagGroup.getName()); - for (String key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - } - } - - tool.close(); - } + private static Logger log = LoggerFactory.getLogger(Example.class); + private static final String TEST_FILES_PATH = "src/test/resources"; + + public static void main(String[] args) throws IOException, + InterruptedException { + + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + + File[] images = new File(TEST_FILES_PATH).listFiles(); + + // list all first-class tags + for (File f : images) { + log.info("\n[" + f.getName() + "]"); + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, ExifTool.Tag.values()); + for (ExifTool.Tag key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key.getName(), + metadata.get(key))); + } + } + + log.info("\n\n** GET TAGS BY GROUP"); + // list all XMP, IPTC and XMP tags + File f = new File(TEST_FILES_PATH + + "/kureckjones_jett_075_02-cropped.tif"); + for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] { + ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, + ExifTool.TagGroup.XMP }) { + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, tagGroup); + log.info(tagGroup.getName()); + for (String key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + } + } + + tool.close(); + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index b5588f3f..bb791663 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -13,199 +13,211 @@ import org.slf4j.LoggerFactory; /** - * TestMetadata

- * + * TestMetadata + *

+ * * @author Michael Rush (michaelrush@gmail.com) * @since Initially created 8/8/13 */ public class TestExifTool extends TestCase { - private static final String TEST_FILES_PATH = "src/test/resources"; - private static Logger log = LoggerFactory.getLogger(TestExifTool.class); - - - public void testSingleTool() throws Exception { - ExifTool tool = new ExifTool(); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.startup(); - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - } - - public void testConcurrent() throws Exception { - - int toolCount = 5; - - List threads = new ArrayList(toolCount); - for (int i=1; i <= toolCount; i++){ - String toolName = "tool"+i; - Thread t = new Thread(toolName){ - @Override - public void run() { - log.info(getName() + ": starting"); - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - runTests(tool,getName()); - log.info(getName() + ": finished"); - } catch (IOException e) { - log.error("",e); - fail(e.getMessage()); - } finally { - tool.shutdown(); - } - log.info(getName() + ": finished"); - } - }; - t.start(); - threads.add(t); - } - - for (Thread t : threads){ - t.run(); - } - } - - public void testManyThreadsOneTool() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Thread[] threads = new Thread[20]; - for(int i=0; i < threads.length; i++) { - final String label = "run "+i; - threads[i] = new Thread(new Runnable() { - public void run() { - try { - for(int j=0; j<5; j++) { - runTests(tool,label); - } - log.info("DONE: "+label+" success!"); - } catch (IOException ex) { - fail(label); - } - } - },label); - } - for(Thread thread : threads) { - thread.start(); - } - for(Thread thread : threads) { - thread.join(); - } - } finally { - tool.shutdown(); - } - } - public void testProcessTimeout() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.setRunTimeout(1); - runTests(tool,"will fail"); - fail("should have failed"); - } catch (IOException ex) { - ; - } finally { - tool.shutdown(); - } - } - - public boolean runTests(ExifTool tool, String runId) throws IOException { - - Map metadata; - File imageFile; - Set keys; - ExifTool.Tag tag; - - imageFile = new File(TEST_FILES_PATH + "/kureckjones_jett_075_02-cropped.tif"); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(22, metadata.size()); - - keys = metadata.keySet(); - - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(728, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(825, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("P 45+", tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 1"); - - - imageFile = new File(TEST_FILES_PATH + "/nexus-s-electric-cars.jpg"); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(23, metadata.size()); - - keys = metadata.keySet(); - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(2560, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(1920, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.ISO; - assertEquals(50, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.SHUTTER_SPEED; - assertEquals("1/64", metadata.get(tag)); - assertEquals(0.015625, tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 2"); - return true; - } - - public void testGroupTags() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Map metadata; - File f = new File(TEST_FILES_PATH + "/iptc_test-photoshop.jpg"); - metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, ExifTool.TagGroup.IPTC); - assertEquals(17, metadata.size()); - assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); - assertEquals("IPTC Status: Copyright Notice", metadata.get("CopyrightNotice")); - assertEquals("IPTC Content: Description Writer", metadata.get("Writer-Editor")); - //for (String key : metadata.keySet()){ - // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - //} - } finally { - tool.shutdown(); - } - } - - public void testTag(){ - assertEquals("string value", "John Doe", ExifTool.Tag.AUTHOR.parseValue("John Doe")); - assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); - assertEquals("double value, from fraction", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); - assertEquals("double value, from decimal", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); - } - - public void testVersionNumber() { - assertTrue(new ExifTool.VersionNumber("1.2").isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); - assertTrue(new ExifTool.VersionNumber(1,2).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber(2,1))); - } - - - //todo TEST automatic daemon restart by killing perl process + private static final String TEST_FILES_PATH = "src/test/resources"; + private static Logger log = LoggerFactory.getLogger(TestExifTool.class); + + public void testSingleTool() throws Exception { + ExifTool tool = new ExifTool(); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + tool.startup(); + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + } + + public void testConcurrent() throws Exception { + + int toolCount = 5; + + List threads = new ArrayList(toolCount); + for (int i = 1; i <= toolCount; i++) { + String toolName = "tool" + i; + Thread t = new Thread(toolName) { + @Override + public void run() { + log.info(getName() + ": starting"); + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + runTests(tool, getName()); + log.info(getName() + ": finished"); + } catch (IOException e) { + log.error("", e); + fail(e.getMessage()); + } finally { + tool.shutdown(); + } + log.info(getName() + ": finished"); + } + }; + t.start(); + threads.add(t); + } + + for (Thread t : threads) { + t.run(); + } + } + + public void testManyThreadsOneTool() throws Exception { + final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + Thread[] threads = new Thread[20]; + for (int i = 0; i < threads.length; i++) { + final String label = "run " + i; + threads[i] = new Thread(new Runnable() { + @Override + public void run() { + try { + for (int j = 0; j < 5; j++) { + runTests(tool, label); + } + log.info("DONE: " + label + " success!"); + } catch (IOException ex) { + fail(label); + } + } + }, label); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + } finally { + tool.shutdown(); + } + } + + public void testProcessTimeout() throws Exception { + final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + tool.setRunTimeout(1); + runTests(tool, "will fail"); + fail("should have failed"); + } catch (IOException ex) { + ; + } finally { + tool.shutdown(); + } + } + + public boolean runTests(ExifTool tool, String runId) throws IOException { + + Map metadata; + File imageFile; + Set keys; + ExifTool.Tag tag; + + imageFile = new File(TEST_FILES_PATH + + "/kureckjones_jett_075_02-cropped.tif"); + metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.values()); + assertEquals(22, metadata.size()); + + keys = metadata.keySet(); + + tag = ExifTool.Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(728, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.IMAGE_HEIGHT; + assertEquals(825, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.MODEL; + assertEquals("P 45+", tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 1"); + + imageFile = new File(TEST_FILES_PATH + "/nexus-s-electric-cars.jpg"); + metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.values()); + assertEquals(23, metadata.size()); + + keys = metadata.keySet(); + tag = ExifTool.Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(2560, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.IMAGE_HEIGHT; + assertEquals(1920, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.MODEL; + assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.ISO; + assertEquals(50, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.SHUTTER_SPEED; + assertEquals("1/64", metadata.get(tag)); + assertEquals(0.015625, tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 2"); + return true; + } + + public void testGroupTags() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + Map metadata; + File f = new File(TEST_FILES_PATH + "/iptc_test-photoshop.jpg"); + metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, + ExifTool.TagGroup.IPTC); + assertEquals(17, metadata.size()); + assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); + assertEquals("IPTC Status: Copyright Notice", + metadata.get("CopyrightNotice")); + assertEquals("IPTC Content: Description Writer", + metadata.get("Writer-Editor")); + // for (String key : metadata.keySet()){ + // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + // } + } finally { + tool.shutdown(); + } + } + + public void testTag() { + assertEquals("string value", "John Doe", + ExifTool.Tag.AUTHOR.parseValue("John Doe")); + assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); + assertEquals("double value, from fraction", .25, + ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); + assertEquals("double value, from decimal", .25, + ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); + } + + public void testVersionNumber() { + assertTrue(new ExifTool.VersionNumber("1.2") + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); + assertTrue(new ExifTool.VersionNumber(1, 2) + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); + assertTrue(new ExifTool.VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); + assertTrue(new ExifTool.VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new ExifTool.VersionNumber(2, 1))); + } + + // todo TEST automatic daemon restart by killing perl process } From df821e11b76e9b9a7083341e4874c384d87ecdfa Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 23:10:13 +0300 Subject: [PATCH 031/148] formatted --- .gitignore | 6 + .../com/thebuzzmedia/exiftool/ExifTool.java | 1538 ++++++++--------- .../com/thebuzzmedia/exiftool/Benchmark.java | 49 +- .../com/thebuzzmedia/exiftool/Example.java | 76 +- .../thebuzzmedia/exiftool/TestExifTool.java | 401 ++--- 5 files changed, 1041 insertions(+), 1029 deletions(-) diff --git a/.gitignore b/.gitignore index 389dc77c..6c1a0c6e 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,9 @@ target dist bin + +/.classpath + +/.project + +/.settings diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 8294cf61..77a16466 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -37,192 +37,240 @@ import java.util.regex.Pattern; import org.apache.commons.io.FilenameUtils; -import org.apache.log4j.Logger; - +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * Class used to provide a Java-like interface to Phil Harvey's excellent, * Perl-based ExifTool. *

- * There are a number of other basic Java wrappers to ExifTool available online, but most of them only abstract out the - * actual Java-external-process execution logic and do no additional work to make integration with the external ExifTool - * any easier or intuitive from the perspective of the Java application written to make use of ExifTool. + * There are a number of other basic Java wrappers to ExifTool available online, + * but most of them only abstract out the actual Java-external-process execution + * logic and do no additional work to make integration with the external + * ExifTool any easier or intuitive from the perspective of the Java application + * written to make use of ExifTool. *

- * This class was written in order to make integration with ExifTool inside of a Java application seamless and - * performant with the goal being that the developer can treat ExifTool as if it were written in Java, garnering all of - * the benefits with none of the added headache of managing an external native process from Java. + * This class was written in order to make integration with ExifTool inside of a + * Java application seamless and performant with the goal being that the + * developer can treat ExifTool as if it were written in Java, garnering all of + * the benefits with none of the added headache of managing an external native + * process from Java. *

- * Phil Harvey's ExifTool is written in Perl and runs on all major platforms (including Windows) so no portability - * issues are introduced into your application by utilizing this class. + * Phil Harvey's ExifTool is written in Perl and runs on all major platforms + * (including Windows) so no portability issues are introduced into your + * application by utilizing this class. *

Usage

- * Assuming ExifTool is installed on the host system correctly and either in the system path or pointed to by - * {@link #exifCmd}, using this class to communicate with ExifTool is as simple as creating an instance ( - * ExifTool tool = new ExifTool()) and then making calls to {@link #getImageMeta(File, Tag...)} or - * {@link #getImageMeta(File, Format, Tag...)} with a list of {@link Tag}s you want to pull values for from the given - * image. + * Assuming ExifTool is installed on the host system correctly and either in the + * system path or pointed to by {@link #exifCmd}, using this class to + * communicate with ExifTool is as simple as creating an instance ( + * ExifTool tool = new ExifTool()) and then making calls to + * {@link #getImageMeta(File, Tag...)} or + * {@link #getImageMeta(File, Format, Tag...)} with a list of {@link Tag}s you + * want to pull values for from the given image. *

- * In this default mode, calls to getImageMeta will automatically start an external ExifTool process to - * handle the request. After ExifTool has parsed the tag values from the file, the external process exits and this class - * parses the result before returning it to the caller. + * In this default mode, calls to getImageMeta will automatically + * start an external ExifTool process to handle the request. After ExifTool has + * parsed the tag values from the file, the external process exits and this + * class parses the result before returning it to the caller. *

- * Results from calls to getImageMeta are returned in a {@link Map} with the {@link Tag} values as the keys - * and {@link String} values for every tag that had a value in the image file as the values. {@link Tag}s with no value - * found in the image are omitted from the result map. + * Results from calls to getImageMeta are returned in a {@link Map} + * with the {@link Tag} values as the keys and {@link String} values for every + * tag that had a value in the image file as the values. {@link Tag}s with no + * value found in the image are omitted from the result map. *

- * While each {@link Tag} provides a hint at which format the resulting value for that tag is returned as from ExifTool - * (see {@link Tag#getType()}), that only applies to values returned with an output format of {@link Format#NUMERIC} and - * it is ultimately up to the caller to decide how best to parse or convert the returned values. + * While each {@link Tag} provides a hint at which format the resulting value + * for that tag is returned as from ExifTool (see {@link Tag#getType()}), that + * only applies to values returned with an output format of + * {@link Format#NUMERIC} and it is ultimately up to the caller to decide how + * best to parse or convert the returned values. *

- * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} convenience method for parsing given - * String values according to the Tag hint automatically for you if that is what you plan on doing, - * otherwise feel free to handle the return values anyway you want. + * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} convenience + * method for parsing given String values according to the Tag hint + * automatically for you if that is what you plan on doing, otherwise feel free + * to handle the return values anyway you want. *

ExifTool -stay_open Support

- * ExifTool 8.36 - * added a new persistent-process feature that allows ExifTool to stay running in a daemon mode and continue accepting - * commands via a file or stdin. + * ExifTool 8.36 added a new persistent-process feature that allows ExifTool to stay + * running in a daemon mode and continue accepting commands via a file or stdin. *

- * This new mode is controlled via the -stay_open True/False command line argument and in a busy system - * that is making thousands of calls to ExifTool, can offer speed improvements of up to 60x (yes, + * This new mode is controlled via the -stay_open True/False + * command line argument and in a busy system that is making thousands of calls + * to ExifTool, can offer speed improvements of up to 60x (yes, * really that much). *

- * This feature was added to ExifTool shortly after user Christian Etter - * discovered the overhead for starting up a new Perl interpreter each time ExifTool is loaded accounts for roughly - * 98.4% of the total - * runtime. + * This feature was added to ExifTool shortly after user Christian Etter discovered + * the overhead for starting up a new Perl interpreter each time ExifTool is + * loaded accounts for roughly 98.4% of the total runtime. *

- * Support for using ExifTool in daemon mode is enabled by passing {@link Feature#STAY_OPEN} to the constructor of the - * class when creating an instance of this class and then simply using the class as you normally would. This class will - * manage a single ExifTool process running in daemon mode in the background to service all future calls to the class. + * Support for using ExifTool in daemon mode is enabled by passing + * {@link Feature#STAY_OPEN} to the constructor of the class when creating an + * instance of this class and then simply using the class as you normally would. + * This class will manage a single ExifTool process running in daemon mode in + * the background to service all future calls to the class. *

- * Because this feature requires ExifTool 8.36 or later, this class will actually verify support for the feature in the - * version of ExifTool pointed at by {@link #exifCmd} before successfully instantiating the class and will notify you - * via an {@link UnsupportedFeatureException} if the native ExifTool doesn't support the requested feature. + * Because this feature requires ExifTool 8.36 or later, this class will + * actually verify support for the feature in the version of ExifTool pointed at + * by {@link #exifCmd} before successfully instantiating the class and will + * notify you via an {@link UnsupportedFeatureException} if the native ExifTool + * doesn't support the requested feature. *

- * In the event of an {@link UnsupportedFeatureException}, the caller can either upgrade the native ExifTool upgrade to - * the version required or simply avoid using that feature to work around the exception. + * In the event of an {@link UnsupportedFeatureException}, the caller can either + * upgrade the native ExifTool upgrade to the version required or simply avoid + * using that feature to work around the exception. *

Automatic Resource Cleanup

- * When {@link Feature#STAY_OPEN} mode is used, there is the potential for leaking both host OS processes (native - * 'exiftool' processes) as well as the read/write streams used to communicate with it unless {@link #close()} is called - * to clean them up when done. Fortunately, this class provides an automatic cleanup mechanism that - * runs, by default, after 10mins of inactivity to clean up those stray resources. + * When {@link Feature#STAY_OPEN} mode is used, there is the potential for + * leaking both host OS processes (native 'exiftool' processes) as well as the + * read/write streams used to communicate with it unless {@link #close()} is + * called to clean them up when done. Fortunately, this class + * provides an automatic cleanup mechanism that runs, by default, after 10mins + * of inactivity to clean up those stray resources. *

- * The inactivity period can be controlled by modifying the {@link #processCleanupDelay} system variable. A value of - * 0 or less disabled the automatic cleanup process and requires you to cleanup ExifTool instances on your - * own by calling {@link #close()} manually. + * The inactivity period can be controlled by modifying the + * {@link #processCleanupDelay} system variable. A value of 0 or + * less disabled the automatic cleanup process and requires you to cleanup + * ExifTool instances on your own by calling {@link #close()} manually. *

- * Any class activity by way of calls to getImageMeta will always reset the inactivity timer, so in a busy - * system the cleanup thread could potentially never run, leaving the original host ExifTool process running forever - * (which is fine). + * Any class activity by way of calls to getImageMeta will always + * reset the inactivity timer, so in a busy system the cleanup thread could + * potentially never run, leaving the original host ExifTool process running + * forever (which is fine). *

- * This design was chosen to help make using the class and not introducing memory leaks and bugs into your code easier - * as well as making very inactive instances of this class light weight while not in-use by cleaning up after + * This design was chosen to help make using the class and not introducing + * memory leaks and bugs into your code easier as well as making very inactive + * instances of this class light weight while not in-use by cleaning up after * themselves. *

- * The only overhead incurred when opening the process back up is a 250-500ms lag while launching the VM interpreter - * again on the first call (depending on host machine speed and load). + * The only overhead incurred when opening the process back up is a 250-500ms + * lag while launching the VM interpreter again on the first call (depending on + * host machine speed and load). *

Reusing a "closed" ExifTool Instance

- * If you or the cleanup thread have called {@link #close()} on an instance of this class, cleaning up the host process - * and read/write streams, the instance of this class can still be safely used. Any followup calls to - * getImageMeta will simply re-instantiate all the required resources necessary to service the call - * (honoring any {@link Feature}s set). + * If you or the cleanup thread have called {@link #close()} on an instance of + * this class, cleaning up the host process and read/write streams, the instance + * of this class can still be safely used. Any followup calls to + * getImageMeta will simply re-instantiate all the required + * resources necessary to service the call (honoring any {@link Feature}s set). *

- * This can be handy behavior to be aware of when writing scheduled processing jobs that may wake up every hour and - * process thousands of pictures then go back to sleep. In order for the process to execute as fast as possible, you - * would want to use ExifTool in daemon mode (pass {@link Feature#STAY_OPEN} to the constructor of this class) and when - * done, instead of {@link #close()}-ing the instance of this class and throwing it out, you can keep the reference + * This can be handy behavior to be aware of when writing scheduled processing + * jobs that may wake up every hour and process thousands of pictures then go + * back to sleep. In order for the process to execute as fast as possible, you + * would want to use ExifTool in daemon mode (pass {@link Feature#STAY_OPEN} to + * the constructor of this class) and when done, instead of {@link #close()}-ing + * the instance of this class and throwing it out, you can keep the reference * around and re-use it again when the job executes again an hour later. *

Performance

- * Extra care is taken to ensure minimal object creation or unnecessary CPU overhead while communicating with the - * external process. + * Extra care is taken to ensure minimal object creation or unnecessary CPU + * overhead while communicating with the external process. *

- * {@link Pattern}s used to split the responses from the process are explicitly compiled and reused, string - * concatenation is minimized, Tag name lookup is done via a static final {@link Map} shared by all - * instances and so on. + * {@link Pattern}s used to split the responses from the process are explicitly + * compiled and reused, string concatenation is minimized, Tag name lookup is + * done via a static final {@link Map} shared by all instances and + * so on. *

- * Additionally, extra care is taken to utilize the most optimal code paths when initiating and using the external - * process, for example, the {@link ProcessBuilder#command(List)} method is used to avoid the copying of array elements - * when {@link ProcessBuilder#command(String...)} is used and avoiding the (hidden) use of {@link StringTokenizer} when + * Additionally, extra care is taken to utilize the most optimal code paths when + * initiating and using the external process, for example, the + * {@link ProcessBuilder#command(List)} method is used to avoid the copying of + * array elements when {@link ProcessBuilder#command(String...)} is used and + * avoiding the (hidden) use of {@link StringTokenizer} when * {@link Runtime#exec(String)} is called. *

- * All of this effort was done to ensure that imgscalr and its supporting classes continue to provide best-of-breed - * performance and memory utilization in long running/high performance environments (e.g. web applications). + * All of this effort was done to ensure that imgscalr and its supporting + * classes continue to provide best-of-breed performance and memory utilization + * in long running/high performance environments (e.g. web applications). *

Thread Safety

- * Instances of this class are not Thread-safe. Both the instance of this class and external ExifTool - * process maintain state specific to the current operation. Use of instances of this class need to be synchronized - * using an external mechanism or in a highly threaded environment (e.g. web application), instances of this class can - * be used along with {@link ThreadLocal}s to ensure Thread-safe, highly parallel use. + * Instances of this class are not Thread-safe. Both the + * instance of this class and external ExifTool process maintain state specific + * to the current operation. Use of instances of this class need to be + * synchronized using an external mechanism or in a highly threaded environment + * (e.g. web application), instances of this class can be used along with + * {@link ThreadLocal}s to ensure Thread-safe, highly parallel use. *

Why ExifTool?

- * ExifTool is written in Perl and requires an external - * process call from Java to make use of. + * ExifTool is + * written in Perl and requires an external process call from Java to make use + * of. *

- * While this would normally preclude a piece of software from inclusion into the imgscalr library (more complex - * integration), there is no other image metadata piece of software available as robust, complete and well-tested as - * ExifTool. In addition, ExifTool already runs on all major platforms (including Windows), so there was not a lack of - * portability introduced by providing an integration for it. + * While this would normally preclude a piece of software from inclusion into + * the imgscalr library (more complex integration), there is no other image + * metadata piece of software available as robust, complete and well-tested as + * ExifTool. In addition, ExifTool already runs on all major platforms + * (including Windows), so there was not a lack of portability introduced by + * providing an integration for it. *

- * Allowing it to be used from Java is a boon to any Java project that needs the ability to read/write image-metadata - * from almost any image or video file format. + * Allowing it to be used from Java is a boon to any Java project that needs the + * ability to read/write image-metadata from almost any image or + * video file format. *

Alternatives

- * If integration with an external Perl process is something your app cannot do and you still need image - * metadata-extraction capability, Drew Noakes has written the 2nd most robust image metadata library I have come - * across: Metadata Extractor that you might want to look - * at. + * If integration with an external Perl process is something your app cannot do + * and you still need image metadata-extraction capability, Drew Noakes has + * written the 2nd most robust image metadata library I have come across: Metadata Extractor + * that you might want to look at. * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ -public class ExifTool -{ +public class ExifTool { - public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; - public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; /** * Name used to identify the (optional) cleanup {@link Thread}. *

- * This is only provided to make debugging and profiling easier for implementers making use of this class such that - * the resources this class creates and uses (i.e. Threads) are readily identifiable in a running VM. + * This is only provided to make debugging and profiling easier for + * implementers making use of this class such that the resources this class + * creates and uses (i.e. Threads) are readily identifiable in a running VM. *

* Default value is "ExifTool Cleanup Thread". */ - private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; + private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; /** * Compiled {@link Pattern} of ": " used to split compact output from * ExifTool evenly into name/value pairs. */ - private static final Pattern TAG_VALUE_PATTERN = Pattern.compile( "\\s*:\\s*"); - private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + private static final Pattern TAG_VALUE_PATTERN = Pattern + .compile("\\s*:\\s*"); + private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - private static Logger log = Logger.getLogger( ExifTool.class); + private static Logger log = LoggerFactory.getLogger(ExifTool.class); /** * The absolute path to the ExifTool executable on the host system running * this class as defined by the "exiftool.path" system * property. *

- * If ExifTool is on your system path and running the command "exiftool" successfully executes it, leaving this - * value unchanged will work fine on any platform. If the ExifTool executable is named something else or not in the - * system path, then this property will need to be set to point at it before using this class. + * If ExifTool is on your system path and running the command "exiftool" + * successfully executes it, leaving this value unchanged will work fine on + * any platform. If the ExifTool executable is named something else or not + * in the system path, then this property will need to be set to point at it + * before using this class. *

* This system property can be set on startup with:
* * -Dexiftool.path=/path/to/exiftool - * or by calling {@link System#setProperty(String, String)} before this class is loaded. + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. *

- * On Windows be sure to double-escape the path to the tool, for example: + * On Windows be sure to double-escape the path to the tool, for example: + * * -Dexiftool.path=C:\\Tools\\exiftool.exe * *

* Default value is "exiftool". *

Relative Paths

- * Relative path values (e.g. "bin/tools/exiftool") are executed with relation to the base directory the VM process - * was started in. Essentially the directory that new File(".").getAbsolutePath() points at during - * runtime. + * Relative path values (e.g. "bin/tools/exiftool") are executed with + * relation to the base directory the VM process was started in. Essentially + * the directory that new File(".").getAbsolutePath() points at + * during runtime. */ - private final String exifCmd; + private final String exifCmd; /** * Interval (in milliseconds) of inactivity before the cleanup thread wakes @@ -230,37 +278,41 @@ public class ExifTool * used to communicate with it when the {@link Feature#STAY_OPEN} feature is * used. *

- * Ever time a call to getImageMeta is processed, the timer keeping track of cleanup is reset; more - * specifically, this class has to experience no activity for this duration of time before the cleanup process is - * fired up and cleans up the host OS process and the stream resources. + * Ever time a call to getImageMeta is processed, the timer + * keeping track of cleanup is reset; more specifically, this class has to + * experience no activity for this duration of time before the cleanup + * process is fired up and cleans up the host OS process and the stream + * resources. *

- * Any subsequent calls to getImageMeta after a cleanup simply re-initializes the resources. + * Any subsequent calls to getImageMeta after a cleanup simply + * re-initializes the resources. *

* This system property can be set on startup with:
* * -Dexiftool.processCleanupDelay=600000 - * or by calling {@link System#setProperty(String, String)} before this class is loaded. + *
or by calling {@link System#setProperty(String, String)} before + * this class is loaded. *

- * Setting this value to 0 disables the automatic cleanup thread completely and the caller will need to manually - * cleanup the external ExifTool process and read/write streams by calling {@link #close()}. + * Setting this value to 0 disables the automatic cleanup thread completely + * and the caller will need to manually cleanup the external ExifTool + * process and read/write streams by calling {@link #close()}. *

* Default value is 600,000 (10 minutes). */ - private final long processCleanupDelay; - - private final Map featureSupportedMap = new HashMap(); - private final Set featureSet = EnumSet.noneOf( Feature.class); - private final ReentrantLock lock = new ReentrantLock(); - private final VersionNumber exifVersion; - private final Timer cleanupTimer; - private TimerTask currentCleanupTask = null; - private AtomicBoolean shuttingDown = new AtomicBoolean( false); - private volatile ExifProcess process; - private int timeoutWhenKeepAlive = 0; - - public ExifTool() - { - this( (Feature[])null); + private final long processCleanupDelay; + + private final Map featureSupportedMap = new HashMap(); + private final Set featureSet = EnumSet.noneOf(Feature.class); + private final ReentrantLock lock = new ReentrantLock(); + private final VersionNumber exifVersion; + private final Timer cleanupTimer; + private TimerTask currentCleanupTask = null; + private AtomicBoolean shuttingDown = new AtomicBoolean(false); + private volatile ExifProcess process; + private int timeoutWhenKeepAlive = 0; + + public ExifTool() { + this((Feature[]) null); } /** @@ -268,34 +320,32 @@ public ExifTool() * system properties exiftool.path and exiftool.processCleanupDelay. * processCleanupDelay is optional. If not found, the default is used. */ - public ExifTool(Feature... features) - { - this( System.getProperty( ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, - DEFAULT_PROCESS_CLEANUP_DELAY), features); + public ExifTool(Feature... features) { + this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( + ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, + DEFAULT_PROCESS_CLEANUP_DELAY), features); } - public ExifTool(String exifToolPath) - { - this( exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[])null); + public ExifTool(String exifToolPath) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); } - public ExifTool(String exifToolPath, Feature... features) - { - this( exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); + public ExifTool(String exifToolPath, Feature... features) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); } - public ExifTool(String exifCmd, long processCleanupDelay, Feature... features) - { + public ExifTool(String exifCmd, long processCleanupDelay, + Feature... features) { this.exifCmd = exifCmd; this.processCleanupDelay = processCleanupDelay; - this.exifVersion = ExifProcess.readVersion( exifCmd); - if( features != null && features.length > 0) - { - for( Feature feature : features) - { - if( !feature.isSupported( exifVersion)) { throw new UnsupportedFeatureException( feature); } - this.featureSet.add( feature); - this.featureSupportedMap.put( feature, true); + this.exifVersion = ExifProcess.readVersion(exifCmd); + if (features != null && features.length > 0) { + for (Feature feature : features) { + if (!feature.isSupported(exifVersion)) { + throw new UnsupportedFeatureException(feature); + } + this.featureSet.add(feature); + this.featureSupportedMap.put(feature, true); } } @@ -303,12 +353,9 @@ public ExifTool(String exifCmd, long processCleanupDelay, Feature... features) * Now that initialization is done, init the cleanup timer if we are * using STAY_OPEN and the delay time set is non-zero. */ - if( isFeatureEnabled( Feature.STAY_OPEN)) - { - cleanupTimer = new Timer( CLEANUP_THREAD_NAME, true); - } - else - { + if (isFeatureEnabled(Feature.STAY_OPEN)) { + cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); + } else { cleanupTimer = null; } } @@ -317,8 +364,7 @@ public ExifTool(String exifCmd, long processCleanupDelay, Feature... features) * Limits the amount of time (in mills) an exif operation can take. Setting * value to greater than 0 to enable. */ - public ExifTool setRunTimeout(int mills) - { + public ExifTool setRunTimeout(int mills) { timeoutWhenKeepAlive = mills; return this; } @@ -327,41 +373,44 @@ public ExifTool setRunTimeout(int mills) * Used to determine if the given {@link Feature} is supported by the * underlying native install of ExifTool pointed at by {@link #exifCmd}. *

- * If support for the given feature has not been checked for yet, this method will automatically call out to - * ExifTool and ensure the requested feature is supported in the current local install. + * If support for the given feature has not been checked for yet, this + * method will automatically call out to ExifTool and ensure the requested + * feature is supported in the current local install. *

- * The external call to ExifTool to confirm feature support is only ever done once per JVM session and stored in a - * static final {@link Map} that all instances of this class share. + * The external call to ExifTool to confirm feature support is only ever + * done once per JVM session and stored in a static final + * {@link Map} that all instances of this class share. * * @param feature - * The feature to check support for in the underlying ExifTool - * install. + * The feature to check support for in the underlying ExifTool + * install. * * @return true if support for the given {@link Feature} was - * confirmed to work with the currently installed ExifTool or false if it is not supported. + * confirmed to work with the currently installed ExifTool or + * false if it is not supported. * * @throws IllegalArgumentException - * if feature is null. + * if feature is null. * @throws RuntimeException - * if any exception occurs while attempting to start the - * external ExifTool process to verify feature support. + * if any exception occurs while attempting to start the + * external ExifTool process to verify feature support. */ - public boolean isFeatureSupported(Feature feature) throws RuntimeException - { - if( feature == null) { throw new IllegalArgumentException( "feature cannot be null"); } + public boolean isFeatureSupported(Feature feature) throws RuntimeException { + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); + } - Boolean supported = featureSupportedMap.get( feature); + Boolean supported = featureSupportedMap.get(feature); /* * If there is no Boolean flag for the feature, support for it hasn't * been checked yet with the native ExifTool install, so we need to do * that. */ - if( supported == null) - { - log.debug( "Support for feature %s has not been checked yet, checking..."); - supported = feature.isSupported( exifVersion); - featureSupportedMap.put( feature, supported); + if (supported == null) { + log.debug("Support for feature %s has not been checked yet, checking..."); + supported = feature.isSupported(exifVersion); + featureSupportedMap.put(feature, supported); } return supported; @@ -373,56 +422,45 @@ public boolean isFeatureSupported(Feature feature) throws RuntimeException * enabled. This method has no effect if the stay open feature is not * enabled. */ - public void startup() - { - if( featureSet.contains( Feature.STAY_OPEN)) - { - shuttingDown.set( false); + public void startup() { + if (featureSet.contains(Feature.STAY_OPEN)) { + shuttingDown.set(false); ensureProcessRunning(); } } - private void ensureProcessRunning() - { - if( process == null || process.isClosed()) - { - synchronized( this) - { - if( process == null || process.isClosed()) - { - log.debug( "Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = ExifProcess.startup( exifCmd); + private void ensureProcessRunning() { + if (process == null || process.isClosed()) { + synchronized (this) { + if (process == null || process.isClosed()) { + log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = ExifProcess.startup(exifCmd); } } } - if( processCleanupDelay > 0) - { - synchronized( this) - { - if( currentCleanupTask != null) - { + if (processCleanupDelay > 0) { + synchronized (this) { + if (currentCleanupTask != null) { currentCleanupTask.cancel(); currentCleanupTask = null; } - currentCleanupTask = new TimerTask() - { + currentCleanupTask = new TimerTask() { @Override - public void run() - { - log.info( "Auto cleanup task running..."); + public void run() { + log.info("Auto cleanup task running..."); process.close(); } }; - cleanupTimer.schedule( currentCleanupTask, processCleanupDelay); + cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); } } } /** - * This is same as {@link #close()}, added for consistency with {@link #startup()} + * This is same as {@link #close()}, added for consistency with + * {@link #startup()} */ - public void shutdown() - { + public void shutdown() { close(); } @@ -431,32 +469,30 @@ public void shutdown() * streams used to communicate with it when {@link Feature#STAY_OPEN} is * enabled. *

- * NOTE: Calling this method does not preclude this instance of {@link ExifTool} from being - * re-used, it merely disposes of the native and internal resources until the next call to getImageMeta - * causes them to be re-instantiated. + * NOTE: Calling this method does not preclude this + * instance of {@link ExifTool} from being re-used, it merely disposes of + * the native and internal resources until the next call to + * getImageMeta causes them to be re-instantiated. *

- * The cleanup thread will automatically call this after an interval of inactivity defined by - * {@link #processCleanupDelay}. + * The cleanup thread will automatically call this after an interval of + * inactivity defined by {@link #processCleanupDelay}. *

- * Calling this method on an instance of this class without {@link Feature#STAY_OPEN} support enabled has no effect. + * Calling this method on an instance of this class without + * {@link Feature#STAY_OPEN} support enabled has no effect. */ - public synchronized void close() - { - shuttingDown.set( true); - if( process != null) - { + public synchronized void close() { + shuttingDown.set(true); + if (process != null) { process.close(); } - if( currentCleanupTask != null) - { + if (currentCleanupTask != null) { currentCleanupTask.cancel(); currentCleanupTask = null; } } - public boolean isStayOpen() - { - return featureSet.contains( Feature.STAY_OPEN); + public boolean isStayOpen() { + return featureSet.contains(Feature.STAY_OPEN); } /** @@ -464,15 +500,16 @@ public boolean isStayOpen() * enabled, this method is used to determine if there is currently a running * ExifTool process associated with this class. *

- * Any dependent processes and streams can be shutdown using {@link #close()} and this class will automatically - * re-create them on the next call to getImageMeta if necessary. + * Any dependent processes and streams can be shutdown using + * {@link #close()} and this class will automatically re-create them on the + * next call to getImageMeta if necessary. * * @return true if there is an external ExifTool process in - * daemon mode associated with this class utilizing the {@link Feature#STAY_OPEN} feature, otherwise returns + * daemon mode associated with this class utilizing the + * {@link Feature#STAY_OPEN} feature, otherwise returns * false. */ - public boolean isRunning() - { + public boolean isRunning() { return process != null && !process.isClosed(); } @@ -480,93 +517,101 @@ public boolean isRunning() * Used to determine if the given {@link Feature} has been enabled for this * particular instance of {@link ExifTool}. *

- * This method is different from {@link #isFeatureSupported(Feature)}, which checks if the given feature is - * supported by the underlying ExifTool install where as this method tells the caller if the given feature has been - * enabled for use in this particular instance. + * This method is different from {@link #isFeatureSupported(Feature)}, which + * checks if the given feature is supported by the underlying ExifTool + * install where as this method tells the caller if the given feature has + * been enabled for use in this particular instance. * * @param feature - * The feature to check if it has been enabled for us or not on - * this instance. + * The feature to check if it has been enabled for us or not on + * this instance. * * @return true if the given {@link Feature} is currently - * enabled on this instance of {@link ExifTool}, otherwise returns false. + * enabled on this instance of {@link ExifTool}, otherwise returns + * false. * * @throws IllegalArgumentException - * if feature is null. + * if feature is null. */ - public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException - { - if( feature == null) { throw new IllegalArgumentException( "feature cannot be null"); } - return featureSet.contains( feature); + public boolean isFeatureEnabled(Feature feature) + throws IllegalArgumentException { + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); + } + return featureSet.contains(feature); } - public Map getImageMeta(File image, Tag... tags) throws IllegalArgumentException, SecurityException, IOException - { + public Map getImageMeta(File image, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { - return getImageMeta( image, Format.NUMERIC, tags); + return getImageMeta(image, Format.NUMERIC, tags); } - public Map getImageMeta(File image, Format format, Tag... tags) throws IllegalArgumentException, SecurityException, - IOException - { + public Map getImageMeta(File image, Format format, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { String[] stringTags = new String[tags.length]; int i = 0; - for( Tag tag : tags) - { + for (Tag tag : tags) { stringTags[i++] = tag.getName(); } - Map result = getImageMeta( image, format, true, stringTags); - return mapByTag( result); + Map result = getImageMeta(image, format, true, + stringTags); + return mapByTag(result); } - public Map getImageMeta(File image, Format format, TagGroup... tags) throws IllegalArgumentException, - SecurityException, IOException - { + public Map getImageMeta(File image, Format format, + TagGroup... tags) throws IllegalArgumentException, + SecurityException, IOException { String[] stringTags = new String[tags.length]; int i = 0; - for( TagGroup tag : tags) - { + for (TagGroup tag : tags) { stringTags[i++] = tag.getValue(); } - return getImageMeta( image, format, false, stringTags); + return getImageMeta(image, format, false, stringTags); } - private Map getImageMeta(final File image, final Format format, final boolean suppressDuplicates, final String... tags) - throws IllegalArgumentException, SecurityException, IOException - { + private Map getImageMeta(final File image, + final Format format, final boolean suppressDuplicates, + final String... tags) throws IllegalArgumentException, + SecurityException, IOException { // Validate input and create Arg Array - final boolean stayOpen = featureSet.contains( Feature.STAY_OPEN); - List args = new ArrayList( tags.length + 4); - if( format == null) - { - throw new IllegalArgumentException( "format cannot be null"); - } - else if( format == Format.NUMERIC) - { - args.add( "-n"); // numeric output + final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + List args = new ArrayList(tags.length + 4); + if (format == null) { + throw new IllegalArgumentException("format cannot be null"); + } else if (format == Format.NUMERIC) { + args.add("-n"); // numeric output } - if( !suppressDuplicates) - { - args.add( "-a"); // suppress duplicates + if (!suppressDuplicates) { + args.add("-a"); // suppress duplicates } - args.add( "-S"); // compact output + args.add("-S"); // compact output - if( tags == null || tags.length == 0) { throw new IllegalArgumentException( - "tags cannot be null and must contain 1 or more Tag to query the image for."); } - for( String tag : tags) - { - args.add( "-" + tag); + if (tags == null || tags.length == 0) { + throw new IllegalArgumentException( + "tags cannot be null and must contain 1 or more Tag to query the image for."); + } + for (String tag : tags) { + args.add("-" + tag); + } + if (image == null) { + throw new IllegalArgumentException( + "image cannot be null and must be a valid stream of image data."); } - if( image == null) { throw new IllegalArgumentException( "image cannot be null and must be a valid stream of image data."); } - if( !image.canRead()) { throw new SecurityException( "Unable to read the given image [" + image.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); } - args.add( image.getAbsolutePath()); + if (!image.canRead()) { + throw new SecurityException( + "Unable to read the given image [" + + image.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + } + args.add(image.getAbsolutePath()); // start process long startTime = System.currentTimeMillis(); - log.debug( String.format( "Querying %d tags from image: %s", tags.length, image.getAbsolutePath())); + log.debug(String.format("Querying %d tags from image: %s", tags.length, + image.getAbsolutePath())); /* * Using ExifTool in daemon mode (-stay_open True) executes different * code paths below. So establish the flag for this once and it is @@ -574,22 +619,20 @@ else if( format == Format.NUMERIC) * to branch to. */ Map resultMap; - if( stayOpen) - { - log.debug( "Using ExifTool in daemon mode (-stay_open True)..."); - resultMap = processStayOpen( args); - } - else - { - log.debug( "Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults( exifCmd, args); + if (stayOpen) { + log.debug("Using ExifTool in daemon mode (-stay_open True)..."); + resultMap = processStayOpen(args); + } else { + log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); + resultMap = ExifProcess.executeToResults(exifCmd, args); } // Print out how long the call to external ExifTool process took. - if( log.isDebugEnabled()) - { - log.debug( String.format( "Image Meta Processed in %d ms [queried %d tags and found %d values]", - (System.currentTimeMillis() - startTime), tags.length, resultMap.size())); + if (log.isDebugEnabled()) { + log.debug(String + .format("Image Meta Processed in %d ms [queried %d tags and found %d values]", + (System.currentTimeMillis() - startTime), + tags.length, resultMap.size())); } return resultMap; @@ -599,40 +642,39 @@ else if( format == Format.NUMERIC) * extract image metadata to exiftool's internal xml format. * * @param input - * the input file + * the input file * @return command output as xml string * @throws IOException - * Signals that an I/O exception has occurred. + * Signals that an I/O exception has occurred. */ - public String getImageMetadataXml(File input, boolean includeBinary) throws IOException - { + public String getImageMetadataXml(File input, boolean includeBinary) + throws IOException { List args = new ArrayList(); - args.add( "-X"); - if( includeBinary) - args.add( "-b"); - args.add( input.getAbsolutePath()); + args.add("-X"); + if (includeBinary) + args.add("-b"); + args.add(input.getAbsolutePath()); - return ExifProcess.executeToString( exifCmd, args); + return ExifProcess.executeToString(exifCmd, args); } /** * extract image metadata to exiftool's internal xml format. * * @param input - * the input file + * the input file * @param output - * the output file + * the output file * @throws IOException - * Signals that an I/O exception has occurred. + * Signals that an I/O exception has occurred. */ - public void getImageMetadataXml(File input, File output, boolean includeBinary) throws IOException - { + public void getImageMetadataXml(File input, File output, + boolean includeBinary) throws IOException { - String result = getImageMetadataXml( input, includeBinary); + String result = getImageMetadataXml(input, includeBinary); - try (FileWriter w = new FileWriter( output)) - { - w.write( result); + try (FileWriter w = new FileWriter(output)) { + w.write(result); } } @@ -640,56 +682,57 @@ public void getImageMetadataXml(File input, File output, boolean includeBinary) * output icc profile from input to output. * * @param input - * the input file + * the input file * @param output - * the output file for icc data + * the output file for icc data * @return the command result from standard output e.g. * "1 output files created" * @throws IOException - * Signals that an I/O exception has occurred. + * Signals that an I/O exception has occurred. */ - public String extractImageIccProfile(File input, File output) throws IOException - { + public String extractImageIccProfile(File input, File output) + throws IOException { List args = new ArrayList(); - args.add( "-icc_profile"); - args.add( input.getAbsolutePath()); + args.add("-icc_profile"); + args.add(input.getAbsolutePath()); - args.add( "-o"); - args.add( output.getAbsolutePath()); + args.add("-o"); + args.add(output.getAbsolutePath()); - return ExifProcess.executeToString( exifCmd, args); + return ExifProcess.executeToString(exifCmd, args); } /** * Extract thumbnail from the given tag. * * @param input - * the input file + * the input file * @param tag - * the tag containing binary data PhotoshopThumbnail or ThumbnailImage + * the tag containing binary data PhotoshopThumbnail or + * ThumbnailImage * @return the thumbnail file created. it is in the same folder as the input * file because of the syntax of exiftool and has the suffix * ".thumb.jpg" * @throws IOException - * Signals that an I/O exception has occurred. + * Signals that an I/O exception has occurred. */ - public File extractThumbnail(File input, Tag tag) throws IOException - { + public File extractThumbnail(File input, Tag tag) throws IOException { List args = new ArrayList(); String suffix = ".thumb.jpg"; - String thumbname = FilenameUtils.getBaseName( input.getName()) + suffix; - - args.add( "-" + tag.getName()); - args.add( input.getAbsolutePath()); - args.add( "-b"); - args.add( "-w"); - args.add( suffix); - String result = ExifProcess.executeToString( exifCmd, args); - File thumbnail = new File( input.getParent() + File.separator + thumbname); - if( !thumbnail.exists()) - throw new IOException( "could not create thumbnail: " + result); + String thumbname = FilenameUtils.getBaseName(input.getName()) + suffix; + + args.add("-" + tag.getName()); + args.add(input.getAbsolutePath()); + args.add("-b"); + args.add("-w"); + args.add(suffix); + String result = ExifProcess.executeToString(exifCmd, args); + File thumbnail = new File(input.getParent() + File.separator + + thumbname); + if (!thumbnail.exists()) + throw new IOException("could not create thumbnail: " + result); return thumbnail; } @@ -697,65 +740,56 @@ public File extractThumbnail(File input, Tag tag) throws IOException * Will attempt 3 times to use the running exif process, and if unable to * complete successfully will throw IOException */ - private Map processStayOpen(List args) throws IOException - { + private Map processStayOpen(List args) + throws IOException { int attempts = 0; - while( attempts < 3 && !shuttingDown.get()) - { + while (attempts < 3 && !shuttingDown.get()) { attempts++; // make sure process is started ensureProcessRunning(); TimerTask attemptTimer = null; - try - { - if( timeoutWhenKeepAlive > 0) - { - attemptTimer = new TimerTask() - { + try { + if (timeoutWhenKeepAlive > 0) { + attemptTimer = new TimerTask() { @Override - public void run() - { - log.warn( "Process ran too long closing, max " + timeoutWhenKeepAlive + " mills"); + public void run() { + log.warn("Process ran too long closing, max " + + timeoutWhenKeepAlive + " mills"); process.close(); } }; - cleanupTimer.schedule( attemptTimer, timeoutWhenKeepAlive); + cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); } - log.debug( "Streaming arguments to ExifTool process..."); - return process.sendArgs( args); - } - catch( IOException ex) - { - if( STREAM_CLOSED_MESSAGE.equals( ex.getMessage()) && !shuttingDown.get()) - { + log.debug("Streaming arguments to ExifTool process..."); + return process.sendArgs(args); + } catch (IOException ex) { + if (STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) + && !shuttingDown.get()) { // only catch "Stream Closed" error (happens when process // has died) - log.warn( String.format( "Caught IOException(\"%s\"), will restart daemon", STREAM_CLOSED_MESSAGE)); + log.warn(String.format( + "Caught IOException(\"%s\"), will restart daemon", + STREAM_CLOSED_MESSAGE)); process.close(); - } - else - { + } else { throw ex; } - } - finally - { - if( attemptTimer != null) + } finally { + if (attemptTimer != null) attemptTimer.cancel(); } } - if( shuttingDown.get()) { throw new IOException( "Shutting Down"); } - throw new IOException( "Ran out of attempts"); + if (shuttingDown.get()) { + throw new IOException("Shutting Down"); + } + throw new IOException("Ran out of attempts"); } - private static Map mapByTag(Map stringMap) - { - Map tagMap = new HashMap( Tag.values().length); - for( Tag tag : Tag.values()) - { - if( stringMap.containsKey( tag.getName())) - { - tagMap.put( tag, stringMap.get( tag.getName())); + private static Map mapByTag(Map stringMap) { + Map tagMap = new HashMap(Tag.values().length); + for (Tag tag : Tag.values()) { + if (stringMap.containsKey(tag.getName())) { + tagMap.put(tag, stringMap.get(tag.getName())); } } return tagMap; @@ -765,143 +799,129 @@ private static Map mapByTag(Map stringMap) /** * Represents an Exif Process. */ - public static class ExifProcess - { - private final ReentrantLock closeLock = new ReentrantLock( false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; - private volatile boolean closed = false; - - public static VersionNumber readVersion(String exifCmd) - { - ExifProcess process = _execute( false, Arrays.asList( exifCmd, "-ver")); - try - { - return new VersionNumber( process.readLine()); - } - catch( IOException ex) - { - throw new RuntimeException( String.format( "Unable to check version number of ExifTool: %s", exifCmd)); - } - finally - { + public static class ExifProcess { + private final ReentrantLock closeLock = new ReentrantLock(false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader reader; + private final OutputStreamWriter writer; + private volatile boolean closed = false; + + public static VersionNumber readVersion(String exifCmd) { + ExifProcess process = _execute(false, + Arrays.asList(exifCmd, "-ver")); + try { + return new VersionNumber(process.readLine()); + } catch (IOException ex) { + throw new RuntimeException(String.format( + "Unable to check version number of ExifTool: %s", + exifCmd)); + } finally { process.close(); } } - public static Map executeToResults(String exifCmd, List args) throws IOException - { - List newArgs = new ArrayList( args.size() + 1); - newArgs.add( exifCmd); - newArgs.addAll( args); - ExifProcess process = _execute( false, newArgs); - try - { + public static Map executeToResults(String exifCmd, + List args) throws IOException { + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { return process.readResponse(); - } - finally - { + } finally { process.close(); } } - public static String executeToString(String exifCmd, List args) throws IOException - { - List newArgs = new ArrayList( args.size() + 1); - newArgs.add( exifCmd); - newArgs.addAll( args); - ExifProcess process = _execute( false, newArgs); - try - { + public static String executeToString(String exifCmd, List args) + throws IOException { + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { return process.readResponseString(); - } - finally - { + } finally { process.close(); } } - public static ExifProcess startup(String exifCmd) - { - List args = Arrays.asList( exifCmd, "-stay_open", "True", "-@", "-"); - return _execute( true, args); + public static ExifProcess startup(String exifCmd) { + List args = Arrays.asList(exifCmd, "-stay_open", "True", + "-@", "-"); + return _execute(true, args); } - public static ExifProcess _execute(boolean keepAlive, List args) - { - log.debug( String.format( "Attempting to start external ExifTool process using args: %s", args)); - try - { - Process process = new ProcessBuilder( args).start(); - log.debug( "\tSuccessful"); - return new ExifProcess( keepAlive, process); - } - catch( Exception e) - { - String message = "Unable to start external ExifTool process using the execution arguments: " + args - + ". Ensure ExifTool is installed correctly and runs using the command path '" + args.get( 0) - + "' as specified by the 'exiftool.path' system property."; - - log.debug( message); - throw new RuntimeException( message, e); + public static ExifProcess _execute(boolean keepAlive, List args) { + log.debug(String + .format("Attempting to start external ExifTool process using args: %s", + args)); + try { + Process process = new ProcessBuilder(args).start(); + log.debug("\tSuccessful"); + return new ExifProcess(keepAlive, process); + } catch (Exception e) { + String message = "Unable to start external ExifTool process using the execution arguments: " + + args + + ". Ensure ExifTool is installed correctly and runs using the command path '" + + args.get(0) + + "' as specified by the 'exiftool.path' system property."; + + log.debug(message); + throw new RuntimeException(message, e); } } - public ExifProcess(boolean keepAlive, Process process) - { + public ExifProcess(boolean keepAlive, Process process) { this.keepAlive = keepAlive; this.process = process; - this.reader = new BufferedReader( new InputStreamReader( process.getInputStream())); - this.writer = new OutputStreamWriter( process.getOutputStream()); + this.reader = new BufferedReader(new InputStreamReader( + process.getInputStream())); + this.writer = new OutputStreamWriter(process.getOutputStream()); } - public synchronized Map sendArgs(List args) throws IOException - { + public synchronized Map sendArgs(List args) + throws IOException { StringBuilder builder = new StringBuilder(); - for( String arg : args) - { - builder.append( arg).append( "\n"); + for (String arg : args) { + builder.append(arg).append("\n"); } - builder.append( "-execute\n"); - writeFlush( builder.toString()); + builder.append("-execute\n"); + writeFlush(builder.toString()); return readResponse(); } - public synchronized void writeFlush(String message) throws IOException - { - if( closed) - throw new IOException( STREAM_CLOSED_MESSAGE); - writer.write( message); + public synchronized void writeFlush(String message) throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + writer.write(message); writer.flush(); } - public synchronized String readLine() throws IOException - { - if( closed) - throw new IOException( STREAM_CLOSED_MESSAGE); + public synchronized String readLine() throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); return reader.readLine(); } - public synchronized Map readResponse() throws IOException - { - if( closed) - throw new IOException( STREAM_CLOSED_MESSAGE); - log.debug( "Reading response back from ExifTool..."); - Map resultMap = new HashMap( 500); + public synchronized Map readResponse() + throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + log.debug("Reading response back from ExifTool..."); + Map resultMap = new HashMap(500); String line; - while( (line = reader.readLine()) != null) - { - if( closed) - throw new IOException( STREAM_CLOSED_MESSAGE); - String[] pair = TAG_VALUE_PATTERN.split( line, 2); + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + String[] pair = TAG_VALUE_PATTERN.split(line, 2); - if( pair.length == 2) - { - resultMap.put( pair[0], pair[1]); - log.debug( String.format( "\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); + if (pair.length == 2) { + resultMap.put(pair[0], pair[1]); + log.debug(String.format("\tRead Tag [name=%s, value=%s]", + pair[0], pair[1])); } /* @@ -911,25 +931,22 @@ public synchronized Map readResponse() throws IOException * otherwise this process will hang indefinitely blocking on the * input stream with no data to read. */ - if( keepAlive && line.equals( "{ready}")) - { + if (keepAlive && line.equals("{ready}")) { break; } } return resultMap; } - public synchronized String readResponseString() throws IOException - { - if( closed) - throw new IOException( STREAM_CLOSED_MESSAGE); - log.debug( "Reading response back from ExifTool..."); + public synchronized String readResponseString() throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + log.debug("Reading response back from ExifTool..."); String line; StringBuilder result = new StringBuilder(); - while( (line = reader.readLine()) != null) - { - if( closed) - throw new IOException( STREAM_CLOSED_MESSAGE); + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); /* * When using a persistent ExifTool process, it terminates its @@ -938,79 +955,58 @@ public synchronized String readResponseString() throws IOException * otherwise this process will hang indefinitely blocking on the * input stream with no data to read. */ - if( keepAlive && line.equals( "{ready}")) - { + if (keepAlive && line.equals("{ready}")) { break; - } - else - result.append( line); + } else + result.append(line); } return result.toString(); } - public boolean isClosed() - { + public boolean isClosed() { return closed; } - public void close() - { - if( !closed) - { + public void close() { + if (!closed) { closeLock.lock(); - try - { - if( !closed) - { + try { + if (!closed) { closed = true; - log.debug( "Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - try - { - writer.write( "-stay_open\nFalse\n"); + log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); + try { + writer.write("-stay_open\nFalse\n"); writer.flush(); - } - catch( IOException ex) - { + } catch (IOException ex) { // log.error(ex,ex); } - try - { - log.debug( "Closing Read stream..."); + try { + log.debug("Closing Read stream..."); reader.close(); - log.debug( "\tSuccessful"); - } - catch( Exception e) - { + log.debug("\tSuccessful"); + } catch (Exception e) { // no-op, just try to close it. } - try - { - log.debug( "Closing Write stream..."); + try { + log.debug("Closing Write stream..."); writer.close(); - log.debug( "\tSuccessful"); - } - catch( Exception e) - { + log.debug("\tSuccessful"); + } catch (Exception e) { // no-op, just try to close it. } - log.debug( "Read/Write streams successfully closed."); + log.debug("Read/Write streams successfully closed."); - try - { + try { process.destroy(); - } - catch( Exception e) - { + } catch (Exception e) { // } // process = null; } - } - finally - { + } finally { closeLock.unlock(); } } @@ -1022,15 +1018,15 @@ public void close() * Enum used to define the different kinds of features in the native * ExifTool executable that this class can help you take advantage of. *

- * These flags are different from {@link Tag}s in that a "feature" is determined to be a special functionality of - * the underlying ExifTool executable that requires a different code-path in this class to take advantage of; for - * example, -stay_open True support. + * These flags are different from {@link Tag}s in that a "feature" is + * determined to be a special functionality of the underlying ExifTool + * executable that requires a different code-path in this class to take + * advantage of; for example, -stay_open True support. * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ - public enum Feature - { + public enum Feature { /** * Enum used to specify that you wish to launch the underlying ExifTool * process with -stay_open True support turned on that this @@ -1038,13 +1034,12 @@ public enum Feature *

* Required ExifTool version is 8.36 or higher. */ - STAY_OPEN( 8, 36); + STAY_OPEN(8, 36); - private VersionNumber requireVersion; + private VersionNumber requireVersion; - private Feature(int... numbers) - { - this.requireVersion = new VersionNumber( numbers); + private Feature(int... numbers) { + this.requireVersion = new VersionNumber(numbers); } /** @@ -1054,14 +1049,12 @@ private Feature(int... numbers) * @return the version of ExifTool required by this feature in order to * work. */ - VersionNumber getVersion() - { + VersionNumber getVersion() { return requireVersion; } - boolean isSupported(VersionNumber exifVersionNumber) - { - return requireVersion.isBeforeOrEqualTo( exifVersionNumber); + boolean isSupported(VersionNumber exifVersionNumber) { + return requireVersion.isBeforeOrEqualTo(exifVersionNumber); } } @@ -1069,35 +1062,29 @@ boolean isSupported(VersionNumber exifVersionNumber) /** * Version Number used to determine if one version is after another. */ - static class VersionNumber - { - private final int[] numbers; + static class VersionNumber { + private final int[] numbers; - public VersionNumber(String str) - { - String[] versionParts = str.trim().split( "\\."); + public VersionNumber(String str) { + String[] versionParts = str.trim().split("\\."); this.numbers = new int[versionParts.length]; - for( int i = 0; i < versionParts.length; i++) - { - numbers[i] = Integer.parseInt( versionParts[i]); + for (int i = 0; i < versionParts.length; i++) { + numbers[i] = Integer.parseInt(versionParts[i]); } } - public VersionNumber(int... numbers) - { + public VersionNumber(int... numbers) { this.numbers = numbers; } - public boolean isBeforeOrEqualTo(VersionNumber other) - { - int max = Math.min( this.numbers.length, other.numbers.length); - for( int i = 0; i < max; i++) - { - if( this.numbers[i] > other.numbers[i]) - { + public boolean isBeforeOrEqualTo(VersionNumber other) { + int max = Math.min(this.numbers.length, other.numbers.length); + for (int i = 0; i < max; i++) { + if (this.numbers[i] > other.numbers[i]) { return false; + } else if (this.numbers[i] < other.numbers[i]) { + return true; } - else if( this.numbers[i] < other.numbers[i]) { return true; } } // assume missing number as zero, so if the current process number // is more digits it is a higher version @@ -1105,16 +1092,13 @@ public boolean isBeforeOrEqualTo(VersionNumber other) } @Override - public String toString() - { + public String toString() { StringBuilder builder = new StringBuilder(); - for( int i = 0; i < numbers.length; i++) - { - if( builder.length() > 0) - { - builder.append( "."); + for (int i = 0; i < numbers.length; i++) { + if (builder.length() > 0) { + builder.append("."); } - builder.append( numbers[i]); + builder.append(numbers[i]); } return builder.toString(); } @@ -1122,34 +1106,42 @@ public String toString() // ================================================================================ /** - * Enum used to define the 2 different output formats that {@link Tag} values can be returned in: numeric or - * human-readable text. + * Enum used to define the 2 different output formats that {@link Tag} + * values can be returned in: numeric or human-readable text. *

- * ExifTool, via the -n command line arg, is capable of returning most values in their raw numeric form - * (e.g. Aperture="2.8010323841") as well as a more human-readable/friendly format (e.g. Aperture="2.8"). + * ExifTool, via the -n command line arg, is capable of + * returning most values in their raw numeric form (e.g. + * Aperture="2.8010323841") as well as a more human-readable/friendly format + * (e.g. Aperture="2.8"). *

- * While the {@link Tag}s defined on this class do provide a hint at the type of the result (see - * {@link Tag#getType()}), that hint only applies when the {@link Format#NUMERIC} form of the value is returned. + * While the {@link Tag}s defined on this class do provide a hint at the + * type of the result (see {@link Tag#getType()}), that hint only applies + * when the {@link Format#NUMERIC} form of the value is returned. *

- * If the caller finds the human-readable format easier to process, {@link Format#HUMAN_READABLE} can be specified - * when calling {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned {@link String} values processed - * manually by the caller. + * If the caller finds the human-readable format easier to process, + * {@link Format#HUMAN_READABLE} can be specified when calling + * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned + * {@link String} values processed manually by the caller. *

- * In order to see the types of values that are returned when {@link Format#HUMAN_READABLE} is used, you can check - * the comprehensive ExifTool Tag - * Guide. + * In order to see the types of values that are returned when + * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive + * ExifTool Tag Guide. *

- * This makes sense with some values like Aperture that in {@link Format#NUMERIC} format end up returning as - * 14-decimal-place, high precision values that are near the intended value (e.g. "2.79999992203711" instead of just - * returning "2.8"). On the other hand, other values (like Orientation) are easier to parse when their numeric value - * (1-8) is returned instead of a much longer friendly name (e.g. "Mirror horizontal and rotate 270 CW"). + * This makes sense with some values like Aperture that in + * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high + * precision values that are near the intended value (e.g. + * "2.79999992203711" instead of just returning "2.8"). On the other hand, + * other values (like Orientation) are easier to parse when their numeric + * value (1-8) is returned instead of a much longer friendly name (e.g. + * "Mirror horizontal and rotate 270 CW"). * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ - public enum Format - { - NUMERIC, HUMAN_READABLE + public enum Format { + NUMERIC, + HUMAN_READABLE } // ================================================================================ @@ -1158,117 +1150,127 @@ public enum Format * extracted from images using this class with an external install of * ExifTool. *

- * Each tag defined also includes a type hint for the parsed value associated with it when the default - * {@link Format#NUMERIC} value format is used. + * Each tag defined also includes a type hint for the parsed value + * associated with it when the default {@link Format#NUMERIC} value format + * is used. *

- * All replies from ExifTool are parsed as {@link String}s and using the type hint from each {@link Tag} can easily - * be converted to the correct data format by using the provided {@link Tag#parseValue(String)} method. + * All replies from ExifTool are parsed as {@link String}s and using the + * type hint from each {@link Tag} can easily be converted to the correct + * data format by using the provided {@link Tag#parseValue(String)} method. *

- * This class does not make an attempt at converting the value automatically in case the caller decides they would - * prefer tag values returned in {@link Format#HUMAN_READABLE} format and to avoid any compatibility issues with - * future versions of ExifTool if a tag's return value is changed. This approach to leaving returned tag values as - * strings until the caller decides they want to parse them is a safer and more robust approach. + * This class does not make an attempt at converting the value automatically + * in case the caller decides they would prefer tag values returned in + * {@link Format#HUMAN_READABLE} format and to avoid any compatibility + * issues with future versions of ExifTool if a tag's return value is + * changed. This approach to leaving returned tag values as strings until + * the caller decides they want to parse them is a safer and more robust + * approach. *

* The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; - * the caller is free to parse or process the returned {@link String} values any way they wish. + * href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/index.html" + * >ExifTool Tag Guide by Phil Harvey; the caller is free to parse or + * process the returned {@link String} values any way they wish. *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but this class makes an attempt at - * pre-defining a convenient list of the most common tags for use. + * ExifTool is capable of parsing almost every tag known to man (1000+), but + * this class makes an attempt at pre-defining a convenient list of the most + * common tags for use. *

- * This list was determined by looking at the common metadata tag values written to images by popular mobile devices - * (iPhone, Android) as well as cameras like simple point and shoots as well as DSLRs. As an additional source of - * input the list of supported/common EXIF formats that Flickr supports was also reviewed to ensure the most - * common/useful tags were being covered here. + * This list was determined by looking at the common metadata tag values + * written to images by popular mobile devices (iPhone, Android) as well as + * cameras like simple point and shoots as well as DSLRs. As an additional + * source of input the list of supported/common EXIF formats that Flickr + * supports was also reviewed to ensure the most common/useful tags were + * being covered here. *

- * Please email me or file an issue if you think this - * list is missing a commonly used tag that should be added to it. + * Please email me or file an issue + * if you think this list is missing a commonly used tag that should be + * added to it. * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ - public enum Tag - { + public enum Tag { // single entry tags - APERTURE( "ApertureValue", Double.class), - AUTHOR( "XPAuthor", String.class), - COLOR_SPACE( "ColorSpace", Integer.class), - COMMENT( "XPComment", String.class), - CONTRAST( "Contrast", Integer.class), - CREATE_DATE( "CreateDate", String.class), - CREATION_DATE( "CreationDate", String.class), - DATE_CREATED( "DateCreated", String.class), - DATE_TIME_ORIGINAL( "DateTimeOriginal", String.class), - DIGITAL_ZOOM_RATIO( "DigitalZoomRatio", Double.class), - EXIF_VERSION( "ExifVersion", String.class), - EXPOSURE_COMPENSATION( "ExposureCompensation", Double.class), - EXPOSURE_PROGRAM( "ExposureProgram", Integer.class), - EXPOSURE_TIME( "ExposureTime", Double.class), - FLASH( "Flash", Integer.class), - FOCAL_LENGTH( "FocalLength", Double.class), - FOCAL_LENGTH_35MM( "FocalLengthIn35mmFormat", Integer.class), - FNUMBER( "FNumber", String.class), - GPS_ALTITUDE( "GPSAltitude", Double.class), - GPS_ALTITUDE_REF( "GPSAltitudeRef", Integer.class), - GPS_BEARING( "GPSDestBearing", Double.class), - GPS_BEARING_REF( "GPSDestBearingRef", String.class), - GPS_DATESTAMP( "GPSDateStamp", String.class), - GPS_LATITUDE( "GPSLatitude", Double.class), - GPS_LATITUDE_REF( "GPSLatitudeRef", String.class), - GPS_LONGITUDE( "GPSLongitude", Double.class), - GPS_LONGITUDE_REF( "GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD( "GPSProcessingMethod", String.class), - GPS_SPEED( "GPSSpeed", Double.class), - GPS_SPEED_REF( "GPSSpeedRef", String.class), - GPS_TIMESTAMP( "GPSTimeStamp", String.class), - IMAGE_HEIGHT( "ImageHeight", Integer.class), - IMAGE_WIDTH( "ImageWidth", Integer.class), - ISO( "ISO", Integer.class), - KEYWORDS( "XPKeywords", String.class), - LENS_MAKE( "LensMake", String.class), - LENS_MODEL( "LensModel", String.class), - MAKE( "Make", String.class), - METERING_MODE( "MeteringMode", Integer.class), - MODEL( "Model", String.class), - ORIENTATION( "Orientation", Integer.class), - OWNER_NAME( "OwnerName", String.class), - RATING( "Rating", Integer.class), - RATING_PERCENT( "RatingPercent", Integer.class), - ROTATION( "Rotation", Integer.class), - SATURATION( "Saturation", Integer.class), - SENSING_METHOD( "SensingMethod", Integer.class), - SHARPNESS( "Sharpness", Integer.class), - SHUTTER_SPEED( "ShutterSpeedValue", Double.class), - SOFTWARE( "Software", String.class), - SUBJECT( "XPSubject", String.class), - TITLE( "XPTitle", String.class), - WHITE_BALANCE( "WhiteBalance", Integer.class), - X_RESOLUTION( "XResolution", Double.class), - Y_RESOLUTION( "YResolution", Double.class), + APERTURE("ApertureValue", Double.class), + AUTHOR("XPAuthor", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATE_DATE("CreateDate", String.class), + CREATION_DATE("CreationDate", String.class), + DATE_CREATED("DateCreated", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + FLASH("Flash", Integer.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + FNUMBER("FNumber", String.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_DATESTAMP("GPSDateStamp", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SENSING_METHOD("SensingMethod", Integer.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), // select ICC metadata - ICC_DESCRIPTION( "ProfileDescription", String.class), - ICC_COLORSPACEDATA( "ColorSpaceData", String.class), + ICC_DESCRIPTION("ProfileDescription", String.class), + ICC_COLORSPACEDATA("ColorSpaceData", String.class), // actually binary data, but what are we doing to do here??? Just use to // save to file... - THUMBNAIL_IMAGE( "ThumbnailImage", String.class), - THUMBNAIL_PHOTOSHOP( "PhotoshopThumbnail", String.class); + THUMBNAIL_IMAGE("ThumbnailImage", String.class), + THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class); /** * Used to get the {@link Tag} identified by the given, case-sensitive, * tag name. * * @param name - * The case-sensitive name of the tag that will be searched - * for. + * The case-sensitive name of the tag that will be searched + * for. * * @return the {@link Tag} identified by the given, case-sensitive, tag * name or null if one couldn't be found. */ - public static Tag forName(String name) - { - for( Tag tag : Tag.values()) - { - if( tag.getName().equals( name)) { return tag; } + public static Tag forName(String name) { + for (Tag tag : Tag.values()) { + if (tag.getName().equals(name)) { + return tag; + } } return null; } @@ -1279,84 +1281,67 @@ public static Tag forName(String name) * by the associated {@link Tag}. * * @param - * The type of the returned value. + * The type of the returned value. * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. + * The {@link String} representation of the tag's value as + * parsed from the image. * * @return the given string value converted to a native Java type (e.g. * Integer, Double, etc.). * * @throws IllegalArgumentException - * if tag is null. + * if tag is null. * @throws NumberFormatException - * if any exception occurs while trying to parse the given value to any of the supported - * numeric types - * in Java via calls to the respective parseXXX methods defined on all the numeric wrapper - * classes (e.g. {@link Integer#parseInt(String)} , {@link Double#parseDouble(String)} and so on). + * if any exception occurs while trying to parse the given + * value to any of the supported numeric types + * in Java via calls to the respective parseXXX + * methods defined on all the numeric wrapper classes (e.g. + * {@link Integer#parseInt(String)} , + * {@link Double#parseDouble(String)} and so on). * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type T before returning the parsed result of - * the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. + * if the type defined by T is incompatible + * with the type defined by {@link Tag#getType()} returned + * by the tag argument passed in. This class + * performs an implicit/unchecked cast to the type + * T before returning the parsed result of the + * type indicated by {@link Tag#getType()}. If the types do + * not match, a ClassCastException will be + * generated by the VM. */ @SuppressWarnings("unchecked") - public T parseValue(String value) throws IllegalArgumentException - { - - if( value != null) - { - if( Boolean.class.isAssignableFrom( this.getType())) - { - return (T)Boolean.valueOf( value); - } - else if( Byte.class.isAssignableFrom( this.getType())) - { - return (T)Byte.valueOf( Byte.parseByte( value)); + public T parseValue(String value) throws IllegalArgumentException { + + if (value != null) { + if (Boolean.class.isAssignableFrom(this.getType())) { + return (T) Boolean.valueOf(value); + } else if (Byte.class.isAssignableFrom(this.getType())) { + return (T) Byte.valueOf(Byte.parseByte(value)); + } else if (Integer.class.isAssignableFrom(this.getType())) { + return (T) Integer.valueOf(Integer.parseInt(value)); + } else if (Short.class.isAssignableFrom(this.getType())) { + return (T) Short.valueOf(Short.parseShort(value)); + } else if (Long.class.isAssignableFrom(this.getType())) { + return (T) Long.valueOf(Long.parseLong(value)); + } else if (Float.class.isAssignableFrom(this.getType())) { + return (T) Float.valueOf(Float.parseFloat(value)); + } else if (Double.class.isAssignableFrom(this.getType())) { + return (T) parseDouble(value); + } else if (Character.class.isAssignableFrom(this.getType())) { + return (T) Character.valueOf(value.charAt(0)); + } else if (String.class.isAssignableFrom(this.getType())) { + return (T) value; } - else if( Integer.class.isAssignableFrom( this.getType())) - { - return (T)Integer.valueOf( Integer.parseInt( value)); - } - else if( Short.class.isAssignableFrom( this.getType())) - { - return (T)Short.valueOf( Short.parseShort( value)); - } - else if( Long.class.isAssignableFrom( this.getType())) - { - return (T)Long.valueOf( Long.parseLong( value)); - } - else if( Float.class.isAssignableFrom( this.getType())) - { - return (T)Float.valueOf( Float.parseFloat( value)); - } - else if( Double.class.isAssignableFrom( this.getType())) - { - return (T)parseDouble( value); - } - else if( Character.class.isAssignableFrom( this.getType())) - { - return (T)Character.valueOf( value.charAt( 0)); - } - else if( String.class.isAssignableFrom( this.getType())) { return (T)value; } } return null; } - private Double parseDouble(String in) - { - if( in.contains( "/")) - { - String[] enumeratorAndDivisor = in.split( "/"); - return Double.parseDouble( enumeratorAndDivisor[0]) / Double.parseDouble( enumeratorAndDivisor[1]); - } - else - { - return Double.parseDouble( in); + private Double parseDouble(String in) { + if (in.contains("/")) { + String[] enumeratorAndDivisor = in.split("/"); + return Double.parseDouble(enumeratorAndDivisor[0]) + / Double.parseDouble(enumeratorAndDivisor[1]); + } else { + return Double.parseDouble(in); } } @@ -1365,8 +1350,7 @@ private Double parseDouble(String in) * * @return the name of the tag (e.g. "Orientation", "ISO", etc.). */ - public String getName() - { + public String getName() { return name; } @@ -1378,43 +1362,41 @@ public String getName() * * @return a hint for the native type of this tag's value. */ - public Class getType() - { + public Class getType() { return type; } - private String name; - private Class type; + private String name; + private Class type; - private Tag(String name, Class type) - { + private Tag(String name, Class type) { this.name = name; this.type = type; } } // ================================================================================ - public enum TagGroup - { - EXIF( "EXIF", "exif:all"), IPTC( "IPTC", "iptc:all"), XMP( "XMP", "xmp:all"), ALL( "ALL", "all"), FILE( "FILE", "file:all"), ICC( - "ICC", "icc_profile:all"); - - private final String name; - private final String value; - - private TagGroup(String name, String value) - { + public enum TagGroup { + EXIF("EXIF", "exif:all"), + IPTC("IPTC", "iptc:all"), + XMP("XMP", "xmp:all"), + ALL("ALL", "all"), + FILE("FILE", "file:all"), + ICC("ICC", "icc_profile:all"); + + private final String name; + private final String value; + + private TagGroup(String name, String value) { this.name = name; this.value = value; } - public String getName() - { + public String getName() { return name; } - public String getValue() - { + public String getValue() { return value; } } @@ -1428,18 +1410,16 @@ public String getValue() * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ - public class UnsupportedFeatureException extends RuntimeException - { - private static final long serialVersionUID = -1332725983656030770L; + public class UnsupportedFeatureException extends RuntimeException { + private static final long serialVersionUID = -1332725983656030770L; - public UnsupportedFeatureException(Feature feature) - { + public UnsupportedFeatureException(Feature feature) { super( - "Use of feature [" - + feature.toString() - + "] requires version " - + feature.getVersion() - + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); + "Use of feature [" + + feature.toString() + + "] requires version " + + feature.getVersion() + + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); } } diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index e286a732..8ec7233b 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -1,28 +1,31 @@ package com.thebuzzmedia.exiftool; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Tag; -import org.apache.log4j.Logger; - import java.io.File; import java.io.IOException; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.thebuzzmedia.exiftool.ExifTool.Feature; +import com.thebuzzmedia.exiftool.ExifTool.Tag; + public class Benchmark { public static final int ITERATIONS = 25; - private static Logger log = Logger.getLogger(Benchmark.class); - + private static Logger log = LoggerFactory.getLogger(Benchmark.class); - public static void main(String[] args) throws IOException, InterruptedException { + public static void main(String[] args) throws IOException, + InterruptedException { - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); - final Tag[] tags = Tag.values(); - final File[] images = new File("src/test/resources").listFiles(); + final Tag[] tags = Tag.values(); + final File[] images = new File("src/test/resources").listFiles(); - log.info("Benchmark [tags=" + tags.length + ", images=" - + images.length + ", iterations=" + ITERATIONS + "]"); - log.info("\t" + (images.length * ITERATIONS) + log.info("Benchmark [tags=" + tags.length + ", images=" + images.length + + ", iterations=" + ITERATIONS + "]"); + log.info("\t" + (images.length * ITERATIONS) + " ExifTool process calls, " + (tags.length * images.length * ITERATIONS) + " total operations.\n"); @@ -36,13 +39,13 @@ public static void main(String[] args) throws IOException, InterruptedException log.info("\t[-stay_open False]"); long elapsedTime = 0; - for (int i = 1; i <= ITERATIONS; i++){ - log.info(String.format("iteration %s of %s", i, ITERATIONS)); + for (int i = 1; i <= ITERATIONS; i++) { + log.info(String.format("iteration %s of %s", i, ITERATIONS)); elapsedTime += run(tool, images, tags); - } + } log.info("\t\tElapsed Time: " + elapsedTime + " ms (" - + ((double) elapsedTime / 1000) + " secs)"); + + ((double) elapsedTime / 1000) + " secs)"); /* * -stay_open True */ @@ -50,13 +53,13 @@ public static void main(String[] args) throws IOException, InterruptedException long elapsedTimeSO = 0; for (int i = 1; i <= ITERATIONS; i++) { - log.info(String.format("iteration %s of %s", i, ITERATIONS)); + log.info(String.format("iteration %s of %s", i, ITERATIONS)); elapsedTimeSO += run(toolSO, images, tags); } log.info("\t\tElapsed Time: " + elapsedTimeSO + " ms (" - + ((double) elapsedTimeSO / 1000) + " secs - " - + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); + + ((double) elapsedTimeSO / 1000) + " secs - " + + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); // Shut down the running exiftool proc. toolSO.close(); @@ -66,9 +69,9 @@ private static long run(ExifTool tool, File[] images, Tag[] tags) throws IllegalArgumentException, SecurityException, IOException { long startTime = System.currentTimeMillis(); - for (File image : images){ - tool.getImageMeta(image, tags); - } + for (File image : images) { + tool.getImageMeta(image, tags); + } return (System.currentTimeMillis() - startTime); } diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index 145018a5..d6f1bc27 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -4,42 +4,52 @@ import java.io.IOException; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + import com.thebuzzmedia.exiftool.ExifTool.Feature; import com.thebuzzmedia.exiftool.ExifTool.Format; -import org.apache.log4j.Logger; public class Example { - private static Logger log = Logger.getLogger(Example.class); - private static final String TEST_FILES_PATH = "src/test/resources"; - - public static void main(String[] args) throws IOException, InterruptedException { - - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); - ExifTool tool = new ExifTool(Feature.STAY_OPEN); - - File[] images = new File(TEST_FILES_PATH).listFiles(); - - //list all first-class tags - for (File f : images) { - log.info("\n[" + f.getName() + "]"); - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, ExifTool.Tag.values()); - for (ExifTool.Tag key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key.getName(), metadata.get(key))); - } - } - - log.info("\n\n** GET TAGS BY GROUP"); - //list all XMP, IPTC and XMP tags - File f = new File(TEST_FILES_PATH + "/kureckjones_jett_075_02-cropped.tif"); - for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] {ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, ExifTool.TagGroup.XMP}){ - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, tagGroup); - log.info(tagGroup.getName()); - for (String key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - } - } - - tool.close(); - } + private static Logger log = LoggerFactory.getLogger(Example.class); + private static final String TEST_FILES_PATH = "src/test/resources"; + + public static void main(String[] args) throws IOException, + InterruptedException { + + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + + File[] images = new File(TEST_FILES_PATH).listFiles(); + + // list all first-class tags + for (File f : images) { + log.info("\n[" + f.getName() + "]"); + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, ExifTool.Tag.values()); + for (ExifTool.Tag key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key.getName(), + metadata.get(key))); + } + } + + log.info("\n\n** GET TAGS BY GROUP"); + // list all XMP, IPTC and XMP tags + File f = new File(TEST_FILES_PATH + + "/kureckjones_jett_075_02-cropped.tif"); + for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] { + ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, + ExifTool.TagGroup.XMP }) { + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, tagGroup); + log.info(tagGroup.getName()); + for (String key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + } + } + + tool.close(); + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index ec60bb1d..bb791663 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -1,8 +1,5 @@ package com.thebuzzmedia.exiftool; -import junit.framework.TestCase; -import org.apache.log4j.Logger; - import java.io.File; import java.io.IOException; import java.util.ArrayList; @@ -10,201 +7,217 @@ import java.util.Map; import java.util.Set; +import junit.framework.TestCase; + +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** - * TestMetadata

- * + * TestMetadata + *

+ * * @author Michael Rush (michaelrush@gmail.com) * @since Initially created 8/8/13 */ public class TestExifTool extends TestCase { - private static final String TEST_FILES_PATH = "src/test/resources"; - private static Logger log = Logger.getLogger(TestExifTool.class); - - - public void testSingleTool() throws Exception { - ExifTool tool = new ExifTool(); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.startup(); - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - } - - public void testConcurrent() throws Exception { - - int toolCount = 5; - - List threads = new ArrayList(toolCount); - for (int i=1; i <= toolCount; i++){ - String toolName = "tool"+i; - Thread t = new Thread(toolName){ - @Override - public void run() { - log.info(getName() + ": starting"); - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - runTests(tool,getName()); - log.info(getName() + ": finished"); - } catch (IOException e) { - log.error(e,e); - fail(e.getMessage()); - } finally { - tool.shutdown(); - } - log.info(getName() + ": finished"); - } - }; - t.start(); - threads.add(t); - } - - for (Thread t : threads){ - t.run(); - } - } - - public void testManyThreadsOneTool() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Thread[] threads = new Thread[20]; - for(int i=0; i < threads.length; i++) { - final String label = "run "+i; - threads[i] = new Thread(new Runnable() { - @Override - public void run() { - try { - for(int j=0; j<5; j++) { - runTests(tool,label); - } - log.info("DONE: "+label+" success!"); - } catch (IOException ex) { - fail(label); - } - } - },label); - } - for(Thread thread : threads) { - thread.start(); - } - for(Thread thread : threads) { - thread.join(); - } - } finally { - tool.shutdown(); - } - } - public void testProcessTimeout() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.setRunTimeout(1); - runTests(tool,"will fail"); - fail("should have failed"); - } catch (IOException ex) { - ; - } finally { - tool.shutdown(); - } - } - - public boolean runTests(ExifTool tool, String runId) throws IOException { - - Map metadata; - File imageFile; - Set keys; - ExifTool.Tag tag; - - imageFile = new File(TEST_FILES_PATH + "/kureckjones_jett_075_02-cropped.tif"); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(22, metadata.size()); - - keys = metadata.keySet(); - - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(728, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(825, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("P 45+", tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 1"); - - - imageFile = new File(TEST_FILES_PATH + "/nexus-s-electric-cars.jpg"); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(23, metadata.size()); - - keys = metadata.keySet(); - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(2560, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(1920, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.ISO; - assertEquals(50, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.SHUTTER_SPEED; - assertEquals("1/64", metadata.get(tag)); - assertEquals(0.015625, tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 2"); - return true; - } - - public void testGroupTags() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Map metadata; - File f = new File(TEST_FILES_PATH + "/iptc_test-photoshop.jpg"); - metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, ExifTool.TagGroup.IPTC); - assertEquals(17, metadata.size()); - assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); - assertEquals("IPTC Status: Copyright Notice", metadata.get("CopyrightNotice")); - assertEquals("IPTC Content: Description Writer", metadata.get("Writer-Editor")); - //for (String key : metadata.keySet()){ - // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - //} - } finally { - tool.shutdown(); - } - } - - public void testTag(){ - assertEquals("string value", "John Doe", ExifTool.Tag.AUTHOR.parseValue("John Doe")); - assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); - assertEquals("double value, from fraction", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); - assertEquals("double value, from decimal", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); - } - - public void testVersionNumber() { - assertTrue(new ExifTool.VersionNumber("1.2").isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); - assertTrue(new ExifTool.VersionNumber(1,2).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber(2,1))); - } - - - //todo TEST automatic daemon restart by killing perl process + private static final String TEST_FILES_PATH = "src/test/resources"; + private static Logger log = LoggerFactory.getLogger(TestExifTool.class); + + public void testSingleTool() throws Exception { + ExifTool tool = new ExifTool(); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + tool.startup(); + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + } + + public void testConcurrent() throws Exception { + + int toolCount = 5; + + List threads = new ArrayList(toolCount); + for (int i = 1; i <= toolCount; i++) { + String toolName = "tool" + i; + Thread t = new Thread(toolName) { + @Override + public void run() { + log.info(getName() + ": starting"); + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + runTests(tool, getName()); + log.info(getName() + ": finished"); + } catch (IOException e) { + log.error("", e); + fail(e.getMessage()); + } finally { + tool.shutdown(); + } + log.info(getName() + ": finished"); + } + }; + t.start(); + threads.add(t); + } + + for (Thread t : threads) { + t.run(); + } + } + + public void testManyThreadsOneTool() throws Exception { + final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + Thread[] threads = new Thread[20]; + for (int i = 0; i < threads.length; i++) { + final String label = "run " + i; + threads[i] = new Thread(new Runnable() { + @Override + public void run() { + try { + for (int j = 0; j < 5; j++) { + runTests(tool, label); + } + log.info("DONE: " + label + " success!"); + } catch (IOException ex) { + fail(label); + } + } + }, label); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + } finally { + tool.shutdown(); + } + } + + public void testProcessTimeout() throws Exception { + final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + tool.setRunTimeout(1); + runTests(tool, "will fail"); + fail("should have failed"); + } catch (IOException ex) { + ; + } finally { + tool.shutdown(); + } + } + + public boolean runTests(ExifTool tool, String runId) throws IOException { + + Map metadata; + File imageFile; + Set keys; + ExifTool.Tag tag; + + imageFile = new File(TEST_FILES_PATH + + "/kureckjones_jett_075_02-cropped.tif"); + metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.values()); + assertEquals(22, metadata.size()); + + keys = metadata.keySet(); + + tag = ExifTool.Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(728, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.IMAGE_HEIGHT; + assertEquals(825, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.MODEL; + assertEquals("P 45+", tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 1"); + + imageFile = new File(TEST_FILES_PATH + "/nexus-s-electric-cars.jpg"); + metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.values()); + assertEquals(23, metadata.size()); + + keys = metadata.keySet(); + tag = ExifTool.Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(2560, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.IMAGE_HEIGHT; + assertEquals(1920, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.MODEL; + assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.ISO; + assertEquals(50, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.SHUTTER_SPEED; + assertEquals("1/64", metadata.get(tag)); + assertEquals(0.015625, tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 2"); + return true; + } + + public void testGroupTags() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + Map metadata; + File f = new File(TEST_FILES_PATH + "/iptc_test-photoshop.jpg"); + metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, + ExifTool.TagGroup.IPTC); + assertEquals(17, metadata.size()); + assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); + assertEquals("IPTC Status: Copyright Notice", + metadata.get("CopyrightNotice")); + assertEquals("IPTC Content: Description Writer", + metadata.get("Writer-Editor")); + // for (String key : metadata.keySet()){ + // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + // } + } finally { + tool.shutdown(); + } + } + + public void testTag() { + assertEquals("string value", "John Doe", + ExifTool.Tag.AUTHOR.parseValue("John Doe")); + assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); + assertEquals("double value, from fraction", .25, + ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); + assertEquals("double value, from decimal", .25, + ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); + } + + public void testVersionNumber() { + assertTrue(new ExifTool.VersionNumber("1.2") + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); + assertTrue(new ExifTool.VersionNumber(1, 2) + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); + assertTrue(new ExifTool.VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); + assertTrue(new ExifTool.VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new ExifTool.VersionNumber(2, 1))); + } + + // todo TEST automatic daemon restart by killing perl process } From fee73d655faa04e1e38066e0ffcbebe323e631b9 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 23:11:24 +0300 Subject: [PATCH 032/148] - formatted --- .gitignore | 7 +- .../com/thebuzzmedia/exiftool/ExifTool.java | 3090 +++++++++-------- .../com/thebuzzmedia/exiftool/Benchmark.java | 96 +- .../com/thebuzzmedia/exiftool/Example.java | 83 +- .../thebuzzmedia/exiftool/TestExifTool.java | 1000 +++--- 5 files changed, 2273 insertions(+), 2003 deletions(-) diff --git a/.gitignore b/.gitignore index 50756ce4..d101a2ee 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,9 @@ bin workspace.xml *.iml .idea -out \ No newline at end of file +out +/.project + +/.classpath + +/.settings diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 9785783d..0fe9c055 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -15,9 +15,6 @@ */ package com.thebuzzmedia.exiftool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.BufferedReader; import java.io.File; import java.io.IOException; @@ -43,9 +40,12 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** - * Provide a Java-like interface to Phil Harvey's excellent, - * Perl-based ExifTool. + * Provide a Java-like interface to Phil Harvey's excellent, Perl-based ExifTool. *

* Initial work done by "Riyad Kalla" software@thebuzzmedia.com. *

@@ -69,13 +69,14 @@ * system path or pointed to by {@link #ENV_EXIF_TOOL_PATH}, using this class to * communicate with ExifTool is as simple as creating an instance ( * ExifTool tool = new ExifTool()) and then making calls to - * {@link #readMetadata(ReadOptions,java.io.File, Object...)} (optionally supplying tags or + * {@link #readMetadata(ReadOptions,java.io.File, Object...)} (optionally + * supplying tags or * {@link #writeMetadata(WriteOptions,java.io.File, java.util.Map)} *

- * In this default mode methods will automatically - * start an external ExifTool process to handle the request. After ExifTool has - * parsed the tag values from the file, the external process exits and this - * class parses the result before returning it to the caller. + * In this default mode methods will automatically start an external ExifTool + * process to handle the request. After ExifTool has parsed the tag values from + * the file, the external process exits and this class parses the result before + * returning it to the caller. *

*

ExifTool -stay_open Support

* ExifTool * Because this feature requires ExifTool 8.36 or later, this class will * actually verify support for the feature in the version of ExifTool pointed at - * by {@link #ENV_EXIF_TOOL_PATH} before successfully instantiating the class and - * will notify you via an {@link UnsupportedFeatureException} if the native + * by {@link #ENV_EXIF_TOOL_PATH} before successfully instantiating the class + * and will notify you via an {@link UnsupportedFeatureException} if the native * ExifTool doesn't support the requested feature. *

* In the event of an {@link UnsupportedFeatureException}, the caller can either @@ -119,9 +120,10 @@ * of inactivity to clean up those stray resources. *

* The inactivity period can be controlled by modifying the - * {@link #ENV_EXIF_TOOL_PROCESSCLEANUPDELAY} system variable. A value of 0 or - * less disabled the automatic cleanup process and requires you to cleanup - * ExifTool instances on your own by calling {@link #close()} manually. + * {@link #ENV_EXIF_TOOL_PROCESSCLEANUPDELAY} system variable. A value of + * 0 or less disabled the automatic cleanup process and requires + * you to cleanup ExifTool instances on your own by calling {@link #close()} + * manually. *

* Any class activity by way of calls to getImageMeta will always * reset the inactivity timer, so in a busy system the cleanup thread could @@ -198,1466 +200,1622 @@ * written the 2nd most robust image metadata library I have come across: Metadata Extractor * that you might want to look at. - * + * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ public class ExifTool { - /** - * If ExifTool is on your system path and running the command "exiftool" - * successfully executes it, the default value unchanged will work fine on - * any platform. If the ExifTool executable is named something else or not - * in the system path, then this property will need to be set to point at it - * before using this class. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.path=/path/to/exiftool - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * On Windows be sure to double-escape the path to the tool, for example: - * - * -Dexiftool.path=C:\\Tools\\exiftool.exe - * - *

- * Default value is "exiftool". - *

Relative Paths

- * Relative path values (e.g. "bin/tools/exiftool") are executed with - * relation to the base directory the VM process was started in. Essentially - * the directory that new File(".").getAbsolutePath() points at - * during runtime. - */ - public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; - /** - * Interval (in milliseconds) of inactivity before the cleanup thread wakes - * up and cleans up the daemon ExifTool process and the read/write streams - * used to communicate with it when the {@link Feature#STAY_OPEN} feature is - * used. - *

- * Ever time a call to getImageMeta is processed, the timer - * keeping track of cleanup is reset; more specifically, this class has to - * experience no activity for this duration of time before the cleanup - * process is fired up and cleans up the host OS process and the stream - * resources. - *

- * Any subsequent calls to getImageMeta after a cleanup simply - * re-initializes the resources. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.processCleanupDelay=600000 - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * Setting this value to 0 disables the automatic cleanup thread completely - * and the caller will need to manually cleanup the external ExifTool - * process and read/write streams by calling {@link #close()}. - *

- * Default value is zero, no inactivity timeout. - */ - public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; - - /** - * Name used to identify the (optional) cleanup {@link Thread}. - *

- * This is only provided to make debugging and profiling easier for - * implementers making use of this class such that the resources this class - * creates and uses (i.e. Threads) are readily identifiable in a running VM. - *

- * Default value is "ExifTool Cleanup Thread". - */ - private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; - - /** - * Compiled {@link Pattern} of ": " used to split compact output from - * ExifTool evenly into name/value pairs. - */ - private static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); - private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - private static final String EXIF_DATE_FORMAT = "yyyy:MM:dd HH:mm:ss"; - - private static Logger log = LoggerFactory.getLogger(ExifTool.class); - - private final Map featureSupportedMap = new HashMap(); - private final Set featureEnabledSet = EnumSet.noneOf(Feature.class); - private ReadOptions defReadOptions = new ReadOptions(); - private WriteOptions defWriteOptions = new WriteOptions(); - private final VersionNumber exifVersion; - private final ExifProxy exifProxy; - - public ExifTool(){ - this((Feature[]) null); - } - - /** - * In this constructor, exifToolPath and processCleanupDelay are read from system properties - * exiftool.path and exiftool.processCleanupDelay. processCleanupDelay is optional. If not found, - * the default is used. - */ - public ExifTool (Feature ... features){ - this( - System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), - Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, DEFAULT_PROCESS_CLEANUP_DELAY), - features - ); - } - - /** - * Pass in the absolute path to the ExifTool executable on the host system. - */ - public ExifTool(String exifToolPath) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY); - } - - public ExifTool(String exifToolPath, Feature ... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); - } - - public ExifTool(String exifCmd, long processCleanupDelay, Feature ... features) { - this.exifVersion = ExifProcess.readVersion(exifCmd); - if (features != null && features.length > 0) { - for (Feature feature : features) { - if ( ! feature.isSupported(exifVersion) ) { - throw new UnsupportedFeatureException(feature); - } - this.featureEnabledSet.add(feature); - this.featureSupportedMap.put(feature,true); - } - } - - List baseArgs = new ArrayList(3); - if (featureEnabledSet.contains(Feature.MWG_MODULE) ) { - baseArgs.addAll(Arrays.asList("-use","MWG")); - } - if (featureEnabledSet.contains(Feature.STAY_OPEN) ) { - KeepAliveExifProxy proxy = new KeepAliveExifProxy(exifCmd,baseArgs); - proxy.setInactiveTimeout(processCleanupDelay); - exifProxy = proxy; - } else { - exifProxy = new SingleUseExifProxy(exifCmd,baseArgs); - } - } - - /** - * Limits the amount of time (in mills) an exif operation can take. Setting value to greater than 0 to enable. - */ - public ExifTool setRunTimeout(long mills) { - defReadOptions = defReadOptions.withRunTimeoutMills(mills); - defWriteOptions = defWriteOptions.withRunTimeoutMills(mills); - return this; - } - - /** - * Used to determine if the given {@link Feature} is supported by the - * underlying native install of ExifTool pointed at by - * {@link #ENV_EXIF_TOOL_PATH}. - *

- * If support for the given feature has not been checked for yet, this - * method will automatically call out to ExifTool and ensure the requested - * feature is supported in the current local install. - *

- * The external call to ExifTool to confirm feature support is only ever - * done once per JVM session and stored in a static final - * {@link Map} that all instances of this class share. - * - * @param feature - * The feature to check support for in the underlying ExifTool - * install. - * - * @return true if support for the given {@link Feature} was - * confirmed to work with the currently installed ExifTool or - * false if it is not supported. - * - * @throws IllegalArgumentException - * if feature is null. - * @throws RuntimeException - * if any exception occurs while attempting to start the - * external ExifTool process to verify feature support. - */ - public boolean isFeatureSupported(Feature feature) throws RuntimeException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); - } - - Boolean supported = featureSupportedMap.get(feature); + /** + * If ExifTool is on your system path and running the command "exiftool" + * successfully executes it, the default value unchanged will work fine on + * any platform. If the ExifTool executable is named something else or not + * in the system path, then this property will need to be set to point at it + * before using this class. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.path=/path/to/exiftool + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * On Windows be sure to double-escape the path to the tool, for example: + * + * -Dexiftool.path=C:\\Tools\\exiftool.exe + * + *

+ * Default value is "exiftool". + *

Relative Paths

+ * Relative path values (e.g. "bin/tools/exiftool") are executed with + * relation to the base directory the VM process was started in. Essentially + * the directory that new File(".").getAbsolutePath() points at + * during runtime. + */ + public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + /** + * Interval (in milliseconds) of inactivity before the cleanup thread wakes + * up and cleans up the daemon ExifTool process and the read/write streams + * used to communicate with it when the {@link Feature#STAY_OPEN} feature is + * used. + *

+ * Ever time a call to getImageMeta is processed, the timer + * keeping track of cleanup is reset; more specifically, this class has to + * experience no activity for this duration of time before the cleanup + * process is fired up and cleans up the host OS process and the stream + * resources. + *

+ * Any subsequent calls to getImageMeta after a cleanup simply + * re-initializes the resources. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.processCleanupDelay=600000 + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * Setting this value to 0 disables the automatic cleanup thread completely + * and the caller will need to manually cleanup the external ExifTool + * process and read/write streams by calling {@link #close()}. + *

+ * Default value is zero, no inactivity timeout. + */ + public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + + /** + * Name used to identify the (optional) cleanup {@link Thread}. + *

+ * This is only provided to make debugging and profiling easier for + * implementers making use of this class such that the resources this class + * creates and uses (i.e. Threads) are readily identifiable in a running VM. + *

+ * Default value is "ExifTool Cleanup Thread". + */ + private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; + + /** + * Compiled {@link Pattern} of ": " used to split compact output from + * ExifTool evenly into name/value pairs. + */ + private static final Pattern TAG_VALUE_PATTERN = Pattern + .compile("\\s*:\\s*"); + private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + private static final String EXIF_DATE_FORMAT = "yyyy:MM:dd HH:mm:ss"; + + private static Logger log = LoggerFactory.getLogger(ExifTool.class); + + private final Map featureSupportedMap = new HashMap(); + private final Set featureEnabledSet = EnumSet + .noneOf(Feature.class); + private ReadOptions defReadOptions = new ReadOptions(); + private WriteOptions defWriteOptions = new WriteOptions(); + private final VersionNumber exifVersion; + private final ExifProxy exifProxy; + + public ExifTool() { + this((Feature[]) null); + } + + /** + * In this constructor, exifToolPath and processCleanupDelay are read from + * system properties exiftool.path and exiftool.processCleanupDelay. + * processCleanupDelay is optional. If not found, the default is used. + */ + public ExifTool(Feature... features) { + this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( + ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, + DEFAULT_PROCESS_CLEANUP_DELAY), features); + } + + /** + * Pass in the absolute path to the ExifTool executable on the host system. + */ + public ExifTool(String exifToolPath) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY); + } + + public ExifTool(String exifToolPath, Feature... features) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); + } + + public ExifTool(String exifCmd, long processCleanupDelay, + Feature... features) { + this.exifVersion = ExifProcess.readVersion(exifCmd); + if (features != null && features.length > 0) { + for (Feature feature : features) { + if (!feature.isSupported(exifVersion)) { + throw new UnsupportedFeatureException(feature); + } + this.featureEnabledSet.add(feature); + this.featureSupportedMap.put(feature, true); + } + } + + List baseArgs = new ArrayList(3); + if (featureEnabledSet.contains(Feature.MWG_MODULE)) { + baseArgs.addAll(Arrays.asList("-use", "MWG")); + } + if (featureEnabledSet.contains(Feature.STAY_OPEN)) { + KeepAliveExifProxy proxy = new KeepAliveExifProxy(exifCmd, baseArgs); + proxy.setInactiveTimeout(processCleanupDelay); + exifProxy = proxy; + } else { + exifProxy = new SingleUseExifProxy(exifCmd, baseArgs); + } + } + + /** + * Limits the amount of time (in mills) an exif operation can take. Setting + * value to greater than 0 to enable. + */ + public ExifTool setRunTimeout(long mills) { + defReadOptions = defReadOptions.withRunTimeoutMills(mills); + defWriteOptions = defWriteOptions.withRunTimeoutMills(mills); + return this; + } + + /** + * Used to determine if the given {@link Feature} is supported by the + * underlying native install of ExifTool pointed at by + * {@link #ENV_EXIF_TOOL_PATH}. + *

+ * If support for the given feature has not been checked for yet, this + * method will automatically call out to ExifTool and ensure the requested + * feature is supported in the current local install. + *

+ * The external call to ExifTool to confirm feature support is only ever + * done once per JVM session and stored in a static final + * {@link Map} that all instances of this class share. + * + * @param feature + * The feature to check support for in the underlying ExifTool + * install. + * + * @return true if support for the given {@link Feature} was + * confirmed to work with the currently installed ExifTool or + * false if it is not supported. + * + * @throws IllegalArgumentException + * if feature is null. + * @throws RuntimeException + * if any exception occurs while attempting to start the + * external ExifTool process to verify feature support. + */ + public boolean isFeatureSupported(Feature feature) throws RuntimeException { + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); + } + + Boolean supported = featureSupportedMap.get(feature); /* * If there is no Boolean flag for the feature, support for it hasn't * been checked yet with the native ExifTool install, so we need to do * that. */ - if (supported == null) { - log.debug("Support for feature %s has not been checked yet, checking..."); - supported = feature.isSupported(exifVersion); - featureSupportedMap.put(feature,supported); - } - - return supported; - } - - /** - * Used to determine if the given {@link Feature} has been enabled for this - * particular instance of {@link ExifTool}. - *

- * This method is different from {@link #isFeatureSupported(Feature)}, which - * checks if the given feature is supported by the underlying ExifTool - * install where as this method tells the caller if the given feature has - * been enabled for use in this particular instance. - * - * @param feature - * The feature to check if it has been enabled for us or not on - * this instance. - * - * @return true if the given {@link Feature} is currently - * enabled on this instance of {@link ExifTool}, otherwise returns - * false. - * - * @throws IllegalArgumentException - * if feature is null. - */ - public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); - } - return featureEnabledSet.contains(feature); - } - - /** - * Used to startup the external ExifTool process and open the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. This method has no effect if the stay open feature is not enabled. - */ - public void startup(){ - exifProxy.startup(); - } - - /** - * This is same as {@link #close()}, added for consistency with {@link #startup()} - */ - public void shutdown(){ - close(); - } - - /** - * Used to shutdown the external ExifTool process and close the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. - *

- * NOTE: Calling this method does not preclude this - * instance of {@link ExifTool} from being re-used, it merely disposes of - * the native and internal resources until the next call to - * getImageMeta causes them to be re-instantiated. - *

- * Calling this method on an instance of this class without - * {@link Feature#STAY_OPEN} support enabled has no effect. - */ - public void close() { - exifProxy.shutdown(); - } - - public boolean isStayOpen() { - return featureEnabledSet.contains(Feature.STAY_OPEN); - } - - /** - * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support - * enabled, this method is used to determine if there is currently a running - * ExifTool process associated with this class. - *

- * Any dependent processes and streams can be shutdown using - * {@link #close()} and this class will automatically re-create them on the - * next call to getImageMeta if necessary. - * - * @return true if there is an external ExifTool process in - * daemon mode associated with this class utilizing the - * {@link Feature#STAY_OPEN} feature, otherwise returns - * false. - */ - public boolean isRunning() { - return exifProxy != null && ! exifProxy.isRunning(); - } - - - public ReadOptions getReadOptions() { - return defReadOptions; - } - - public ExifTool setReadOptions(ReadOptions options) { - defReadOptions = options; - return this; - } - - public WriteOptions getWriteOptions() { - return defWriteOptions; - } - - public ExifTool setWriteOptions(WriteOptions options) { - defWriteOptions = options; - return this; - } - //================================================================================ - //OLD API - public static enum Format{NUMERIC, HUMAN_READABLE} - - public Map getImageMeta(File image, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - return getImageMeta(image, Format.NUMERIC, tags); - } - - public Map getImageMeta(File image, Format format, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - - String [] stringTags = new String[tags.length]; - int i=0; - for (Tag tag : tags){ - stringTags[i++] = tag.getKey(); - } - Map result = getImageMeta(image, format, true, stringTags); - return Tag.toTagMap(result); - } - - public Map getImageMeta(File image, Format format, TagGroup... tags) - throws IllegalArgumentException, SecurityException, IOException { - String [] stringTags = new String[tags.length]; - int i=0; - for (TagGroup tag : tags){ - stringTags[i++] = tag.getKey(); - } - return getImageMeta(image, format, false, stringTags); - } - - public Map getImageMeta(File file, Format format, boolean supressDuplicates, String... tags) throws IOException { - ReadOptions options = defReadOptions.withNumericOutput(format == Format.NUMERIC).withShowDuplicates(!supressDuplicates).withConvertTypes(false); - Map result = readMetadata(options, file, tags); - Map data = new TreeMap(); - for(Map.Entry entry : result.entrySet()) { - data.put(entry.getKey().toString(), entry.getValue()!=null?entry.getValue().toString():""); - } - return data; - } - - public void addImageMetadata(File image, Map values) throws IOException { - writeMetadata(defWriteOptions.withDeleteBackupFile(false),image,values); - } - //================================================================================ - public Map readMetadata(File file, Object... tags) throws IOException { - return readMetadata(defReadOptions,file,tags); - } - /** - * Reads metadata from the file. - */ - public Map readMetadata(ReadOptions options, File file, Object... tags) throws IOException { - if (file == null){ - throw new IllegalArgumentException("file cannot be null and must be a valid stream of image data."); - } - if (!file.canRead()){ - throw new SecurityException("Unable to read the given image ["+file.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); - } - - List args = new ArrayList(tags.length+2); - if ( options.numericOutput ) { - args.add("-n"); // numeric output - } - if ( options.showDuplicates) { - args.add("-a"); - } - if ( ! options.showEmptyTags ) { - args.add("-S"); // compact output - } - for(Object tag: tags) { - if ( tag instanceof MetadataTag ) { - args.add("-"+((MetadataTag) tag).getKey()); - } else { - args.add("-" + tag); - } - } - args.add(file.getAbsolutePath()); - - Map resultMap = exifProxy.execute(options.runTimeoutMills,args); - - Map metadata = new HashMap(resultMap.size()); - - for(Object tag: tags) { - MetadataTag metaTag; - if (tag instanceof MetadataTag) { - metaTag = (MetadataTag) tag; - } else { - metaTag = toTag(tag.toString()); - } - if ( metaTag.isMapped() ) { - String input = resultMap.remove(metaTag.getKey()); - if ( ! options.showEmptyTags && (input == null || input.isEmpty()) ) { - continue; - } - Object value = options.convertTypes ? deserialize(metaTag.getKey(), input, metaTag.getType()) : input; - //maps with tag passed in, as caller expects to fetch - metadata.put(tag, value); - } - } - for(Map.Entry entry : resultMap.entrySet()) { - if ( ! options.showEmptyTags && entry.getValue() == null || entry.getValue().isEmpty() ) { - continue; - } - if ( options.convertTypes) { - MetadataTag metaTag = toTag(entry.getKey()); - Object value = deserialize(metaTag.getKey(), entry.getValue(), metaTag.getType()); - metadata.put(entry.getKey(), value); - } else { - metadata.put(entry.getKey(),entry.getValue()); - - } - } - return metadata; - } - - public void writeMetadata(File image, Map values) throws IOException { - writeMetadata(defWriteOptions, image, values); - } - /** - * Takes a map of tags (either (@link Tag) or Strings for keys) and replaces/appends them to the metadata. - */ - public void writeMetadata(WriteOptions options, File image, Map values) throws IOException { - if (image == null){ - throw new IllegalArgumentException("image cannot be null and must be a valid stream of image data."); - } - if (values == null || values.isEmpty()){ - throw new IllegalArgumentException("values cannot be null and must contain 1 or more tag to value mappings"); - } - - if (!image.canWrite()){ - throw new SecurityException("Unable to write the given image [" + image.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to write to it."); - } - - log.info("Adding Tags {} to {}", values, image.getAbsolutePath()); - - List args = new ArrayList(values.size()+3); - for(Map.Entry entry : values.entrySet()) { - args.addAll(serializeToArgs(entry.getKey(),entry.getValue())); - } - args.add(image.getAbsolutePath()); - - //start process - long startTime = System.currentTimeMillis(); - try { - exifProxy.execute(options.runTimeoutMills, args); - } finally { - if ( options.deleteBackupFile ) { - File origBackup = new File(image.getAbsolutePath()+"_original"); - if ( origBackup.exists() ) origBackup.delete(); - } - } - - // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()){ - log.debug(String.format("Image Meta Processed in %d ms [added %d tags]", - (System.currentTimeMillis() - startTime), values.size())); - } - } - //================================================================================ - //STATIC helpers - - static List serializeToArgs(Object tag, Object value) { - final Class tagType; - final String tagName; - if ( tag instanceof MetadataTag ) { - tagName = ((MetadataTag) tag).getKey(); - tagType = ((MetadataTag) tag).getType(); - } else { - tagName = tag.toString(); - tagType = null; - } - - //pre process - if ( value != null ) { - if ( value.getClass().isArray() ) { - //convert array to iterable, this is lame - int len = Array.getLength(value); - List newList = new ArrayList(len); - for (int i = 0; i < len; i++) { - Object item = Array.get(value,i); - newList.add(item); - } - value = newList; - } else if ( value instanceof Number && Date.class.equals(tagType) ) { - //if we know this is a date field and data is a number assume it is unix epoch time - Date date = new Date(((Number) value).longValue()); - value = date; - } - } - - List args = new ArrayList(4); - String arg; - if (value == null ) { - arg = String.format("-%s=",tagName); - } else if ( value instanceof Number ) { - arg = String.format("-%s#=%s",tagName,value); - } else if(value instanceof Date) { - SimpleDateFormat formatter = new SimpleDateFormat(EXIF_DATE_FORMAT); - arg = String.format("-%s=%s",tagName,formatter.format((Date)value)); - } else if (value instanceof Iterable) { - Iterable it = (Iterable) value; - args.add("-sep"); - args.add(","); - StringBuilder itemList = new StringBuilder(); - for(Object item : it) { - if ( itemList.length() > 0 ) { - itemList.append(","); - } - itemList.append(item); - } - arg = String.format("-%s=%s",tagName, itemList); - } else { - if ( tagType != null && tagType.isArray() ) { - args.add("-sep"); - args.add(","); - } - arg = String.format("-%s=%s",tagName,value); - } - args.add(arg); - return args; - } - - static Object deserialize(String tagName, String value, Class expectedType) { - try { - if ( Boolean.class.equals(expectedType) ) { - if ( value == null ) return null; - value = value.trim().toLowerCase(); - switch (value.charAt(0)) { - case 'n': case 'f': case '0': return false; - } - if ( value.equals("off") ) { - return false; - } - return true; - } else if ( Date.class.equals(expectedType) ) { - if ( value == null ) return null; - SimpleDateFormat formatter = new SimpleDateFormat(EXIF_DATE_FORMAT); - return formatter.parse(value); - } else if ( Integer.class.equals(expectedType) ) { - if ( value == null ) return 0; - return Integer.parseInt(value); - } else if ( Long.class.equals(expectedType) ) { - if ( value == null ) return 0; - return Long.parseLong(value); - } else if ( Float.class.equals(expectedType) ) { - if ( value == null ) return 0; - return Float.parseFloat(value); - } else if ( Double.class.equals(expectedType) ) { - if ( value == null ) return 0; - String[] enumeratorAndDivisor = value.split("/"); - if ( enumeratorAndDivisor.length == 2 ) { - return Double.parseDouble(enumeratorAndDivisor[0]) / Double.parseDouble(enumeratorAndDivisor[1]); - } else { - return Double.parseDouble(value); - } - } else if ( String[].class.equals(expectedType) ) { - if ( value == null ) return new String[0]; - return value.split(","); - } else { - return value; - } - } catch (ParseException ex) { - log.warn("Invalid format, Tag:"+tagName); - return null; - } catch (NumberFormatException ex) { - log.warn("Invalid format, Tag:"+tagName); - return null; - } - - } - - static MetadataTag toTag(String name) { - for(Tag tag: Tag.values()) { - if ( tag.getKey().equalsIgnoreCase(name) ) { - return tag; - } - } - for(MwgTag tag: MwgTag.values()) { - if ( tag.getKey().equalsIgnoreCase(name) ) { - return tag; - } - } - return new CustomTag(name,String.class); - } - - //================================================================================ - /** - * Represents an external exif process. Works for both single use and keep alive modes. - * This is the actual process, with streams for reading and writing data. - */ - public static final class ExifProcess { - public static VersionNumber readVersion(String exifCmd) { - ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, "-ver")); - try { - return new VersionNumber(process.readLine()); - } catch (IOException ex) { - throw new RuntimeException(String.format("Unable to check version number of ExifTool: %s", exifCmd)); - } finally { - process.close(); - } - } - - private final ReentrantLock closeLock = new ReentrantLock(false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; - private volatile boolean closed = false; - - public ExifProcess(boolean keepAlive, List args) { - this.keepAlive = keepAlive; - log.debug(String.format("Attempting to start ExifTool process using args: %s", args)); - try { - this.process = new ProcessBuilder(args).start(); - this.reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream()); - log.debug("\tSuccessful"); - } catch (Exception e) { - String message = "Unable to start external ExifTool process using the execution arguments: " - + args - + ". Ensure ExifTool is installed correctly and runs using the command path '" - + args.get(0) - + "' as specified by the 'exiftool.path' system property."; - - log.debug(message); - throw new RuntimeException(message, e); - } - } - - public synchronized Map sendToRunning(List args) throws IOException { - if (!keepAlive) { - throw new IOException("Not KeepAlive Process"); - } - StringBuilder builder = new StringBuilder(); - for (String arg : args) { - builder.append(arg).append("\n"); - } - builder.append("-execute\n"); - writeFlush(builder.toString()); - return readResponse(); - } - - public synchronized void writeFlush(String message) throws IOException { - if (closed) throw new IOException(STREAM_CLOSED_MESSAGE); - writer.write(message); - writer.flush(); - } - - public synchronized String readLine() throws IOException { - if (closed) throw new IOException(STREAM_CLOSED_MESSAGE); - return reader.readLine(); - } - - public synchronized Map readResponse() throws IOException { - if (closed) throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - Map resultMap = new HashMap(500); - String line; - - while ((line = reader.readLine()) != null) { - if (closed) throw new IOException(STREAM_CLOSED_MESSAGE); - String[] pair = TAG_VALUE_PATTERN.split(line, 2); - - if (pair.length == 2) { - resultMap.put(pair[0], pair[1]); - log.debug(String.format("\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); - } - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need to - * look for it and break from this loop when we see it otherwise - * this process will hang indefinitely blocking on the input stream - * with no data to read. - */ - if (keepAlive && line.equals("{ready}")) { - break; - } - } - return resultMap; - } - - public boolean isClosed() { - return closed; - } - - public void close() { - if (!closed) { - closeLock.lock(); - try { - if (!closed) { - closed = true; - try { - log.debug("Closing Read stream..."); - reader.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - writer.write("-stay_open\nFalse\n"); - writer.flush(); - } catch (IOException ex) { - //log.error(ex,ex); - } - - try { - log.debug("Closing Write stream..."); - writer.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - log.debug("Read/Write streams successfully closed."); - - try { - process.destroy(); - } catch (Exception e) { - // - } - //process = null; - - } - } finally { - closeLock.unlock(); - } - } - } - } - - /** - * A Proxy to an Exif Process, will restart if backing exif process died, or run new one on every call. - * @author Matt Gile, msgile - */ - public interface ExifProxy { - public void startup(); - public Map execute(long runTimeoutMills, List args) throws IOException; - public boolean isRunning(); - public void shutdown(); - } - - /** - * Manages an external exif process in keep alive mode. - */ - public static class KeepAliveExifProxy implements ExifProxy { - private final List startupArgs; - private final AtomicBoolean shuttingDown = new AtomicBoolean(false); - private final Timer cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - private long inactivityTimeout = 0; - private volatile long lastRunStart = 0; - private volatile ExifProcess process; - - public KeepAliveExifProxy(String exifCmd, List baseArgs) { - inactivityTimeout = Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, DEFAULT_PROCESS_CLEANUP_DELAY); - startupArgs = new ArrayList(baseArgs.size()+5); - startupArgs.add(exifCmd); - startupArgs.addAll(Arrays.asList("-stay_open", "True")); - startupArgs.addAll(baseArgs); - startupArgs.addAll(Arrays.asList("-@", "-")); - //runs every minute to check if process has been inactive too long - cleanupTimer.schedule(new TimerTask() { - @Override - public void run() { - if ( process != null && lastRunStart > 0 && inactivityTimeout > 0 ) { - if ( (System.currentTimeMillis()-lastRunStart) > inactivityTimeout) { - synchronized (this) { - if ( process != null ) { - process.close(); - } - } - } - } - } - },60*1000); //every minute - } - - public void setInactiveTimeout(long mills) { - this.inactivityTimeout = mills; - } - - public void startup() { - shuttingDown.set(false); - if (process ==null || process.isClosed()) { - synchronized (this){ - if (process ==null || process.isClosed() ){ - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = new ExifProcess(true, startupArgs); - } - } - } - } - - public Map execute(final long runTimeoutMills, List args) throws IOException { - lastRunStart = System.currentTimeMillis(); - int attempts = 0; - while (attempts < 3 && ! shuttingDown.get()){ - attempts++; - if (process ==null || process.isClosed()) { - synchronized (this){ - if (process ==null || process.isClosed() ){ - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = new ExifProcess(true, startupArgs); - } - } - } - TimerTask attemptTimer = null; - try { - if ( runTimeoutMills > 0 ) { - attemptTimer = new TimerTask() { - public void run() { - if (process != null && ! process.isClosed()) { - log.warn("Process ran too long closing, max " + runTimeoutMills + " mills"); - process.close(); - } - } - }; - cleanupTimer.schedule(attemptTimer, runTimeoutMills); - } - log.debug("Streaming arguments to ExifTool process..."); - return process.sendToRunning(args); - } catch (IOException ex){ - if ( STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) && ! shuttingDown.get() ){ - //only catch "Stream Closed" error (happens when process has died) - log.warn(String.format("Caught IOException(\"%s\"), will restart daemon",STREAM_CLOSED_MESSAGE)); - process.close(); - } else { - throw ex; - } - } finally { - if ( attemptTimer != null ) attemptTimer.cancel(); - } - } - if ( shuttingDown.get() ) { - throw new IOException("Shutting Down"); - } - throw new IOException("Ran out of attempts"); - } - - public boolean isRunning() { - return process != null && ! process.isClosed(); - } - - public void shutdown() { - shuttingDown.set(true); - } - } - - public static class SingleUseExifProxy implements ExifProxy { - private final Timer cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - private final List baseArgs; - - public SingleUseExifProxy(String exifCmd, List defaultArgs) { - this.baseArgs = new ArrayList(defaultArgs.size()+1); - this.baseArgs.add(exifCmd); - this.baseArgs.addAll(defaultArgs); - } - - public Map execute(final long runTimeoutMills, List args) throws IOException { - List newArgs = new ArrayList(baseArgs.size()+args.size()); - newArgs.addAll(baseArgs); - newArgs.addAll(args); - final ExifProcess process = new ExifProcess(false, newArgs); - TimerTask attemptTimer = null; - if ( runTimeoutMills > 0 ) { - attemptTimer = new TimerTask() { - public void run() { - if ( ! process.isClosed() ) { - log.warn("Process ran too long closing, max " + runTimeoutMills + " mills"); - process.close(); - } - } - }; - cleanupTimer.schedule(attemptTimer, runTimeoutMills); - } - try { - return process.readResponse(); - } finally { - process.close(); - if ( attemptTimer != null ) attemptTimer.cancel(); - } - } - - public void startup() { - ; - } - - public boolean isRunning() { - return false; - } - - public void shutdown() { - ; - } - } - //================================================================================ - /** - * All the read options, is immutable, copy on change, fluent style "with" setters. - */ - public static class ReadOptions { - private final long runTimeoutMills; - private final boolean convertTypes; - private final boolean numericOutput; - private final boolean showDuplicates; - private final boolean showEmptyTags; - - public ReadOptions() { - this(0,false,false,false,false); - } - - private ReadOptions(long runTimeoutMills, boolean convertTypes, boolean numericOutput, boolean showDuplicates, boolean showEmptyTags) { - this.runTimeoutMills = runTimeoutMills; - this.convertTypes = convertTypes; - this.numericOutput = numericOutput; - this.showDuplicates = showDuplicates; - this.showEmptyTags = showEmptyTags; - } - - public String toString() { - return String.format("%s(runTimeout:%,d convertTypes:%s showDuplicates:%s showEmptyTags:%s)", - getClass().getSimpleName(),runTimeoutMills,convertTypes,showDuplicates,showEmptyTags); - } - - /** - * Sets the maximum time a process can run - */ - public ReadOptions withRunTimeoutMills(long mills) { - return new ReadOptions(mills,convertTypes,numericOutput, showDuplicates,showEmptyTags); - } - - /** - * By default all values will be returned as the strings printed by the exiftool. - * If this is enabled then {@link MetadataTag#getType()} is used to cast the string into a java type. - */ - public ReadOptions withConvertTypes(boolean enabled) { - return new ReadOptions(runTimeoutMills,enabled,numericOutput, showDuplicates,showEmptyTags); - } - - /** - * Setting this to true will add the "-n" option causing the ExifTool to output of some tags to change. - *

- * ExifTool, via the -n command line arg, is capable of - * returning most values in their raw numeric form (e.g. - * Aperture="2.8010323841") as well as a more human-readable/friendly format - * (e.g. Aperture="2.8"). - *

- * While the {@link Tag}s defined on this class do provide a hint at the - * type of the result (see {@link MetadataTag#getType()}), that hint only applies - * when the numeric value is returned. - *

- * If the caller finds the human-readable format easier to process, - * Set this to false, the default. - *

- * In order to see the types of values that are returned when human readable - * is used (default), you can check the comprehensive - * ExifTool Tag Guide. - *

- * This makes sense with some values like Aperture that in numeric - * format end up returning as 14-decimal-place, high - * precision values that are near the intended value (e.g. - * "2.79999992203711" instead of just returning "2.8"). On the other hand, - * other values (like Orientation) are easier to parse when their numeric - * value (1-8) is returned instead of a much longer friendly name (e.g. - * "Mirror horizontal and rotate 270 CW"). - * - * Attempted from work done by - * @author Riyad Kalla (software@thebuzzmedia.com) - */ - public ReadOptions withNumericOutput(boolean enabled) { - return new ReadOptions(runTimeoutMills,convertTypes,enabled, showDuplicates,showEmptyTags); - } - - /** - * If enabled will show tags which are duplicated between different tag regions, relates to the "-a" option in ExifTool. - */ - public ReadOptions withShowDuplicates(boolean enabled) { - return new ReadOptions(runTimeoutMills,convertTypes,numericOutput,enabled,showEmptyTags); - } - - public ReadOptions withShowEmptyTags(boolean enabled) { - return new ReadOptions(runTimeoutMills,convertTypes,numericOutput,showDuplicates,enabled); - } - } - - //================================================================================ - /** - * All the write options, is immutable, copy on change, fluent style "with" setters. - */ - public static class WriteOptions { - private final long runTimeoutMills; - private final boolean deleteBackupFile; - - public WriteOptions() { - this(0,false); - } - - private WriteOptions(long runTimeoutMills, boolean deleteBackupFile) { - this.runTimeoutMills = runTimeoutMills; - this.deleteBackupFile = deleteBackupFile; - } - - public String toString() { - return String.format("%s(runTimeOut:%,d deleteBackupFile:%s)",getClass().getSimpleName(),runTimeoutMills,deleteBackupFile); - } - - public WriteOptions withRunTimeoutMills(long mills) { - return new WriteOptions(mills,deleteBackupFile); - } - /** - * ExifTool automatically makes a backup copy a file before writing metadata tags in the form - * "file.ext_original", by default this tool will delete that original file after the writing is done. - */ - public WriteOptions withDeleteBackupFile(boolean enabled) { - return new WriteOptions(runTimeoutMills,enabled); - } - } - - //================================================================================ - /** - * Enum used to define the different kinds of features in the native - * ExifTool executable that this class can help you take advantage of. - *

- * These flags are different from {@link Tag}s in that a "feature" is - * determined to be a special functionality of the underlying ExifTool - * executable that requires a different code-path in this class to take - * advantage of; for example, -stay_open True support. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Feature { - /** - * Enum used to specify that you wish to launch the underlying ExifTool - * process with -stay_open True support turned on that this - * class can then take advantage of. - *

- * Required ExifTool version is 8.36 or higher. - */ - STAY_OPEN(8,36), - /** - * Acitves the MWG modules. The Metadata Working Group (MWG) recommends - * techniques to allow certain overlapping EXIF, IPTC and XMP tags to be - * reconciled when reading, and synchronized when writing. The MWG Composite tags - * below are designed to aid in the implementation of these recommendations. - * Will add the args " -use MWG" - * - * @see ExifTool MWG Docs - * !! Note these version numbers are not correct - */ - MWG_MODULE(8,36), - ; - - - private VersionNumber requireVersion; - private Feature(int... numbers) { - this.requireVersion = new VersionNumber(numbers); - } - /** - * Used to get the version of ExifTool required by this feature in order - * to work. - * - * @return the version of ExifTool required by this feature in order to - * work. - */ - VersionNumber getVersion() { - return requireVersion; - } - - boolean isSupported(VersionNumber exifVersionNumber) { - return requireVersion.isBeforeOrEqualTo(exifVersionNumber); - } - } - - //================================================================================ - /** - * Version Number used to determine if one version is after another. - * @author Matt Gile, msgile - */ - static class VersionNumber { - private final int[] numbers; - - public VersionNumber(String str) { - String[] versionParts = str.trim().split("\\."); - this.numbers = new int[versionParts.length]; - for(int i=0; i other.numbers[i] ) { - return false; - } else if ( this.numbers[i] < other.numbers[i] ) { - return true; - } - } - //assume missing number as zero, so if the current process number is more digits it is a higher version - return this.numbers.length <= other.numbers.length; - } - - public String toString() { - StringBuilder builder = new StringBuilder(); - for (int number : numbers) { - if (builder.length() > 0) { - builder.append("."); - } - builder.append(number); - } - return builder.toString(); - } - } - - - //================================================================================ - /** - * Base type for all "tag" passed to exiftool. - * The key is the value passed to the exiftool like "-creator". - * The Types is used for automatic type conversions. - * - */ - public interface MetadataTag { - /** - * Returns the values passed to exiftool - */ - public String getKey(); - /** - * The types - */ - public Class getType(); - public boolean isMapped(); - } - - //================================================================================ - /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifTool. - *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default humanReadable is false. - *

- * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. - *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. - *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. - *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Tag implements MetadataTag { - //single entry tags - APERTURE("ApertureValue", Double.class), - AUTHOR("XPAuthor", String.class), - COLOR_SPACE("ColorSpace", Integer.class), - COMMENT("XPComment", String.class), - CONTRAST("Contrast", Integer.class), - CREATE_DATE("CreateDate", Date.class), - CREATION_DATE("CreationDate", Date.class), - DATE_CREATED("DateCreated", Date.class), - DATE_TIME_ORIGINAL("DateTimeOriginal", Date.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - FLASH("Flash", Integer.class), - FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), - FNUMBER("FNumber", String.class), - GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), - GPS_DATESTAMP("GPSDateStamp", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), - GPS_LONGITUDE("GPSLongitude", Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), - GPS_SPEED("GPSSpeed", Double.class), - GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), - IMAGE_WIDTH("ImageWidth", Integer.class), - ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), - LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), - MAKE("Make", String.class), - METERING_MODE("MeteringMode", Integer.class), - MODEL("Model", String.class), - ORIENTATION("Orientation", Integer.class), - OWNER_NAME("OwnerName", String.class), - RATING("Rating", Integer.class), - RATING_PERCENT("RatingPercent", Integer.class), - ROTATION("Rotation", Integer.class), - SATURATION("Saturation", Integer.class), - SENSING_METHOD("SensingMethod", Integer.class), - SHARPNESS("Sharpness", Integer.class), - SHUTTER_SPEED("ShutterSpeedValue", Double.class), - SOFTWARE("Software", String.class), - SUBJECT("XPSubject", String.class), - TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), - X_RESOLUTION("XResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), - ; - - /** - * Used to get the {@link Tag} identified by the given, case-sensitive, - * tag name. - * - * @param name - * The case-sensitive name of the tag that will be searched - * for. - * - * @return the {@link Tag} identified by the given, case-sensitive, tag - * name or null if one couldn't be found. - */ - public static Tag forName(String name) { - for (Tag tag : Tag.values()){ - if (tag.getKey().equals(name)){ - return tag; - } - } - return null; - } - - public static Map toTagMap(Map values) { - Map tagMap = new EnumMap(Tag.class); - for (Tag tag : Tag.values()){ - if (values.containsKey(tag.getKey())){ - tagMap.put(tag, values.get(tag.getKey())); - } - } - return tagMap; - - } - - /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifTool process) into the type described - * by the associated {@link Tag}. - * - * @param - * The type of the returned value. - * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. - * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). - * - * @throws IllegalArgumentException - * if tag is null. - * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). - * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. - */ - @SuppressWarnings("unchecked") - public T parseValue(String value) throws IllegalArgumentException { - return (T) deserialize(getKey(),value,getType()); - } - - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ - public String getName() { - return name; - } - - /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifTool Tag Guide. - * - * @return a hint for the native type of this tag's value. - */ - public Class getType() { - return type; - } - - public String getKey() { return name; } - public boolean isMapped() { return true; } - - private String name; - private Class type; - - private Tag(String name, Class type) { - this.name = name; - this.type = type; - } - } - //================================================================================ - public enum MwgTag implements MetadataTag { - LOCATION("Location",String.class), - CITY("City",String.class), - STATE("State",String.class), - COUNTRY("Country",String.class), - - COPYRIGHT("Copyright",String.class), - - DATE_TIME_ORIGINAL("DateTimeOriginal",Date.class), - CREATE_DATE("CreateDate",Date.class), - MODIFY_DATE("ModifyDate",Date.class), - - CREATOR("Creator",String.class), - DESCRIPTION("Description",String.class), - KEYWORDS("Keywords",String[].class), - - ORIENTATION("Orientation",Integer.class), - RATING("Rating",Integer.class), - - ; - - - private String name; - private Class type; - private MwgTag(String name, Class type) { - this.name = name; - this.type = type; - } - public String getKey() { return name; } - public Class getType() { return type; } - public boolean isMapped() { return true; } - public String toString() { return name; } - } - - //================================================================================ - - /** - * A Custom Tag that the user defines. Used to cover tags not in the enum. - */ - public static class CustomTag implements MetadataTag { - private final String name; - private final Class type; - private final boolean mapped; - - public CustomTag(String name, Class type) { - this(name,type,!name.trim().endsWith(":all")); - } - public CustomTag(String name, Class type, boolean mapped) { - this.name = name.trim(); - this.type = type; - this.mapped = mapped; - } - - public String getKey() { - return name; - } - - public Class getType() { - return type; - } - - public boolean isMapped() { - return mapped; - } - - public String toString() { - return getKey(); - } - } - - - //================================================================================ - public enum TagGroup implements MetadataTag { - EXIF("EXIF","exif:all"), - IPTC("IPTC","iptc:all"), - XMP("XMP","xmp:all"), - ALL("ALL","all"); - - private final String name; - private final String key; - - private TagGroup(String name, String key) { - this.name = name; - this.key = key; - } - - public String getName() { - return name; - } - public String getKey() { - return key; - } - - public Class getType() { - return Void.class; - } - - public boolean isMapped() { - return false; - } - - } - - - //================================================================================ - /** - * Class used to define an exception that occurs when the caller attempts to - * use a {@link Feature} that the underlying native ExifTool install does - * not support (i.e. the version isn't new enough). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public class UnsupportedFeatureException extends RuntimeException { - private static final long serialVersionUID = -1332725983656030770L; - - public UnsupportedFeatureException(Feature feature) { - super( - "Use of feature [" - + feature.toString() - + "] requires version " - + feature.getVersion() - + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); - } - } + if (supported == null) { + log.debug("Support for feature %s has not been checked yet, checking..."); + supported = feature.isSupported(exifVersion); + featureSupportedMap.put(feature, supported); + } + + return supported; + } + + /** + * Used to determine if the given {@link Feature} has been enabled for this + * particular instance of {@link ExifTool}. + *

+ * This method is different from {@link #isFeatureSupported(Feature)}, which + * checks if the given feature is supported by the underlying ExifTool + * install where as this method tells the caller if the given feature has + * been enabled for use in this particular instance. + * + * @param feature + * The feature to check if it has been enabled for us or not on + * this instance. + * + * @return true if the given {@link Feature} is currently + * enabled on this instance of {@link ExifTool}, otherwise returns + * false. + * + * @throws IllegalArgumentException + * if feature is null. + */ + public boolean isFeatureEnabled(Feature feature) + throws IllegalArgumentException { + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); + } + return featureEnabledSet.contains(feature); + } + + /** + * Used to startup the external ExifTool process and open the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. This method has no effect if the stay open feature is not + * enabled. + */ + public void startup() { + exifProxy.startup(); + } + + /** + * This is same as {@link #close()}, added for consistency with + * {@link #startup()} + */ + public void shutdown() { + close(); + } + + /** + * Used to shutdown the external ExifTool process and close the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. + *

+ * NOTE: Calling this method does not preclude this + * instance of {@link ExifTool} from being re-used, it merely disposes of + * the native and internal resources until the next call to + * getImageMeta causes them to be re-instantiated. + *

+ * Calling this method on an instance of this class without + * {@link Feature#STAY_OPEN} support enabled has no effect. + */ + public void close() { + exifProxy.shutdown(); + } + + public boolean isStayOpen() { + return featureEnabledSet.contains(Feature.STAY_OPEN); + } + + /** + * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support + * enabled, this method is used to determine if there is currently a running + * ExifTool process associated with this class. + *

+ * Any dependent processes and streams can be shutdown using + * {@link #close()} and this class will automatically re-create them on the + * next call to getImageMeta if necessary. + * + * @return true if there is an external ExifTool process in + * daemon mode associated with this class utilizing the + * {@link Feature#STAY_OPEN} feature, otherwise returns + * false. + */ + public boolean isRunning() { + return exifProxy != null && !exifProxy.isRunning(); + } + + public ReadOptions getReadOptions() { + return defReadOptions; + } + + public ExifTool setReadOptions(ReadOptions options) { + defReadOptions = options; + return this; + } + + public WriteOptions getWriteOptions() { + return defWriteOptions; + } + + public ExifTool setWriteOptions(WriteOptions options) { + defWriteOptions = options; + return this; + } + + // ================================================================================ + // OLD API + public static enum Format { + NUMERIC, + HUMAN_READABLE + } + + public Map getImageMeta(File image, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { + return getImageMeta(image, Format.NUMERIC, tags); + } + + public Map getImageMeta(File image, Format format, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { + + String[] stringTags = new String[tags.length]; + int i = 0; + for (Tag tag : tags) { + stringTags[i++] = tag.getKey(); + } + Map result = getImageMeta(image, format, true, + stringTags); + return Tag.toTagMap(result); + } + + public Map getImageMeta(File image, Format format, + TagGroup... tags) throws IllegalArgumentException, + SecurityException, IOException { + String[] stringTags = new String[tags.length]; + int i = 0; + for (TagGroup tag : tags) { + stringTags[i++] = tag.getKey(); + } + return getImageMeta(image, format, false, stringTags); + } + + public Map getImageMeta(File file, Format format, + boolean supressDuplicates, String... tags) throws IOException { + ReadOptions options = defReadOptions + .withNumericOutput(format == Format.NUMERIC) + .withShowDuplicates(!supressDuplicates).withConvertTypes(false); + Map result = readMetadata(options, file, tags); + Map data = new TreeMap(); + for (Map.Entry entry : result.entrySet()) { + data.put(entry.getKey().toString(), + entry.getValue() != null ? entry.getValue().toString() : ""); + } + return data; + } + + public void addImageMetadata(File image, Map values) + throws IOException { + writeMetadata(defWriteOptions.withDeleteBackupFile(false), image, + values); + } + + // ================================================================================ + public Map readMetadata(File file, Object... tags) + throws IOException { + return readMetadata(defReadOptions, file, tags); + } + + /** + * Reads metadata from the file. + */ + public Map readMetadata(ReadOptions options, File file, + Object... tags) throws IOException { + if (file == null) { + throw new IllegalArgumentException( + "file cannot be null and must be a valid stream of image data."); + } + if (!file.canRead()) { + throw new SecurityException( + "Unable to read the given image [" + + file.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + } + + List args = new ArrayList(tags.length + 2); + if (options.numericOutput) { + args.add("-n"); // numeric output + } + if (options.showDuplicates) { + args.add("-a"); + } + if (!options.showEmptyTags) { + args.add("-S"); // compact output + } + for (Object tag : tags) { + if (tag instanceof MetadataTag) { + args.add("-" + ((MetadataTag) tag).getKey()); + } else { + args.add("-" + tag); + } + } + args.add(file.getAbsolutePath()); + + Map resultMap = exifProxy.execute( + options.runTimeoutMills, args); + + Map metadata = new HashMap( + resultMap.size()); + + for (Object tag : tags) { + MetadataTag metaTag; + if (tag instanceof MetadataTag) { + metaTag = (MetadataTag) tag; + } else { + metaTag = toTag(tag.toString()); + } + if (metaTag.isMapped()) { + String input = resultMap.remove(metaTag.getKey()); + if (!options.showEmptyTags + && (input == null || input.isEmpty())) { + continue; + } + Object value = options.convertTypes ? deserialize( + metaTag.getKey(), input, metaTag.getType()) : input; + // maps with tag passed in, as caller expects to fetch + metadata.put(tag, value); + } + } + for (Map.Entry entry : resultMap.entrySet()) { + if (!options.showEmptyTags && entry.getValue() == null + || entry.getValue().isEmpty()) { + continue; + } + if (options.convertTypes) { + MetadataTag metaTag = toTag(entry.getKey()); + Object value = deserialize(metaTag.getKey(), entry.getValue(), + metaTag.getType()); + metadata.put(entry.getKey(), value); + } else { + metadata.put(entry.getKey(), entry.getValue()); + + } + } + return metadata; + } + + public void writeMetadata(File image, Map values) + throws IOException { + writeMetadata(defWriteOptions, image, values); + } + + /** + * Takes a map of tags (either (@link Tag) or Strings for keys) and + * replaces/appends them to the metadata. + */ + public void writeMetadata(WriteOptions options, File image, + Map values) throws IOException { + if (image == null) { + throw new IllegalArgumentException( + "image cannot be null and must be a valid stream of image data."); + } + if (values == null || values.isEmpty()) { + throw new IllegalArgumentException( + "values cannot be null and must contain 1 or more tag to value mappings"); + } + + if (!image.canWrite()) { + throw new SecurityException( + "Unable to write the given image [" + + image.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to write to it."); + } + + log.info("Adding Tags {} to {}", values, image.getAbsolutePath()); + + List args = new ArrayList(values.size() + 3); + for (Map.Entry entry : values.entrySet()) { + args.addAll(serializeToArgs(entry.getKey(), entry.getValue())); + } + args.add(image.getAbsolutePath()); + + // start process + long startTime = System.currentTimeMillis(); + try { + exifProxy.execute(options.runTimeoutMills, args); + } finally { + if (options.deleteBackupFile) { + File origBackup = new File(image.getAbsolutePath() + + "_original"); + if (origBackup.exists()) + origBackup.delete(); + } + } + + // Print out how long the call to external ExifTool process took. + if (log.isDebugEnabled()) { + log.debug(String.format( + "Image Meta Processed in %d ms [added %d tags]", + (System.currentTimeMillis() - startTime), values.size())); + } + } + + // ================================================================================ + // STATIC helpers + + static List serializeToArgs(Object tag, Object value) { + final Class tagType; + final String tagName; + if (tag instanceof MetadataTag) { + tagName = ((MetadataTag) tag).getKey(); + tagType = ((MetadataTag) tag).getType(); + } else { + tagName = tag.toString(); + tagType = null; + } + + // pre process + if (value != null) { + if (value.getClass().isArray()) { + // convert array to iterable, this is lame + int len = Array.getLength(value); + List newList = new ArrayList(len); + for (int i = 0; i < len; i++) { + Object item = Array.get(value, i); + newList.add(item); + } + value = newList; + } else if (value instanceof Number && Date.class.equals(tagType)) { + // if we know this is a date field and data is a number assume + // it is unix epoch time + Date date = new Date(((Number) value).longValue()); + value = date; + } + } + + List args = new ArrayList(4); + String arg; + if (value == null) { + arg = String.format("-%s=", tagName); + } else if (value instanceof Number) { + arg = String.format("-%s#=%s", tagName, value); + } else if (value instanceof Date) { + SimpleDateFormat formatter = new SimpleDateFormat(EXIF_DATE_FORMAT); + arg = String.format("-%s=%s", tagName, + formatter.format((Date) value)); + } else if (value instanceof Iterable) { + Iterable it = (Iterable) value; + args.add("-sep"); + args.add(","); + StringBuilder itemList = new StringBuilder(); + for (Object item : it) { + if (itemList.length() > 0) { + itemList.append(","); + } + itemList.append(item); + } + arg = String.format("-%s=%s", tagName, itemList); + } else { + if (tagType != null && tagType.isArray()) { + args.add("-sep"); + args.add(","); + } + arg = String.format("-%s=%s", tagName, value); + } + args.add(arg); + return args; + } + + static Object deserialize(String tagName, String value, Class expectedType) { + try { + if (Boolean.class.equals(expectedType)) { + if (value == null) + return null; + value = value.trim().toLowerCase(); + switch (value.charAt(0)) { + case 'n': + case 'f': + case '0': + return false; + } + if (value.equals("off")) { + return false; + } + return true; + } else if (Date.class.equals(expectedType)) { + if (value == null) + return null; + SimpleDateFormat formatter = new SimpleDateFormat( + EXIF_DATE_FORMAT); + return formatter.parse(value); + } else if (Integer.class.equals(expectedType)) { + if (value == null) + return 0; + return Integer.parseInt(value); + } else if (Long.class.equals(expectedType)) { + if (value == null) + return 0; + return Long.parseLong(value); + } else if (Float.class.equals(expectedType)) { + if (value == null) + return 0; + return Float.parseFloat(value); + } else if (Double.class.equals(expectedType)) { + if (value == null) + return 0; + String[] enumeratorAndDivisor = value.split("/"); + if (enumeratorAndDivisor.length == 2) { + return Double.parseDouble(enumeratorAndDivisor[0]) + / Double.parseDouble(enumeratorAndDivisor[1]); + } else { + return Double.parseDouble(value); + } + } else if (String[].class.equals(expectedType)) { + if (value == null) + return new String[0]; + return value.split(","); + } else { + return value; + } + } catch (ParseException ex) { + log.warn("Invalid format, Tag:" + tagName); + return null; + } catch (NumberFormatException ex) { + log.warn("Invalid format, Tag:" + tagName); + return null; + } + + } + + static MetadataTag toTag(String name) { + for (Tag tag : Tag.values()) { + if (tag.getKey().equalsIgnoreCase(name)) { + return tag; + } + } + for (MwgTag tag : MwgTag.values()) { + if (tag.getKey().equalsIgnoreCase(name)) { + return tag; + } + } + return new CustomTag(name, String.class); + } + + // ================================================================================ + /** + * Represents an external exif process. Works for both single use and keep + * alive modes. This is the actual process, with streams for reading and + * writing data. + */ + public static final class ExifProcess { + public static VersionNumber readVersion(String exifCmd) { + ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, + "-ver")); + try { + return new VersionNumber(process.readLine()); + } catch (IOException ex) { + throw new RuntimeException(String.format( + "Unable to check version number of ExifTool: %s", + exifCmd)); + } finally { + process.close(); + } + } + + private final ReentrantLock closeLock = new ReentrantLock(false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader reader; + private final OutputStreamWriter writer; + private volatile boolean closed = false; + + public ExifProcess(boolean keepAlive, List args) { + this.keepAlive = keepAlive; + log.debug(String + .format("Attempting to start ExifTool process using args: %s", + args)); + try { + this.process = new ProcessBuilder(args).start(); + this.reader = new BufferedReader(new InputStreamReader( + process.getInputStream())); + this.writer = new OutputStreamWriter(process.getOutputStream()); + log.debug("\tSuccessful"); + } catch (Exception e) { + String message = "Unable to start external ExifTool process using the execution arguments: " + + args + + ". Ensure ExifTool is installed correctly and runs using the command path '" + + args.get(0) + + "' as specified by the 'exiftool.path' system property."; + + log.debug(message); + throw new RuntimeException(message, e); + } + } + + public synchronized Map sendToRunning(List args) + throws IOException { + if (!keepAlive) { + throw new IOException("Not KeepAlive Process"); + } + StringBuilder builder = new StringBuilder(); + for (String arg : args) { + builder.append(arg).append("\n"); + } + builder.append("-execute\n"); + writeFlush(builder.toString()); + return readResponse(); + } + + public synchronized void writeFlush(String message) throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + writer.write(message); + writer.flush(); + } + + public synchronized String readLine() throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + return reader.readLine(); + } + + public synchronized Map readResponse() + throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + log.debug("Reading response back from ExifTool..."); + Map resultMap = new HashMap(500); + String line; + + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + String[] pair = TAG_VALUE_PATTERN.split(line, 2); + + if (pair.length == 2) { + resultMap.put(pair[0], pair[1]); + log.debug(String.format("\tRead Tag [name=%s, value=%s]", + pair[0], pair[1])); + } + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } + } + return resultMap; + } + + public boolean isClosed() { + return closed; + } + + public void close() { + if (!closed) { + closeLock.lock(); + try { + if (!closed) { + closed = true; + try { + log.debug("Closing Read stream..."); + reader.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); + writer.write("-stay_open\nFalse\n"); + writer.flush(); + } catch (IOException ex) { + // log.error(ex,ex); + } + + try { + log.debug("Closing Write stream..."); + writer.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + log.debug("Read/Write streams successfully closed."); + + try { + process.destroy(); + } catch (Exception e) { + // + } + // process = null; + + } + } finally { + closeLock.unlock(); + } + } + } + } + + /** + * A Proxy to an Exif Process, will restart if backing exif process died, or + * run new one on every call. + * + * @author Matt Gile, msgile + */ + public interface ExifProxy { + public void startup(); + + public Map execute(long runTimeoutMills, + List args) throws IOException; + + public boolean isRunning(); + + public void shutdown(); + } + + /** + * Manages an external exif process in keep alive mode. + */ + public static class KeepAliveExifProxy implements ExifProxy { + private final List startupArgs; + private final AtomicBoolean shuttingDown = new AtomicBoolean(false); + private final Timer cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); + private long inactivityTimeout = 0; + private volatile long lastRunStart = 0; + private volatile ExifProcess process; + + public KeepAliveExifProxy(String exifCmd, List baseArgs) { + inactivityTimeout = Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, + DEFAULT_PROCESS_CLEANUP_DELAY); + startupArgs = new ArrayList(baseArgs.size() + 5); + startupArgs.add(exifCmd); + startupArgs.addAll(Arrays.asList("-stay_open", "True")); + startupArgs.addAll(baseArgs); + startupArgs.addAll(Arrays.asList("-@", "-")); + // runs every minute to check if process has been inactive too long + cleanupTimer.schedule(new TimerTask() { + @Override + public void run() { + if (process != null && lastRunStart > 0 + && inactivityTimeout > 0) { + if ((System.currentTimeMillis() - lastRunStart) > inactivityTimeout) { + synchronized (this) { + if (process != null) { + process.close(); + } + } + } + } + } + }, 60 * 1000); // every minute + } + + public void setInactiveTimeout(long mills) { + this.inactivityTimeout = mills; + } + + @Override + public void startup() { + shuttingDown.set(false); + if (process == null || process.isClosed()) { + synchronized (this) { + if (process == null || process.isClosed()) { + log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = new ExifProcess(true, startupArgs); + } + } + } + } + + @Override + public Map execute(final long runTimeoutMills, + List args) throws IOException { + lastRunStart = System.currentTimeMillis(); + int attempts = 0; + while (attempts < 3 && !shuttingDown.get()) { + attempts++; + if (process == null || process.isClosed()) { + synchronized (this) { + if (process == null || process.isClosed()) { + log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = new ExifProcess(true, startupArgs); + } + } + } + TimerTask attemptTimer = null; + try { + if (runTimeoutMills > 0) { + attemptTimer = new TimerTask() { + @Override + public void run() { + if (process != null && !process.isClosed()) { + log.warn("Process ran too long closing, max " + + runTimeoutMills + " mills"); + process.close(); + } + } + }; + cleanupTimer.schedule(attemptTimer, runTimeoutMills); + } + log.debug("Streaming arguments to ExifTool process..."); + return process.sendToRunning(args); + } catch (IOException ex) { + if (STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) + && !shuttingDown.get()) { + // only catch "Stream Closed" error (happens when + // process has died) + log.warn(String + .format("Caught IOException(\"%s\"), will restart daemon", + STREAM_CLOSED_MESSAGE)); + process.close(); + } else { + throw ex; + } + } finally { + if (attemptTimer != null) + attemptTimer.cancel(); + } + } + if (shuttingDown.get()) { + throw new IOException("Shutting Down"); + } + throw new IOException("Ran out of attempts"); + } + + @Override + public boolean isRunning() { + return process != null && !process.isClosed(); + } + + @Override + public void shutdown() { + shuttingDown.set(true); + } + } + + public static class SingleUseExifProxy implements ExifProxy { + private final Timer cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); + private final List baseArgs; + + public SingleUseExifProxy(String exifCmd, List defaultArgs) { + this.baseArgs = new ArrayList(defaultArgs.size() + 1); + this.baseArgs.add(exifCmd); + this.baseArgs.addAll(defaultArgs); + } + + @Override + public Map execute(final long runTimeoutMills, + List args) throws IOException { + List newArgs = new ArrayList(baseArgs.size() + + args.size()); + newArgs.addAll(baseArgs); + newArgs.addAll(args); + final ExifProcess process = new ExifProcess(false, newArgs); + TimerTask attemptTimer = null; + if (runTimeoutMills > 0) { + attemptTimer = new TimerTask() { + @Override + public void run() { + if (!process.isClosed()) { + log.warn("Process ran too long closing, max " + + runTimeoutMills + " mills"); + process.close(); + } + } + }; + cleanupTimer.schedule(attemptTimer, runTimeoutMills); + } + try { + return process.readResponse(); + } finally { + process.close(); + if (attemptTimer != null) + attemptTimer.cancel(); + } + } + + @Override + public void startup() { + ; + } + + @Override + public boolean isRunning() { + return false; + } + + @Override + public void shutdown() { + ; + } + } + + // ================================================================================ + /** + * All the read options, is immutable, copy on change, fluent style "with" + * setters. + */ + public static class ReadOptions { + private final long runTimeoutMills; + private final boolean convertTypes; + private final boolean numericOutput; + private final boolean showDuplicates; + private final boolean showEmptyTags; + + public ReadOptions() { + this(0, false, false, false, false); + } + + private ReadOptions(long runTimeoutMills, boolean convertTypes, + boolean numericOutput, boolean showDuplicates, + boolean showEmptyTags) { + this.runTimeoutMills = runTimeoutMills; + this.convertTypes = convertTypes; + this.numericOutput = numericOutput; + this.showDuplicates = showDuplicates; + this.showEmptyTags = showEmptyTags; + } + + @Override + public String toString() { + return String + .format("%s(runTimeout:%,d convertTypes:%s showDuplicates:%s showEmptyTags:%s)", + getClass().getSimpleName(), runTimeoutMills, + convertTypes, showDuplicates, showEmptyTags); + } + + /** + * Sets the maximum time a process can run + */ + public ReadOptions withRunTimeoutMills(long mills) { + return new ReadOptions(mills, convertTypes, numericOutput, + showDuplicates, showEmptyTags); + } + + /** + * By default all values will be returned as the strings printed by the + * exiftool. If this is enabled then {@link MetadataTag#getType()} is + * used to cast the string into a java type. + */ + public ReadOptions withConvertTypes(boolean enabled) { + return new ReadOptions(runTimeoutMills, enabled, numericOutput, + showDuplicates, showEmptyTags); + } + + /** + * Setting this to true will add the "-n" option causing the ExifTool to + * output of some tags to change. + *

+ * ExifTool, via the -n command line arg, is capable of + * returning most values in their raw numeric form (e.g. + * Aperture="2.8010323841") as well as a more human-readable/friendly + * format (e.g. Aperture="2.8"). + *

+ * While the {@link Tag}s defined on this class do provide a hint at the + * type of the result (see {@link MetadataTag#getType()}), that hint + * only applies when the numeric value is returned. + *

+ * If the caller finds the human-readable format easier to process, Set + * this to false, the default. + *

+ * In order to see the types of values that are returned when human + * readable is used (default), you can check the comprehensive + * ExifTool Tag Guide. + *

+ * This makes sense with some values like Aperture that in numeric + * format end up returning as 14-decimal-place, high precision values + * that are near the intended value (e.g. "2.79999992203711" instead of + * just returning "2.8"). On the other hand, other values (like + * Orientation) are easier to parse when their numeric value (1-8) is + * returned instead of a much longer friendly name (e.g. + * "Mirror horizontal and rotate 270 CW"). + * + * Attempted from work done by + * + * @author Riyad Kalla (software@thebuzzmedia.com) + */ + public ReadOptions withNumericOutput(boolean enabled) { + return new ReadOptions(runTimeoutMills, convertTypes, enabled, + showDuplicates, showEmptyTags); + } + + /** + * If enabled will show tags which are duplicated between different tag + * regions, relates to the "-a" option in ExifTool. + */ + public ReadOptions withShowDuplicates(boolean enabled) { + return new ReadOptions(runTimeoutMills, convertTypes, + numericOutput, enabled, showEmptyTags); + } + + public ReadOptions withShowEmptyTags(boolean enabled) { + return new ReadOptions(runTimeoutMills, convertTypes, + numericOutput, showDuplicates, enabled); + } + } + + // ================================================================================ + /** + * All the write options, is immutable, copy on change, fluent style "with" + * setters. + */ + public static class WriteOptions { + private final long runTimeoutMills; + private final boolean deleteBackupFile; + + public WriteOptions() { + this(0, false); + } + + private WriteOptions(long runTimeoutMills, boolean deleteBackupFile) { + this.runTimeoutMills = runTimeoutMills; + this.deleteBackupFile = deleteBackupFile; + } + + @Override + public String toString() { + return String.format("%s(runTimeOut:%,d deleteBackupFile:%s)", + getClass().getSimpleName(), runTimeoutMills, + deleteBackupFile); + } + + public WriteOptions withRunTimeoutMills(long mills) { + return new WriteOptions(mills, deleteBackupFile); + } + + /** + * ExifTool automatically makes a backup copy a file before writing + * metadata tags in the form "file.ext_original", by default this tool + * will delete that original file after the writing is done. + */ + public WriteOptions withDeleteBackupFile(boolean enabled) { + return new WriteOptions(runTimeoutMills, enabled); + } + } + + // ================================================================================ + /** + * Enum used to define the different kinds of features in the native + * ExifTool executable that this class can help you take advantage of. + *

+ * These flags are different from {@link Tag}s in that a "feature" is + * determined to be a special functionality of the underlying ExifTool + * executable that requires a different code-path in this class to take + * advantage of; for example, -stay_open True support. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Feature { + /** + * Enum used to specify that you wish to launch the underlying ExifTool + * process with -stay_open True support turned on that this + * class can then take advantage of. + *

+ * Required ExifTool version is 8.36 or higher. + */ + STAY_OPEN(8, 36), + /** + * Acitves the MWG modules. The Metadata Working Group (MWG) recommends + * techniques to allow certain overlapping EXIF, IPTC and XMP tags to be + * reconciled when reading, and synchronized when writing. The MWG + * Composite tags below are designed to aid in the implementation of + * these recommendations. Will add the args " -use MWG" + * + * @see ExifTool + * MWG Docs !! Note these version numbers are not correct + */ + MWG_MODULE(8, 36), ; + + private VersionNumber requireVersion; + + private Feature(int... numbers) { + this.requireVersion = new VersionNumber(numbers); + } + + /** + * Used to get the version of ExifTool required by this feature in order + * to work. + * + * @return the version of ExifTool required by this feature in order to + * work. + */ + VersionNumber getVersion() { + return requireVersion; + } + + boolean isSupported(VersionNumber exifVersionNumber) { + return requireVersion.isBeforeOrEqualTo(exifVersionNumber); + } + } + + // ================================================================================ + /** + * Version Number used to determine if one version is after another. + * + * @author Matt Gile, msgile + */ + static class VersionNumber { + private final int[] numbers; + + public VersionNumber(String str) { + String[] versionParts = str.trim().split("\\."); + this.numbers = new int[versionParts.length]; + for (int i = 0; i < versionParts.length; i++) { + numbers[i] = Integer.parseInt(versionParts[i]); + } + } + + public VersionNumber(int... numbers) { + this.numbers = numbers; + } + + public boolean isBeforeOrEqualTo(VersionNumber other) { + int max = Math.min(this.numbers.length, other.numbers.length); + for (int i = 0; i < max; i++) { + if (this.numbers[i] > other.numbers[i]) { + return false; + } else if (this.numbers[i] < other.numbers[i]) { + return true; + } + } + // assume missing number as zero, so if the current process number + // is more digits it is a higher version + return this.numbers.length <= other.numbers.length; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + for (int number : numbers) { + if (builder.length() > 0) { + builder.append("."); + } + builder.append(number); + } + return builder.toString(); + } + } + + // ================================================================================ + /** + * Base type for all "tag" passed to exiftool. The key is the value passed + * to the exiftool like "-creator". The Types is used for automatic type + * conversions. + * + */ + public interface MetadataTag { + /** + * Returns the values passed to exiftool + */ + public String getKey(); + + /** + * The types + */ + public Class getType(); + + public boolean isMapped(); + } + + // ================================================================================ + /** + * Enum used to pre-define a convenient list of tags that can be easily + * extracted from images using this class with an external install of + * ExifTool. + *

+ * Each tag defined also includes a type hint for the parsed value + * associated with it when the default humanReadable is false. + *

+ * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or + * process the returned {@link String} values any way they wish. + *

Tag Support

+ * ExifTool is capable of parsing almost every tag known to man (1000+), but + * this class makes an attempt at pre-defining a convenient list of the most + * common tags for use. + *

+ * This list was determined by looking at the common metadata tag values + * written to images by popular mobile devices (iPhone, Android) as well as + * cameras like simple point and shoots as well as DSLRs. As an additional + * source of input the list of supported/common EXIF formats that Flickr + * supports was also reviewed to ensure the most common/useful tags were + * being covered here. + *

+ * Please email me or file an issue + * if you think this list is missing a commonly used tag that should be + * added to it. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Tag implements MetadataTag { + // single entry tags + APERTURE("ApertureValue", Double.class), + AUTHOR("XPAuthor", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATE_DATE("CreateDate", Date.class), + CREATION_DATE("CreationDate", Date.class), + DATE_CREATED("DateCreated", Date.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", Date.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + FLASH("Flash", Integer.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + FNUMBER("FNumber", String.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_DATESTAMP("GPSDateStamp", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SENSING_METHOD("SensingMethod", Integer.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), ; + + /** + * Used to get the {@link Tag} identified by the given, case-sensitive, + * tag name. + * + * @param name + * The case-sensitive name of the tag that will be searched + * for. + * + * @return the {@link Tag} identified by the given, case-sensitive, tag + * name or null if one couldn't be found. + */ + public static Tag forName(String name) { + for (Tag tag : Tag.values()) { + if (tag.getKey().equals(name)) { + return tag; + } + } + return null; + } + + public static Map toTagMap(Map values) { + Map tagMap = new EnumMap(Tag.class); + for (Tag tag : Tag.values()) { + if (values.containsKey(tag.getKey())) { + tagMap.put(tag, values.get(tag.getKey())); + } + } + return tagMap; + + } + + /** + * Convenience method used to convert the given string Tag value + * (returned from the external ExifTool process) into the type described + * by the associated {@link Tag}. + * + * @param + * The type of the returned value. + * @param value + * The {@link String} representation of the tag's value as + * parsed from the image. + * + * @return the given string value converted to a native Java type (e.g. + * Integer, Double, etc.). + * + * @throws IllegalArgumentException + * if tag is null. + * @throws NumberFormatException + * if any exception occurs while trying to parse the given + * value to any of the supported numeric types + * in Java via calls to the respective parseXXX + * methods defined on all the numeric wrapper classes (e.g. + * {@link Integer#parseInt(String)} , + * {@link Double#parseDouble(String)} and so on). + * @throws ClassCastException + * if the type defined by T is incompatible + * with the type defined by {@link Tag#getType()} returned + * by the tag argument passed in. This class + * performs an implicit/unchecked cast to the type + * T before returning the parsed result of the + * type indicated by {@link Tag#getType()}. If the types do + * not match, a ClassCastException will be + * generated by the VM. + */ + @SuppressWarnings("unchecked") + public T parseValue(String value) throws IllegalArgumentException { + return (T) deserialize(getKey(), value, getType()); + } + + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ + public String getName() { + return name; + } + + /** + * Used to get a hint for the native type of this tag's value as + * specified by Phil Harvey's ExifTool Tag Guide. + * + * @return a hint for the native type of this tag's value. + */ + @Override + public Class getType() { + return type; + } + + @Override + public String getKey() { + return name; + } + + @Override + public boolean isMapped() { + return true; + } + + private String name; + private Class type; + + private Tag(String name, Class type) { + this.name = name; + this.type = type; + } + } + + // ================================================================================ + public enum MwgTag implements MetadataTag { + LOCATION("Location", String.class), + CITY("City", String.class), + STATE("State", String.class), + COUNTRY("Country", String.class), + + COPYRIGHT("Copyright", String.class), + + DATE_TIME_ORIGINAL("DateTimeOriginal", Date.class), + CREATE_DATE("CreateDate", Date.class), + MODIFY_DATE("ModifyDate", Date.class), + + CREATOR("Creator", String.class), + DESCRIPTION("Description", String.class), + KEYWORDS("Keywords", String[].class), + + ORIENTATION("Orientation", Integer.class), + RATING("Rating", Integer.class), + + ; + + private String name; + private Class type; + + private MwgTag(String name, Class type) { + this.name = name; + this.type = type; + } + + @Override + public String getKey() { + return name; + } + + @Override + public Class getType() { + return type; + } + + @Override + public boolean isMapped() { + return true; + } + + @Override + public String toString() { + return name; + } + } + + // ================================================================================ + + /** + * A Custom Tag that the user defines. Used to cover tags not in the enum. + */ + public static class CustomTag implements MetadataTag { + private final String name; + private final Class type; + private final boolean mapped; + + public CustomTag(String name, Class type) { + this(name, type, !name.trim().endsWith(":all")); + } + + public CustomTag(String name, Class type, boolean mapped) { + this.name = name.trim(); + this.type = type; + this.mapped = mapped; + } + + @Override + public String getKey() { + return name; + } + + @Override + public Class getType() { + return type; + } + + @Override + public boolean isMapped() { + return mapped; + } + + @Override + public String toString() { + return getKey(); + } + } + + // ================================================================================ + public enum TagGroup implements MetadataTag { + EXIF("EXIF", "exif:all"), + IPTC("IPTC", "iptc:all"), + XMP("XMP", "xmp:all"), + ALL("ALL", "all"); + + private final String name; + private final String key; + + private TagGroup(String name, String key) { + this.name = name; + this.key = key; + } + + public String getName() { + return name; + } + + @Override + public String getKey() { + return key; + } + + @Override + public Class getType() { + return Void.class; + } + + @Override + public boolean isMapped() { + return false; + } + + } + + // ================================================================================ + /** + * Class used to define an exception that occurs when the caller attempts to + * use a {@link Feature} that the underlying native ExifTool install does + * not support (i.e. the version isn't new enough). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public class UnsupportedFeatureException extends RuntimeException { + private static final long serialVersionUID = -1332725983656030770L; + + public UnsupportedFeatureException(Feature feature) { + super( + "Use of feature [" + + feature.toString() + + "] requires version " + + feature.getVersion() + + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); + } + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index 6145f0a7..8ec7233b 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -1,76 +1,78 @@ package com.thebuzzmedia.exiftool; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Tag; +import java.io.File; +import java.io.IOException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.IOException; +import com.thebuzzmedia.exiftool.ExifTool.Feature; +import com.thebuzzmedia.exiftool.ExifTool.Tag; public class Benchmark { - public static final int ITERATIONS = 25; - private static Logger log = LoggerFactory.getLogger(Benchmark.class); - + public static final int ITERATIONS = 25; + private static Logger log = LoggerFactory.getLogger(Benchmark.class); - public static void main(String[] args) throws IOException, InterruptedException { + public static void main(String[] args) throws IOException, + InterruptedException { - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); - final Tag[] tags = Tag.values(); - final File[] images = new File("src/test/resources").listFiles(); + final Tag[] tags = Tag.values(); + final File[] images = new File("src/test/resources").listFiles(); - log.info("Benchmark [tags=" + tags.length + ", images=" - + images.length + ", iterations=" + ITERATIONS + "]"); - log.info("\t" + (images.length * ITERATIONS) - + " ExifTool process calls, " - + (tags.length * images.length * ITERATIONS) - + " total operations.\n"); + log.info("Benchmark [tags=" + tags.length + ", images=" + images.length + + ", iterations=" + ITERATIONS + "]"); + log.info("\t" + (images.length * ITERATIONS) + + " ExifTool process calls, " + + (tags.length * images.length * ITERATIONS) + + " total operations.\n"); - ExifTool tool = new ExifTool(); - ExifTool toolSO = new ExifTool(Feature.STAY_OPEN); + ExifTool tool = new ExifTool(); + ExifTool toolSO = new ExifTool(Feature.STAY_OPEN); /* * -stay_open False */ - log.info("\t[-stay_open False]"); - long elapsedTime = 0; + log.info("\t[-stay_open False]"); + long elapsedTime = 0; - for (int i = 1; i <= ITERATIONS; i++){ - log.info(String.format("iteration %s of %s", i, ITERATIONS)); - elapsedTime += run(tool, images, tags); - } + for (int i = 1; i <= ITERATIONS; i++) { + log.info(String.format("iteration %s of %s", i, ITERATIONS)); + elapsedTime += run(tool, images, tags); + } - log.info("\t\tElapsed Time: " + elapsedTime + " ms (" - + ((double) elapsedTime / 1000) + " secs)"); + log.info("\t\tElapsed Time: " + elapsedTime + " ms (" + + ((double) elapsedTime / 1000) + " secs)"); /* * -stay_open True */ - log.info("\n\t[-stay_open True]"); - long elapsedTimeSO = 0; + log.info("\n\t[-stay_open True]"); + long elapsedTimeSO = 0; - for (int i = 1; i <= ITERATIONS; i++) { - log.info(String.format("iteration %s of %s", i, ITERATIONS)); - elapsedTimeSO += run(toolSO, images, tags); - } + for (int i = 1; i <= ITERATIONS; i++) { + log.info(String.format("iteration %s of %s", i, ITERATIONS)); + elapsedTimeSO += run(toolSO, images, tags); + } - log.info("\t\tElapsed Time: " + elapsedTimeSO + " ms (" - + ((double) elapsedTimeSO / 1000) + " secs - " - + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); + log.info("\t\tElapsed Time: " + elapsedTimeSO + " ms (" + + ((double) elapsedTimeSO / 1000) + " secs - " + + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); - // Shut down the running exiftool proc. - toolSO.close(); - } + // Shut down the running exiftool proc. + toolSO.close(); + } - private static long run(ExifTool tool, File[] images, Tag[] tags) - throws IllegalArgumentException, SecurityException, IOException { - long startTime = System.currentTimeMillis(); + private static long run(ExifTool tool, File[] images, Tag[] tags) + throws IllegalArgumentException, SecurityException, IOException { + long startTime = System.currentTimeMillis(); - for (File image : images){ - tool.getImageMeta(image, tags); - } + for (File image : images) { + tool.getImageMeta(image, tags); + } - return (System.currentTimeMillis() - startTime); - } + return (System.currentTimeMillis() - startTime); + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index 27e536e7..35439204 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -1,46 +1,55 @@ package com.thebuzzmedia.exiftool; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Format; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.io.IOException; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import com.thebuzzmedia.exiftool.ExifTool.Feature; +import com.thebuzzmedia.exiftool.ExifTool.Format; + public class Example { - private static Logger log = LoggerFactory.getLogger(Example.class); - private static final String TEST_FILES_PATH = "src/test/resources"; - - public static void main(String[] args) throws IOException, InterruptedException { - - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); - ExifTool tool = new ExifTool(Feature.STAY_OPEN); - - File[] images = new File(TEST_FILES_PATH).listFiles(); - - //list all first-class tags - for (File f : images) { - log.info("\n[{}]", f.getName()); - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, ExifTool.Tag.values()); - for (ExifTool.Tag key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key.getKey(), metadata.get(key))); - } - } - - log.info("\n\n** GET TAGS BY GROUP"); - //list all XMP, IPTC and XMP tags - File f = new File(TEST_FILES_PATH + "/kureckjones_jett_075_02-cropped.tif"); - for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] {ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, ExifTool.TagGroup.XMP}){ - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, tagGroup); - log.info(tagGroup.getKey()); - for (String key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - } - } - - tool.close(); - } + private static Logger log = LoggerFactory.getLogger(Example.class); + private static final String TEST_FILES_PATH = "src/test/resources"; + + public static void main(String[] args) throws IOException, + InterruptedException { + + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + + File[] images = new File(TEST_FILES_PATH).listFiles(); + + // list all first-class tags + for (File f : images) { + log.info("\n[{}]", f.getName()); + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, ExifTool.Tag.values()); + for (ExifTool.Tag key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key.getKey(), + metadata.get(key))); + } + } + + log.info("\n\n** GET TAGS BY GROUP"); + // list all XMP, IPTC and XMP tags + File f = new File(TEST_FILES_PATH + + "/kureckjones_jett_075_02-cropped.tif"); + for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] { + ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, + ExifTool.TagGroup.XMP }) { + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, tagGroup); + log.info(tagGroup.getKey()); + for (String key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + } + } + + tool.close(); + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 5fdfd815..52756adc 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -1,8 +1,8 @@ package com.thebuzzmedia.exiftool; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; @@ -20,460 +20,556 @@ import java.util.Map; import java.util.Set; -import static org.junit.Assert.*; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * TestMetadata

- * + * TestMetadata + *

+ * * @author Michael Rush (michaelrush@gmail.com) * @since Initially created 8/8/13 */ public class TestExifTool { - private static Logger log = LoggerFactory.getLogger(TestExifTool.class); - - @Test - public void testSingleTool() throws Exception { - ExifTool tool = new ExifTool(); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.startup(); - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - } - - @Test - public void testConcurrent() throws Exception { - - int toolCount = 5; - - List threads = new ArrayList(toolCount); - for (int i=1; i <= toolCount; i++){ - String toolName = "tool"+i; - Thread t = new Thread(toolName){ - @Override - public void run() { - log.info(getName() + ": starting"); - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - runTests(tool,getName()); - log.info(getName() + ": finished"); - } catch (IOException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } catch (URISyntaxException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } finally { - tool.shutdown(); - } - log.info(getName() + ": finished"); - } - }; - t.start(); - threads.add(t); - } - - for (Thread t : threads){ - t.run(); - } - } - - @Test - public void testManyThreadsOneTool() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Thread[] threads = new Thread[20]; - for(int i=0; i < threads.length; i++) { - final String label = "run "+i; - threads[i] = new Thread(new Runnable() { - public void run() { - try { - for(int j=0; j<5; j++) { - runTests(tool,label); - } - log.info("DONE: "+label+" success!"); - } catch (IOException ex) { - fail(label); - } catch (URISyntaxException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } - } - },label); - } - for(Thread thread : threads) { - thread.start(); - } - for(Thread thread : threads) { - thread.join(); - } - } finally { - tool.shutdown(); - } - } - - @Test - public void testProcessTimeout() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.setRunTimeout(1); - runTests(tool,"will fail"); - fail("should have failed"); - } catch (IOException ex) { - ; - } finally { - tool.shutdown(); - } - } - - public boolean runTests(ExifTool tool, String runId) throws IOException, URISyntaxException { - - Map metadata; - File imageFile; - Set keys; - ExifTool.Tag tag; - - URL url = getClass().getResource("/kureckjones_jett_075_02-cropped.tif"); - imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(22, metadata.size()); - - keys = metadata.keySet(); - - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(728, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(825, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("P 45+", tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 1"); - - - url = getClass().getResource("/nexus-s-electric-cars.jpg"); - imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(23, metadata.size()); - - keys = metadata.keySet(); - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(2560, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(1920, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.ISO; - assertEquals(50, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.SHUTTER_SPEED; - assertEquals("1/64", metadata.get(tag)); - assertEquals(0.015625, tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 2"); - return true; - } - - @Test - public void testGroupTags() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Map metadata; - - URL url = getClass().getResource("/iptc_test-photoshop.jpg"); - File f = new File(url.toURI()); - metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, ExifTool.TagGroup.IPTC); - assertEquals(17, metadata.size()); - assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); - assertEquals("IPTC Status: Copyright Notice", metadata.get("CopyrightNotice")); - assertEquals("IPTC Content: Description Writer", metadata.get("Writer-Editor")); - //for (String key : metadata.keySet()){ - // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - //} - } finally { - tool.shutdown(); - } - } - - @Test - public void testTag(){ - assertEquals("string value", "John Doe", ExifTool.Tag.AUTHOR.parseValue("John Doe")); - assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); - assertEquals("double value, from fraction", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); - assertEquals("double value, from decimal", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); - } - - @Test - public void testVersionNumber() { - assertTrue(new ExifTool.VersionNumber("1.2").isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); - assertTrue(new ExifTool.VersionNumber(1,2).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber(2,1))); - } - - @Test - public void testWriteTagStringNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteTagString() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteTagStringInvalidformat() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - String newDate = "2egek opkpgrpok"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - - // Now change it to an invalid value which should fail - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's not updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - // might not exist - if(backup_url != null) { - Path backupFile = Paths.get(backup_url.toURI()); - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - } - - @Test - public void testWriteTagNumberNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteTagNumber() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteMultipleTag() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteMultipleTagNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.writeMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWritingWithImplicitTypes() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.MWG_MODULE); - tool.setReadOptions(tool.getReadOptions().withNumericOutput(true).withConvertTypes(true)); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - File imageFile = Paths.get(url.toURI()).toFile(); - try { - // Test what orientation value is at the start - SimpleDateFormat formatter = new SimpleDateFormat("yyyy:MM:dd hh:mm:ss"); - - Map metadata = tool.readMetadata(imageFile, ExifTool.Tag.ORIENTATION, ExifTool.MwgTag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", 1, metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("Wrong starting value", formatter.parse("2010:12:10 17:07:05"), metadata.get(ExifTool.MwgTag.DATE_TIME_ORIGINAL)); - - // Now change them - Map data = new HashMap(); - Date dateTimeOrig = formatter.parse("2014:01:23 10:07:05"); - data.put(ExifTool.MwgTag.DATE_TIME_ORIGINAL, dateTimeOrig); - data.put(ExifTool.Tag.ORIENTATION, 3); - Date createDate = formatter.parse("2013:02:21 10:07:05"); - data.put(ExifTool.MwgTag.CREATE_DATE, createDate.getTime()); - data.put(ExifTool.MwgTag.KEYWORDS, new String[]{"a", "b", "c"}); - tool.writeMetadata(tool.getWriteOptions().withDeleteBackupFile(false),imageFile, data); - - // Finally check the updated value - metadata = tool.readMetadata(imageFile, ExifTool.Tag.ORIENTATION, imageFile, ExifTool.MwgTag.DATE_TIME_ORIGINAL, ExifTool.MwgTag.CREATE_DATE, ExifTool.MwgTag.KEYWORDS); - assertEquals("Orientation tag updated value is wrong", 3, metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, metadata.get(ExifTool.MwgTag.DATE_TIME_ORIGINAL)); - assertEquals("CreateDate tag is wrong", createDate, metadata.get(ExifTool.MwgTag.CREATE_DATE)); - assertEquals("Keywords tag is wrong", "a", ((String[]) metadata.get(ExifTool.MwgTag.KEYWORDS))[0]); - - // Finally copy the source file back over so the next test run is not affected by the change - - } finally { - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - if ( backup_url != null ) { - Path backupFile = Paths.get(backup_url.toURI()); - Files.move(backupFile, imageFile.toPath(), StandardCopyOption.REPLACE_EXISTING); - } - - } - } - - //todo TEST automatic daemon restart by killing perl process + private static Logger log = LoggerFactory.getLogger(TestExifTool.class); + + @Test + public void testSingleTool() throws Exception { + ExifTool tool = new ExifTool(); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + tool.startup(); + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + } + + @Test + public void testConcurrent() throws Exception { + + int toolCount = 5; + + List threads = new ArrayList(toolCount); + for (int i = 1; i <= toolCount; i++) { + String toolName = "tool" + i; + Thread t = new Thread(toolName) { + @Override + public void run() { + log.info(getName() + ": starting"); + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + runTests(tool, getName()); + log.info(getName() + ": finished"); + } catch (IOException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } catch (URISyntaxException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } finally { + tool.shutdown(); + } + log.info(getName() + ": finished"); + } + }; + t.start(); + threads.add(t); + } + + for (Thread t : threads) { + t.run(); + } + } + + @Test + public void testManyThreadsOneTool() throws Exception { + final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + Thread[] threads = new Thread[20]; + for (int i = 0; i < threads.length; i++) { + final String label = "run " + i; + threads[i] = new Thread(new Runnable() { + @Override + public void run() { + try { + for (int j = 0; j < 5; j++) { + runTests(tool, label); + } + log.info("DONE: " + label + " success!"); + } catch (IOException ex) { + fail(label); + } catch (URISyntaxException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } + } + }, label); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + } finally { + tool.shutdown(); + } + } + + @Test + public void testProcessTimeout() throws Exception { + final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + tool.setRunTimeout(1); + runTests(tool, "will fail"); + fail("should have failed"); + } catch (IOException ex) { + ; + } finally { + tool.shutdown(); + } + } + + public boolean runTests(ExifTool tool, String runId) throws IOException, + URISyntaxException { + + Map metadata; + File imageFile; + Set keys; + ExifTool.Tag tag; + + URL url = getClass() + .getResource("/kureckjones_jett_075_02-cropped.tif"); + imageFile = new File(url.toURI()); + metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.values()); + assertEquals(22, metadata.size()); + + keys = metadata.keySet(); + + tag = ExifTool.Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(728, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.IMAGE_HEIGHT; + assertEquals(825, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.MODEL; + assertEquals("P 45+", tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 1"); + + url = getClass().getResource("/nexus-s-electric-cars.jpg"); + imageFile = new File(url.toURI()); + metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.values()); + assertEquals(23, metadata.size()); + + keys = metadata.keySet(); + tag = ExifTool.Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(2560, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.IMAGE_HEIGHT; + assertEquals(1920, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.MODEL; + assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.ISO; + assertEquals(50, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.SHUTTER_SPEED; + assertEquals("1/64", metadata.get(tag)); + assertEquals(0.015625, tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 2"); + return true; + } + + @Test + public void testGroupTags() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + Map metadata; + + URL url = getClass().getResource("/iptc_test-photoshop.jpg"); + File f = new File(url.toURI()); + metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, + ExifTool.TagGroup.IPTC); + assertEquals(17, metadata.size()); + assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); + assertEquals("IPTC Status: Copyright Notice", + metadata.get("CopyrightNotice")); + assertEquals("IPTC Content: Description Writer", + metadata.get("Writer-Editor")); + // for (String key : metadata.keySet()){ + // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + // } + } finally { + tool.shutdown(); + } + } + + @Test + public void testTag() { + assertEquals("string value", "John Doe", + ExifTool.Tag.AUTHOR.parseValue("John Doe")); + assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); + assertEquals("double value, from fraction", .25, + ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); + assertEquals("double value, from decimal", .25, + ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); + } + + @Test + public void testVersionNumber() { + assertTrue(new ExifTool.VersionNumber("1.2") + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); + assertTrue(new ExifTool.VersionNumber(1, 2) + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); + assertTrue(new ExifTool.VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); + assertTrue(new ExifTool.VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new ExifTool.VersionNumber(2, 1))); + } + + @Test + public void testWriteTagStringNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's updated + metadata = tool + .getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteTagString() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's updated + metadata = tool + .getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteTagStringInvalidformat() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + String newDate = "2egek opkpgrpok"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + + // Now change it to an invalid value which should fail + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's not updated + metadata = tool + .getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + // might not exist + if (backup_url != null) { + Path backupFile = Paths.get(backup_url.toURI()); + Files.move(backupFile, imageFile, + StandardCopyOption.REPLACE_EXISTING); + } + } + + @Test + public void testWriteTagNumberNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + + // Now change it + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteTagNumber() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + + // Now change it + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteMultipleTag() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteMultipleTagNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.writeMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWritingWithImplicitTypes() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.MWG_MODULE); + tool.setReadOptions(tool.getReadOptions().withNumericOutput(true) + .withConvertTypes(true)); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + File imageFile = Paths.get(url.toURI()).toFile(); + try { + // Test what orientation value is at the start + SimpleDateFormat formatter = new SimpleDateFormat( + "yyyy:MM:dd hh:mm:ss"); + + Map metadata = tool.readMetadata(imageFile, + ExifTool.Tag.ORIENTATION, + ExifTool.MwgTag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", 1, + metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("Wrong starting value", + formatter.parse("2010:12:10 17:07:05"), + metadata.get(ExifTool.MwgTag.DATE_TIME_ORIGINAL)); + + // Now change them + Map data = new HashMap(); + Date dateTimeOrig = formatter.parse("2014:01:23 10:07:05"); + data.put(ExifTool.MwgTag.DATE_TIME_ORIGINAL, dateTimeOrig); + data.put(ExifTool.Tag.ORIENTATION, 3); + Date createDate = formatter.parse("2013:02:21 10:07:05"); + data.put(ExifTool.MwgTag.CREATE_DATE, createDate.getTime()); + data.put(ExifTool.MwgTag.KEYWORDS, new String[] { "a", "b", "c" }); + tool.writeMetadata( + tool.getWriteOptions().withDeleteBackupFile(false), + imageFile, data); + + // Finally check the updated value + metadata = tool.readMetadata(imageFile, ExifTool.Tag.ORIENTATION, + imageFile, ExifTool.MwgTag.DATE_TIME_ORIGINAL, + ExifTool.MwgTag.CREATE_DATE, ExifTool.MwgTag.KEYWORDS); + assertEquals("Orientation tag updated value is wrong", 3, + metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, + metadata.get(ExifTool.MwgTag.DATE_TIME_ORIGINAL)); + assertEquals("CreateDate tag is wrong", createDate, + metadata.get(ExifTool.MwgTag.CREATE_DATE)); + assertEquals("Keywords tag is wrong", "a", + ((String[]) metadata.get(ExifTool.MwgTag.KEYWORDS))[0]); + + // Finally copy the source file back over so the next test run is + // not affected by the change + + } finally { + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + if (backup_url != null) { + Path backupFile = Paths.get(backup_url.toURI()); + Files.move(backupFile, imageFile.toPath(), + StandardCopyOption.REPLACE_EXISTING); + } + + } + } + + // todo TEST automatic daemon restart by killing perl process } From 619a13f87f88ab1c81f22aa50a5bd5640945f885 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 25 Jul 2014 23:12:46 +0300 Subject: [PATCH 033/148] - formatted --- .gitignore | 4 + .../com/thebuzzmedia/exiftool/ExifTool.java | 155 +++++++++--------- .../com/thebuzzmedia/exiftool/Benchmark.java | 4 +- .../com/thebuzzmedia/exiftool/Example.java | 6 +- 4 files changed, 88 insertions(+), 81 deletions(-) diff --git a/.gitignore b/.gitignore index 83850880..3d471c24 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,7 @@ dist bin /.project + +/.classpath + +/.settings diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index f28fa2d5..be279f30 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -202,7 +202,7 @@ * written the 2nd most robust image metadata library I have come across: Metadata Extractor * that you might want to look at. - * + * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ @@ -359,15 +359,15 @@ public class ExifTool { * The external call to ExifTool to confirm feature support is only ever * done once per JVM session and stored in a static final * {@link Map} that all instances of this class share. - * + * * @param feature * The feature to check support for in the underlying ExifTool * install. - * + * * @return true if support for the given {@link Feature} was * confirmed to work with the currently installed ExifTool or * false if it is not supported. - * + * * @throws IllegalArgumentException * if feature is null. * @throws RuntimeException @@ -487,8 +487,8 @@ protected static void checkFeatureSupport(Feature... features) * important that robust IOException handling right here. */ } finally { - // Close r/w streams to exited process. - streams.close(); + // Close r/w streams to exited process. + streams.close(); } // Ensure the version found is >= the required version. @@ -661,7 +661,8 @@ private Feature(String version) { * @since 1.1 */ public enum Format { - NUMERIC, HUMAN_READABLE; + NUMERIC, + HUMAN_READABLE; } /** @@ -786,8 +787,7 @@ public enum Tag { TITLE("XPTitle", String.class), WHITE_BALANCE("WhiteBalance", Integer.class), X_RESOLUTION("XResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), - ; + Y_RESOLUTION("YResolution", Double.class), ; private static final Map TAG_LOOKUP_MAP; /** @@ -981,15 +981,15 @@ public ExifTool(Feature... features) throws UnsupportedFeatureException { } } - public void shutdownCleanupTask() { - if(currentCleanupTask != null) { - currentCleanupTask.cancel(); - } - currentCleanupTask = null; - if(cleanupTimer != null) { - cleanupTimer.cancel(); - } - } + public void shutdownCleanupTask() { + if (currentCleanupTask != null) { + currentCleanupTask.cancel(); + } + currentCleanupTask = null; + if (cleanupTimer != null) { + cleanupTimer.cancel(); + } + } /** * Used to shutdown the external ExifTool process and close the read/write @@ -1266,13 +1266,13 @@ public Map getImageMeta(File image, Format format, Tag... tags) return resultMap; } - - public void setImageMeta(File image, Map tags) - throws IllegalArgumentException, SecurityException, IOException { + + public void setImageMeta(File image, Map tags) + throws IllegalArgumentException, SecurityException, IOException { setImageMeta(image, Format.NUMERIC, tags); } - - public void setImageMeta(File image, Format format, Map tags ) + + public void setImageMeta(File image, Format format, Map tags) throws IllegalArgumentException, SecurityException, IOException { if (image == null) throw new IllegalArgumentException( @@ -1338,7 +1338,7 @@ public void setImageMeta(File image, Format format, Map tags ) streams.writer.write("-S\n"); // compact output - for ( Entry entry :tags.entrySet() ) { + for (Entry entry : tags.entrySet()) { streams.writer.write('-'); streams.writer.write(entry.getKey().name); streams.writer.write("='"); @@ -1371,8 +1371,9 @@ public void setImageMeta(File image, Format format, Map tags ) args.add("-S"); // compact output - for ( Entry entry :tags.entrySet() ) - args.add("-" + entry.getKey().name + "='" + entry.getValue() + "'" ); + for (Entry entry : tags.entrySet()) + args.add("-" + entry.getKey().name + "='" + entry.getValue() + + "'"); args.add(image.getAbsolutePath()); @@ -1495,16 +1496,16 @@ public Feature getFeature() { return feature; } } - + /** - * Class used to handle XMP Sidecar files using exiftool. + * Class used to handle XMP Sidecar files using exiftool. * * @author Clinton LaForest (clafore@bgsu.edu) * @since 1.2_thespiritx */ public class Sidecar { public Sidecar(Feature feature) { - + } /** @@ -1512,13 +1513,13 @@ public Sidecar(Feature feature) { * * @param xmp * The xmp sidecar file. - * + * * @param file - * The image file. + * The image file. * * @param preserve - * true - preserves name mappings - * false - uses preferred name mappings + * true - preserves name mappings + * false - uses preferred name mappings * * @return void * @@ -1540,20 +1541,21 @@ public void merge(File xmp, File file, Boolean preserve) { long startTime = System.currentTimeMillis(); if (DEBUG) - log("Writing %s tags to image: %s", xmp.getAbsolutePath(), file.getAbsolutePath()); + log("Writing %s tags to image: %s", xmp.getAbsolutePath(), + file.getAbsolutePath()); long exifToolCallElapsedTime = 0; /* - * Using ExifTool in daemon mode (-stay_open True) executes different - * code paths below. So establish the flag for this once and it is - * reused a multitude of times later in this method to figure out where - * to branch to. + * Using ExifTool in daemon mode (-stay_open True) executes + * different code paths below. So establish the flag for this once + * and it is reused a multitude of times later in this method to + * figure out where to branch to. */ boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); - + args.clear(); - + if (stayOpen) { log("\tUsing ExifTool in daemon mode (-stay_open True)..."); @@ -1561,9 +1563,9 @@ public void merge(File xmp, File file, Boolean preserve) { resetCleanupTask(); /* - * If this is our first time calling getImageMeta with a stayOpen - * connection, set up the persistent process and run it so it is - * ready to receive commands from us. + * If this is our first time calling getImageMeta with a + * stayOpen connection, set up the persistent process and run it + * so it is ready to receive commands from us. */ if (streams == null) { log("\tStarting daemon ExifTool process and creating read/write streams (this only happens once)..."); @@ -1582,30 +1584,30 @@ public void merge(File xmp, File file, Boolean preserve) { try { streams.writer.write("-tagsfromfile\n"); - + streams.writer.write(file.getAbsolutePath()); streams.writer.write("\n"); - - if(preserve){ + + if (preserve) { streams.writer.write("-all:all"); streams.writer.write("\n"); } else { streams.writer.write("-xmp"); streams.writer.write("\n"); } - + streams.writer.write(xmp.getAbsolutePath()); streams.writer.write("\n"); - + log("\tExecuting ExifTool..."); - + // Begin tracking the duration ExifTool takes to respond. exifToolCallElapsedTime = System.currentTimeMillis(); - + // Run ExifTool on our file with all the given arguments. streams.writer.write("-execute\n"); streams.writer.flush(); - + } catch (IOException e) { log("\tError received in stayopen stream: %s", e.getMessage()); @@ -1614,21 +1616,21 @@ public void merge(File xmp, File file, Boolean preserve) { log("\tUsing ExifTool in non-daemon mode (-stay_open False)..."); /* - * Since we are not using a stayOpen process, we need to setup the - * execution arguments completely each time. + * Since we are not using a stayOpen process, we need to setup + * the execution arguments completely each time. */ args.add(EXIF_TOOL_PATH); args.add("-tagsfromfile"); // compact output args.add(file.getAbsolutePath()); - - if(preserve) { + + if (preserve) { args.add("-all:all"); } else { args.add("-xmp"); } - + args.add(xmp.getAbsolutePath()); // Run the ExifTool with our args. @@ -1637,7 +1639,7 @@ public void merge(File xmp, File file, Boolean preserve) { // Begin tracking the duration ExifTool takes to respond. exifToolCallElapsedTime = System.currentTimeMillis(); } - + log("\tReading response back from ExifTool..."); String line = null; @@ -1645,18 +1647,17 @@ public void merge(File xmp, File file, Boolean preserve) { try { while ((line = streams.reader.readLine()) != null) { /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need to - * look for it and break from this loop when we see it otherwise - * this process will hang indefinitely blocking on the input stream - * with no data to read. + * When using a persistent ExifTool process, it terminates + * its output to us with a "{ready}" clause on a new line, + * we need to look for it and break from this loop when we + * see it otherwise this process will hang indefinitely + * blocking on the input stream with no data to read. */ if (stayOpen && line.equals("{ready}")) break; } } catch (IOException e) { - log("\tError received in response: %d", - e.getMessage()); + log("\tError received in response: %d", e.getMessage()); } // Print out how long the call to external ExifTool process took. @@ -1664,38 +1665,40 @@ public void merge(File xmp, File file, Boolean preserve) { (System.currentTimeMillis() - exifToolCallElapsedTime)); /* - * If we are not using a persistent ExifTool process, then after running - * the command above, the process exited in which case we need to clean - * our streams up since it no longer exists. If we were using a - * persistent ExifTool process, leave the streams open for future calls. + * If we are not using a persistent ExifTool process, then after + * running the command above, the process exited in which case we + * need to clean our streams up since it no longer exists. If we + * were using a persistent ExifTool process, leave the streams open + * for future calls. */ if (!stayOpen) streams.close(); if (DEBUG) log("\tImage Meta Processed in %d ms [write %s tags]", - (System.currentTimeMillis() - startTime), xmp.getAbsolutePath()); - + (System.currentTimeMillis() - startTime), + xmp.getAbsolutePath()); + } - + /** * Used to export a XMP Sidecar file from an image. * * @param xmp * The xmp sidecar file. - * + * * @param file - * The image file. + * The image file. * * @param preserve - * true - preserves name mappings - * false - uses preferred name mappings + * true - preserves name mappings + * false - uses preferred name mappings * * @return void * */ public void export(File xmp, File file, boolean preserve) { - + } } } diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index f6b792fb..aa22c00c 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -14,8 +14,8 @@ public class Benchmark { public static void main(String[] args) throws IOException, InterruptedException { -// System.setProperty("exiftool.path", "D:\\Tools\\exiftool.exe"); -// System.setProperty("exiftool.debug", "false"); + // System.setProperty("exiftool.path", "D:\\Tools\\exiftool.exe"); + // System.setProperty("exiftool.debug", "false"); System.out.println("Benchmark [tags=" + TAGS.length + ", images=" + IMAGES.length + ", iterations=" + ITERS + "]"); diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index d21eff7e..2e424db3 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -14,9 +14,9 @@ public class Example { public static void main(String[] args) throws IOException, InterruptedException { -// System.setProperty("imgscalr.ext.exiftool.path", -// "D:\\Tools\\exiftool.exe"); -// System.setProperty("imgscalr.ext.exiftool.debug", "false"); + // System.setProperty("imgscalr.ext.exiftool.path", + // "D:\\Tools\\exiftool.exe"); + // System.setProperty("imgscalr.ext.exiftool.debug", "false"); ExifTool tool = new ExifTool(Feature.STAY_OPEN); From 5d8a4c857ff70530e3597bc69d82d82585dc762d Mon Sep 17 00:00:00 2001 From: msgile Date: Fri, 25 Jul 2014 16:54:23 -0700 Subject: [PATCH 034/148] * ExifTool now reads process.err stream and on "error" will throw IOExceptions * ExifTool can now rebuild corrupt metadata for JPEGS --- .../com/thebuzzmedia/exiftool/ExifTool.java | 124 +++++++++++------- .../exiftool/LineReaderThread.java | 85 ++++++++++++ 2 files changed, 164 insertions(+), 45 deletions(-) create mode 100644 src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 9785783d..bcacc85c 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -20,6 +20,7 @@ import java.io.BufferedReader; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; @@ -271,15 +272,10 @@ public class ExifTool { */ private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; - /** - * Compiled {@link Pattern} of ": " used to split compact output from - * ExifTool evenly into name/value pairs. - */ - private static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; private static final String EXIF_DATE_FORMAT = "yyyy:MM:dd HH:mm:ss"; - private static Logger log = LoggerFactory.getLogger(ExifTool.class); + private static final Logger log = LoggerFactory.getLogger(ExifTool.class); private final Map featureSupportedMap = new HashMap(); private final Set featureEnabledSet = EnumSet.noneOf(Feature.class); @@ -620,26 +616,18 @@ public void writeMetadata(File image, Map values) throws IOExcept /** * Takes a map of tags (either (@link Tag) or Strings for keys) and replaces/appends them to the metadata. */ - public void writeMetadata(WriteOptions options, File image, Map values) throws IOException { - if (image == null){ - throw new IllegalArgumentException("image cannot be null and must be a valid stream of image data."); - } - if (values == null || values.isEmpty()){ - throw new IllegalArgumentException("values cannot be null and must contain 1 or more tag to value mappings"); - } + public void writeMetadata(WriteOptions options, File file, Map values) throws IOException { + if ( file == null ) throw new NullPointerException("File is null"); + if ( ! file.exists() ) throw new FileNotFoundException(String.format("File \"%s\" does not exits",file.getAbsolutePath())); + if ( ! file.canWrite() ) throw new SecurityException(String.format("File \"%s\" cannot be written to",file.getAbsolutePath())); - if (!image.canWrite()){ - throw new SecurityException("Unable to write the given image [" + image.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to write to it."); - } - - log.info("Adding Tags {} to {}", values, image.getAbsolutePath()); + log.info("Adding Tags {} to {}", values, file.getAbsolutePath()); List args = new ArrayList(values.size()+3); for(Map.Entry entry : values.entrySet()) { args.addAll(serializeToArgs(entry.getKey(),entry.getValue())); } - args.add(image.getAbsolutePath()); + args.add(file.getAbsolutePath()); //start process long startTime = System.currentTimeMillis(); @@ -647,15 +635,39 @@ public void writeMetadata(WriteOptions options, File image, Map v exifProxy.execute(options.runTimeoutMills, args); } finally { if ( options.deleteBackupFile ) { - File origBackup = new File(image.getAbsolutePath()+"_original"); + File origBackup = new File(file.getAbsolutePath()+"_original"); if ( origBackup.exists() ) origBackup.delete(); } } // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()){ - log.debug(String.format("Image Meta Processed in %d ms [added %d tags]", - (System.currentTimeMillis() - startTime), values.size())); + if (log.isDebugEnabled()) log.debug(String.format("Image Meta Processed in %d ms [added %d tags]", (System.currentTimeMillis() - startTime), values.size())); + + } + + public void rebuildMetadata(File file) throws IOException { + rebuildMetadata(getWriteOptions(),file); + } + + /** + * Rewrite all the the metadata tags in a JPEG image. This will not work for TIFF files. + * Use this when the image has some corrupt tags. + * + * @link http://www.sno.phy.queensu.ca/~phil/exiftool/faq.html#Q20 + */ + public void rebuildMetadata(WriteOptions options, File file) throws IOException { + if ( file == null ) throw new NullPointerException("File is null"); + if ( ! file.exists() ) throw new FileNotFoundException(String.format("File \"%s\" does not exits",file.getAbsolutePath())); + if ( ! file.canWrite() ) throw new SecurityException(String.format("File \"%s\" cannot be written to",file.getAbsolutePath())); + + List args = Arrays.asList("-all=", "-tagsfromfile", "@", "-all:all", "-unsafe",file.getAbsolutePath()); + try { + exifProxy.execute(options.runTimeoutMills, args); + } finally { + if ( options.deleteBackupFile ) { + File origBackup = new File(file.getAbsolutePath()+"_original"); + if ( origBackup.exists() ) origBackup.delete(); + } } } //================================================================================ @@ -791,6 +803,12 @@ static MetadataTag toTag(String name) { * This is the actual process, with streams for reading and writing data. */ public static final class ExifProcess { + /** + * Compiled {@link Pattern} of ": " used to split compact output from + * ExifTool evenly into name/value pairs. + */ + private static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); + public static VersionNumber readVersion(String exifCmd) { ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, "-ver")); try { @@ -805,8 +823,9 @@ public static VersionNumber readVersion(String exifCmd) { private final ReentrantLock closeLock = new ReentrantLock(false); private final boolean keepAlive; private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; + private final BufferedReader out; + private final OutputStreamWriter in; + private final LineReaderThread errReader; private volatile boolean closed = false; public ExifProcess(boolean keepAlive, List args) { @@ -814,8 +833,10 @@ public ExifProcess(boolean keepAlive, List args) { log.debug(String.format("Attempting to start ExifTool process using args: %s", args)); try { this.process = new ProcessBuilder(args).start(); - this.reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream()); + this.out = new BufferedReader(new InputStreamReader(process.getInputStream())); + this.in = new OutputStreamWriter(process.getOutputStream()); + this.errReader = new LineReaderThread("exif-process-err-reader",new BufferedReader(new InputStreamReader(process.getErrorStream()))); + errReader.start(); log.debug("\tSuccessful"); } catch (Exception e) { String message = "Unable to start external ExifTool process using the execution arguments: " @@ -844,13 +865,13 @@ public synchronized Map sendToRunning(List args) throws public synchronized void writeFlush(String message) throws IOException { if (closed) throw new IOException(STREAM_CLOSED_MESSAGE); - writer.write(message); - writer.flush(); + in.write(message); + in.flush(); } public synchronized String readLine() throws IOException { if (closed) throw new IOException(STREAM_CLOSED_MESSAGE); - return reader.readLine(); + return out.readLine(); } public synchronized Map readResponse() throws IOException { @@ -858,27 +879,32 @@ public synchronized Map readResponse() throws IOException { log.debug("Reading response back from ExifTool..."); Map resultMap = new HashMap(500); String line; - - while ((line = reader.readLine()) != null) { + while ((line = out.readLine()) != null) { if (closed) throw new IOException(STREAM_CLOSED_MESSAGE); String[] pair = TAG_VALUE_PATTERN.split(line, 2); - if (pair.length == 2) { resultMap.put(pair[0], pair[1]); log.debug(String.format("\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); } - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need to - * look for it and break from this loop when we see it otherwise - * this process will hang indefinitely blocking on the input stream - * with no data to read. - */ + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need to + * look for it and break from this loop when we see it otherwise + * this process will hang indefinitely blocking on the input stream + * with no data to read. + */ if (keepAlive && line.equals("{ready}")) { break; } } + if ( errReader.hasLines() ) { + for(String error : errReader.takeLines()) { + if ( error.toLowerCase().startsWith("error") ) { + throw new IOException(error); + } + } + } return resultMap; } @@ -894,7 +920,7 @@ public void close() { closed = true; try { log.debug("Closing Read stream..."); - reader.close(); + out.close(); log.debug("\tSuccessful"); } catch (Exception e) { // no-op, just try to close it. @@ -902,15 +928,23 @@ public void close() { try { log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - writer.write("-stay_open\nFalse\n"); - writer.flush(); + in.write("-stay_open\nFalse\n"); + in.flush(); } catch (IOException ex) { //log.error(ex,ex); } try { log.debug("Closing Write stream..."); - writer.close(); + in.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + log.debug("Closing Error stream..."); + errReader.close(); log.debug("\tSuccessful"); } catch (Exception e) { // no-op, just try to close it. diff --git a/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java b/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java new file mode 100644 index 00000000..c875892c --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java @@ -0,0 +1,85 @@ +package com.thebuzzmedia.exiftool; + +import java.io.BufferedReader; +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.concurrent.ArrayBlockingQueue; +import java.util.concurrent.BlockingQueue; + +/** + * A Thread which reads lines from a BufferedReader and puts them in a queue, so they can be read from with out blocking. + * This is used when reading from a process.err input. + * + * Remember to start thread!! + * + * @author msgile + * @author $LastChangedBy$ + * @version $Revision$ $LastChangedDate$ + * @since 7/25/14 + */ +public class LineReaderThread extends Thread { + private BufferedReader reader; + private BlockingQueue lineBuffer = new ArrayBlockingQueue(10,true); + + public LineReaderThread(String name, BufferedReader reader) { + super(name); + this.reader = reader; + } + public LineReaderThread(ThreadGroup group, String name, BufferedReader reader) { + super(group, name); + this.reader = reader; + } + + @Override + public void run() { + String line; + try { + while((line = reader.readLine()) != null) { + line = line.trim(); + if ( ! line.isEmpty() ) { + lineBuffer.put(line); + } + } + } catch (IOException ex) { + //exit + } catch (InterruptedException ignored) { + //exit + } + } + + public boolean isEmpty() { + return lineBuffer.isEmpty(); + } + + public boolean hasLines() { + return ! lineBuffer.isEmpty(); + } + + /** + * Takes all lines from the buffer or returns empty list. + */ + public List takeLines() { + List lines = new ArrayList(lineBuffer.size()); + lineBuffer.drainTo(lines); + return lines; + } + + /** + * Reads line without blocking, will return Null if no lines in buffer. + */ + public String readLine() { + return lineBuffer.poll(); + } + + public void close() { + interrupt(); + try { + reader.close(); + } catch (IOException ignored) { + ; + } + } + + +} From 4835403590e00c5d3a516bc67da20ba6fa192bab Mon Sep 17 00:00:00 2001 From: msgile Date: Fri, 25 Jul 2014 17:14:37 -0700 Subject: [PATCH 035/148] Added Exception (sub of IOException) ExifError, for Exif Errors --- .../com/thebuzzmedia/exiftool/ExifError.java | 16 ++++++++++++++++ .../java/com/thebuzzmedia/exiftool/ExifTool.java | 2 +- 2 files changed, 17 insertions(+), 1 deletion(-) create mode 100644 src/main/java/com/thebuzzmedia/exiftool/ExifError.java diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifError.java b/src/main/java/com/thebuzzmedia/exiftool/ExifError.java new file mode 100644 index 00000000..843b62d6 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifError.java @@ -0,0 +1,16 @@ +package com.thebuzzmedia.exiftool; + +import java.io.IOException; + +/** + * Represents an error from the ExifTool + * @author msgile + * @author $LastChangedBy$ + * @version $Revision$ $LastChangedDate$ + * @since 7/25/14 + */ +public class ExifError extends IOException { + public ExifError(String message) { + super(message); + } +} diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index bcacc85c..b94a5599 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -901,7 +901,7 @@ public synchronized Map readResponse() throws IOException { if ( errReader.hasLines() ) { for(String error : errReader.takeLines()) { if ( error.toLowerCase().startsWith("error") ) { - throw new IOException(error); + throw new ExifError(error); } } } From 04f775cd3acf003f9d54f17263edc44fb160bb99 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 11:32:20 +0300 Subject: [PATCH 036/148] - fix tests - after tests finishes there are 2 phantom exiftool processes --- src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index bb791663..ed33a515 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -136,7 +136,7 @@ public boolean runTests(ExifTool tool, String runId) throws IOException { + "/kureckjones_jett_075_02-cropped.tif"); metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(22, metadata.size()); + assertEquals(25, metadata.size()); keys = metadata.keySet(); @@ -154,7 +154,7 @@ public boolean runTests(ExifTool tool, String runId) throws IOException { imageFile = new File(TEST_FILES_PATH + "/nexus-s-electric-cars.jpg"); metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(23, metadata.size()); + assertEquals(24, metadata.size()); keys = metadata.keySet(); tag = ExifTool.Tag.IMAGE_WIDTH; From f5df6102f6bd3de44e847a48b6d6415e6fd67dd7 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 11:41:46 +0300 Subject: [PATCH 037/148] - formatted --- .gitignore | 6 + .../com/thebuzzmedia/exiftool/ExifTool.java | 2244 +++++++++-------- .../com/thebuzzmedia/exiftool/Benchmark.java | 48 +- .../com/thebuzzmedia/exiftool/Example.java | 77 +- .../thebuzzmedia/exiftool/TestExifTool.java | 911 ++++--- 5 files changed, 1715 insertions(+), 1571 deletions(-) diff --git a/.gitignore b/.gitignore index 4d5433b3..c505b6c3 100644 --- a/.gitignore +++ b/.gitignore @@ -3,3 +3,9 @@ dist bin *.iml .idea + +/.classpath + +/.project + +/.settings diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index da3c1545..d2b3c831 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -15,8 +15,21 @@ */ package com.thebuzzmedia.exiftool; -import java.io.*; -import java.util.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; @@ -69,10 +82,10 @@ * {@link Format#NUMERIC} and it is ultimately up to the caller to decide how * best to parse or convert the returned values. *

- * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} - * convenience method for parsing given String values according to - * the Tag hint automatically for you if that is what you plan on doing, - * otherwise feel free to handle the return values anyway you want. + * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} convenience + * method for parsing given String values according to the Tag hint + * automatically for you if that is what you plan on doing, otherwise feel free + * to handle the return values anyway you want. *

ExifTool -stay_open Support

* ExifTool * Because this feature requires ExifTool 8.36 or later, this class will * actually verify support for the feature in the version of ExifTool pointed at - * by {@link #exifCmd} before successfully instantiating the class and - * will notify you via an {@link UnsupportedFeatureException} if the native - * ExifTool doesn't support the requested feature. + * by {@link #exifCmd} before successfully instantiating the class and will + * notify you via an {@link UnsupportedFeatureException} if the native ExifTool + * doesn't support the requested feature. *

* In the event of an {@link UnsupportedFeatureException}, the caller can either * upgrade the native ExifTool upgrade to the version required or simply avoid @@ -194,1107 +207,1148 @@ * written the 2nd most robust image metadata library I have come across: Metadata Extractor * that you might want to look at. - * + * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ public class ExifTool { - public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; - public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; - - /** - * Name used to identify the (optional) cleanup {@link Thread}. - *

- * This is only provided to make debugging and profiling easier for - * implementers making use of this class such that the resources this class - * creates and uses (i.e. Threads) are readily identifiable in a running VM. - *

- * Default value is "ExifTool Cleanup Thread". - */ - private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; - - /** - * Compiled {@link Pattern} of ": " used to split compact output from - * ExifTool evenly into name/value pairs. - */ - private static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); - private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - - private static Logger log = LoggerFactory.getLogger(ExifTool.class); - - /** - * The absolute path to the ExifTool executable on the host system running - * this class as defined by the "exiftool.path" system - * property. - *

- * If ExifTool is on your system path and running the command "exiftool" - * successfully executes it, leaving this value unchanged will work fine on - * any platform. If the ExifTool executable is named something else or not - * in the system path, then this property will need to be set to point at it - * before using this class. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.path=/path/to/exiftool - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * On Windows be sure to double-escape the path to the tool, for example: - * - * -Dexiftool.path=C:\\Tools\\exiftool.exe - * - *

- * Default value is "exiftool". - *

Relative Paths

- * Relative path values (e.g. "bin/tools/exiftool") are executed with - * relation to the base directory the VM process was started in. Essentially - * the directory that new File(".").getAbsolutePath() points at - * during runtime. - */ - private final String exifCmd; - - /** - * Interval (in milliseconds) of inactivity before the cleanup thread wakes - * up and cleans up the daemon ExifTool process and the read/write streams - * used to communicate with it when the {@link Feature#STAY_OPEN} feature is - * used. - *

- * Ever time a call to getImageMeta is processed, the timer - * keeping track of cleanup is reset; more specifically, this class has to - * experience no activity for this duration of time before the cleanup - * process is fired up and cleans up the host OS process and the stream - * resources. - *

- * Any subsequent calls to getImageMeta after a cleanup simply - * re-initializes the resources. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.processCleanupDelay=600000 - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * Setting this value to 0 disables the automatic cleanup thread completely - * and the caller will need to manually cleanup the external ExifTool - * process and read/write streams by calling {@link #close()}. - *

- * Default value is 600,000 (10 minutes). - */ - private final long processCleanupDelay; - - private final Map featureSupportedMap = new HashMap(); - private final Set featureSet = EnumSet.noneOf(Feature.class); - private final ReentrantLock lock = new ReentrantLock(); - private final VersionNumber exifVersion; - private final Timer cleanupTimer; - private TimerTask currentCleanupTask = null; - private AtomicBoolean shuttingDown = new AtomicBoolean(false); - private volatile ExifProcess process; - private int timeoutWhenKeepAlive = 0; - - public ExifTool(){ - this((Feature[]) null); - } - - /** - * In this constructor, exifToolPath and processCleanupDelay are gotten from system properties - * exiftool.path and exiftool.processCleanupDelay. processCleanupDelay is optional. If not found, - * the default is used. - */ - public ExifTool (Feature ... features){ - this( - System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), - Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, DEFAULT_PROCESS_CLEANUP_DELAY), - features - ); - } - - public ExifTool(String exifToolPath) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); - } - - public ExifTool(String exifToolPath, Feature ... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); - } - - public ExifTool(String exifCmd, long processCleanupDelay, Feature ... features) { - this.exifCmd = exifCmd; - this.processCleanupDelay = processCleanupDelay; - this.exifVersion = ExifProcess.readVersion(exifCmd); - if (features != null && features.length > 0) { - for (Feature feature : features) { - if ( ! feature.isSupported(exifVersion) ) { - throw new UnsupportedFeatureException(feature); - } - this.featureSet.add(feature); - this.featureSupportedMap.put(feature,true); - } - } - - /* - * Now that initialization is done, init the cleanup timer if we are - * using STAY_OPEN and the delay time set is non-zero. - */ - if (isFeatureEnabled(Feature.STAY_OPEN) ) { - cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - } else { - cleanupTimer = null; - } - } - - /** - * Limits the amount of time (in mills) an exif operation can take. Setting value to greater than 0 to enable. - */ - public ExifTool setRunTimeout(int mills) { - timeoutWhenKeepAlive = mills; - return this; - } - - /** - * Used to determine if the given {@link Feature} is supported by the - * underlying native install of ExifTool pointed at by - * {@link #exifCmd}. - *

- * If support for the given feature has not been checked for yet, this - * method will automatically call out to ExifTool and ensure the requested - * feature is supported in the current local install. - *

- * The external call to ExifTool to confirm feature support is only ever - * done once per JVM session and stored in a static final - * {@link Map} that all instances of this class share. - * - * @param feature - * The feature to check support for in the underlying ExifTool - * install. - * - * @return true if support for the given {@link Feature} was - * confirmed to work with the currently installed ExifTool or - * false if it is not supported. - * - * @throws IllegalArgumentException - * if feature is null. - * @throws RuntimeException - * if any exception occurs while attempting to start the - * external ExifTool process to verify feature support. - */ - public boolean isFeatureSupported(Feature feature) throws RuntimeException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); - } - - Boolean supported = featureSupportedMap.get(feature); + public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + + /** + * Name used to identify the (optional) cleanup {@link Thread}. + *

+ * This is only provided to make debugging and profiling easier for + * implementers making use of this class such that the resources this class + * creates and uses (i.e. Threads) are readily identifiable in a running VM. + *

+ * Default value is "ExifTool Cleanup Thread". + */ + private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; + + /** + * Compiled {@link Pattern} of ": " used to split compact output from + * ExifTool evenly into name/value pairs. + */ + private static final Pattern TAG_VALUE_PATTERN = Pattern + .compile("\\s*:\\s*"); + private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + + private static Logger log = LoggerFactory.getLogger(ExifTool.class); + + /** + * The absolute path to the ExifTool executable on the host system running + * this class as defined by the "exiftool.path" system + * property. + *

+ * If ExifTool is on your system path and running the command "exiftool" + * successfully executes it, leaving this value unchanged will work fine on + * any platform. If the ExifTool executable is named something else or not + * in the system path, then this property will need to be set to point at it + * before using this class. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.path=/path/to/exiftool + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * On Windows be sure to double-escape the path to the tool, for example: + * + * -Dexiftool.path=C:\\Tools\\exiftool.exe + * + *

+ * Default value is "exiftool". + *

Relative Paths

+ * Relative path values (e.g. "bin/tools/exiftool") are executed with + * relation to the base directory the VM process was started in. Essentially + * the directory that new File(".").getAbsolutePath() points at + * during runtime. + */ + private final String exifCmd; + + /** + * Interval (in milliseconds) of inactivity before the cleanup thread wakes + * up and cleans up the daemon ExifTool process and the read/write streams + * used to communicate with it when the {@link Feature#STAY_OPEN} feature is + * used. + *

+ * Ever time a call to getImageMeta is processed, the timer + * keeping track of cleanup is reset; more specifically, this class has to + * experience no activity for this duration of time before the cleanup + * process is fired up and cleans up the host OS process and the stream + * resources. + *

+ * Any subsequent calls to getImageMeta after a cleanup simply + * re-initializes the resources. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.processCleanupDelay=600000 + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * Setting this value to 0 disables the automatic cleanup thread completely + * and the caller will need to manually cleanup the external ExifTool + * process and read/write streams by calling {@link #close()}. + *

+ * Default value is 600,000 (10 minutes). + */ + private final long processCleanupDelay; + + private final Map featureSupportedMap = new HashMap(); + private final Set featureSet = EnumSet.noneOf(Feature.class); + private final ReentrantLock lock = new ReentrantLock(); + private final VersionNumber exifVersion; + private final Timer cleanupTimer; + private TimerTask currentCleanupTask = null; + private AtomicBoolean shuttingDown = new AtomicBoolean(false); + private volatile ExifProcess process; + private int timeoutWhenKeepAlive = 0; + + public ExifTool() { + this((Feature[]) null); + } + + /** + * In this constructor, exifToolPath and processCleanupDelay are gotten from + * system properties exiftool.path and exiftool.processCleanupDelay. + * processCleanupDelay is optional. If not found, the default is used. + */ + public ExifTool(Feature... features) { + this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( + ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, + DEFAULT_PROCESS_CLEANUP_DELAY), features); + } + + public ExifTool(String exifToolPath) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); + } + + public ExifTool(String exifToolPath, Feature... features) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); + } + + public ExifTool(String exifCmd, long processCleanupDelay, + Feature... features) { + this.exifCmd = exifCmd; + this.processCleanupDelay = processCleanupDelay; + this.exifVersion = ExifProcess.readVersion(exifCmd); + if (features != null && features.length > 0) { + for (Feature feature : features) { + if (!feature.isSupported(exifVersion)) { + throw new UnsupportedFeatureException(feature); + } + this.featureSet.add(feature); + this.featureSupportedMap.put(feature, true); + } + } + + /* + * Now that initialization is done, init the cleanup timer if we are + * using STAY_OPEN and the delay time set is non-zero. + */ + if (isFeatureEnabled(Feature.STAY_OPEN)) { + cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); + } else { + cleanupTimer = null; + } + } + + /** + * Limits the amount of time (in mills) an exif operation can take. Setting + * value to greater than 0 to enable. + */ + public ExifTool setRunTimeout(int mills) { + timeoutWhenKeepAlive = mills; + return this; + } + + /** + * Used to determine if the given {@link Feature} is supported by the + * underlying native install of ExifTool pointed at by {@link #exifCmd}. + *

+ * If support for the given feature has not been checked for yet, this + * method will automatically call out to ExifTool and ensure the requested + * feature is supported in the current local install. + *

+ * The external call to ExifTool to confirm feature support is only ever + * done once per JVM session and stored in a static final + * {@link Map} that all instances of this class share. + * + * @param feature + * The feature to check support for in the underlying ExifTool + * install. + * + * @return true if support for the given {@link Feature} was + * confirmed to work with the currently installed ExifTool or + * false if it is not supported. + * + * @throws IllegalArgumentException + * if feature is null. + * @throws RuntimeException + * if any exception occurs while attempting to start the + * external ExifTool process to verify feature support. + */ + public boolean isFeatureSupported(Feature feature) throws RuntimeException { + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); + } + + Boolean supported = featureSupportedMap.get(feature); /* * If there is no Boolean flag for the feature, support for it hasn't * been checked yet with the native ExifTool install, so we need to do * that. */ - if (supported == null) { - log.debug("Support for feature %s has not been checked yet, checking..."); - supported = feature.isSupported(exifVersion); - featureSupportedMap.put(feature,supported); - } - - return supported; - } - - - - - - /** - * Used to startup the external ExifTool process and open the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. This method has no effect if the stay open feature is not enabled. - */ - public void startup(){ - if (featureSet.contains(Feature.STAY_OPEN)){ - shuttingDown.set(false); - ensureProcessRunning(); - } - } - private void ensureProcessRunning(){ - if (process ==null || process.isClosed()) { - synchronized (this){ - if (process ==null || process.isClosed() ){ - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = ExifProcess.startup(exifCmd); - } - } - } - if ( processCleanupDelay > 0 ) { - synchronized (this) { - if ( currentCleanupTask != null ) { - currentCleanupTask.cancel(); - currentCleanupTask = null; - } - currentCleanupTask = new TimerTask() { - @Override - public void run() { - log.info("Auto cleanup task running..."); - process.close(); - } - }; - cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); - } - } - } - - /** - * This is same as {@link #close()}, added for consistency with {@link #startup()} - */ - public void shutdown(){ - close(); - } - - - /** - * Used to shutdown the external ExifTool process and close the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. - *

- * NOTE: Calling this method does not preclude this - * instance of {@link ExifTool} from being re-used, it merely disposes of - * the native and internal resources until the next call to - * getImageMeta causes them to be re-instantiated. - *

- * The cleanup thread will automatically call this after an interval of - * inactivity defined by {@link #processCleanupDelay}. - *

- * Calling this method on an instance of this class without - * {@link Feature#STAY_OPEN} support enabled has no effect. - */ - public synchronized void close() { - shuttingDown.set(true); - if ( process != null ) { - process.close(); - } - if(currentCleanupTask != null) { - currentCleanupTask.cancel(); - currentCleanupTask = null; - } - } - - public boolean isStayOpen() { - return featureSet.contains(Feature.STAY_OPEN); - } - - /** - * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support - * enabled, this method is used to determine if there is currently a running - * ExifTool process associated with this class. - *

- * Any dependent processes and streams can be shutdown using - * {@link #close()} and this class will automatically re-create them on the - * next call to getImageMeta if necessary. - * - * @return true if there is an external ExifTool process in - * daemon mode associated with this class utilizing the - * {@link Feature#STAY_OPEN} feature, otherwise returns - * false. - */ - public boolean isRunning() { - return process != null && ! process.isClosed(); - } - - /** - * Used to determine if the given {@link Feature} has been enabled for this - * particular instance of {@link ExifTool}. - *

- * This method is different from {@link #isFeatureSupported(Feature)}, which - * checks if the given feature is supported by the underlying ExifTool - * install where as this method tells the caller if the given feature has - * been enabled for use in this particular instance. - * - * @param feature - * The feature to check if it has been enabled for us or not on - * this instance. - * - * @return true if the given {@link Feature} is currently - * enabled on this instance of {@link ExifTool}, otherwise returns - * false. - * - * @throws IllegalArgumentException - * if feature is null. - */ - public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); - } - return featureSet.contains(feature); - } - - public Map getImageMeta(File image, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - - return getImageMeta(image, Format.NUMERIC, tags); - } - - public Map getImageMeta(File image, Format format, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - - String [] stringTags = new String[tags.length]; - int i=0; - for (Tag tag : tags){ - stringTags[i++] = tag.getName(); - } - Map result = getImageMeta(image, format, true, stringTags); - return mapByTag(result); - } - - public Map getImageMeta(File image, Format format, TagGroup... tags) - throws IllegalArgumentException, SecurityException, IOException { - String [] stringTags = new String[tags.length]; - int i=0; - for (TagGroup tag : tags){ - stringTags[i++] = tag.getValue(); - } - return getImageMeta(image, format, false, stringTags); - } - - private Map getImageMeta(final File image, final Format format, final boolean suppressDuplicates, final String... tags) - throws IllegalArgumentException, SecurityException, IOException { - - - //Validate input and create Arg Array - final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); - List args = new ArrayList(tags.length+4); - if (format == null){ - throw new IllegalArgumentException("format cannot be null"); - } else if (format == Format.NUMERIC){ - args.add("-n"); // numeric output - } - if (!suppressDuplicates){ - args.add("-a"); //suppress duplicates - } - args.add("-S"); // compact output - - if (tags == null || tags.length == 0){ - throw new IllegalArgumentException("tags cannot be null and must contain 1 or more Tag to query the image for."); - } - for (String tag : tags) { - args.add("-" + tag); - } - if (image == null){ - throw new IllegalArgumentException("image cannot be null and must be a valid stream of image data."); - } - if (!image.canRead()){ - throw new SecurityException("Unable to read the given image ["+image.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); - } - args.add(image.getAbsolutePath()); - - //start process - long startTime = System.currentTimeMillis(); - log.debug(String.format("Querying %d tags from image: %s", tags.length, image.getAbsolutePath())); + if (supported == null) { + log.debug("Support for feature %s has not been checked yet, checking..."); + supported = feature.isSupported(exifVersion); + featureSupportedMap.put(feature, supported); + } + + return supported; + } + + /** + * Used to startup the external ExifTool process and open the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. This method has no effect if the stay open feature is not + * enabled. + */ + public void startup() { + if (featureSet.contains(Feature.STAY_OPEN)) { + shuttingDown.set(false); + ensureProcessRunning(); + } + } + + private void ensureProcessRunning() { + if (process == null || process.isClosed()) { + synchronized (this) { + if (process == null || process.isClosed()) { + log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = ExifProcess.startup(exifCmd); + } + } + } + if (processCleanupDelay > 0) { + synchronized (this) { + if (currentCleanupTask != null) { + currentCleanupTask.cancel(); + currentCleanupTask = null; + } + currentCleanupTask = new TimerTask() { + @Override + public void run() { + log.info("Auto cleanup task running..."); + process.close(); + } + }; + cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); + } + } + } + + /** + * This is same as {@link #close()}, added for consistency with + * {@link #startup()} + */ + public void shutdown() { + close(); + } + + /** + * Used to shutdown the external ExifTool process and close the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. + *

+ * NOTE: Calling this method does not preclude this + * instance of {@link ExifTool} from being re-used, it merely disposes of + * the native and internal resources until the next call to + * getImageMeta causes them to be re-instantiated. + *

+ * The cleanup thread will automatically call this after an interval of + * inactivity defined by {@link #processCleanupDelay}. + *

+ * Calling this method on an instance of this class without + * {@link Feature#STAY_OPEN} support enabled has no effect. + */ + public synchronized void close() { + shuttingDown.set(true); + if (process != null) { + process.close(); + } + if (currentCleanupTask != null) { + currentCleanupTask.cancel(); + currentCleanupTask = null; + } + } + + public boolean isStayOpen() { + return featureSet.contains(Feature.STAY_OPEN); + } + + /** + * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support + * enabled, this method is used to determine if there is currently a running + * ExifTool process associated with this class. + *

+ * Any dependent processes and streams can be shutdown using + * {@link #close()} and this class will automatically re-create them on the + * next call to getImageMeta if necessary. + * + * @return true if there is an external ExifTool process in + * daemon mode associated with this class utilizing the + * {@link Feature#STAY_OPEN} feature, otherwise returns + * false. + */ + public boolean isRunning() { + return process != null && !process.isClosed(); + } + + /** + * Used to determine if the given {@link Feature} has been enabled for this + * particular instance of {@link ExifTool}. + *

+ * This method is different from {@link #isFeatureSupported(Feature)}, which + * checks if the given feature is supported by the underlying ExifTool + * install where as this method tells the caller if the given feature has + * been enabled for use in this particular instance. + * + * @param feature + * The feature to check if it has been enabled for us or not on + * this instance. + * + * @return true if the given {@link Feature} is currently + * enabled on this instance of {@link ExifTool}, otherwise returns + * false. + * + * @throws IllegalArgumentException + * if feature is null. + */ + public boolean isFeatureEnabled(Feature feature) + throws IllegalArgumentException { + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); + } + return featureSet.contains(feature); + } + + public Map getImageMeta(File image, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { + + return getImageMeta(image, Format.NUMERIC, tags); + } + + public Map getImageMeta(File image, Format format, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { + + String[] stringTags = new String[tags.length]; + int i = 0; + for (Tag tag : tags) { + stringTags[i++] = tag.getName(); + } + Map result = getImageMeta(image, format, true, + stringTags); + return mapByTag(result); + } + + public Map getImageMeta(File image, Format format, + TagGroup... tags) throws IllegalArgumentException, + SecurityException, IOException { + String[] stringTags = new String[tags.length]; + int i = 0; + for (TagGroup tag : tags) { + stringTags[i++] = tag.getValue(); + } + return getImageMeta(image, format, false, stringTags); + } + + private Map getImageMeta(final File image, + final Format format, final boolean suppressDuplicates, + final String... tags) throws IllegalArgumentException, + SecurityException, IOException { + + // Validate input and create Arg Array + final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + List args = new ArrayList(tags.length + 4); + if (format == null) { + throw new IllegalArgumentException("format cannot be null"); + } else if (format == Format.NUMERIC) { + args.add("-n"); // numeric output + } + if (!suppressDuplicates) { + args.add("-a"); // suppress duplicates + } + args.add("-S"); // compact output + + if (tags == null || tags.length == 0) { + throw new IllegalArgumentException( + "tags cannot be null and must contain 1 or more Tag to query the image for."); + } + for (String tag : tags) { + args.add("-" + tag); + } + if (image == null) { + throw new IllegalArgumentException( + "image cannot be null and must be a valid stream of image data."); + } + if (!image.canRead()) { + throw new SecurityException( + "Unable to read the given image [" + + image.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + } + args.add(image.getAbsolutePath()); + + // start process + long startTime = System.currentTimeMillis(); + log.debug(String.format("Querying %d tags from image: %s", tags.length, + image.getAbsolutePath())); /* * Using ExifTool in daemon mode (-stay_open True) executes different * code paths below. So establish the flag for this once and it is * reused a multitude of times later in this method to figure out where * to branch to. */ - Map resultMap; - if (stayOpen) { - log.debug("Using ExifTool in daemon mode (-stay_open True)..."); - resultMap = processStayOpen(args); - } else { - log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd,args); - } - - // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()){ - log.debug(String.format("Image Meta Processed in %d ms [queried %d tags and found %d values]", - (System.currentTimeMillis() - startTime), tags.length, - resultMap.size())); - } - - return resultMap; - } - - public void addImageMetadata(File image, Map values) throws IOException { - - final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); - - if (image == null){ - throw new IllegalArgumentException("image cannot be null and must be a valid stream of image data."); - } - if (values == null || values.isEmpty()){ - throw new IllegalArgumentException("values cannot be null and must contain 1 or more tag to value mappings"); - } - - if (!image.canWrite()){ - throw new SecurityException("Unable to write the given image [" + image.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to write to it."); - } - - log.info("Adding Tags {} to {}", values, image.getAbsolutePath()); - - Map resultMap; - if (stayOpen) { - log.debug("Using ExifTool in daemon mode (-stay_open True)..."); - resultMap = processStayOpen(createCommandList(image.getAbsolutePath(), values)); - } else { - log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd, createCommandList(image.getAbsolutePath(), values)); - } - - //start process - long startTime = System.currentTimeMillis(); - - // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()){ - log.debug(String.format("Image Meta Processed in %d ms [added %d tags]", - (System.currentTimeMillis() - startTime), values.size())); - } - } - - private List createCommandList(String filename, Map values) { - - List args = new ArrayList(64); - - for(Map.Entry entry : values.entrySet()) { - Tag tag = entry.getKey(); - Object value = entry.getValue(); - - StringBuilder arg = new StringBuilder(); - arg.append("-").append(tag.getName()); - if (value instanceof Number){ - arg.append("#"); - } - arg.append("="); - if(value != null) { - if(value instanceof String) { - arg.append("\"").append(value.toString()).append("\""); - } else { - arg.append(value.toString()); - } - } - args.add(arg.toString()); - - } - - args.add(filename); - return args; - - } - - /** - * Will attempt 3 times to use the running exif process, and if unable to complete successfully will throw IOException - */ - private Map processStayOpen(List args) throws IOException { - int attempts = 0; - while (attempts < 3 && ! shuttingDown.get()){ - attempts++; - //make sure process is started - ensureProcessRunning(); - TimerTask attemptTimer = null; - try { - if ( timeoutWhenKeepAlive > 0 ) { - attemptTimer = new TimerTask() { - public void run() { - log.warn("Process ran too long closing, max "+timeoutWhenKeepAlive+" mills"); - process.close(); - } - }; - cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); - } - log.debug("Streaming arguments to ExifTool process..."); - return process.sendArgs(args); - } catch (IOException ex){ - if ( STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) && ! shuttingDown.get() ){ - //only catch "Stream Closed" error (happens when process has died) - log.warn(String.format("Caught IOException(\"%s\"), will restart daemon",STREAM_CLOSED_MESSAGE)); - process.close(); - } else { - throw ex; - } - } finally { - if ( attemptTimer != null ) attemptTimer.cancel(); - } - } - if ( shuttingDown.get() ) { - throw new IOException("Shutting Down"); - } - throw new IOException("Ran out of attempts"); - } - - private static Map mapByTag(Map stringMap){ - Map tagMap = new HashMap(Tag.values().length); - for (Tag tag : Tag.values()){ - if (stringMap.containsKey(tag.getName())){ - tagMap.put(tag, stringMap.get(tag.getName())); - } - } - return tagMap; - } - - - //================================================================================ - /** - * Represents an Exif Process. - */ - public static class ExifProcess { - private final ReentrantLock closeLock = new ReentrantLock(false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; - private volatile boolean closed = false; - - public static VersionNumber readVersion(String exifCmd) { - ExifProcess process =_execute(false, Arrays.asList(exifCmd,"-ver")); - try { - return new VersionNumber(process.readLine()); - } catch (IOException ex) { - throw new RuntimeException(String.format("Unable to check version number of ExifTool: %s",exifCmd)); - } finally { - process.close(); - } - } - - public static Map executeToResults(String exifCmd, List args) throws IOException { - List newArgs = new ArrayList(args.size()+1); - newArgs.add(exifCmd); - newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); - try { - return process.readResponse(); - } finally { - process.close(); - } - } - - public static ExifProcess startup(String exifCmd) { - List args = Arrays.asList(exifCmd,"-stay_open", "True", "-@", "-"); - return _execute(true, args); - } - - public static ExifProcess _execute(boolean keepAlive, List args) { - log.debug(String.format("Attempting to start external ExifTool process using args: %s", args)); - try { - Process process = new ProcessBuilder(args).start(); - log.debug("\tSuccessful"); - return new ExifProcess(keepAlive,process); - } catch (Exception e) { - String message = "Unable to start external ExifTool process using the execution arguments: " - + args - + ". Ensure ExifTool is installed correctly and runs using the command path '" - + args.get(0) - + "' as specified by the 'exiftool.path' system property."; - - log.debug(message); - throw new RuntimeException(message, e); - } - } - - public ExifProcess(boolean keepAlive,Process process) { - this.keepAlive = keepAlive; - this.process = process; - this.reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream()); - } - - public synchronized Map sendArgs(List args) throws IOException { - StringBuilder builder = new StringBuilder(); - for(String arg : args) { - builder.append(arg).append("\n"); - } - builder.append("-execute\n"); - writeFlush(builder.toString()); - return readResponse(); - } - - - public synchronized void writeFlush(String message) throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - writer.write(message); - writer.flush(); - } - - public synchronized String readLine() throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - return reader.readLine(); - } - - public synchronized Map readResponse() throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - Map resultMap = new HashMap(500); - String line; - - while ((line = reader.readLine()) != null) { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - String[] pair = TAG_VALUE_PATTERN.split(line, 2); - - if (pair.length == 2) { - resultMap.put(pair[0], pair[1]); - log.debug(String.format("\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); - } - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need to - * look for it and break from this loop when we see it otherwise - * this process will hang indefinitely blocking on the input stream - * with no data to read. - */ - if (keepAlive && line.equals("{ready}")){ - break; - } - } - return resultMap; - } - - public boolean isClosed() { - return closed; - } - - public void close() { - if ( ! closed ) { - closeLock.lock(); - try { - if ( ! closed ) { - closed = true; - log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - try { - writer.write("-stay_open\nFalse\n"); - writer.flush(); - } catch (IOException ex) { - //log.error(ex,ex); - } - try { - log.debug("Closing Read stream..."); - reader.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log.debug("Closing Write stream..."); - writer.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - log.debug("Read/Write streams successfully closed."); - - try { - process.destroy(); - } catch (Exception e) { - // - } - //process = null; - - } - } finally { - closeLock.unlock(); - } - } - } - } - - //================================================================================ - /** - * Enum used to define the different kinds of features in the native - * ExifTool executable that this class can help you take advantage of. - *

- * These flags are different from {@link Tag}s in that a "feature" is - * determined to be a special functionality of the underlying ExifTool - * executable that requires a different code-path in this class to take - * advantage of; for example, -stay_open True support. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Feature { - /** - * Enum used to specify that you wish to launch the underlying ExifTool - * process with -stay_open True support turned on that this - * class can then take advantage of. - *

- * Required ExifTool version is 8.36 or higher. - */ - STAY_OPEN(8,36); - - - private VersionNumber requireVersion; - private Feature(int... numbers) { - this.requireVersion = new VersionNumber(numbers); - } - /** - * Used to get the version of ExifTool required by this feature in order - * to work. - * - * @return the version of ExifTool required by this feature in order to - * work. - */ - VersionNumber getVersion() { - return requireVersion; - } - - boolean isSupported(VersionNumber exifVersionNumber) { - return requireVersion.isBeforeOrEqualTo(exifVersionNumber); - } - } - - //================================================================================ - /** - * Version Number used to determine if one version is after another. - */ - static class VersionNumber { - private final int[] numbers; - - public VersionNumber(String str) { - String[] versionParts = str.trim().split("\\."); - this.numbers = new int[versionParts.length]; - for(int i=0; i other.numbers[i] ) { - return false; - } else if ( this.numbers[i] < other.numbers[i] ) { - return true; - } - } - //assume missing number as zero, so if the current process number is more digits it is a higher version - return this.numbers.length <= other.numbers.length; - } - - public String toString() { - StringBuilder builder = new StringBuilder(); - for(int i=0; i 0 ) { - builder.append("."); - } - builder.append(numbers[i]); - } - return builder.toString(); - } - } - - - //================================================================================ - /** - * Enum used to define the 2 different output formats that {@link Tag} - * values can be returned in: numeric or human-readable text. - *

- * ExifTool, via the -n command line arg, is capable of - * returning most values in their raw numeric form (e.g. - * Aperture="2.8010323841") as well as a more human-readable/friendly format - * (e.g. Aperture="2.8"). - *

- * While the {@link Tag}s defined on this class do provide a hint at the - * type of the result (see {@link Tag#getType()}), that hint only applies - * when the {@link Format#NUMERIC} form of the value is returned. - *

- * If the caller finds the human-readable format easier to process, - * {@link Format#HUMAN_READABLE} can be specified when calling - * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned - * {@link String} values processed manually by the caller. - *

- * In order to see the types of values that are returned when - * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive - * ExifTool Tag Guide. - *

- * This makes sense with some values like Aperture that in - * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high - * precision values that are near the intended value (e.g. - * "2.79999992203711" instead of just returning "2.8"). On the other hand, - * other values (like Orientation) are easier to parse when their numeric - * value (1-8) is returned instead of a much longer friendly name (e.g. - * "Mirror horizontal and rotate 270 CW"). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Format { - NUMERIC, HUMAN_READABLE - } - //================================================================================ - /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifTool. - *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default {@link Format#NUMERIC} value format - * is used. - *

- * All replies from ExifTool are parsed as {@link String}s and using the - * type hint from each {@link Tag} can easily be converted to the correct - * data format by using the provided {@link Tag#parseValue(String)} - * method. - *

- * This class does not make an attempt at converting the value automatically - * in case the caller decides they would prefer tag values returned in - * {@link Format#HUMAN_READABLE} format and to avoid any compatibility - * issues with future versions of ExifTool if a tag's return value is - * changed. This approach to leaving returned tag values as strings until - * the caller decides they want to parse them is a safer and more robust - * approach. - *

- * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. - *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. - *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. - *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Tag { - //single entry tags - APERTURE("ApertureValue", Double.class), - AUTHOR("XPAuthor", String.class), - COLOR_SPACE("ColorSpace", Integer.class), - COMMENT("XPComment", String.class), - CONTRAST("Contrast", Integer.class), - CREATE_DATE("CreateDate", String.class), - CREATION_DATE("CreationDate", String.class), - DATE_CREATED("DateCreated", String.class), - DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - FLASH("Flash", Integer.class), - FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), - FNUMBER("FNumber", String.class), - GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), - GPS_DATESTAMP("GPSDateStamp", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), - GPS_LONGITUDE("GPSLongitude", Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), - GPS_SPEED("GPSSpeed", Double.class), - GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), - IMAGE_WIDTH("ImageWidth", Integer.class), - ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), - LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), - MAKE("Make", String.class), - METERING_MODE("MeteringMode", Integer.class), - MODEL("Model", String.class), - ORIENTATION("Orientation", Integer.class), - OWNER_NAME("OwnerName", String.class), - RATING("Rating", Integer.class), - RATING_PERCENT("RatingPercent", Integer.class), - ROTATION("Rotation", Integer.class), - SATURATION("Saturation", Integer.class), - SENSING_METHOD("SensingMethod", Integer.class), - SHARPNESS("Sharpness", Integer.class), - SHUTTER_SPEED("ShutterSpeedValue", Double.class), - SOFTWARE("Software", String.class), - SUBJECT("XPSubject", String.class), - TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), - X_RESOLUTION("XResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), - ; - - /** - * Used to get the {@link Tag} identified by the given, case-sensitive, - * tag name. - * - * @param name - * The case-sensitive name of the tag that will be searched - * for. - * - * @return the {@link Tag} identified by the given, case-sensitive, tag - * name or null if one couldn't be found. - */ - public static Tag forName(String name) { - for (Tag tag : Tag.values()){ - if (tag.getName().equals(name)){ - return tag; - } - } - return null; - } - - /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifTool process) into the type described - * by the associated {@link Tag}. - * - * @param - * The type of the returned value. - * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. - * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). - * - * @throws IllegalArgumentException - * if tag is null. - * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). - * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. - */ - @SuppressWarnings("unchecked") - public T parseValue(String value) throws IllegalArgumentException { - - if (value != null) { - if (Boolean.class.isAssignableFrom(this.getType())){ - return (T) Boolean.valueOf(value); - } else if (Byte.class.isAssignableFrom(this.getType())){ - return (T) Byte.valueOf(Byte.parseByte(value)); - } else if (Integer.class.isAssignableFrom(this.getType())){ - return (T) Integer.valueOf(Integer.parseInt(value)); - } else if (Short.class.isAssignableFrom(this.getType())){ - return (T) Short.valueOf(Short.parseShort(value)); - } else if (Long.class.isAssignableFrom(this.getType())){ - return (T) Long.valueOf(Long.parseLong(value)); - } else if (Float.class.isAssignableFrom(this.getType())){ - return (T) Float.valueOf(Float.parseFloat(value)); - } else if (Double.class.isAssignableFrom(this.getType())){ - return (T) parseDouble(value); - } else if (Character.class.isAssignableFrom(this.getType())){ - return (T) Character.valueOf(value.charAt(0)); - } else if (String.class.isAssignableFrom(this.getType())){ - return (T) value; - } - } - return null; - } - - private Double parseDouble(String in) { - if (in.contains("/")) { - String[] enumeratorAndDivisor = in.split("/"); - return Double.parseDouble(enumeratorAndDivisor[0]) / Double.parseDouble(enumeratorAndDivisor[1]); - } else { - return Double.parseDouble(in); - } - } - - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ - public String getName() { - return name; - } - - /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifTool Tag Guide. - * - * @return a hint for the native type of this tag's value. - */ - public Class getType() { - return type; - } - - private String name; - private Class type; - - private Tag(String name, Class type) { - this.name = name; - this.type = type; - } - } - - //================================================================================ - public enum TagGroup { - EXIF("EXIF","exif:all"), - IPTC("IPTC", "iptc:all"), - XMP("XMP", "xmp:all"), - ALL("ALL", "all"); - - private final String name; - private final String value; - - private TagGroup(String name, String value) { - this.name = name; - this.value = value; - } - - public String getName() { - return name; - } - - public String getValue() { - return value; - } - } - - - //================================================================================ - /** - * Class used to define an exception that occurs when the caller attempts to - * use a {@link Feature} that the underlying native ExifTool install does - * not support (i.e. the version isn't new enough). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public class UnsupportedFeatureException extends RuntimeException { - private static final long serialVersionUID = -1332725983656030770L; - - public UnsupportedFeatureException(Feature feature) { - super( - "Use of feature [" - + feature.toString() - + "] requires version " - + feature.getVersion() - + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); - } - - } + Map resultMap; + if (stayOpen) { + log.debug("Using ExifTool in daemon mode (-stay_open True)..."); + resultMap = processStayOpen(args); + } else { + log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); + resultMap = ExifProcess.executeToResults(exifCmd, args); + } + + // Print out how long the call to external ExifTool process took. + if (log.isDebugEnabled()) { + log.debug(String + .format("Image Meta Processed in %d ms [queried %d tags and found %d values]", + (System.currentTimeMillis() - startTime), + tags.length, resultMap.size())); + } + + return resultMap; + } + + public void addImageMetadata(File image, Map values) + throws IOException { + + final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + + if (image == null) { + throw new IllegalArgumentException( + "image cannot be null and must be a valid stream of image data."); + } + if (values == null || values.isEmpty()) { + throw new IllegalArgumentException( + "values cannot be null and must contain 1 or more tag to value mappings"); + } + + if (!image.canWrite()) { + throw new SecurityException( + "Unable to write the given image [" + + image.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to write to it."); + } + + log.info("Adding Tags {} to {}", values, image.getAbsolutePath()); + + Map resultMap; + if (stayOpen) { + log.debug("Using ExifTool in daemon mode (-stay_open True)..."); + resultMap = processStayOpen(createCommandList( + image.getAbsolutePath(), values)); + } else { + log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); + resultMap = ExifProcess.executeToResults(exifCmd, + createCommandList(image.getAbsolutePath(), values)); + } + + // start process + long startTime = System.currentTimeMillis(); + + // Print out how long the call to external ExifTool process took. + if (log.isDebugEnabled()) { + log.debug(String.format( + "Image Meta Processed in %d ms [added %d tags]", + (System.currentTimeMillis() - startTime), values.size())); + } + } + + private List createCommandList(String filename, + Map values) { + + List args = new ArrayList(64); + + for (Map.Entry entry : values.entrySet()) { + Tag tag = entry.getKey(); + Object value = entry.getValue(); + + StringBuilder arg = new StringBuilder(); + arg.append("-").append(tag.getName()); + if (value instanceof Number) { + arg.append("#"); + } + arg.append("="); + if (value != null) { + if (value instanceof String) { + arg.append("\"").append(value.toString()).append("\""); + } else { + arg.append(value.toString()); + } + } + args.add(arg.toString()); + + } + + args.add(filename); + return args; + + } + + /** + * Will attempt 3 times to use the running exif process, and if unable to + * complete successfully will throw IOException + */ + private Map processStayOpen(List args) + throws IOException { + int attempts = 0; + while (attempts < 3 && !shuttingDown.get()) { + attempts++; + // make sure process is started + ensureProcessRunning(); + TimerTask attemptTimer = null; + try { + if (timeoutWhenKeepAlive > 0) { + attemptTimer = new TimerTask() { + @Override + public void run() { + log.warn("Process ran too long closing, max " + + timeoutWhenKeepAlive + " mills"); + process.close(); + } + }; + cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); + } + log.debug("Streaming arguments to ExifTool process..."); + return process.sendArgs(args); + } catch (IOException ex) { + if (STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) + && !shuttingDown.get()) { + // only catch "Stream Closed" error (happens when process + // has died) + log.warn(String.format( + "Caught IOException(\"%s\"), will restart daemon", + STREAM_CLOSED_MESSAGE)); + process.close(); + } else { + throw ex; + } + } finally { + if (attemptTimer != null) + attemptTimer.cancel(); + } + } + if (shuttingDown.get()) { + throw new IOException("Shutting Down"); + } + throw new IOException("Ran out of attempts"); + } + + private static Map mapByTag(Map stringMap) { + Map tagMap = new HashMap(Tag.values().length); + for (Tag tag : Tag.values()) { + if (stringMap.containsKey(tag.getName())) { + tagMap.put(tag, stringMap.get(tag.getName())); + } + } + return tagMap; + } + + // ================================================================================ + /** + * Represents an Exif Process. + */ + public static class ExifProcess { + private final ReentrantLock closeLock = new ReentrantLock(false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader reader; + private final OutputStreamWriter writer; + private volatile boolean closed = false; + + public static VersionNumber readVersion(String exifCmd) { + ExifProcess process = _execute(false, + Arrays.asList(exifCmd, "-ver")); + try { + return new VersionNumber(process.readLine()); + } catch (IOException ex) { + throw new RuntimeException(String.format( + "Unable to check version number of ExifTool: %s", + exifCmd)); + } finally { + process.close(); + } + } + + public static Map executeToResults(String exifCmd, + List args) throws IOException { + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { + return process.readResponse(); + } finally { + process.close(); + } + } + + public static ExifProcess startup(String exifCmd) { + List args = Arrays.asList(exifCmd, "-stay_open", "True", + "-@", "-"); + return _execute(true, args); + } + + public static ExifProcess _execute(boolean keepAlive, List args) { + log.debug(String + .format("Attempting to start external ExifTool process using args: %s", + args)); + try { + Process process = new ProcessBuilder(args).start(); + log.debug("\tSuccessful"); + return new ExifProcess(keepAlive, process); + } catch (Exception e) { + String message = "Unable to start external ExifTool process using the execution arguments: " + + args + + ". Ensure ExifTool is installed correctly and runs using the command path '" + + args.get(0) + + "' as specified by the 'exiftool.path' system property."; + + log.debug(message); + throw new RuntimeException(message, e); + } + } + + public ExifProcess(boolean keepAlive, Process process) { + this.keepAlive = keepAlive; + this.process = process; + this.reader = new BufferedReader(new InputStreamReader( + process.getInputStream())); + this.writer = new OutputStreamWriter(process.getOutputStream()); + } + + public synchronized Map sendArgs(List args) + throws IOException { + StringBuilder builder = new StringBuilder(); + for (String arg : args) { + builder.append(arg).append("\n"); + } + builder.append("-execute\n"); + writeFlush(builder.toString()); + return readResponse(); + } + + public synchronized void writeFlush(String message) throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + writer.write(message); + writer.flush(); + } + + public synchronized String readLine() throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + return reader.readLine(); + } + + public synchronized Map readResponse() + throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + log.debug("Reading response back from ExifTool..."); + Map resultMap = new HashMap(500); + String line; + + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + String[] pair = TAG_VALUE_PATTERN.split(line, 2); + + if (pair.length == 2) { + resultMap.put(pair[0], pair[1]); + log.debug(String.format("\tRead Tag [name=%s, value=%s]", + pair[0], pair[1])); + } + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } + } + return resultMap; + } + + public boolean isClosed() { + return closed; + } + + public void close() { + if (!closed) { + closeLock.lock(); + try { + if (!closed) { + closed = true; + log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); + try { + writer.write("-stay_open\nFalse\n"); + writer.flush(); + } catch (IOException ex) { + // log.error(ex,ex); + } + try { + log.debug("Closing Read stream..."); + reader.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + log.debug("Closing Write stream..."); + writer.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + log.debug("Read/Write streams successfully closed."); + + try { + process.destroy(); + } catch (Exception e) { + // + } + // process = null; + + } + } finally { + closeLock.unlock(); + } + } + } + } + + // ================================================================================ + /** + * Enum used to define the different kinds of features in the native + * ExifTool executable that this class can help you take advantage of. + *

+ * These flags are different from {@link Tag}s in that a "feature" is + * determined to be a special functionality of the underlying ExifTool + * executable that requires a different code-path in this class to take + * advantage of; for example, -stay_open True support. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Feature { + /** + * Enum used to specify that you wish to launch the underlying ExifTool + * process with -stay_open True support turned on that this + * class can then take advantage of. + *

+ * Required ExifTool version is 8.36 or higher. + */ + STAY_OPEN(8, 36); + + private VersionNumber requireVersion; + + private Feature(int... numbers) { + this.requireVersion = new VersionNumber(numbers); + } + + /** + * Used to get the version of ExifTool required by this feature in order + * to work. + * + * @return the version of ExifTool required by this feature in order to + * work. + */ + VersionNumber getVersion() { + return requireVersion; + } + + boolean isSupported(VersionNumber exifVersionNumber) { + return requireVersion.isBeforeOrEqualTo(exifVersionNumber); + } + } + + // ================================================================================ + /** + * Version Number used to determine if one version is after another. + */ + static class VersionNumber { + private final int[] numbers; + + public VersionNumber(String str) { + String[] versionParts = str.trim().split("\\."); + this.numbers = new int[versionParts.length]; + for (int i = 0; i < versionParts.length; i++) { + numbers[i] = Integer.parseInt(versionParts[i]); + } + } + + public VersionNumber(int... numbers) { + this.numbers = numbers; + } + + public boolean isBeforeOrEqualTo(VersionNumber other) { + int max = Math.min(this.numbers.length, other.numbers.length); + for (int i = 0; i < max; i++) { + if (this.numbers[i] > other.numbers[i]) { + return false; + } else if (this.numbers[i] < other.numbers[i]) { + return true; + } + } + // assume missing number as zero, so if the current process number + // is more digits it is a higher version + return this.numbers.length <= other.numbers.length; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < numbers.length; i++) { + if (builder.length() > 0) { + builder.append("."); + } + builder.append(numbers[i]); + } + return builder.toString(); + } + } + + // ================================================================================ + /** + * Enum used to define the 2 different output formats that {@link Tag} + * values can be returned in: numeric or human-readable text. + *

+ * ExifTool, via the -n command line arg, is capable of + * returning most values in their raw numeric form (e.g. + * Aperture="2.8010323841") as well as a more human-readable/friendly format + * (e.g. Aperture="2.8"). + *

+ * While the {@link Tag}s defined on this class do provide a hint at the + * type of the result (see {@link Tag#getType()}), that hint only applies + * when the {@link Format#NUMERIC} form of the value is returned. + *

+ * If the caller finds the human-readable format easier to process, + * {@link Format#HUMAN_READABLE} can be specified when calling + * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned + * {@link String} values processed manually by the caller. + *

+ * In order to see the types of values that are returned when + * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive + * ExifTool Tag Guide. + *

+ * This makes sense with some values like Aperture that in + * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high + * precision values that are near the intended value (e.g. + * "2.79999992203711" instead of just returning "2.8"). On the other hand, + * other values (like Orientation) are easier to parse when their numeric + * value (1-8) is returned instead of a much longer friendly name (e.g. + * "Mirror horizontal and rotate 270 CW"). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Format { + NUMERIC, + HUMAN_READABLE + } + + // ================================================================================ + /** + * Enum used to pre-define a convenient list of tags that can be easily + * extracted from images using this class with an external install of + * ExifTool. + *

+ * Each tag defined also includes a type hint for the parsed value + * associated with it when the default {@link Format#NUMERIC} value format + * is used. + *

+ * All replies from ExifTool are parsed as {@link String}s and using the + * type hint from each {@link Tag} can easily be converted to the correct + * data format by using the provided {@link Tag#parseValue(String)} method. + *

+ * This class does not make an attempt at converting the value automatically + * in case the caller decides they would prefer tag values returned in + * {@link Format#HUMAN_READABLE} format and to avoid any compatibility + * issues with future versions of ExifTool if a tag's return value is + * changed. This approach to leaving returned tag values as strings until + * the caller decides they want to parse them is a safer and more robust + * approach. + *

+ * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or + * process the returned {@link String} values any way they wish. + *

Tag Support

+ * ExifTool is capable of parsing almost every tag known to man (1000+), but + * this class makes an attempt at pre-defining a convenient list of the most + * common tags for use. + *

+ * This list was determined by looking at the common metadata tag values + * written to images by popular mobile devices (iPhone, Android) as well as + * cameras like simple point and shoots as well as DSLRs. As an additional + * source of input the list of supported/common EXIF formats that Flickr + * supports was also reviewed to ensure the most common/useful tags were + * being covered here. + *

+ * Please email me or file an issue + * if you think this list is missing a commonly used tag that should be + * added to it. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Tag { + // single entry tags + APERTURE("ApertureValue", Double.class), + AUTHOR("XPAuthor", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATE_DATE("CreateDate", String.class), + CREATION_DATE("CreationDate", String.class), + DATE_CREATED("DateCreated", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + FLASH("Flash", Integer.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + FNUMBER("FNumber", String.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_DATESTAMP("GPSDateStamp", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SENSING_METHOD("SensingMethod", Integer.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), ; + + /** + * Used to get the {@link Tag} identified by the given, case-sensitive, + * tag name. + * + * @param name + * The case-sensitive name of the tag that will be searched + * for. + * + * @return the {@link Tag} identified by the given, case-sensitive, tag + * name or null if one couldn't be found. + */ + public static Tag forName(String name) { + for (Tag tag : Tag.values()) { + if (tag.getName().equals(name)) { + return tag; + } + } + return null; + } + + /** + * Convenience method used to convert the given string Tag value + * (returned from the external ExifTool process) into the type described + * by the associated {@link Tag}. + * + * @param + * The type of the returned value. + * @param value + * The {@link String} representation of the tag's value as + * parsed from the image. + * + * @return the given string value converted to a native Java type (e.g. + * Integer, Double, etc.). + * + * @throws IllegalArgumentException + * if tag is null. + * @throws NumberFormatException + * if any exception occurs while trying to parse the given + * value to any of the supported numeric types + * in Java via calls to the respective parseXXX + * methods defined on all the numeric wrapper classes (e.g. + * {@link Integer#parseInt(String)} , + * {@link Double#parseDouble(String)} and so on). + * @throws ClassCastException + * if the type defined by T is incompatible + * with the type defined by {@link Tag#getType()} returned + * by the tag argument passed in. This class + * performs an implicit/unchecked cast to the type + * T before returning the parsed result of the + * type indicated by {@link Tag#getType()}. If the types do + * not match, a ClassCastException will be + * generated by the VM. + */ + @SuppressWarnings("unchecked") + public T parseValue(String value) throws IllegalArgumentException { + + if (value != null) { + if (Boolean.class.isAssignableFrom(this.getType())) { + return (T) Boolean.valueOf(value); + } else if (Byte.class.isAssignableFrom(this.getType())) { + return (T) Byte.valueOf(Byte.parseByte(value)); + } else if (Integer.class.isAssignableFrom(this.getType())) { + return (T) Integer.valueOf(Integer.parseInt(value)); + } else if (Short.class.isAssignableFrom(this.getType())) { + return (T) Short.valueOf(Short.parseShort(value)); + } else if (Long.class.isAssignableFrom(this.getType())) { + return (T) Long.valueOf(Long.parseLong(value)); + } else if (Float.class.isAssignableFrom(this.getType())) { + return (T) Float.valueOf(Float.parseFloat(value)); + } else if (Double.class.isAssignableFrom(this.getType())) { + return (T) parseDouble(value); + } else if (Character.class.isAssignableFrom(this.getType())) { + return (T) Character.valueOf(value.charAt(0)); + } else if (String.class.isAssignableFrom(this.getType())) { + return (T) value; + } + } + return null; + } + + private Double parseDouble(String in) { + if (in.contains("/")) { + String[] enumeratorAndDivisor = in.split("/"); + return Double.parseDouble(enumeratorAndDivisor[0]) + / Double.parseDouble(enumeratorAndDivisor[1]); + } else { + return Double.parseDouble(in); + } + } + + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ + public String getName() { + return name; + } + + /** + * Used to get a hint for the native type of this tag's value as + * specified by Phil Harvey's ExifTool Tag Guide. + * + * @return a hint for the native type of this tag's value. + */ + public Class getType() { + return type; + } + + private String name; + private Class type; + + private Tag(String name, Class type) { + this.name = name; + this.type = type; + } + } + + // ================================================================================ + public enum TagGroup { + EXIF("EXIF", "exif:all"), + IPTC("IPTC", "iptc:all"), + XMP("XMP", "xmp:all"), + ALL("ALL", "all"); + + private final String name; + private final String value; + + private TagGroup(String name, String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + } + + // ================================================================================ + /** + * Class used to define an exception that occurs when the caller attempts to + * use a {@link Feature} that the underlying native ExifTool install does + * not support (i.e. the version isn't new enough). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public class UnsupportedFeatureException extends RuntimeException { + private static final long serialVersionUID = -1332725983656030770L; + + public UnsupportedFeatureException(Feature feature) { + super( + "Use of feature [" + + feature.toString() + + "] requires version " + + feature.getVersion() + + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); + } + + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index a914eb75..8ec7233b 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -1,29 +1,31 @@ package com.thebuzzmedia.exiftool; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Tag; +import java.io.File; +import java.io.IOException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.IOException; +import com.thebuzzmedia.exiftool.ExifTool.Feature; +import com.thebuzzmedia.exiftool.ExifTool.Tag; public class Benchmark { public static final int ITERATIONS = 25; - private static Logger log = LoggerFactory.getLogger(Benchmark.class); - + private static Logger log = LoggerFactory.getLogger(Benchmark.class); - public static void main(String[] args) throws IOException, InterruptedException { + public static void main(String[] args) throws IOException, + InterruptedException { - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); - final Tag[] tags = Tag.values(); - final File[] images = new File("src/test/resources").listFiles(); + final Tag[] tags = Tag.values(); + final File[] images = new File("src/test/resources").listFiles(); - log.info("Benchmark [tags=" + tags.length + ", images=" - + images.length + ", iterations=" + ITERATIONS + "]"); - log.info("\t" + (images.length * ITERATIONS) + log.info("Benchmark [tags=" + tags.length + ", images=" + images.length + + ", iterations=" + ITERATIONS + "]"); + log.info("\t" + (images.length * ITERATIONS) + " ExifTool process calls, " + (tags.length * images.length * ITERATIONS) + " total operations.\n"); @@ -37,13 +39,13 @@ public static void main(String[] args) throws IOException, InterruptedException log.info("\t[-stay_open False]"); long elapsedTime = 0; - for (int i = 1; i <= ITERATIONS; i++){ - log.info(String.format("iteration %s of %s", i, ITERATIONS)); + for (int i = 1; i <= ITERATIONS; i++) { + log.info(String.format("iteration %s of %s", i, ITERATIONS)); elapsedTime += run(tool, images, tags); - } + } log.info("\t\tElapsed Time: " + elapsedTime + " ms (" - + ((double) elapsedTime / 1000) + " secs)"); + + ((double) elapsedTime / 1000) + " secs)"); /* * -stay_open True */ @@ -51,13 +53,13 @@ public static void main(String[] args) throws IOException, InterruptedException long elapsedTimeSO = 0; for (int i = 1; i <= ITERATIONS; i++) { - log.info(String.format("iteration %s of %s", i, ITERATIONS)); + log.info(String.format("iteration %s of %s", i, ITERATIONS)); elapsedTimeSO += run(toolSO, images, tags); } log.info("\t\tElapsed Time: " + elapsedTimeSO + " ms (" - + ((double) elapsedTimeSO / 1000) + " secs - " - + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); + + ((double) elapsedTimeSO / 1000) + " secs - " + + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); // Shut down the running exiftool proc. toolSO.close(); @@ -67,9 +69,9 @@ private static long run(ExifTool tool, File[] images, Tag[] tags) throws IllegalArgumentException, SecurityException, IOException { long startTime = System.currentTimeMillis(); - for (File image : images){ - tool.getImageMeta(image, tags); - } + for (File image : images) { + tool.getImageMeta(image, tags); + } return (System.currentTimeMillis() - startTime); } diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index bca4631e..d25636cb 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -4,43 +4,52 @@ import java.io.IOException; import java.util.Map; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Format; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.thebuzzmedia.exiftool.ExifTool.Feature; +import com.thebuzzmedia.exiftool.ExifTool.Format; + public class Example { - private static Logger log = LoggerFactory.getLogger(Example.class); - private static final String TEST_FILES_PATH = "src/test/resources"; - - public static void main(String[] args) throws IOException, InterruptedException { - - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); - ExifTool tool = new ExifTool(Feature.STAY_OPEN); - - File[] images = new File(TEST_FILES_PATH).listFiles(); - - //list all first-class tags - for (File f : images) { - log.info("\n[{}]", f.getName()); - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, ExifTool.Tag.values()); - for (ExifTool.Tag key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key.getName(), metadata.get(key))); - } - } - - log.info("\n\n** GET TAGS BY GROUP"); - //list all XMP, IPTC and XMP tags - File f = new File(TEST_FILES_PATH + "/kureckjones_jett_075_02-cropped.tif"); - for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] {ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, ExifTool.TagGroup.XMP}){ - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, tagGroup); - log.info(tagGroup.getName()); - for (String key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - } - } - - tool.close(); - } + private static Logger log = LoggerFactory.getLogger(Example.class); + private static final String TEST_FILES_PATH = "src/test/resources"; + + public static void main(String[] args) throws IOException, + InterruptedException { + + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + + File[] images = new File(TEST_FILES_PATH).listFiles(); + + // list all first-class tags + for (File f : images) { + log.info("\n[{}]", f.getName()); + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, ExifTool.Tag.values()); + for (ExifTool.Tag key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key.getName(), + metadata.get(key))); + } + } + + log.info("\n\n** GET TAGS BY GROUP"); + // list all XMP, IPTC and XMP tags + File f = new File(TEST_FILES_PATH + + "/kureckjones_jett_075_02-cropped.tif"); + for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] { + ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, + ExifTool.TagGroup.XMP }) { + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, tagGroup); + log.info(tagGroup.getName()); + for (String key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + } + } + + tool.close(); + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 034b45fc..02fc76fe 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -1,8 +1,8 @@ package com.thebuzzmedia.exiftool; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; @@ -18,427 +18,500 @@ import java.util.Map; import java.util.Set; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * TestMetadata

- * + * TestMetadata + *

+ * * @author Michael Rush (michaelrush@gmail.com) * @since Initially created 8/8/13 */ public class TestExifTool { - private static Logger log = LoggerFactory.getLogger(TestExifTool.class); - - @Test - public void testSingleTool() throws Exception { - ExifTool tool = new ExifTool(); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.startup(); - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - } - - @Test - public void testConcurrent() throws Exception { - - int toolCount = 5; - - List threads = new ArrayList(toolCount); - for (int i=1; i <= toolCount; i++){ - String toolName = "tool"+i; - Thread t = new Thread(toolName){ - @Override - public void run() { - log.info(getName() + ": starting"); - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - runTests(tool,getName()); - log.info(getName() + ": finished"); - } catch (IOException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } catch (URISyntaxException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } finally { - tool.shutdown(); - } - log.info(getName() + ": finished"); - } - }; - t.start(); - threads.add(t); - } - - for (Thread t : threads){ - t.run(); - } - } - - @Test - public void testManyThreadsOneTool() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Thread[] threads = new Thread[20]; - for(int i=0; i < threads.length; i++) { - final String label = "run "+i; - threads[i] = new Thread(new Runnable() { - public void run() { - try { - for(int j=0; j<5; j++) { - runTests(tool,label); - } - log.info("DONE: "+label+" success!"); - } catch (IOException ex) { - fail(label); - } catch (URISyntaxException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } - } - },label); - } - for(Thread thread : threads) { - thread.start(); - } - for(Thread thread : threads) { - thread.join(); - } - } finally { - tool.shutdown(); - } - } - - @Test - public void testProcessTimeout() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.setRunTimeout(1); - runTests(tool,"will fail"); - fail("should have failed"); - } catch (IOException ex) { - ; - } finally { - tool.shutdown(); - } - } - - public boolean runTests(ExifTool tool, String runId) throws IOException, URISyntaxException { - - Map metadata; - File imageFile; - Set keys; - ExifTool.Tag tag; - - URL url = getClass().getResource("/kureckjones_jett_075_02-cropped.tif"); - imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(22, metadata.size()); - - keys = metadata.keySet(); - - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(728, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(825, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("P 45+", tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 1"); - - - url = getClass().getResource("/nexus-s-electric-cars.jpg"); - imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(23, metadata.size()); - - keys = metadata.keySet(); - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(2560, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(1920, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.ISO; - assertEquals(50, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.SHUTTER_SPEED; - assertEquals("1/64", metadata.get(tag)); - assertEquals(0.015625, tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 2"); - return true; - } - - @Test - public void testGroupTags() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Map metadata; - - URL url = getClass().getResource("/iptc_test-photoshop.jpg"); - File f = new File(url.toURI()); - metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, ExifTool.TagGroup.IPTC); - assertEquals(17, metadata.size()); - assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); - assertEquals("IPTC Status: Copyright Notice", metadata.get("CopyrightNotice")); - assertEquals("IPTC Content: Description Writer", metadata.get("Writer-Editor")); - //for (String key : metadata.keySet()){ - // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - //} - } finally { - tool.shutdown(); - } - } - - @Test - public void testTag(){ - assertEquals("string value", "John Doe", ExifTool.Tag.AUTHOR.parseValue("John Doe")); - assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); - assertEquals("double value, from fraction", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); - assertEquals("double value, from decimal", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); - } - - @Test - public void testVersionNumber() { - assertTrue(new ExifTool.VersionNumber("1.2").isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); - assertTrue(new ExifTool.VersionNumber(1,2).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber(2,1))); - } - - - @Test - public void testWriteTagStringNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - - } - - @Test - public void testWriteTagString() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteTagStringInvalidformat() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - String newDate = "2egek opkpgrpok"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - - // Now change it to an invalid value which should fail - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's not updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - // might not exist - if(backup_url != null) { - Path backupFile = Paths.get(backup_url.toURI()); - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - } - - @Test - public void testWriteTagNumberNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - - } - - @Test - public void testWriteTagNumber() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - - } - - - @Test - public void testWriteMulipleTag() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - - } - - @Test - public void testWriteMulipleTagNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - - } - - //todo TEST automatic daemon restart by killing perl process + private static Logger log = LoggerFactory.getLogger(TestExifTool.class); + + @Test + public void testSingleTool() throws Exception { + ExifTool tool = new ExifTool(); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + tool.startup(); + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + } + + @Test + public void testConcurrent() throws Exception { + + int toolCount = 5; + + List threads = new ArrayList(toolCount); + for (int i = 1; i <= toolCount; i++) { + String toolName = "tool" + i; + Thread t = new Thread(toolName) { + @Override + public void run() { + log.info(getName() + ": starting"); + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + runTests(tool, getName()); + log.info(getName() + ": finished"); + } catch (IOException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } catch (URISyntaxException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } finally { + tool.shutdown(); + } + log.info(getName() + ": finished"); + } + }; + t.start(); + threads.add(t); + } + + for (Thread t : threads) { + t.run(); + } + } + + @Test + public void testManyThreadsOneTool() throws Exception { + final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + Thread[] threads = new Thread[20]; + for (int i = 0; i < threads.length; i++) { + final String label = "run " + i; + threads[i] = new Thread(new Runnable() { + @Override + public void run() { + try { + for (int j = 0; j < 5; j++) { + runTests(tool, label); + } + log.info("DONE: " + label + " success!"); + } catch (IOException ex) { + fail(label); + } catch (URISyntaxException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } + } + }, label); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + } finally { + tool.shutdown(); + } + } + + @Test + public void testProcessTimeout() throws Exception { + final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + tool.setRunTimeout(1); + runTests(tool, "will fail"); + fail("should have failed"); + } catch (IOException ex) { + ; + } finally { + tool.shutdown(); + } + } + + public boolean runTests(ExifTool tool, String runId) throws IOException, + URISyntaxException { + + Map metadata; + File imageFile; + Set keys; + ExifTool.Tag tag; + + URL url = getClass() + .getResource("/kureckjones_jett_075_02-cropped.tif"); + imageFile = new File(url.toURI()); + metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.values()); + assertEquals(22, metadata.size()); + + keys = metadata.keySet(); + + tag = ExifTool.Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(728, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.IMAGE_HEIGHT; + assertEquals(825, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.MODEL; + assertEquals("P 45+", tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 1"); + + url = getClass().getResource("/nexus-s-electric-cars.jpg"); + imageFile = new File(url.toURI()); + metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.values()); + assertEquals(23, metadata.size()); + + keys = metadata.keySet(); + tag = ExifTool.Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(2560, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.IMAGE_HEIGHT; + assertEquals(1920, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.MODEL; + assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.ISO; + assertEquals(50, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.SHUTTER_SPEED; + assertEquals("1/64", metadata.get(tag)); + assertEquals(0.015625, tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 2"); + return true; + } + + @Test + public void testGroupTags() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + Map metadata; + + URL url = getClass().getResource("/iptc_test-photoshop.jpg"); + File f = new File(url.toURI()); + metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, + ExifTool.TagGroup.IPTC); + assertEquals(17, metadata.size()); + assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); + assertEquals("IPTC Status: Copyright Notice", + metadata.get("CopyrightNotice")); + assertEquals("IPTC Content: Description Writer", + metadata.get("Writer-Editor")); + // for (String key : metadata.keySet()){ + // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + // } + } finally { + tool.shutdown(); + } + } + + @Test + public void testTag() { + assertEquals("string value", "John Doe", + ExifTool.Tag.AUTHOR.parseValue("John Doe")); + assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); + assertEquals("double value, from fraction", .25, + ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); + assertEquals("double value, from decimal", .25, + ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); + } + + @Test + public void testVersionNumber() { + assertTrue(new ExifTool.VersionNumber("1.2") + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); + assertTrue(new ExifTool.VersionNumber(1, 2) + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); + assertTrue(new ExifTool.VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); + assertTrue(new ExifTool.VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new ExifTool.VersionNumber(2, 1))); + } + + @Test + public void testWriteTagStringNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's updated + metadata = tool + .getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + + } + + @Test + public void testWriteTagString() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's updated + metadata = tool + .getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteTagStringInvalidformat() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + String newDate = "2egek opkpgrpok"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + + // Now change it to an invalid value which should fail + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's not updated + metadata = tool + .getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + // might not exist + if (backup_url != null) { + Path backupFile = Paths.get(backup_url.toURI()); + Files.move(backupFile, imageFile, + StandardCopyOption.REPLACE_EXISTING); + } + } + + @Test + public void testWriteTagNumberNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + + // Now change it + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + + } + + @Test + public void testWriteTagNumber() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + + // Now change it + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + + } + + @Test + public void testWriteMulipleTag() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + + } + + @Test + public void testWriteMulipleTagNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + + } + + // todo TEST automatic daemon restart by killing perl process } From 3882deff3bb63ff1532d543ec42f73c95de8cdf2 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 11:54:59 +0300 Subject: [PATCH 038/148] - formatted --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 4 ++-- src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java | 5 ----- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index a7adc9e3..9a13cb05 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -713,6 +713,7 @@ private List createCommandList(String filename, return args; } + /** * extract image metadata to exiftool's internal xml format. * @@ -1328,8 +1329,7 @@ public enum Tag { // actually binary data, but what are we doing to do here??? Just use to // save to file... THUMBNAIL_IMAGE("ThumbnailImage", String.class), - THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class), - ; + THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class), ; /** * Used to get the {@link Tag} identified by the given, case-sensitive, diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 73b3ebe3..a9f3291b 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -22,11 +22,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import junit.framework.TestCase; - -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - /** * TestMetadata *

From ad90557605b4ac051195e63b7b2af226ec062660 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 12:04:47 +0300 Subject: [PATCH 039/148] - formatted --- .gitignore | 6 + .../com/thebuzzmedia/exiftool/ExifTool.java | 2244 +++++++++-------- .../com/thebuzzmedia/exiftool/Benchmark.java | 48 +- .../com/thebuzzmedia/exiftool/Example.java | 77 +- .../thebuzzmedia/exiftool/TestExifTool.java | 911 ++++--- 5 files changed, 1715 insertions(+), 1571 deletions(-) diff --git a/.gitignore b/.gitignore index e92c07db..748b91f3 100644 --- a/.gitignore +++ b/.gitignore @@ -5,3 +5,9 @@ bin workspace.xml *.iml .idea + +/.classpath + +/.project + +/.settings diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index da3c1545..d2b3c831 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -15,8 +15,21 @@ */ package com.thebuzzmedia.exiftool; -import java.io.*; -import java.util.*; +import java.io.BufferedReader; +import java.io.File; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.EnumSet; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.Set; +import java.util.StringTokenizer; +import java.util.Timer; +import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; @@ -69,10 +82,10 @@ * {@link Format#NUMERIC} and it is ultimately up to the caller to decide how * best to parse or convert the returned values. *

- * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} - * convenience method for parsing given String values according to - * the Tag hint automatically for you if that is what you plan on doing, - * otherwise feel free to handle the return values anyway you want. + * The {@link Tag} Enum provides the {@link Tag#parseValue(String)} convenience + * method for parsing given String values according to the Tag hint + * automatically for you if that is what you plan on doing, otherwise feel free + * to handle the return values anyway you want. *

ExifTool -stay_open Support

* ExifTool * Because this feature requires ExifTool 8.36 or later, this class will * actually verify support for the feature in the version of ExifTool pointed at - * by {@link #exifCmd} before successfully instantiating the class and - * will notify you via an {@link UnsupportedFeatureException} if the native - * ExifTool doesn't support the requested feature. + * by {@link #exifCmd} before successfully instantiating the class and will + * notify you via an {@link UnsupportedFeatureException} if the native ExifTool + * doesn't support the requested feature. *

* In the event of an {@link UnsupportedFeatureException}, the caller can either * upgrade the native ExifTool upgrade to the version required or simply avoid @@ -194,1107 +207,1148 @@ * written the 2nd most robust image metadata library I have come across: Metadata Extractor * that you might want to look at. - * + * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ public class ExifTool { - public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; - public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; - - /** - * Name used to identify the (optional) cleanup {@link Thread}. - *

- * This is only provided to make debugging and profiling easier for - * implementers making use of this class such that the resources this class - * creates and uses (i.e. Threads) are readily identifiable in a running VM. - *

- * Default value is "ExifTool Cleanup Thread". - */ - private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; - - /** - * Compiled {@link Pattern} of ": " used to split compact output from - * ExifTool evenly into name/value pairs. - */ - private static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); - private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - - private static Logger log = LoggerFactory.getLogger(ExifTool.class); - - /** - * The absolute path to the ExifTool executable on the host system running - * this class as defined by the "exiftool.path" system - * property. - *

- * If ExifTool is on your system path and running the command "exiftool" - * successfully executes it, leaving this value unchanged will work fine on - * any platform. If the ExifTool executable is named something else or not - * in the system path, then this property will need to be set to point at it - * before using this class. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.path=/path/to/exiftool - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * On Windows be sure to double-escape the path to the tool, for example: - * - * -Dexiftool.path=C:\\Tools\\exiftool.exe - * - *

- * Default value is "exiftool". - *

Relative Paths

- * Relative path values (e.g. "bin/tools/exiftool") are executed with - * relation to the base directory the VM process was started in. Essentially - * the directory that new File(".").getAbsolutePath() points at - * during runtime. - */ - private final String exifCmd; - - /** - * Interval (in milliseconds) of inactivity before the cleanup thread wakes - * up and cleans up the daemon ExifTool process and the read/write streams - * used to communicate with it when the {@link Feature#STAY_OPEN} feature is - * used. - *

- * Ever time a call to getImageMeta is processed, the timer - * keeping track of cleanup is reset; more specifically, this class has to - * experience no activity for this duration of time before the cleanup - * process is fired up and cleans up the host OS process and the stream - * resources. - *

- * Any subsequent calls to getImageMeta after a cleanup simply - * re-initializes the resources. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.processCleanupDelay=600000 - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * Setting this value to 0 disables the automatic cleanup thread completely - * and the caller will need to manually cleanup the external ExifTool - * process and read/write streams by calling {@link #close()}. - *

- * Default value is 600,000 (10 minutes). - */ - private final long processCleanupDelay; - - private final Map featureSupportedMap = new HashMap(); - private final Set featureSet = EnumSet.noneOf(Feature.class); - private final ReentrantLock lock = new ReentrantLock(); - private final VersionNumber exifVersion; - private final Timer cleanupTimer; - private TimerTask currentCleanupTask = null; - private AtomicBoolean shuttingDown = new AtomicBoolean(false); - private volatile ExifProcess process; - private int timeoutWhenKeepAlive = 0; - - public ExifTool(){ - this((Feature[]) null); - } - - /** - * In this constructor, exifToolPath and processCleanupDelay are gotten from system properties - * exiftool.path and exiftool.processCleanupDelay. processCleanupDelay is optional. If not found, - * the default is used. - */ - public ExifTool (Feature ... features){ - this( - System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), - Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, DEFAULT_PROCESS_CLEANUP_DELAY), - features - ); - } - - public ExifTool(String exifToolPath) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); - } - - public ExifTool(String exifToolPath, Feature ... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); - } - - public ExifTool(String exifCmd, long processCleanupDelay, Feature ... features) { - this.exifCmd = exifCmd; - this.processCleanupDelay = processCleanupDelay; - this.exifVersion = ExifProcess.readVersion(exifCmd); - if (features != null && features.length > 0) { - for (Feature feature : features) { - if ( ! feature.isSupported(exifVersion) ) { - throw new UnsupportedFeatureException(feature); - } - this.featureSet.add(feature); - this.featureSupportedMap.put(feature,true); - } - } - - /* - * Now that initialization is done, init the cleanup timer if we are - * using STAY_OPEN and the delay time set is non-zero. - */ - if (isFeatureEnabled(Feature.STAY_OPEN) ) { - cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - } else { - cleanupTimer = null; - } - } - - /** - * Limits the amount of time (in mills) an exif operation can take. Setting value to greater than 0 to enable. - */ - public ExifTool setRunTimeout(int mills) { - timeoutWhenKeepAlive = mills; - return this; - } - - /** - * Used to determine if the given {@link Feature} is supported by the - * underlying native install of ExifTool pointed at by - * {@link #exifCmd}. - *

- * If support for the given feature has not been checked for yet, this - * method will automatically call out to ExifTool and ensure the requested - * feature is supported in the current local install. - *

- * The external call to ExifTool to confirm feature support is only ever - * done once per JVM session and stored in a static final - * {@link Map} that all instances of this class share. - * - * @param feature - * The feature to check support for in the underlying ExifTool - * install. - * - * @return true if support for the given {@link Feature} was - * confirmed to work with the currently installed ExifTool or - * false if it is not supported. - * - * @throws IllegalArgumentException - * if feature is null. - * @throws RuntimeException - * if any exception occurs while attempting to start the - * external ExifTool process to verify feature support. - */ - public boolean isFeatureSupported(Feature feature) throws RuntimeException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); - } - - Boolean supported = featureSupportedMap.get(feature); + public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + + /** + * Name used to identify the (optional) cleanup {@link Thread}. + *

+ * This is only provided to make debugging and profiling easier for + * implementers making use of this class such that the resources this class + * creates and uses (i.e. Threads) are readily identifiable in a running VM. + *

+ * Default value is "ExifTool Cleanup Thread". + */ + private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; + + /** + * Compiled {@link Pattern} of ": " used to split compact output from + * ExifTool evenly into name/value pairs. + */ + private static final Pattern TAG_VALUE_PATTERN = Pattern + .compile("\\s*:\\s*"); + private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + + private static Logger log = LoggerFactory.getLogger(ExifTool.class); + + /** + * The absolute path to the ExifTool executable on the host system running + * this class as defined by the "exiftool.path" system + * property. + *

+ * If ExifTool is on your system path and running the command "exiftool" + * successfully executes it, leaving this value unchanged will work fine on + * any platform. If the ExifTool executable is named something else or not + * in the system path, then this property will need to be set to point at it + * before using this class. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.path=/path/to/exiftool + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * On Windows be sure to double-escape the path to the tool, for example: + * + * -Dexiftool.path=C:\\Tools\\exiftool.exe + * + *

+ * Default value is "exiftool". + *

Relative Paths

+ * Relative path values (e.g. "bin/tools/exiftool") are executed with + * relation to the base directory the VM process was started in. Essentially + * the directory that new File(".").getAbsolutePath() points at + * during runtime. + */ + private final String exifCmd; + + /** + * Interval (in milliseconds) of inactivity before the cleanup thread wakes + * up and cleans up the daemon ExifTool process and the read/write streams + * used to communicate with it when the {@link Feature#STAY_OPEN} feature is + * used. + *

+ * Ever time a call to getImageMeta is processed, the timer + * keeping track of cleanup is reset; more specifically, this class has to + * experience no activity for this duration of time before the cleanup + * process is fired up and cleans up the host OS process and the stream + * resources. + *

+ * Any subsequent calls to getImageMeta after a cleanup simply + * re-initializes the resources. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.processCleanupDelay=600000 + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * Setting this value to 0 disables the automatic cleanup thread completely + * and the caller will need to manually cleanup the external ExifTool + * process and read/write streams by calling {@link #close()}. + *

+ * Default value is 600,000 (10 minutes). + */ + private final long processCleanupDelay; + + private final Map featureSupportedMap = new HashMap(); + private final Set featureSet = EnumSet.noneOf(Feature.class); + private final ReentrantLock lock = new ReentrantLock(); + private final VersionNumber exifVersion; + private final Timer cleanupTimer; + private TimerTask currentCleanupTask = null; + private AtomicBoolean shuttingDown = new AtomicBoolean(false); + private volatile ExifProcess process; + private int timeoutWhenKeepAlive = 0; + + public ExifTool() { + this((Feature[]) null); + } + + /** + * In this constructor, exifToolPath and processCleanupDelay are gotten from + * system properties exiftool.path and exiftool.processCleanupDelay. + * processCleanupDelay is optional. If not found, the default is used. + */ + public ExifTool(Feature... features) { + this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( + ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, + DEFAULT_PROCESS_CLEANUP_DELAY), features); + } + + public ExifTool(String exifToolPath) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); + } + + public ExifTool(String exifToolPath, Feature... features) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); + } + + public ExifTool(String exifCmd, long processCleanupDelay, + Feature... features) { + this.exifCmd = exifCmd; + this.processCleanupDelay = processCleanupDelay; + this.exifVersion = ExifProcess.readVersion(exifCmd); + if (features != null && features.length > 0) { + for (Feature feature : features) { + if (!feature.isSupported(exifVersion)) { + throw new UnsupportedFeatureException(feature); + } + this.featureSet.add(feature); + this.featureSupportedMap.put(feature, true); + } + } + + /* + * Now that initialization is done, init the cleanup timer if we are + * using STAY_OPEN and the delay time set is non-zero. + */ + if (isFeatureEnabled(Feature.STAY_OPEN)) { + cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); + } else { + cleanupTimer = null; + } + } + + /** + * Limits the amount of time (in mills) an exif operation can take. Setting + * value to greater than 0 to enable. + */ + public ExifTool setRunTimeout(int mills) { + timeoutWhenKeepAlive = mills; + return this; + } + + /** + * Used to determine if the given {@link Feature} is supported by the + * underlying native install of ExifTool pointed at by {@link #exifCmd}. + *

+ * If support for the given feature has not been checked for yet, this + * method will automatically call out to ExifTool and ensure the requested + * feature is supported in the current local install. + *

+ * The external call to ExifTool to confirm feature support is only ever + * done once per JVM session and stored in a static final + * {@link Map} that all instances of this class share. + * + * @param feature + * The feature to check support for in the underlying ExifTool + * install. + * + * @return true if support for the given {@link Feature} was + * confirmed to work with the currently installed ExifTool or + * false if it is not supported. + * + * @throws IllegalArgumentException + * if feature is null. + * @throws RuntimeException + * if any exception occurs while attempting to start the + * external ExifTool process to verify feature support. + */ + public boolean isFeatureSupported(Feature feature) throws RuntimeException { + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); + } + + Boolean supported = featureSupportedMap.get(feature); /* * If there is no Boolean flag for the feature, support for it hasn't * been checked yet with the native ExifTool install, so we need to do * that. */ - if (supported == null) { - log.debug("Support for feature %s has not been checked yet, checking..."); - supported = feature.isSupported(exifVersion); - featureSupportedMap.put(feature,supported); - } - - return supported; - } - - - - - - /** - * Used to startup the external ExifTool process and open the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. This method has no effect if the stay open feature is not enabled. - */ - public void startup(){ - if (featureSet.contains(Feature.STAY_OPEN)){ - shuttingDown.set(false); - ensureProcessRunning(); - } - } - private void ensureProcessRunning(){ - if (process ==null || process.isClosed()) { - synchronized (this){ - if (process ==null || process.isClosed() ){ - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = ExifProcess.startup(exifCmd); - } - } - } - if ( processCleanupDelay > 0 ) { - synchronized (this) { - if ( currentCleanupTask != null ) { - currentCleanupTask.cancel(); - currentCleanupTask = null; - } - currentCleanupTask = new TimerTask() { - @Override - public void run() { - log.info("Auto cleanup task running..."); - process.close(); - } - }; - cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); - } - } - } - - /** - * This is same as {@link #close()}, added for consistency with {@link #startup()} - */ - public void shutdown(){ - close(); - } - - - /** - * Used to shutdown the external ExifTool process and close the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. - *

- * NOTE: Calling this method does not preclude this - * instance of {@link ExifTool} from being re-used, it merely disposes of - * the native and internal resources until the next call to - * getImageMeta causes them to be re-instantiated. - *

- * The cleanup thread will automatically call this after an interval of - * inactivity defined by {@link #processCleanupDelay}. - *

- * Calling this method on an instance of this class without - * {@link Feature#STAY_OPEN} support enabled has no effect. - */ - public synchronized void close() { - shuttingDown.set(true); - if ( process != null ) { - process.close(); - } - if(currentCleanupTask != null) { - currentCleanupTask.cancel(); - currentCleanupTask = null; - } - } - - public boolean isStayOpen() { - return featureSet.contains(Feature.STAY_OPEN); - } - - /** - * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support - * enabled, this method is used to determine if there is currently a running - * ExifTool process associated with this class. - *

- * Any dependent processes and streams can be shutdown using - * {@link #close()} and this class will automatically re-create them on the - * next call to getImageMeta if necessary. - * - * @return true if there is an external ExifTool process in - * daemon mode associated with this class utilizing the - * {@link Feature#STAY_OPEN} feature, otherwise returns - * false. - */ - public boolean isRunning() { - return process != null && ! process.isClosed(); - } - - /** - * Used to determine if the given {@link Feature} has been enabled for this - * particular instance of {@link ExifTool}. - *

- * This method is different from {@link #isFeatureSupported(Feature)}, which - * checks if the given feature is supported by the underlying ExifTool - * install where as this method tells the caller if the given feature has - * been enabled for use in this particular instance. - * - * @param feature - * The feature to check if it has been enabled for us or not on - * this instance. - * - * @return true if the given {@link Feature} is currently - * enabled on this instance of {@link ExifTool}, otherwise returns - * false. - * - * @throws IllegalArgumentException - * if feature is null. - */ - public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); - } - return featureSet.contains(feature); - } - - public Map getImageMeta(File image, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - - return getImageMeta(image, Format.NUMERIC, tags); - } - - public Map getImageMeta(File image, Format format, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - - String [] stringTags = new String[tags.length]; - int i=0; - for (Tag tag : tags){ - stringTags[i++] = tag.getName(); - } - Map result = getImageMeta(image, format, true, stringTags); - return mapByTag(result); - } - - public Map getImageMeta(File image, Format format, TagGroup... tags) - throws IllegalArgumentException, SecurityException, IOException { - String [] stringTags = new String[tags.length]; - int i=0; - for (TagGroup tag : tags){ - stringTags[i++] = tag.getValue(); - } - return getImageMeta(image, format, false, stringTags); - } - - private Map getImageMeta(final File image, final Format format, final boolean suppressDuplicates, final String... tags) - throws IllegalArgumentException, SecurityException, IOException { - - - //Validate input and create Arg Array - final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); - List args = new ArrayList(tags.length+4); - if (format == null){ - throw new IllegalArgumentException("format cannot be null"); - } else if (format == Format.NUMERIC){ - args.add("-n"); // numeric output - } - if (!suppressDuplicates){ - args.add("-a"); //suppress duplicates - } - args.add("-S"); // compact output - - if (tags == null || tags.length == 0){ - throw new IllegalArgumentException("tags cannot be null and must contain 1 or more Tag to query the image for."); - } - for (String tag : tags) { - args.add("-" + tag); - } - if (image == null){ - throw new IllegalArgumentException("image cannot be null and must be a valid stream of image data."); - } - if (!image.canRead()){ - throw new SecurityException("Unable to read the given image ["+image.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); - } - args.add(image.getAbsolutePath()); - - //start process - long startTime = System.currentTimeMillis(); - log.debug(String.format("Querying %d tags from image: %s", tags.length, image.getAbsolutePath())); + if (supported == null) { + log.debug("Support for feature %s has not been checked yet, checking..."); + supported = feature.isSupported(exifVersion); + featureSupportedMap.put(feature, supported); + } + + return supported; + } + + /** + * Used to startup the external ExifTool process and open the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. This method has no effect if the stay open feature is not + * enabled. + */ + public void startup() { + if (featureSet.contains(Feature.STAY_OPEN)) { + shuttingDown.set(false); + ensureProcessRunning(); + } + } + + private void ensureProcessRunning() { + if (process == null || process.isClosed()) { + synchronized (this) { + if (process == null || process.isClosed()) { + log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = ExifProcess.startup(exifCmd); + } + } + } + if (processCleanupDelay > 0) { + synchronized (this) { + if (currentCleanupTask != null) { + currentCleanupTask.cancel(); + currentCleanupTask = null; + } + currentCleanupTask = new TimerTask() { + @Override + public void run() { + log.info("Auto cleanup task running..."); + process.close(); + } + }; + cleanupTimer.schedule(currentCleanupTask, processCleanupDelay); + } + } + } + + /** + * This is same as {@link #close()}, added for consistency with + * {@link #startup()} + */ + public void shutdown() { + close(); + } + + /** + * Used to shutdown the external ExifTool process and close the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. + *

+ * NOTE: Calling this method does not preclude this + * instance of {@link ExifTool} from being re-used, it merely disposes of + * the native and internal resources until the next call to + * getImageMeta causes them to be re-instantiated. + *

+ * The cleanup thread will automatically call this after an interval of + * inactivity defined by {@link #processCleanupDelay}. + *

+ * Calling this method on an instance of this class without + * {@link Feature#STAY_OPEN} support enabled has no effect. + */ + public synchronized void close() { + shuttingDown.set(true); + if (process != null) { + process.close(); + } + if (currentCleanupTask != null) { + currentCleanupTask.cancel(); + currentCleanupTask = null; + } + } + + public boolean isStayOpen() { + return featureSet.contains(Feature.STAY_OPEN); + } + + /** + * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support + * enabled, this method is used to determine if there is currently a running + * ExifTool process associated with this class. + *

+ * Any dependent processes and streams can be shutdown using + * {@link #close()} and this class will automatically re-create them on the + * next call to getImageMeta if necessary. + * + * @return true if there is an external ExifTool process in + * daemon mode associated with this class utilizing the + * {@link Feature#STAY_OPEN} feature, otherwise returns + * false. + */ + public boolean isRunning() { + return process != null && !process.isClosed(); + } + + /** + * Used to determine if the given {@link Feature} has been enabled for this + * particular instance of {@link ExifTool}. + *

+ * This method is different from {@link #isFeatureSupported(Feature)}, which + * checks if the given feature is supported by the underlying ExifTool + * install where as this method tells the caller if the given feature has + * been enabled for use in this particular instance. + * + * @param feature + * The feature to check if it has been enabled for us or not on + * this instance. + * + * @return true if the given {@link Feature} is currently + * enabled on this instance of {@link ExifTool}, otherwise returns + * false. + * + * @throws IllegalArgumentException + * if feature is null. + */ + public boolean isFeatureEnabled(Feature feature) + throws IllegalArgumentException { + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); + } + return featureSet.contains(feature); + } + + public Map getImageMeta(File image, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { + + return getImageMeta(image, Format.NUMERIC, tags); + } + + public Map getImageMeta(File image, Format format, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { + + String[] stringTags = new String[tags.length]; + int i = 0; + for (Tag tag : tags) { + stringTags[i++] = tag.getName(); + } + Map result = getImageMeta(image, format, true, + stringTags); + return mapByTag(result); + } + + public Map getImageMeta(File image, Format format, + TagGroup... tags) throws IllegalArgumentException, + SecurityException, IOException { + String[] stringTags = new String[tags.length]; + int i = 0; + for (TagGroup tag : tags) { + stringTags[i++] = tag.getValue(); + } + return getImageMeta(image, format, false, stringTags); + } + + private Map getImageMeta(final File image, + final Format format, final boolean suppressDuplicates, + final String... tags) throws IllegalArgumentException, + SecurityException, IOException { + + // Validate input and create Arg Array + final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + List args = new ArrayList(tags.length + 4); + if (format == null) { + throw new IllegalArgumentException("format cannot be null"); + } else if (format == Format.NUMERIC) { + args.add("-n"); // numeric output + } + if (!suppressDuplicates) { + args.add("-a"); // suppress duplicates + } + args.add("-S"); // compact output + + if (tags == null || tags.length == 0) { + throw new IllegalArgumentException( + "tags cannot be null and must contain 1 or more Tag to query the image for."); + } + for (String tag : tags) { + args.add("-" + tag); + } + if (image == null) { + throw new IllegalArgumentException( + "image cannot be null and must be a valid stream of image data."); + } + if (!image.canRead()) { + throw new SecurityException( + "Unable to read the given image [" + + image.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + } + args.add(image.getAbsolutePath()); + + // start process + long startTime = System.currentTimeMillis(); + log.debug(String.format("Querying %d tags from image: %s", tags.length, + image.getAbsolutePath())); /* * Using ExifTool in daemon mode (-stay_open True) executes different * code paths below. So establish the flag for this once and it is * reused a multitude of times later in this method to figure out where * to branch to. */ - Map resultMap; - if (stayOpen) { - log.debug("Using ExifTool in daemon mode (-stay_open True)..."); - resultMap = processStayOpen(args); - } else { - log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd,args); - } - - // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()){ - log.debug(String.format("Image Meta Processed in %d ms [queried %d tags and found %d values]", - (System.currentTimeMillis() - startTime), tags.length, - resultMap.size())); - } - - return resultMap; - } - - public void addImageMetadata(File image, Map values) throws IOException { - - final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); - - if (image == null){ - throw new IllegalArgumentException("image cannot be null and must be a valid stream of image data."); - } - if (values == null || values.isEmpty()){ - throw new IllegalArgumentException("values cannot be null and must contain 1 or more tag to value mappings"); - } - - if (!image.canWrite()){ - throw new SecurityException("Unable to write the given image [" + image.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to write to it."); - } - - log.info("Adding Tags {} to {}", values, image.getAbsolutePath()); - - Map resultMap; - if (stayOpen) { - log.debug("Using ExifTool in daemon mode (-stay_open True)..."); - resultMap = processStayOpen(createCommandList(image.getAbsolutePath(), values)); - } else { - log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd, createCommandList(image.getAbsolutePath(), values)); - } - - //start process - long startTime = System.currentTimeMillis(); - - // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()){ - log.debug(String.format("Image Meta Processed in %d ms [added %d tags]", - (System.currentTimeMillis() - startTime), values.size())); - } - } - - private List createCommandList(String filename, Map values) { - - List args = new ArrayList(64); - - for(Map.Entry entry : values.entrySet()) { - Tag tag = entry.getKey(); - Object value = entry.getValue(); - - StringBuilder arg = new StringBuilder(); - arg.append("-").append(tag.getName()); - if (value instanceof Number){ - arg.append("#"); - } - arg.append("="); - if(value != null) { - if(value instanceof String) { - arg.append("\"").append(value.toString()).append("\""); - } else { - arg.append(value.toString()); - } - } - args.add(arg.toString()); - - } - - args.add(filename); - return args; - - } - - /** - * Will attempt 3 times to use the running exif process, and if unable to complete successfully will throw IOException - */ - private Map processStayOpen(List args) throws IOException { - int attempts = 0; - while (attempts < 3 && ! shuttingDown.get()){ - attempts++; - //make sure process is started - ensureProcessRunning(); - TimerTask attemptTimer = null; - try { - if ( timeoutWhenKeepAlive > 0 ) { - attemptTimer = new TimerTask() { - public void run() { - log.warn("Process ran too long closing, max "+timeoutWhenKeepAlive+" mills"); - process.close(); - } - }; - cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); - } - log.debug("Streaming arguments to ExifTool process..."); - return process.sendArgs(args); - } catch (IOException ex){ - if ( STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) && ! shuttingDown.get() ){ - //only catch "Stream Closed" error (happens when process has died) - log.warn(String.format("Caught IOException(\"%s\"), will restart daemon",STREAM_CLOSED_MESSAGE)); - process.close(); - } else { - throw ex; - } - } finally { - if ( attemptTimer != null ) attemptTimer.cancel(); - } - } - if ( shuttingDown.get() ) { - throw new IOException("Shutting Down"); - } - throw new IOException("Ran out of attempts"); - } - - private static Map mapByTag(Map stringMap){ - Map tagMap = new HashMap(Tag.values().length); - for (Tag tag : Tag.values()){ - if (stringMap.containsKey(tag.getName())){ - tagMap.put(tag, stringMap.get(tag.getName())); - } - } - return tagMap; - } - - - //================================================================================ - /** - * Represents an Exif Process. - */ - public static class ExifProcess { - private final ReentrantLock closeLock = new ReentrantLock(false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; - private volatile boolean closed = false; - - public static VersionNumber readVersion(String exifCmd) { - ExifProcess process =_execute(false, Arrays.asList(exifCmd,"-ver")); - try { - return new VersionNumber(process.readLine()); - } catch (IOException ex) { - throw new RuntimeException(String.format("Unable to check version number of ExifTool: %s",exifCmd)); - } finally { - process.close(); - } - } - - public static Map executeToResults(String exifCmd, List args) throws IOException { - List newArgs = new ArrayList(args.size()+1); - newArgs.add(exifCmd); - newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); - try { - return process.readResponse(); - } finally { - process.close(); - } - } - - public static ExifProcess startup(String exifCmd) { - List args = Arrays.asList(exifCmd,"-stay_open", "True", "-@", "-"); - return _execute(true, args); - } - - public static ExifProcess _execute(boolean keepAlive, List args) { - log.debug(String.format("Attempting to start external ExifTool process using args: %s", args)); - try { - Process process = new ProcessBuilder(args).start(); - log.debug("\tSuccessful"); - return new ExifProcess(keepAlive,process); - } catch (Exception e) { - String message = "Unable to start external ExifTool process using the execution arguments: " - + args - + ". Ensure ExifTool is installed correctly and runs using the command path '" - + args.get(0) - + "' as specified by the 'exiftool.path' system property."; - - log.debug(message); - throw new RuntimeException(message, e); - } - } - - public ExifProcess(boolean keepAlive,Process process) { - this.keepAlive = keepAlive; - this.process = process; - this.reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream()); - } - - public synchronized Map sendArgs(List args) throws IOException { - StringBuilder builder = new StringBuilder(); - for(String arg : args) { - builder.append(arg).append("\n"); - } - builder.append("-execute\n"); - writeFlush(builder.toString()); - return readResponse(); - } - - - public synchronized void writeFlush(String message) throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - writer.write(message); - writer.flush(); - } - - public synchronized String readLine() throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - return reader.readLine(); - } - - public synchronized Map readResponse() throws IOException { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - Map resultMap = new HashMap(500); - String line; - - while ((line = reader.readLine()) != null) { - if ( closed ) throw new IOException(STREAM_CLOSED_MESSAGE); - String[] pair = TAG_VALUE_PATTERN.split(line, 2); - - if (pair.length == 2) { - resultMap.put(pair[0], pair[1]); - log.debug(String.format("\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); - } - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need to - * look for it and break from this loop when we see it otherwise - * this process will hang indefinitely blocking on the input stream - * with no data to read. - */ - if (keepAlive && line.equals("{ready}")){ - break; - } - } - return resultMap; - } - - public boolean isClosed() { - return closed; - } - - public void close() { - if ( ! closed ) { - closeLock.lock(); - try { - if ( ! closed ) { - closed = true; - log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - try { - writer.write("-stay_open\nFalse\n"); - writer.flush(); - } catch (IOException ex) { - //log.error(ex,ex); - } - try { - log.debug("Closing Read stream..."); - reader.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log.debug("Closing Write stream..."); - writer.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - log.debug("Read/Write streams successfully closed."); - - try { - process.destroy(); - } catch (Exception e) { - // - } - //process = null; - - } - } finally { - closeLock.unlock(); - } - } - } - } - - //================================================================================ - /** - * Enum used to define the different kinds of features in the native - * ExifTool executable that this class can help you take advantage of. - *

- * These flags are different from {@link Tag}s in that a "feature" is - * determined to be a special functionality of the underlying ExifTool - * executable that requires a different code-path in this class to take - * advantage of; for example, -stay_open True support. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Feature { - /** - * Enum used to specify that you wish to launch the underlying ExifTool - * process with -stay_open True support turned on that this - * class can then take advantage of. - *

- * Required ExifTool version is 8.36 or higher. - */ - STAY_OPEN(8,36); - - - private VersionNumber requireVersion; - private Feature(int... numbers) { - this.requireVersion = new VersionNumber(numbers); - } - /** - * Used to get the version of ExifTool required by this feature in order - * to work. - * - * @return the version of ExifTool required by this feature in order to - * work. - */ - VersionNumber getVersion() { - return requireVersion; - } - - boolean isSupported(VersionNumber exifVersionNumber) { - return requireVersion.isBeforeOrEqualTo(exifVersionNumber); - } - } - - //================================================================================ - /** - * Version Number used to determine if one version is after another. - */ - static class VersionNumber { - private final int[] numbers; - - public VersionNumber(String str) { - String[] versionParts = str.trim().split("\\."); - this.numbers = new int[versionParts.length]; - for(int i=0; i other.numbers[i] ) { - return false; - } else if ( this.numbers[i] < other.numbers[i] ) { - return true; - } - } - //assume missing number as zero, so if the current process number is more digits it is a higher version - return this.numbers.length <= other.numbers.length; - } - - public String toString() { - StringBuilder builder = new StringBuilder(); - for(int i=0; i 0 ) { - builder.append("."); - } - builder.append(numbers[i]); - } - return builder.toString(); - } - } - - - //================================================================================ - /** - * Enum used to define the 2 different output formats that {@link Tag} - * values can be returned in: numeric or human-readable text. - *

- * ExifTool, via the -n command line arg, is capable of - * returning most values in their raw numeric form (e.g. - * Aperture="2.8010323841") as well as a more human-readable/friendly format - * (e.g. Aperture="2.8"). - *

- * While the {@link Tag}s defined on this class do provide a hint at the - * type of the result (see {@link Tag#getType()}), that hint only applies - * when the {@link Format#NUMERIC} form of the value is returned. - *

- * If the caller finds the human-readable format easier to process, - * {@link Format#HUMAN_READABLE} can be specified when calling - * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned - * {@link String} values processed manually by the caller. - *

- * In order to see the types of values that are returned when - * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive - * ExifTool Tag Guide. - *

- * This makes sense with some values like Aperture that in - * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high - * precision values that are near the intended value (e.g. - * "2.79999992203711" instead of just returning "2.8"). On the other hand, - * other values (like Orientation) are easier to parse when their numeric - * value (1-8) is returned instead of a much longer friendly name (e.g. - * "Mirror horizontal and rotate 270 CW"). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Format { - NUMERIC, HUMAN_READABLE - } - //================================================================================ - /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifTool. - *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default {@link Format#NUMERIC} value format - * is used. - *

- * All replies from ExifTool are parsed as {@link String}s and using the - * type hint from each {@link Tag} can easily be converted to the correct - * data format by using the provided {@link Tag#parseValue(String)} - * method. - *

- * This class does not make an attempt at converting the value automatically - * in case the caller decides they would prefer tag values returned in - * {@link Format#HUMAN_READABLE} format and to avoid any compatibility - * issues with future versions of ExifTool if a tag's return value is - * changed. This approach to leaving returned tag values as strings until - * the caller decides they want to parse them is a safer and more robust - * approach. - *

- * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. - *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. - *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. - *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Tag { - //single entry tags - APERTURE("ApertureValue", Double.class), - AUTHOR("XPAuthor", String.class), - COLOR_SPACE("ColorSpace", Integer.class), - COMMENT("XPComment", String.class), - CONTRAST("Contrast", Integer.class), - CREATE_DATE("CreateDate", String.class), - CREATION_DATE("CreationDate", String.class), - DATE_CREATED("DateCreated", String.class), - DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - FLASH("Flash", Integer.class), - FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), - FNUMBER("FNumber", String.class), - GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), - GPS_DATESTAMP("GPSDateStamp", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), - GPS_LONGITUDE("GPSLongitude", Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), - GPS_SPEED("GPSSpeed", Double.class), - GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), - IMAGE_WIDTH("ImageWidth", Integer.class), - ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), - LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), - MAKE("Make", String.class), - METERING_MODE("MeteringMode", Integer.class), - MODEL("Model", String.class), - ORIENTATION("Orientation", Integer.class), - OWNER_NAME("OwnerName", String.class), - RATING("Rating", Integer.class), - RATING_PERCENT("RatingPercent", Integer.class), - ROTATION("Rotation", Integer.class), - SATURATION("Saturation", Integer.class), - SENSING_METHOD("SensingMethod", Integer.class), - SHARPNESS("Sharpness", Integer.class), - SHUTTER_SPEED("ShutterSpeedValue", Double.class), - SOFTWARE("Software", String.class), - SUBJECT("XPSubject", String.class), - TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), - X_RESOLUTION("XResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), - ; - - /** - * Used to get the {@link Tag} identified by the given, case-sensitive, - * tag name. - * - * @param name - * The case-sensitive name of the tag that will be searched - * for. - * - * @return the {@link Tag} identified by the given, case-sensitive, tag - * name or null if one couldn't be found. - */ - public static Tag forName(String name) { - for (Tag tag : Tag.values()){ - if (tag.getName().equals(name)){ - return tag; - } - } - return null; - } - - /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifTool process) into the type described - * by the associated {@link Tag}. - * - * @param - * The type of the returned value. - * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. - * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). - * - * @throws IllegalArgumentException - * if tag is null. - * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). - * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. - */ - @SuppressWarnings("unchecked") - public T parseValue(String value) throws IllegalArgumentException { - - if (value != null) { - if (Boolean.class.isAssignableFrom(this.getType())){ - return (T) Boolean.valueOf(value); - } else if (Byte.class.isAssignableFrom(this.getType())){ - return (T) Byte.valueOf(Byte.parseByte(value)); - } else if (Integer.class.isAssignableFrom(this.getType())){ - return (T) Integer.valueOf(Integer.parseInt(value)); - } else if (Short.class.isAssignableFrom(this.getType())){ - return (T) Short.valueOf(Short.parseShort(value)); - } else if (Long.class.isAssignableFrom(this.getType())){ - return (T) Long.valueOf(Long.parseLong(value)); - } else if (Float.class.isAssignableFrom(this.getType())){ - return (T) Float.valueOf(Float.parseFloat(value)); - } else if (Double.class.isAssignableFrom(this.getType())){ - return (T) parseDouble(value); - } else if (Character.class.isAssignableFrom(this.getType())){ - return (T) Character.valueOf(value.charAt(0)); - } else if (String.class.isAssignableFrom(this.getType())){ - return (T) value; - } - } - return null; - } - - private Double parseDouble(String in) { - if (in.contains("/")) { - String[] enumeratorAndDivisor = in.split("/"); - return Double.parseDouble(enumeratorAndDivisor[0]) / Double.parseDouble(enumeratorAndDivisor[1]); - } else { - return Double.parseDouble(in); - } - } - - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ - public String getName() { - return name; - } - - /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifTool Tag Guide. - * - * @return a hint for the native type of this tag's value. - */ - public Class getType() { - return type; - } - - private String name; - private Class type; - - private Tag(String name, Class type) { - this.name = name; - this.type = type; - } - } - - //================================================================================ - public enum TagGroup { - EXIF("EXIF","exif:all"), - IPTC("IPTC", "iptc:all"), - XMP("XMP", "xmp:all"), - ALL("ALL", "all"); - - private final String name; - private final String value; - - private TagGroup(String name, String value) { - this.name = name; - this.value = value; - } - - public String getName() { - return name; - } - - public String getValue() { - return value; - } - } - - - //================================================================================ - /** - * Class used to define an exception that occurs when the caller attempts to - * use a {@link Feature} that the underlying native ExifTool install does - * not support (i.e. the version isn't new enough). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public class UnsupportedFeatureException extends RuntimeException { - private static final long serialVersionUID = -1332725983656030770L; - - public UnsupportedFeatureException(Feature feature) { - super( - "Use of feature [" - + feature.toString() - + "] requires version " - + feature.getVersion() - + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); - } - - } + Map resultMap; + if (stayOpen) { + log.debug("Using ExifTool in daemon mode (-stay_open True)..."); + resultMap = processStayOpen(args); + } else { + log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); + resultMap = ExifProcess.executeToResults(exifCmd, args); + } + + // Print out how long the call to external ExifTool process took. + if (log.isDebugEnabled()) { + log.debug(String + .format("Image Meta Processed in %d ms [queried %d tags and found %d values]", + (System.currentTimeMillis() - startTime), + tags.length, resultMap.size())); + } + + return resultMap; + } + + public void addImageMetadata(File image, Map values) + throws IOException { + + final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + + if (image == null) { + throw new IllegalArgumentException( + "image cannot be null and must be a valid stream of image data."); + } + if (values == null || values.isEmpty()) { + throw new IllegalArgumentException( + "values cannot be null and must contain 1 or more tag to value mappings"); + } + + if (!image.canWrite()) { + throw new SecurityException( + "Unable to write the given image [" + + image.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to write to it."); + } + + log.info("Adding Tags {} to {}", values, image.getAbsolutePath()); + + Map resultMap; + if (stayOpen) { + log.debug("Using ExifTool in daemon mode (-stay_open True)..."); + resultMap = processStayOpen(createCommandList( + image.getAbsolutePath(), values)); + } else { + log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); + resultMap = ExifProcess.executeToResults(exifCmd, + createCommandList(image.getAbsolutePath(), values)); + } + + // start process + long startTime = System.currentTimeMillis(); + + // Print out how long the call to external ExifTool process took. + if (log.isDebugEnabled()) { + log.debug(String.format( + "Image Meta Processed in %d ms [added %d tags]", + (System.currentTimeMillis() - startTime), values.size())); + } + } + + private List createCommandList(String filename, + Map values) { + + List args = new ArrayList(64); + + for (Map.Entry entry : values.entrySet()) { + Tag tag = entry.getKey(); + Object value = entry.getValue(); + + StringBuilder arg = new StringBuilder(); + arg.append("-").append(tag.getName()); + if (value instanceof Number) { + arg.append("#"); + } + arg.append("="); + if (value != null) { + if (value instanceof String) { + arg.append("\"").append(value.toString()).append("\""); + } else { + arg.append(value.toString()); + } + } + args.add(arg.toString()); + + } + + args.add(filename); + return args; + + } + + /** + * Will attempt 3 times to use the running exif process, and if unable to + * complete successfully will throw IOException + */ + private Map processStayOpen(List args) + throws IOException { + int attempts = 0; + while (attempts < 3 && !shuttingDown.get()) { + attempts++; + // make sure process is started + ensureProcessRunning(); + TimerTask attemptTimer = null; + try { + if (timeoutWhenKeepAlive > 0) { + attemptTimer = new TimerTask() { + @Override + public void run() { + log.warn("Process ran too long closing, max " + + timeoutWhenKeepAlive + " mills"); + process.close(); + } + }; + cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); + } + log.debug("Streaming arguments to ExifTool process..."); + return process.sendArgs(args); + } catch (IOException ex) { + if (STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) + && !shuttingDown.get()) { + // only catch "Stream Closed" error (happens when process + // has died) + log.warn(String.format( + "Caught IOException(\"%s\"), will restart daemon", + STREAM_CLOSED_MESSAGE)); + process.close(); + } else { + throw ex; + } + } finally { + if (attemptTimer != null) + attemptTimer.cancel(); + } + } + if (shuttingDown.get()) { + throw new IOException("Shutting Down"); + } + throw new IOException("Ran out of attempts"); + } + + private static Map mapByTag(Map stringMap) { + Map tagMap = new HashMap(Tag.values().length); + for (Tag tag : Tag.values()) { + if (stringMap.containsKey(tag.getName())) { + tagMap.put(tag, stringMap.get(tag.getName())); + } + } + return tagMap; + } + + // ================================================================================ + /** + * Represents an Exif Process. + */ + public static class ExifProcess { + private final ReentrantLock closeLock = new ReentrantLock(false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader reader; + private final OutputStreamWriter writer; + private volatile boolean closed = false; + + public static VersionNumber readVersion(String exifCmd) { + ExifProcess process = _execute(false, + Arrays.asList(exifCmd, "-ver")); + try { + return new VersionNumber(process.readLine()); + } catch (IOException ex) { + throw new RuntimeException(String.format( + "Unable to check version number of ExifTool: %s", + exifCmd)); + } finally { + process.close(); + } + } + + public static Map executeToResults(String exifCmd, + List args) throws IOException { + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { + return process.readResponse(); + } finally { + process.close(); + } + } + + public static ExifProcess startup(String exifCmd) { + List args = Arrays.asList(exifCmd, "-stay_open", "True", + "-@", "-"); + return _execute(true, args); + } + + public static ExifProcess _execute(boolean keepAlive, List args) { + log.debug(String + .format("Attempting to start external ExifTool process using args: %s", + args)); + try { + Process process = new ProcessBuilder(args).start(); + log.debug("\tSuccessful"); + return new ExifProcess(keepAlive, process); + } catch (Exception e) { + String message = "Unable to start external ExifTool process using the execution arguments: " + + args + + ". Ensure ExifTool is installed correctly and runs using the command path '" + + args.get(0) + + "' as specified by the 'exiftool.path' system property."; + + log.debug(message); + throw new RuntimeException(message, e); + } + } + + public ExifProcess(boolean keepAlive, Process process) { + this.keepAlive = keepAlive; + this.process = process; + this.reader = new BufferedReader(new InputStreamReader( + process.getInputStream())); + this.writer = new OutputStreamWriter(process.getOutputStream()); + } + + public synchronized Map sendArgs(List args) + throws IOException { + StringBuilder builder = new StringBuilder(); + for (String arg : args) { + builder.append(arg).append("\n"); + } + builder.append("-execute\n"); + writeFlush(builder.toString()); + return readResponse(); + } + + public synchronized void writeFlush(String message) throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + writer.write(message); + writer.flush(); + } + + public synchronized String readLine() throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + return reader.readLine(); + } + + public synchronized Map readResponse() + throws IOException { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + log.debug("Reading response back from ExifTool..."); + Map resultMap = new HashMap(500); + String line; + + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(STREAM_CLOSED_MESSAGE); + String[] pair = TAG_VALUE_PATTERN.split(line, 2); + + if (pair.length == 2) { + resultMap.put(pair[0], pair[1]); + log.debug(String.format("\tRead Tag [name=%s, value=%s]", + pair[0], pair[1])); + } + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } + } + return resultMap; + } + + public boolean isClosed() { + return closed; + } + + public void close() { + if (!closed) { + closeLock.lock(); + try { + if (!closed) { + closed = true; + log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); + try { + writer.write("-stay_open\nFalse\n"); + writer.flush(); + } catch (IOException ex) { + // log.error(ex,ex); + } + try { + log.debug("Closing Read stream..."); + reader.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + log.debug("Closing Write stream..."); + writer.close(); + log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + log.debug("Read/Write streams successfully closed."); + + try { + process.destroy(); + } catch (Exception e) { + // + } + // process = null; + + } + } finally { + closeLock.unlock(); + } + } + } + } + + // ================================================================================ + /** + * Enum used to define the different kinds of features in the native + * ExifTool executable that this class can help you take advantage of. + *

+ * These flags are different from {@link Tag}s in that a "feature" is + * determined to be a special functionality of the underlying ExifTool + * executable that requires a different code-path in this class to take + * advantage of; for example, -stay_open True support. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Feature { + /** + * Enum used to specify that you wish to launch the underlying ExifTool + * process with -stay_open True support turned on that this + * class can then take advantage of. + *

+ * Required ExifTool version is 8.36 or higher. + */ + STAY_OPEN(8, 36); + + private VersionNumber requireVersion; + + private Feature(int... numbers) { + this.requireVersion = new VersionNumber(numbers); + } + + /** + * Used to get the version of ExifTool required by this feature in order + * to work. + * + * @return the version of ExifTool required by this feature in order to + * work. + */ + VersionNumber getVersion() { + return requireVersion; + } + + boolean isSupported(VersionNumber exifVersionNumber) { + return requireVersion.isBeforeOrEqualTo(exifVersionNumber); + } + } + + // ================================================================================ + /** + * Version Number used to determine if one version is after another. + */ + static class VersionNumber { + private final int[] numbers; + + public VersionNumber(String str) { + String[] versionParts = str.trim().split("\\."); + this.numbers = new int[versionParts.length]; + for (int i = 0; i < versionParts.length; i++) { + numbers[i] = Integer.parseInt(versionParts[i]); + } + } + + public VersionNumber(int... numbers) { + this.numbers = numbers; + } + + public boolean isBeforeOrEqualTo(VersionNumber other) { + int max = Math.min(this.numbers.length, other.numbers.length); + for (int i = 0; i < max; i++) { + if (this.numbers[i] > other.numbers[i]) { + return false; + } else if (this.numbers[i] < other.numbers[i]) { + return true; + } + } + // assume missing number as zero, so if the current process number + // is more digits it is a higher version + return this.numbers.length <= other.numbers.length; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < numbers.length; i++) { + if (builder.length() > 0) { + builder.append("."); + } + builder.append(numbers[i]); + } + return builder.toString(); + } + } + + // ================================================================================ + /** + * Enum used to define the 2 different output formats that {@link Tag} + * values can be returned in: numeric or human-readable text. + *

+ * ExifTool, via the -n command line arg, is capable of + * returning most values in their raw numeric form (e.g. + * Aperture="2.8010323841") as well as a more human-readable/friendly format + * (e.g. Aperture="2.8"). + *

+ * While the {@link Tag}s defined on this class do provide a hint at the + * type of the result (see {@link Tag#getType()}), that hint only applies + * when the {@link Format#NUMERIC} form of the value is returned. + *

+ * If the caller finds the human-readable format easier to process, + * {@link Format#HUMAN_READABLE} can be specified when calling + * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned + * {@link String} values processed manually by the caller. + *

+ * In order to see the types of values that are returned when + * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive + * ExifTool Tag Guide. + *

+ * This makes sense with some values like Aperture that in + * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high + * precision values that are near the intended value (e.g. + * "2.79999992203711" instead of just returning "2.8"). On the other hand, + * other values (like Orientation) are easier to parse when their numeric + * value (1-8) is returned instead of a much longer friendly name (e.g. + * "Mirror horizontal and rotate 270 CW"). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Format { + NUMERIC, + HUMAN_READABLE + } + + // ================================================================================ + /** + * Enum used to pre-define a convenient list of tags that can be easily + * extracted from images using this class with an external install of + * ExifTool. + *

+ * Each tag defined also includes a type hint for the parsed value + * associated with it when the default {@link Format#NUMERIC} value format + * is used. + *

+ * All replies from ExifTool are parsed as {@link String}s and using the + * type hint from each {@link Tag} can easily be converted to the correct + * data format by using the provided {@link Tag#parseValue(String)} method. + *

+ * This class does not make an attempt at converting the value automatically + * in case the caller decides they would prefer tag values returned in + * {@link Format#HUMAN_READABLE} format and to avoid any compatibility + * issues with future versions of ExifTool if a tag's return value is + * changed. This approach to leaving returned tag values as strings until + * the caller decides they want to parse them is a safer and more robust + * approach. + *

+ * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or + * process the returned {@link String} values any way they wish. + *

Tag Support

+ * ExifTool is capable of parsing almost every tag known to man (1000+), but + * this class makes an attempt at pre-defining a convenient list of the most + * common tags for use. + *

+ * This list was determined by looking at the common metadata tag values + * written to images by popular mobile devices (iPhone, Android) as well as + * cameras like simple point and shoots as well as DSLRs. As an additional + * source of input the list of supported/common EXIF formats that Flickr + * supports was also reviewed to ensure the most common/useful tags were + * being covered here. + *

+ * Please email me or file an issue + * if you think this list is missing a commonly used tag that should be + * added to it. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public enum Tag { + // single entry tags + APERTURE("ApertureValue", Double.class), + AUTHOR("XPAuthor", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATE_DATE("CreateDate", String.class), + CREATION_DATE("CreationDate", String.class), + DATE_CREATED("DateCreated", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + FLASH("Flash", Integer.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + FNUMBER("FNumber", String.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_DATESTAMP("GPSDateStamp", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SENSING_METHOD("SensingMethod", Integer.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), ; + + /** + * Used to get the {@link Tag} identified by the given, case-sensitive, + * tag name. + * + * @param name + * The case-sensitive name of the tag that will be searched + * for. + * + * @return the {@link Tag} identified by the given, case-sensitive, tag + * name or null if one couldn't be found. + */ + public static Tag forName(String name) { + for (Tag tag : Tag.values()) { + if (tag.getName().equals(name)) { + return tag; + } + } + return null; + } + + /** + * Convenience method used to convert the given string Tag value + * (returned from the external ExifTool process) into the type described + * by the associated {@link Tag}. + * + * @param + * The type of the returned value. + * @param value + * The {@link String} representation of the tag's value as + * parsed from the image. + * + * @return the given string value converted to a native Java type (e.g. + * Integer, Double, etc.). + * + * @throws IllegalArgumentException + * if tag is null. + * @throws NumberFormatException + * if any exception occurs while trying to parse the given + * value to any of the supported numeric types + * in Java via calls to the respective parseXXX + * methods defined on all the numeric wrapper classes (e.g. + * {@link Integer#parseInt(String)} , + * {@link Double#parseDouble(String)} and so on). + * @throws ClassCastException + * if the type defined by T is incompatible + * with the type defined by {@link Tag#getType()} returned + * by the tag argument passed in. This class + * performs an implicit/unchecked cast to the type + * T before returning the parsed result of the + * type indicated by {@link Tag#getType()}. If the types do + * not match, a ClassCastException will be + * generated by the VM. + */ + @SuppressWarnings("unchecked") + public T parseValue(String value) throws IllegalArgumentException { + + if (value != null) { + if (Boolean.class.isAssignableFrom(this.getType())) { + return (T) Boolean.valueOf(value); + } else if (Byte.class.isAssignableFrom(this.getType())) { + return (T) Byte.valueOf(Byte.parseByte(value)); + } else if (Integer.class.isAssignableFrom(this.getType())) { + return (T) Integer.valueOf(Integer.parseInt(value)); + } else if (Short.class.isAssignableFrom(this.getType())) { + return (T) Short.valueOf(Short.parseShort(value)); + } else if (Long.class.isAssignableFrom(this.getType())) { + return (T) Long.valueOf(Long.parseLong(value)); + } else if (Float.class.isAssignableFrom(this.getType())) { + return (T) Float.valueOf(Float.parseFloat(value)); + } else if (Double.class.isAssignableFrom(this.getType())) { + return (T) parseDouble(value); + } else if (Character.class.isAssignableFrom(this.getType())) { + return (T) Character.valueOf(value.charAt(0)); + } else if (String.class.isAssignableFrom(this.getType())) { + return (T) value; + } + } + return null; + } + + private Double parseDouble(String in) { + if (in.contains("/")) { + String[] enumeratorAndDivisor = in.split("/"); + return Double.parseDouble(enumeratorAndDivisor[0]) + / Double.parseDouble(enumeratorAndDivisor[1]); + } else { + return Double.parseDouble(in); + } + } + + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ + public String getName() { + return name; + } + + /** + * Used to get a hint for the native type of this tag's value as + * specified by Phil Harvey's ExifTool Tag Guide. + * + * @return a hint for the native type of this tag's value. + */ + public Class getType() { + return type; + } + + private String name; + private Class type; + + private Tag(String name, Class type) { + this.name = name; + this.type = type; + } + } + + // ================================================================================ + public enum TagGroup { + EXIF("EXIF", "exif:all"), + IPTC("IPTC", "iptc:all"), + XMP("XMP", "xmp:all"), + ALL("ALL", "all"); + + private final String name; + private final String value; + + private TagGroup(String name, String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } + } + + // ================================================================================ + /** + * Class used to define an exception that occurs when the caller attempts to + * use a {@link Feature} that the underlying native ExifTool install does + * not support (i.e. the version isn't new enough). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ + public class UnsupportedFeatureException extends RuntimeException { + private static final long serialVersionUID = -1332725983656030770L; + + public UnsupportedFeatureException(Feature feature) { + super( + "Use of feature [" + + feature.toString() + + "] requires version " + + feature.getVersion() + + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); + } + + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index a914eb75..8ec7233b 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -1,29 +1,31 @@ package com.thebuzzmedia.exiftool; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Tag; +import java.io.File; +import java.io.IOException; + import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.io.File; -import java.io.IOException; +import com.thebuzzmedia.exiftool.ExifTool.Feature; +import com.thebuzzmedia.exiftool.ExifTool.Tag; public class Benchmark { public static final int ITERATIONS = 25; - private static Logger log = LoggerFactory.getLogger(Benchmark.class); - + private static Logger log = LoggerFactory.getLogger(Benchmark.class); - public static void main(String[] args) throws IOException, InterruptedException { + public static void main(String[] args) throws IOException, + InterruptedException { - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); - final Tag[] tags = Tag.values(); - final File[] images = new File("src/test/resources").listFiles(); + final Tag[] tags = Tag.values(); + final File[] images = new File("src/test/resources").listFiles(); - log.info("Benchmark [tags=" + tags.length + ", images=" - + images.length + ", iterations=" + ITERATIONS + "]"); - log.info("\t" + (images.length * ITERATIONS) + log.info("Benchmark [tags=" + tags.length + ", images=" + images.length + + ", iterations=" + ITERATIONS + "]"); + log.info("\t" + (images.length * ITERATIONS) + " ExifTool process calls, " + (tags.length * images.length * ITERATIONS) + " total operations.\n"); @@ -37,13 +39,13 @@ public static void main(String[] args) throws IOException, InterruptedException log.info("\t[-stay_open False]"); long elapsedTime = 0; - for (int i = 1; i <= ITERATIONS; i++){ - log.info(String.format("iteration %s of %s", i, ITERATIONS)); + for (int i = 1; i <= ITERATIONS; i++) { + log.info(String.format("iteration %s of %s", i, ITERATIONS)); elapsedTime += run(tool, images, tags); - } + } log.info("\t\tElapsed Time: " + elapsedTime + " ms (" - + ((double) elapsedTime / 1000) + " secs)"); + + ((double) elapsedTime / 1000) + " secs)"); /* * -stay_open True */ @@ -51,13 +53,13 @@ public static void main(String[] args) throws IOException, InterruptedException long elapsedTimeSO = 0; for (int i = 1; i <= ITERATIONS; i++) { - log.info(String.format("iteration %s of %s", i, ITERATIONS)); + log.info(String.format("iteration %s of %s", i, ITERATIONS)); elapsedTimeSO += run(toolSO, images, tags); } log.info("\t\tElapsed Time: " + elapsedTimeSO + " ms (" - + ((double) elapsedTimeSO / 1000) + " secs - " - + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); + + ((double) elapsedTimeSO / 1000) + " secs - " + + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); // Shut down the running exiftool proc. toolSO.close(); @@ -67,9 +69,9 @@ private static long run(ExifTool tool, File[] images, Tag[] tags) throws IllegalArgumentException, SecurityException, IOException { long startTime = System.currentTimeMillis(); - for (File image : images){ - tool.getImageMeta(image, tags); - } + for (File image : images) { + tool.getImageMeta(image, tags); + } return (System.currentTimeMillis() - startTime); } diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index bca4631e..d25636cb 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -4,43 +4,52 @@ import java.io.IOException; import java.util.Map; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Format; import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.thebuzzmedia.exiftool.ExifTool.Feature; +import com.thebuzzmedia.exiftool.ExifTool.Format; + public class Example { - private static Logger log = LoggerFactory.getLogger(Example.class); - private static final String TEST_FILES_PATH = "src/test/resources"; - - public static void main(String[] args) throws IOException, InterruptedException { - - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); - ExifTool tool = new ExifTool(Feature.STAY_OPEN); - - File[] images = new File(TEST_FILES_PATH).listFiles(); - - //list all first-class tags - for (File f : images) { - log.info("\n[{}]", f.getName()); - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, ExifTool.Tag.values()); - for (ExifTool.Tag key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key.getName(), metadata.get(key))); - } - } - - log.info("\n\n** GET TAGS BY GROUP"); - //list all XMP, IPTC and XMP tags - File f = new File(TEST_FILES_PATH + "/kureckjones_jett_075_02-cropped.tif"); - for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] {ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, ExifTool.TagGroup.XMP}){ - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, tagGroup); - log.info(tagGroup.getName()); - for (String key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - } - } - - tool.close(); - } + private static Logger log = LoggerFactory.getLogger(Example.class); + private static final String TEST_FILES_PATH = "src/test/resources"; + + public static void main(String[] args) throws IOException, + InterruptedException { + + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + + File[] images = new File(TEST_FILES_PATH).listFiles(); + + // list all first-class tags + for (File f : images) { + log.info("\n[{}]", f.getName()); + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, ExifTool.Tag.values()); + for (ExifTool.Tag key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key.getName(), + metadata.get(key))); + } + } + + log.info("\n\n** GET TAGS BY GROUP"); + // list all XMP, IPTC and XMP tags + File f = new File(TEST_FILES_PATH + + "/kureckjones_jett_075_02-cropped.tif"); + for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] { + ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, + ExifTool.TagGroup.XMP }) { + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, tagGroup); + log.info(tagGroup.getName()); + for (String key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + } + } + + tool.close(); + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 034b45fc..02fc76fe 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -1,8 +1,8 @@ package com.thebuzzmedia.exiftool; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; @@ -18,427 +18,500 @@ import java.util.Map; import java.util.Set; -import static org.junit.Assert.assertEquals; -import static org.junit.Assert.assertTrue; -import static org.junit.Assert.fail; - +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * TestMetadata

- * + * TestMetadata + *

+ * * @author Michael Rush (michaelrush@gmail.com) * @since Initially created 8/8/13 */ public class TestExifTool { - private static Logger log = LoggerFactory.getLogger(TestExifTool.class); - - @Test - public void testSingleTool() throws Exception { - ExifTool tool = new ExifTool(); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.startup(); - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - } - - @Test - public void testConcurrent() throws Exception { - - int toolCount = 5; - - List threads = new ArrayList(toolCount); - for (int i=1; i <= toolCount; i++){ - String toolName = "tool"+i; - Thread t = new Thread(toolName){ - @Override - public void run() { - log.info(getName() + ": starting"); - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - runTests(tool,getName()); - log.info(getName() + ": finished"); - } catch (IOException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } catch (URISyntaxException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } finally { - tool.shutdown(); - } - log.info(getName() + ": finished"); - } - }; - t.start(); - threads.add(t); - } - - for (Thread t : threads){ - t.run(); - } - } - - @Test - public void testManyThreadsOneTool() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Thread[] threads = new Thread[20]; - for(int i=0; i < threads.length; i++) { - final String label = "run "+i; - threads[i] = new Thread(new Runnable() { - public void run() { - try { - for(int j=0; j<5; j++) { - runTests(tool,label); - } - log.info("DONE: "+label+" success!"); - } catch (IOException ex) { - fail(label); - } catch (URISyntaxException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } - } - },label); - } - for(Thread thread : threads) { - thread.start(); - } - for(Thread thread : threads) { - thread.join(); - } - } finally { - tool.shutdown(); - } - } - - @Test - public void testProcessTimeout() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.setRunTimeout(1); - runTests(tool,"will fail"); - fail("should have failed"); - } catch (IOException ex) { - ; - } finally { - tool.shutdown(); - } - } - - public boolean runTests(ExifTool tool, String runId) throws IOException, URISyntaxException { - - Map metadata; - File imageFile; - Set keys; - ExifTool.Tag tag; - - URL url = getClass().getResource("/kureckjones_jett_075_02-cropped.tif"); - imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(22, metadata.size()); - - keys = metadata.keySet(); - - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(728, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(825, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("P 45+", tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 1"); - - - url = getClass().getResource("/nexus-s-electric-cars.jpg"); - imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(23, metadata.size()); - - keys = metadata.keySet(); - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(2560, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(1920, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.ISO; - assertEquals(50, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.SHUTTER_SPEED; - assertEquals("1/64", metadata.get(tag)); - assertEquals(0.015625, tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 2"); - return true; - } - - @Test - public void testGroupTags() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Map metadata; - - URL url = getClass().getResource("/iptc_test-photoshop.jpg"); - File f = new File(url.toURI()); - metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, ExifTool.TagGroup.IPTC); - assertEquals(17, metadata.size()); - assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); - assertEquals("IPTC Status: Copyright Notice", metadata.get("CopyrightNotice")); - assertEquals("IPTC Content: Description Writer", metadata.get("Writer-Editor")); - //for (String key : metadata.keySet()){ - // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - //} - } finally { - tool.shutdown(); - } - } - - @Test - public void testTag(){ - assertEquals("string value", "John Doe", ExifTool.Tag.AUTHOR.parseValue("John Doe")); - assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); - assertEquals("double value, from fraction", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); - assertEquals("double value, from decimal", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); - } - - @Test - public void testVersionNumber() { - assertTrue(new ExifTool.VersionNumber("1.2").isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); - assertTrue(new ExifTool.VersionNumber(1,2).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber(2,1))); - } - - - @Test - public void testWriteTagStringNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - - } - - @Test - public void testWriteTagString() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteTagStringInvalidformat() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - String newDate = "2egek opkpgrpok"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - - // Now change it to an invalid value which should fail - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's not updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - // might not exist - if(backup_url != null) { - Path backupFile = Paths.get(backup_url.toURI()); - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - } - - @Test - public void testWriteTagNumberNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - - } - - @Test - public void testWriteTagNumber() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - - } - - - @Test - public void testWriteMulipleTag() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - - } - - @Test - public void testWriteMulipleTagNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - - } - - //todo TEST automatic daemon restart by killing perl process + private static Logger log = LoggerFactory.getLogger(TestExifTool.class); + + @Test + public void testSingleTool() throws Exception { + ExifTool tool = new ExifTool(); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + tool.startup(); + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + } + + @Test + public void testConcurrent() throws Exception { + + int toolCount = 5; + + List threads = new ArrayList(toolCount); + for (int i = 1; i <= toolCount; i++) { + String toolName = "tool" + i; + Thread t = new Thread(toolName) { + @Override + public void run() { + log.info(getName() + ": starting"); + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + runTests(tool, getName()); + log.info(getName() + ": finished"); + } catch (IOException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } catch (URISyntaxException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } finally { + tool.shutdown(); + } + log.info(getName() + ": finished"); + } + }; + t.start(); + threads.add(t); + } + + for (Thread t : threads) { + t.run(); + } + } + + @Test + public void testManyThreadsOneTool() throws Exception { + final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + Thread[] threads = new Thread[20]; + for (int i = 0; i < threads.length; i++) { + final String label = "run " + i; + threads[i] = new Thread(new Runnable() { + @Override + public void run() { + try { + for (int j = 0; j < 5; j++) { + runTests(tool, label); + } + log.info("DONE: " + label + " success!"); + } catch (IOException ex) { + fail(label); + } catch (URISyntaxException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } + } + }, label); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + } finally { + tool.shutdown(); + } + } + + @Test + public void testProcessTimeout() throws Exception { + final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + tool.setRunTimeout(1); + runTests(tool, "will fail"); + fail("should have failed"); + } catch (IOException ex) { + ; + } finally { + tool.shutdown(); + } + } + + public boolean runTests(ExifTool tool, String runId) throws IOException, + URISyntaxException { + + Map metadata; + File imageFile; + Set keys; + ExifTool.Tag tag; + + URL url = getClass() + .getResource("/kureckjones_jett_075_02-cropped.tif"); + imageFile = new File(url.toURI()); + metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.values()); + assertEquals(22, metadata.size()); + + keys = metadata.keySet(); + + tag = ExifTool.Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(728, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.IMAGE_HEIGHT; + assertEquals(825, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.MODEL; + assertEquals("P 45+", tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 1"); + + url = getClass().getResource("/nexus-s-electric-cars.jpg"); + imageFile = new File(url.toURI()); + metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.values()); + assertEquals(23, metadata.size()); + + keys = metadata.keySet(); + tag = ExifTool.Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(2560, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.IMAGE_HEIGHT; + assertEquals(1920, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.MODEL; + assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.ISO; + assertEquals(50, tag.parseValue(metadata.get(tag))); + + tag = ExifTool.Tag.SHUTTER_SPEED; + assertEquals("1/64", metadata.get(tag)); + assertEquals(0.015625, tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 2"); + return true; + } + + @Test + public void testGroupTags() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + try { + Map metadata; + + URL url = getClass().getResource("/iptc_test-photoshop.jpg"); + File f = new File(url.toURI()); + metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, + ExifTool.TagGroup.IPTC); + assertEquals(17, metadata.size()); + assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); + assertEquals("IPTC Status: Copyright Notice", + metadata.get("CopyrightNotice")); + assertEquals("IPTC Content: Description Writer", + metadata.get("Writer-Editor")); + // for (String key : metadata.keySet()){ + // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + // } + } finally { + tool.shutdown(); + } + } + + @Test + public void testTag() { + assertEquals("string value", "John Doe", + ExifTool.Tag.AUTHOR.parseValue("John Doe")); + assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); + assertEquals("double value, from fraction", .25, + ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); + assertEquals("double value, from decimal", .25, + ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); + } + + @Test + public void testVersionNumber() { + assertTrue(new ExifTool.VersionNumber("1.2") + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); + assertTrue(new ExifTool.VersionNumber(1, 2) + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); + assertTrue(new ExifTool.VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); + assertTrue(new ExifTool.VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new ExifTool.VersionNumber(2, 1))); + } + + @Test + public void testWriteTagStringNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's updated + metadata = tool + .getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + + } + + @Test + public void testWriteTagString() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's updated + metadata = tool + .getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteTagStringInvalidformat() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + String newDate = "2egek opkpgrpok"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + + // Now change it to an invalid value which should fail + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's not updated + metadata = tool + .getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + // might not exist + if (backup_url != null) { + Path backupFile = Paths.get(backup_url.toURI()); + Files.move(backupFile, imageFile, + StandardCopyOption.REPLACE_EXISTING); + } + } + + @Test + public void testWriteTagNumberNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + + // Now change it + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + + } + + @Test + public void testWriteTagNumber() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + + // Now change it + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + + } + + @Test + public void testWriteMulipleTag() throws Exception { + ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + + } + + @Test + public void testWriteMulipleTagNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, + ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(ExifTool.Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, + ExifTool.Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(ExifTool.Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + + } + + // todo TEST automatic daemon restart by killing perl process } From ffcb7d0d021fc4f8812ce52bc8a8a5d63c6be7c7 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 14:09:48 +0300 Subject: [PATCH 040/148] - extract inner classes in their own files to ease up the integration process --- .../thebuzzmedia/exiftool/ExifProcess.java | 230 +++++++ .../com/thebuzzmedia/exiftool/ExifTool.java | 639 +----------------- .../com/thebuzzmedia/exiftool/Feature.java | 46 ++ .../com/thebuzzmedia/exiftool/Format.java | 43 ++ .../java/com/thebuzzmedia/exiftool/Tag.java | 233 +++++++ .../com/thebuzzmedia/exiftool/TagGroup.java | 27 + .../exiftool/UnsupportedFeatureException.java | 25 + .../thebuzzmedia/exiftool/VersionNumber.java | 47 ++ .../com/thebuzzmedia/exiftool/Benchmark.java | 3 - .../com/thebuzzmedia/exiftool/Example.java | 15 +- .../thebuzzmedia/exiftool/TestExifTool.java | 212 +++--- 11 files changed, 766 insertions(+), 754 deletions(-) create mode 100644 src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Feature.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Format.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Tag.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/TagGroup.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java new file mode 100644 index 00000000..f9721162 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -0,0 +1,230 @@ +package com.thebuzzmedia.exiftool; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +// ================================================================================ +/** + * Represents an Exif Process. + */ +public class ExifProcess { + private final ReentrantLock closeLock = new ReentrantLock(false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader reader; + private final OutputStreamWriter writer; + private volatile boolean closed = false; + + public static VersionNumber readVersion(String exifCmd) { + ExifProcess process = _execute(false, + Arrays.asList(exifCmd, "-ver")); + try { + return new VersionNumber(process.readLine()); + } catch (IOException ex) { + throw new RuntimeException(String.format( + "Unable to check version number of ExifTool: %s", + exifCmd)); + } finally { + process.close(); + } + } + + public static Map executeToResults(String exifCmd, + List args) throws IOException { + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { + return process.readResponse(); + } finally { + process.close(); + } + } + + public static String executeToString(String exifCmd, List args) + throws IOException { + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs); + try { + return process.readResponseString(); + } finally { + process.close(); + } + } + + public static ExifProcess startup(String exifCmd) { + List args = Arrays.asList(exifCmd, "-stay_open", "True", + "-@", "-"); + return _execute(true, args); + } + + public static ExifProcess _execute(boolean keepAlive, List args) { + ExifTool.log.debug(String + .format("Attempting to start external ExifTool process using args: %s", + args)); + try { + Process process = new ProcessBuilder(args).start(); + ExifTool.log.debug("\tSuccessful"); + return new ExifProcess(keepAlive, process); + } catch (Exception e) { + String message = "Unable to start external ExifTool process using the execution arguments: " + + args + + ". Ensure ExifTool is installed correctly and runs using the command path '" + + args.get(0) + + "' as specified by the 'exiftool.path' system property."; + + ExifTool.log.debug(message); + throw new RuntimeException(message, e); + } + } + + public ExifProcess(boolean keepAlive, Process process) { + this.keepAlive = keepAlive; + this.process = process; + this.reader = new BufferedReader(new InputStreamReader( + process.getInputStream())); + this.writer = new OutputStreamWriter(process.getOutputStream()); + } + + public synchronized Map sendArgs(List args) + throws IOException { + StringBuilder builder = new StringBuilder(); + for (String arg : args) { + builder.append(arg).append("\n"); + } + builder.append("-execute\n"); + writeFlush(builder.toString()); + return readResponse(); + } + + public synchronized void writeFlush(String message) throws IOException { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + writer.write(message); + writer.flush(); + } + + public synchronized String readLine() throws IOException { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + return reader.readLine(); + } + + public synchronized Map readResponse() + throws IOException { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + ExifTool.log.debug("Reading response back from ExifTool..."); + Map resultMap = new HashMap(500); + String line; + + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + String[] pair = ExifTool.TAG_VALUE_PATTERN.split(line, 2); + + if (pair.length == 2) { + resultMap.put(pair[0], pair[1]); + ExifTool.log.debug(String.format("\tRead Tag [name=%s, value=%s]", + pair[0], pair[1])); + } + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } + } + return resultMap; + } + + public synchronized String readResponseString() throws IOException { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + ExifTool.log.debug("Reading response back from ExifTool..."); + String line; + StringBuilder result = new StringBuilder(); + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } else + result.append(line); + } + return result.toString(); + } + + public boolean isClosed() { + return closed; + } + + public void close() { + if (!closed) { + closeLock.lock(); + try { + if (!closed) { + closed = true; + ExifTool.log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); + try { + writer.write("-stay_open\nFalse\n"); + writer.flush(); + } catch (IOException ex) { + // log.error(ex,ex); + } + try { + ExifTool.log.debug("Closing Read stream..."); + reader.close(); + ExifTool.log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + ExifTool.log.debug("Closing Write stream..."); + writer.close(); + ExifTool.log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + ExifTool.log.debug("Read/Write streams successfully closed."); + + try { + process.destroy(); + } catch (Exception e) { + // + } + // process = null; + + } + } finally { + closeLock.unlock(); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 9a13cb05..9e06dce2 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -16,14 +16,10 @@ package com.thebuzzmedia.exiftool; -import java.io.BufferedReader; import java.io.File; import java.io.FileWriter; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; import java.util.ArrayList; -import java.util.Arrays; import java.util.EnumSet; import java.util.HashMap; import java.util.List; @@ -235,11 +231,11 @@ public class ExifTool { * Compiled {@link Pattern} of ": " used to split compact output from * ExifTool evenly into name/value pairs. */ - private static final Pattern TAG_VALUE_PATTERN = Pattern + static final Pattern TAG_VALUE_PATTERN = Pattern .compile("\\s*:\\s*"); - private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - private static Logger log = LoggerFactory.getLogger(ExifTool.class); + static Logger log = LoggerFactory.getLogger(ExifTool.class); /** * The absolute path to the ExifTool executable on the host system running @@ -870,633 +866,4 @@ private static Map mapByTag(Map stringMap) { } return tagMap; } - - // ================================================================================ - /** - * Represents an Exif Process. - */ - public static class ExifProcess { - private final ReentrantLock closeLock = new ReentrantLock(false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; - private volatile boolean closed = false; - - public static VersionNumber readVersion(String exifCmd) { - ExifProcess process = _execute(false, - Arrays.asList(exifCmd, "-ver")); - try { - return new VersionNumber(process.readLine()); - } catch (IOException ex) { - throw new RuntimeException(String.format( - "Unable to check version number of ExifTool: %s", - exifCmd)); - } finally { - process.close(); - } - } - - public static Map executeToResults(String exifCmd, - List args) throws IOException { - List newArgs = new ArrayList(args.size() + 1); - newArgs.add(exifCmd); - newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); - try { - return process.readResponse(); - } finally { - process.close(); - } - } - - public static String executeToString(String exifCmd, List args) - throws IOException { - List newArgs = new ArrayList(args.size() + 1); - newArgs.add(exifCmd); - newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); - try { - return process.readResponseString(); - } finally { - process.close(); - } - } - - public static ExifProcess startup(String exifCmd) { - List args = Arrays.asList(exifCmd, "-stay_open", "True", - "-@", "-"); - return _execute(true, args); - } - - public static ExifProcess _execute(boolean keepAlive, List args) { - log.debug(String - .format("Attempting to start external ExifTool process using args: %s", - args)); - try { - Process process = new ProcessBuilder(args).start(); - log.debug("\tSuccessful"); - return new ExifProcess(keepAlive, process); - } catch (Exception e) { - String message = "Unable to start external ExifTool process using the execution arguments: " - + args - + ". Ensure ExifTool is installed correctly and runs using the command path '" - + args.get(0) - + "' as specified by the 'exiftool.path' system property."; - - log.debug(message); - throw new RuntimeException(message, e); - } - } - - public ExifProcess(boolean keepAlive, Process process) { - this.keepAlive = keepAlive; - this.process = process; - this.reader = new BufferedReader(new InputStreamReader( - process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream()); - } - - public synchronized Map sendArgs(List args) - throws IOException { - StringBuilder builder = new StringBuilder(); - for (String arg : args) { - builder.append(arg).append("\n"); - } - builder.append("-execute\n"); - writeFlush(builder.toString()); - return readResponse(); - } - - public synchronized void writeFlush(String message) throws IOException { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - writer.write(message); - writer.flush(); - } - - public synchronized String readLine() throws IOException { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - return reader.readLine(); - } - - public synchronized Map readResponse() - throws IOException { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - Map resultMap = new HashMap(500); - String line; - - while ((line = reader.readLine()) != null) { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - String[] pair = TAG_VALUE_PATTERN.split(line, 2); - - if (pair.length == 2) { - resultMap.put(pair[0], pair[1]); - log.debug(String.format("\tRead Tag [name=%s, value=%s]", - pair[0], pair[1])); - } - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need - * to look for it and break from this loop when we see it - * otherwise this process will hang indefinitely blocking on the - * input stream with no data to read. - */ - if (keepAlive && line.equals("{ready}")) { - break; - } - } - return resultMap; - } - - public synchronized String readResponseString() throws IOException { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - String line; - StringBuilder result = new StringBuilder(); - while ((line = reader.readLine()) != null) { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need - * to look for it and break from this loop when we see it - * otherwise this process will hang indefinitely blocking on the - * input stream with no data to read. - */ - if (keepAlive && line.equals("{ready}")) { - break; - } else - result.append(line); - } - return result.toString(); - } - - public boolean isClosed() { - return closed; - } - - public void close() { - if (!closed) { - closeLock.lock(); - try { - if (!closed) { - closed = true; - log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - try { - writer.write("-stay_open\nFalse\n"); - writer.flush(); - } catch (IOException ex) { - // log.error(ex,ex); - } - try { - log.debug("Closing Read stream..."); - reader.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log.debug("Closing Write stream..."); - writer.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - log.debug("Read/Write streams successfully closed."); - - try { - process.destroy(); - } catch (Exception e) { - // - } - // process = null; - - } - } finally { - closeLock.unlock(); - } - } - } - } - - // ================================================================================ - /** - * Enum used to define the different kinds of features in the native - * ExifTool executable that this class can help you take advantage of. - *

- * These flags are different from {@link Tag}s in that a "feature" is - * determined to be a special functionality of the underlying ExifTool - * executable that requires a different code-path in this class to take - * advantage of; for example, -stay_open True support. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Feature { - /** - * Enum used to specify that you wish to launch the underlying ExifTool - * process with -stay_open True support turned on that this - * class can then take advantage of. - *

- * Required ExifTool version is 8.36 or higher. - */ - STAY_OPEN(8, 36); - - private VersionNumber requireVersion; - - private Feature(int... numbers) { - this.requireVersion = new VersionNumber(numbers); - } - - /** - * Used to get the version of ExifTool required by this feature in order - * to work. - * - * @return the version of ExifTool required by this feature in order to - * work. - */ - VersionNumber getVersion() { - return requireVersion; - } - - boolean isSupported(VersionNumber exifVersionNumber) { - return requireVersion.isBeforeOrEqualTo(exifVersionNumber); - } - } - - // ================================================================================ - /** - * Version Number used to determine if one version is after another. - */ - static class VersionNumber { - private final int[] numbers; - - public VersionNumber(String str) { - String[] versionParts = str.trim().split("\\."); - this.numbers = new int[versionParts.length]; - for (int i = 0; i < versionParts.length; i++) { - numbers[i] = Integer.parseInt(versionParts[i]); - } - } - - public VersionNumber(int... numbers) { - this.numbers = numbers; - } - - public boolean isBeforeOrEqualTo(VersionNumber other) { - int max = Math.min(this.numbers.length, other.numbers.length); - for (int i = 0; i < max; i++) { - if (this.numbers[i] > other.numbers[i]) { - return false; - } else if (this.numbers[i] < other.numbers[i]) { - return true; - } - } - // assume missing number as zero, so if the current process number - // is more digits it is a higher version - return this.numbers.length <= other.numbers.length; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - for (int i = 0; i < numbers.length; i++) { - if (builder.length() > 0) { - builder.append("."); - } - builder.append(numbers[i]); - } - return builder.toString(); - } - } - - // ================================================================================ - /** - * Enum used to define the 2 different output formats that {@link Tag} - * values can be returned in: numeric or human-readable text. - *

- * ExifTool, via the -n command line arg, is capable of - * returning most values in their raw numeric form (e.g. - * Aperture="2.8010323841") as well as a more human-readable/friendly format - * (e.g. Aperture="2.8"). - *

- * While the {@link Tag}s defined on this class do provide a hint at the - * type of the result (see {@link Tag#getType()}), that hint only applies - * when the {@link Format#NUMERIC} form of the value is returned. - *

- * If the caller finds the human-readable format easier to process, - * {@link Format#HUMAN_READABLE} can be specified when calling - * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned - * {@link String} values processed manually by the caller. - *

- * In order to see the types of values that are returned when - * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive - * ExifTool Tag Guide. - *

- * This makes sense with some values like Aperture that in - * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high - * precision values that are near the intended value (e.g. - * "2.79999992203711" instead of just returning "2.8"). On the other hand, - * other values (like Orientation) are easier to parse when their numeric - * value (1-8) is returned instead of a much longer friendly name (e.g. - * "Mirror horizontal and rotate 270 CW"). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Format { - NUMERIC, - HUMAN_READABLE - } - - // ================================================================================ - /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifTool. - *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default {@link Format#NUMERIC} value format - * is used. - *

- * All replies from ExifTool are parsed as {@link String}s and using the - * type hint from each {@link Tag} can easily be converted to the correct - * data format by using the provided {@link Tag#parseValue(String)} method. - *

- * This class does not make an attempt at converting the value automatically - * in case the caller decides they would prefer tag values returned in - * {@link Format#HUMAN_READABLE} format and to avoid any compatibility - * issues with future versions of ExifTool if a tag's return value is - * changed. This approach to leaving returned tag values as strings until - * the caller decides they want to parse them is a safer and more robust - * approach. - *

- * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. - *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. - *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. - *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Tag { - // single entry tags - APERTURE("ApertureValue", Double.class), - AUTHOR("XPAuthor", String.class), - COLOR_SPACE("ColorSpace", Integer.class), - COMMENT("XPComment", String.class), - CONTRAST("Contrast", Integer.class), - CREATE_DATE("CreateDate", String.class), - CREATION_DATE("CreationDate", String.class), - DATE_CREATED("DateCreated", String.class), - DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - FLASH("Flash", Integer.class), - FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), - FNUMBER("FNumber", String.class), - GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), - GPS_DATESTAMP("GPSDateStamp", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), - GPS_LONGITUDE("GPSLongitude", Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), - GPS_SPEED("GPSSpeed", Double.class), - GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), - IMAGE_WIDTH("ImageWidth", Integer.class), - ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), - LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), - MAKE("Make", String.class), - METERING_MODE("MeteringMode", Integer.class), - MODEL("Model", String.class), - ORIENTATION("Orientation", Integer.class), - OWNER_NAME("OwnerName", String.class), - RATING("Rating", Integer.class), - RATING_PERCENT("RatingPercent", Integer.class), - ROTATION("Rotation", Integer.class), - SATURATION("Saturation", Integer.class), - SENSING_METHOD("SensingMethod", Integer.class), - SHARPNESS("Sharpness", Integer.class), - SHUTTER_SPEED("ShutterSpeedValue", Double.class), - SOFTWARE("Software", String.class), - SUBJECT("XPSubject", String.class), - TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), - X_RESOLUTION("XResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), - // select ICC metadata - ICC_DESCRIPTION("ProfileDescription", String.class), - ICC_COLORSPACEDATA("ColorSpaceData", String.class), - // actually binary data, but what are we doing to do here??? Just use to - // save to file... - THUMBNAIL_IMAGE("ThumbnailImage", String.class), - THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class), ; - - /** - * Used to get the {@link Tag} identified by the given, case-sensitive, - * tag name. - * - * @param name - * The case-sensitive name of the tag that will be searched - * for. - * - * @return the {@link Tag} identified by the given, case-sensitive, tag - * name or null if one couldn't be found. - */ - public static Tag forName(String name) { - for (Tag tag : Tag.values()) { - if (tag.getName().equals(name)) { - return tag; - } - } - return null; - } - - /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifTool process) into the type described - * by the associated {@link Tag}. - * - * @param - * The type of the returned value. - * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. - * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). - * - * @throws IllegalArgumentException - * if tag is null. - * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). - * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. - */ - @SuppressWarnings("unchecked") - public T parseValue(String value) throws IllegalArgumentException { - - if (value != null) { - if (Boolean.class.isAssignableFrom(this.getType())) { - return (T) Boolean.valueOf(value); - } else if (Byte.class.isAssignableFrom(this.getType())) { - return (T) Byte.valueOf(Byte.parseByte(value)); - } else if (Integer.class.isAssignableFrom(this.getType())) { - return (T) Integer.valueOf(Integer.parseInt(value)); - } else if (Short.class.isAssignableFrom(this.getType())) { - return (T) Short.valueOf(Short.parseShort(value)); - } else if (Long.class.isAssignableFrom(this.getType())) { - return (T) Long.valueOf(Long.parseLong(value)); - } else if (Float.class.isAssignableFrom(this.getType())) { - return (T) Float.valueOf(Float.parseFloat(value)); - } else if (Double.class.isAssignableFrom(this.getType())) { - return (T) parseDouble(value); - } else if (Character.class.isAssignableFrom(this.getType())) { - return (T) Character.valueOf(value.charAt(0)); - } else if (String.class.isAssignableFrom(this.getType())) { - return (T) value; - } - } - return null; - } - - private Double parseDouble(String in) { - if (in.contains("/")) { - String[] enumeratorAndDivisor = in.split("/"); - return Double.parseDouble(enumeratorAndDivisor[0]) - / Double.parseDouble(enumeratorAndDivisor[1]); - } else { - return Double.parseDouble(in); - } - } - - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ - public String getName() { - return name; - } - - /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifTool Tag Guide. - * - * @return a hint for the native type of this tag's value. - */ - public Class getType() { - return type; - } - - private String name; - private Class type; - - private Tag(String name, Class type) { - this.name = name; - this.type = type; - } - } - - // ================================================================================ - public enum TagGroup { - EXIF("EXIF", "exif:all"), - IPTC("IPTC", "iptc:all"), - XMP("XMP", "xmp:all"), - ALL("ALL", "all"), - FILE("FILE", "file:all"), - ICC("ICC", "icc_profile:all"); - - private final String name; - private final String value; - - private TagGroup(String name, String value) { - this.name = name; - this.value = value; - } - - public String getName() { - return name; - } - - public String getValue() { - return value; - } - } - - // ================================================================================ - /** - * Class used to define an exception that occurs when the caller attempts to - * use a {@link Feature} that the underlying native ExifTool install does - * not support (i.e. the version isn't new enough). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public class UnsupportedFeatureException extends RuntimeException { - private static final long serialVersionUID = -1332725983656030770L; - - public UnsupportedFeatureException(Feature feature) { - super( - "Use of feature [" - + feature.toString() - + "] requires version " - + feature.getVersion() - + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); - } - - } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Feature.java b/src/main/java/com/thebuzzmedia/exiftool/Feature.java new file mode 100644 index 00000000..a9c602bf --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Feature.java @@ -0,0 +1,46 @@ +package com.thebuzzmedia.exiftool; + +// ================================================================================ +/** + * Enum used to define the different kinds of features in the native + * ExifTool executable that this class can help you take advantage of. + *

+ * These flags are different from {@link Tag}s in that a "feature" is + * determined to be a special functionality of the underlying ExifTool + * executable that requires a different code-path in this class to take + * advantage of; for example, -stay_open True support. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public enum Feature { + /** + * Enum used to specify that you wish to launch the underlying ExifTool + * process with -stay_open True support turned on that this + * class can then take advantage of. + *

+ * Required ExifTool version is 8.36 or higher. + */ + STAY_OPEN(8, 36); + + private VersionNumber requireVersion; + + private Feature(int... numbers) { + this.requireVersion = new VersionNumber(numbers); + } + + /** + * Used to get the version of ExifTool required by this feature in order + * to work. + * + * @return the version of ExifTool required by this feature in order to + * work. + */ + VersionNumber getVersion() { + return requireVersion; + } + + boolean isSupported(VersionNumber exifVersionNumber) { + return requireVersion.isBeforeOrEqualTo(exifVersionNumber); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Format.java b/src/main/java/com/thebuzzmedia/exiftool/Format.java new file mode 100644 index 00000000..41b07a3d --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Format.java @@ -0,0 +1,43 @@ +package com.thebuzzmedia.exiftool; + +import java.io.File; + +// ================================================================================ +/** + * Enum used to define the 2 different output formats that {@link Tag} + * values can be returned in: numeric or human-readable text. + *

+ * ExifTool, via the -n command line arg, is capable of + * returning most values in their raw numeric form (e.g. + * Aperture="2.8010323841") as well as a more human-readable/friendly format + * (e.g. Aperture="2.8"). + *

+ * While the {@link Tag}s defined on this class do provide a hint at the + * type of the result (see {@link Tag#getType()}), that hint only applies + * when the {@link Format#NUMERIC} form of the value is returned. + *

+ * If the caller finds the human-readable format easier to process, + * {@link Format#HUMAN_READABLE} can be specified when calling + * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned + * {@link String} values processed manually by the caller. + *

+ * In order to see the types of values that are returned when + * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive + * ExifTool Tag Guide. + *

+ * This makes sense with some values like Aperture that in + * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high + * precision values that are near the intended value (e.g. + * "2.79999992203711" instead of just returning "2.8"). On the other hand, + * other values (like Orientation) are easier to parse when their numeric + * value (1-8) is returned instead of a much longer friendly name (e.g. + * "Mirror horizontal and rotate 270 CW"). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public enum Format { + NUMERIC, + HUMAN_READABLE +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Tag.java b/src/main/java/com/thebuzzmedia/exiftool/Tag.java new file mode 100644 index 00000000..c736fb0b --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Tag.java @@ -0,0 +1,233 @@ +package com.thebuzzmedia.exiftool; + + +// ================================================================================ +/** + * Enum used to pre-define a convenient list of tags that can be easily + * extracted from images using this class with an external install of + * ExifTool. + *

+ * Each tag defined also includes a type hint for the parsed value + * associated with it when the default {@link Format#NUMERIC} value format + * is used. + *

+ * All replies from ExifTool are parsed as {@link String}s and using the + * type hint from each {@link Tag} can easily be converted to the correct + * data format by using the provided {@link Tag#parseValue(String)} method. + *

+ * This class does not make an attempt at converting the value automatically + * in case the caller decides they would prefer tag values returned in + * {@link Format#HUMAN_READABLE} format and to avoid any compatibility + * issues with future versions of ExifTool if a tag's return value is + * changed. This approach to leaving returned tag values as strings until + * the caller decides they want to parse them is a safer and more robust + * approach. + *

+ * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or + * process the returned {@link String} values any way they wish. + *

Tag Support

+ * ExifTool is capable of parsing almost every tag known to man (1000+), but + * this class makes an attempt at pre-defining a convenient list of the most + * common tags for use. + *

+ * This list was determined by looking at the common metadata tag values + * written to images by popular mobile devices (iPhone, Android) as well as + * cameras like simple point and shoots as well as DSLRs. As an additional + * source of input the list of supported/common EXIF formats that Flickr + * supports was also reviewed to ensure the most common/useful tags were + * being covered here. + *

+ * Please email me or file an issue + * if you think this list is missing a commonly used tag that should be + * added to it. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public enum Tag { + // single entry tags + APERTURE("ApertureValue", Double.class), + AUTHOR("XPAuthor", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATE_DATE("CreateDate", String.class), + CREATION_DATE("CreationDate", String.class), + DATE_CREATED("DateCreated", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + FLASH("Flash", Integer.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + FNUMBER("FNumber", String.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_DATESTAMP("GPSDateStamp", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SENSING_METHOD("SensingMethod", Integer.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), + // select ICC metadata + ICC_DESCRIPTION("ProfileDescription", String.class), + ICC_COLORSPACEDATA("ColorSpaceData", String.class), + // actually binary data, but what are we doing to do here??? Just use to + // save to file... + THUMBNAIL_IMAGE("ThumbnailImage", String.class), + THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class), ; + + /** + * Used to get the {@link Tag} identified by the given, case-sensitive, + * tag name. + * + * @param name + * The case-sensitive name of the tag that will be searched + * for. + * + * @return the {@link Tag} identified by the given, case-sensitive, tag + * name or null if one couldn't be found. + */ + public static Tag forName(String name) { + for (Tag tag : Tag.values()) { + if (tag.getName().equals(name)) { + return tag; + } + } + return null; + } + + /** + * Convenience method used to convert the given string Tag value + * (returned from the external ExifTool process) into the type described + * by the associated {@link Tag}. + * + * @param + * The type of the returned value. + * @param value + * The {@link String} representation of the tag's value as + * parsed from the image. + * + * @return the given string value converted to a native Java type (e.g. + * Integer, Double, etc.). + * + * @throws IllegalArgumentException + * if tag is null. + * @throws NumberFormatException + * if any exception occurs while trying to parse the given + * value to any of the supported numeric types + * in Java via calls to the respective parseXXX + * methods defined on all the numeric wrapper classes (e.g. + * {@link Integer#parseInt(String)} , + * {@link Double#parseDouble(String)} and so on). + * @throws ClassCastException + * if the type defined by T is incompatible + * with the type defined by {@link Tag#getType()} returned + * by the tag argument passed in. This class + * performs an implicit/unchecked cast to the type + * T before returning the parsed result of the + * type indicated by {@link Tag#getType()}. If the types do + * not match, a ClassCastException will be + * generated by the VM. + */ + @SuppressWarnings("unchecked") + public T parseValue(String value) throws IllegalArgumentException { + + if (value != null) { + if (Boolean.class.isAssignableFrom(this.getType())) { + return (T) Boolean.valueOf(value); + } else if (Byte.class.isAssignableFrom(this.getType())) { + return (T) Byte.valueOf(Byte.parseByte(value)); + } else if (Integer.class.isAssignableFrom(this.getType())) { + return (T) Integer.valueOf(Integer.parseInt(value)); + } else if (Short.class.isAssignableFrom(this.getType())) { + return (T) Short.valueOf(Short.parseShort(value)); + } else if (Long.class.isAssignableFrom(this.getType())) { + return (T) Long.valueOf(Long.parseLong(value)); + } else if (Float.class.isAssignableFrom(this.getType())) { + return (T) Float.valueOf(Float.parseFloat(value)); + } else if (Double.class.isAssignableFrom(this.getType())) { + return (T) parseDouble(value); + } else if (Character.class.isAssignableFrom(this.getType())) { + return (T) Character.valueOf(value.charAt(0)); + } else if (String.class.isAssignableFrom(this.getType())) { + return (T) value; + } + } + return null; + } + + private Double parseDouble(String in) { + if (in.contains("/")) { + String[] enumeratorAndDivisor = in.split("/"); + return Double.parseDouble(enumeratorAndDivisor[0]) + / Double.parseDouble(enumeratorAndDivisor[1]); + } else { + return Double.parseDouble(in); + } + } + + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ + public String getName() { + return name; + } + + /** + * Used to get a hint for the native type of this tag's value as + * specified by Phil Harvey's ExifTool Tag Guide. + * + * @return a hint for the native type of this tag's value. + */ + public Class getType() { + return type; + } + + private String name; + private Class type; + + private Tag(String name, Class type) { + this.name = name; + this.type = type; + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java b/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java new file mode 100644 index 00000000..836bc95d --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java @@ -0,0 +1,27 @@ +package com.thebuzzmedia.exiftool; + +// ================================================================================ +public enum TagGroup { + EXIF("EXIF", "exif:all"), + IPTC("IPTC", "iptc:all"), + XMP("XMP", "xmp:all"), + ALL("ALL", "all"), + FILE("FILE", "file:all"), + ICC("ICC", "icc_profile:all"); + + private final String name; + private final String value; + + private TagGroup(String name, String value) { + this.name = name; + this.value = value; + } + + public String getName() { + return name; + } + + public String getValue() { + return value; + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java b/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java new file mode 100644 index 00000000..d9e8f0a0 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java @@ -0,0 +1,25 @@ +package com.thebuzzmedia.exiftool; + + +// ================================================================================ +/** + * Class used to define an exception that occurs when the caller attempts to + * use a {@link Feature} that the underlying native ExifTool install does + * not support (i.e. the version isn't new enough). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public class UnsupportedFeatureException extends RuntimeException { + private static final long serialVersionUID = -1332725983656030770L; + + public UnsupportedFeatureException(Feature feature) { + super( + "Use of feature [" + + feature.toString() + + "] requires version " + + feature.getVersion() + + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); + } + +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java b/src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java new file mode 100644 index 00000000..63605239 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java @@ -0,0 +1,47 @@ +package com.thebuzzmedia.exiftool; + +// ================================================================================ +/** + * Version Number used to determine if one version is after another. + */ +class VersionNumber { + private final int[] numbers; + + public VersionNumber(String str) { + String[] versionParts = str.trim().split("\\."); + this.numbers = new int[versionParts.length]; + for (int i = 0; i < versionParts.length; i++) { + numbers[i] = Integer.parseInt(versionParts[i]); + } + } + + public VersionNumber(int... numbers) { + this.numbers = numbers; + } + + public boolean isBeforeOrEqualTo(VersionNumber other) { + int max = Math.min(this.numbers.length, other.numbers.length); + for (int i = 0; i < max; i++) { + if (this.numbers[i] > other.numbers[i]) { + return false; + } else if (this.numbers[i] < other.numbers[i]) { + return true; + } + } + // assume missing number as zero, so if the current process number + // is more digits it is a higher version + return this.numbers.length <= other.numbers.length; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + for (int i = 0; i < numbers.length; i++) { + if (builder.length() > 0) { + builder.append("."); + } + builder.append(numbers[i]); + } + return builder.toString(); + } +} \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index 8ec7233b..22a94a68 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -6,9 +6,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Tag; - public class Benchmark { public static final int ITERATIONS = 25; diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index d25636cb..f289d3bd 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -7,9 +7,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Format; - public class Example { private static Logger log = LoggerFactory.getLogger(Example.class); @@ -27,9 +24,9 @@ public static void main(String[] args) throws IOException, // list all first-class tags for (File f : images) { log.info("\n[{}]", f.getName()); - Map metadata = tool.getImageMeta(f, - Format.HUMAN_READABLE, ExifTool.Tag.values()); - for (ExifTool.Tag key : metadata.keySet()) { + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, Tag.values()); + for (Tag key : metadata.keySet()) { log.info(String.format("\t\t%s: %s", key.getName(), metadata.get(key))); } @@ -39,9 +36,9 @@ public static void main(String[] args) throws IOException, // list all XMP, IPTC and XMP tags File f = new File(TEST_FILES_PATH + "/kureckjones_jett_075_02-cropped.tif"); - for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] { - ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, - ExifTool.TagGroup.XMP }) { + for (TagGroup tagGroup : new TagGroup[] { + TagGroup.EXIF, TagGroup.IPTC, + TagGroup.XMP }) { Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, tagGroup); log.info(tagGroup.getName()); diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index a9f3291b..de5aa1e0 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -44,14 +44,14 @@ public void testSingleTool() throws Exception { tool.shutdown(); } - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + tool = new ExifTool(Feature.STAY_OPEN); try { assertTrue(runTests(tool, "")); } finally { tool.shutdown(); } - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + tool = new ExifTool(Feature.STAY_OPEN); try { tool.startup(); assertTrue(runTests(tool, "")); @@ -72,7 +72,7 @@ public void testConcurrent() throws Exception { @Override public void run() { log.info(getName() + ": starting"); - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); try { runTests(tool, getName()); log.info(getName() + ": finished"); @@ -99,7 +99,7 @@ public void run() { @Test public void testManyThreadsOneTool() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + final ExifTool tool = new ExifTool(Feature.STAY_OPEN); try { Thread[] threads = new Thread[20]; for (int i = 0; i < threads.length; i++) { @@ -134,7 +134,7 @@ public void run() { @Test public void testProcessTimeout() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + final ExifTool tool = new ExifTool(Feature.STAY_OPEN); try { tool.setRunTimeout(1); runTests(tool, "will fail"); @@ -149,52 +149,52 @@ public void testProcessTimeout() throws Exception { public boolean runTests(ExifTool tool, String runId) throws IOException, URISyntaxException { - Map metadata; + Map metadata; File imageFile; - Set keys; - ExifTool.Tag tag; + Set keys; + Tag tag; URL url = getClass() .getResource("/kureckjones_jett_075_02-cropped.tif"); imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.values()); + metadata = tool.getImageMeta(imageFile, Format.HUMAN_READABLE, + Tag.values()); assertEquals(25, metadata.size()); keys = metadata.keySet(); - tag = ExifTool.Tag.IMAGE_WIDTH; + tag = Tag.IMAGE_WIDTH; assertTrue(keys.contains(tag)); assertEquals(728, tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.IMAGE_HEIGHT; + tag = Tag.IMAGE_HEIGHT; assertEquals(825, tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.MODEL; + tag = Tag.MODEL; assertEquals("P 45+", tag.parseValue(metadata.get(tag))); log.info(runId + ": finished image 1"); url = getClass().getResource("/nexus-s-electric-cars.jpg"); imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.values()); + metadata = tool.getImageMeta(imageFile, Format.HUMAN_READABLE, + Tag.values()); assertEquals(24, metadata.size()); keys = metadata.keySet(); - tag = ExifTool.Tag.IMAGE_WIDTH; + tag = Tag.IMAGE_WIDTH; assertTrue(keys.contains(tag)); assertEquals(2560, tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.IMAGE_HEIGHT; + tag = Tag.IMAGE_HEIGHT; assertEquals(1920, tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.MODEL; + tag = Tag.MODEL; assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.ISO; + tag = Tag.ISO; assertEquals(50, tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.SHUTTER_SPEED; + tag = Tag.SHUTTER_SPEED; assertEquals("1/64", metadata.get(tag)); assertEquals(0.015625, tag.parseValue(metadata.get(tag))); log.info(runId + ": finished image 2"); @@ -203,14 +203,14 @@ public boolean runTests(ExifTool tool, String runId) throws IOException, @Test public void testGroupTags() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); try { Map metadata; URL url = getClass().getResource("/iptc_test-photoshop.jpg"); File f = new File(url.toURI()); - metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, - ExifTool.TagGroup.IPTC); + metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, + TagGroup.IPTC); assertEquals(17, metadata.size()); assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); assertEquals("IPTC Status: Copyright Notice", @@ -228,24 +228,24 @@ public void testGroupTags() throws Exception { @Test public void testTag() { assertEquals("string value", "John Doe", - ExifTool.Tag.AUTHOR.parseValue("John Doe")); - assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); + Tag.AUTHOR.parseValue("John Doe")); + assertEquals("integer value", 200, Tag.ISO.parseValue("200")); assertEquals("double value, from fraction", .25, - ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); + Tag.SHUTTER_SPEED.parseValue("1/4")); assertEquals("double value, from decimal", .25, - ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); + Tag.SHUTTER_SPEED.parseValue(".25")); } @Test public void testVersionNumber() { - assertTrue(new ExifTool.VersionNumber("1.2") - .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); - assertTrue(new ExifTool.VersionNumber(1, 2) - .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); - assertTrue(new ExifTool.VersionNumber(1, 2, 3) - .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); - assertTrue(new ExifTool.VersionNumber(1, 2, 3) - .isBeforeOrEqualTo(new ExifTool.VersionNumber(2, 1))); + assertTrue(new VersionNumber("1.2") + .isBeforeOrEqualTo(new VersionNumber("1.2.3"))); + assertTrue(new VersionNumber(1, 2) + .isBeforeOrEqualTo(new VersionNumber("1.2"))); + assertTrue(new VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new VersionNumber("1.3"))); + assertTrue(new VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new VersionNumber(2, 1))); } @Test @@ -255,25 +255,25 @@ public void testWriteTagStringNonDaemon() throws Exception { Path imageFile = Paths.get(url.toURI()); // Check the value is correct at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Now change it String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check that it's updated metadata = tool .getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -287,30 +287,30 @@ public void testWriteTagStringNonDaemon() throws Exception { @Test public void testWriteTagString() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Check the value is correct at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Now change it String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check that it's updated metadata = tool .getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -323,20 +323,20 @@ public void testWriteTagString() throws Exception { @Test public void testWriteTagStringInvalidformat() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Check the value is correct at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); String newDate = "2egek opkpgrpok"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); // Now change it to an invalid value which should fail tool.addImageMetadata(imageFile.toFile(), newValues); @@ -344,10 +344,10 @@ public void testWriteTagStringInvalidformat() throws Exception { // Finally check that it's not updated metadata = tool .getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -368,23 +368,23 @@ public void testWriteTagNumberNonDaemon() throws Exception { Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.ORIENTATION); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION); assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); + Map newValues = new HashMap(); + newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check the updated value metadata = tool.getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); + Format.HUMAN_READABLE, Tag.ORIENTATION); assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(ExifTool.Tag.ORIENTATION)); + metadata.get(Tag.ORIENTATION)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -398,28 +398,28 @@ public void testWriteTagNumberNonDaemon() throws Exception { @Test public void testWriteTagNumber() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.ORIENTATION); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION); assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); + Map newValues = new HashMap(); + newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check the updated value metadata = tool.getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); + Format.HUMAN_READABLE, Tag.ORIENTATION); assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(ExifTool.Tag.ORIENTATION)); + metadata.get(Tag.ORIENTATION)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -433,35 +433,35 @@ public void testWriteTagNumber() throws Exception { @Test public void testWriteMulipleTag() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Now change them String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check the updated value metadata = tool.getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Format.HUMAN_READABLE, Tag.ORIENTATION, + Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(ExifTool.Tag.ORIENTATION)); + metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -480,30 +480,30 @@ public void testWriteMulipleTagNonDaemon() throws Exception { Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Now change them String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check the updated value metadata = tool.getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Format.HUMAN_READABLE, Tag.ORIENTATION, + Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(ExifTool.Tag.ORIENTATION)); + metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is not // affected by the change From b9ef8d8aac892feec335c1e7764c61c9dd86df1b Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 14:12:29 +0300 Subject: [PATCH 041/148] - extract in new files to ease up the integration process --- .../com/thebuzzmedia/exiftool/CustomTag.java | 40 + .../thebuzzmedia/exiftool/ExifProcess.java | 171 +++ .../com/thebuzzmedia/exiftool/ExifProxy.java | 22 + .../com/thebuzzmedia/exiftool/ExifTool.java | 998 +----------------- .../com/thebuzzmedia/exiftool/Feature.java | 58 + .../com/thebuzzmedia/exiftool/Format.java | 8 + .../exiftool/KeepAliveExifProxy.java | 136 +++ .../thebuzzmedia/exiftool/MetadataTag.java | 22 + .../com/thebuzzmedia/exiftool/MwgTag.java | 54 + .../thebuzzmedia/exiftool/ReadOptions.java | 104 ++ .../exiftool/SingleUseExifProxy.java | 66 ++ .../java/com/thebuzzmedia/exiftool/Tag.java | 202 ++++ .../com/thebuzzmedia/exiftool/TagGroup.java | 37 + .../exiftool/UnsupportedFeatureException.java | 23 + .../thebuzzmedia/exiftool/VersionNumber.java | 49 + .../thebuzzmedia/exiftool/WriteOptions.java | 39 + .../com/thebuzzmedia/exiftool/Benchmark.java | 3 - .../com/thebuzzmedia/exiftool/Example.java | 15 +- .../thebuzzmedia/exiftool/TestExifTool.java | 244 ++--- 19 files changed, 1163 insertions(+), 1128 deletions(-) create mode 100644 src/main/java/com/thebuzzmedia/exiftool/CustomTag.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/ExifProxy.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Feature.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Format.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/MwgTag.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/ReadOptions.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Tag.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/TagGroup.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/WriteOptions.java diff --git a/src/main/java/com/thebuzzmedia/exiftool/CustomTag.java b/src/main/java/com/thebuzzmedia/exiftool/CustomTag.java new file mode 100644 index 00000000..076cb40b --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/CustomTag.java @@ -0,0 +1,40 @@ +package com.thebuzzmedia.exiftool; + +/** + * A Custom Tag that the user defines. Used to cover tags not in the enum. + */ +public class CustomTag implements MetadataTag { + private final String name; + private final Class type; + private final boolean mapped; + + public CustomTag(String name, Class type) { + this(name, type, !name.trim().endsWith(":all")); + } + + public CustomTag(String name, Class type, boolean mapped) { + this.name = name.trim(); + this.type = type; + this.mapped = mapped; + } + + @Override + public String getKey() { + return name; + } + + @Override + public Class getType() { + return type; + } + + @Override + public boolean isMapped() { + return mapped; + } + + @Override + public String toString() { + return getKey(); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java new file mode 100644 index 00000000..776fe4e0 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -0,0 +1,171 @@ +package com.thebuzzmedia.exiftool; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; + +// ================================================================================ +/** + * Represents an external exif process. Works for both single use and keep alive + * modes. This is the actual process, with streams for reading and writing data. + */ +public final class ExifProcess { + public static VersionNumber readVersion(String exifCmd) { + ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, + "-ver")); + try { + return new VersionNumber(process.readLine()); + } catch (IOException ex) { + throw new RuntimeException(String.format( + "Unable to check version number of ExifTool: %s", exifCmd)); + } finally { + process.close(); + } + } + + private final ReentrantLock closeLock = new ReentrantLock(false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader reader; + private final OutputStreamWriter writer; + private volatile boolean closed = false; + + public ExifProcess(boolean keepAlive, List args) { + this.keepAlive = keepAlive; + ExifTool.log.debug(String.format( + "Attempting to start ExifTool process using args: %s", args)); + try { + this.process = new ProcessBuilder(args).start(); + this.reader = new BufferedReader(new InputStreamReader( + process.getInputStream())); + this.writer = new OutputStreamWriter(process.getOutputStream()); + ExifTool.log.debug("\tSuccessful"); + } catch (Exception e) { + String message = "Unable to start external ExifTool process using the execution arguments: " + + args + + ". Ensure ExifTool is installed correctly and runs using the command path '" + + args.get(0) + + "' as specified by the 'exiftool.path' system property."; + + ExifTool.log.debug(message); + throw new RuntimeException(message, e); + } + } + + public synchronized Map sendToRunning(List args) + throws IOException { + if (!keepAlive) { + throw new IOException("Not KeepAlive Process"); + } + StringBuilder builder = new StringBuilder(); + for (String arg : args) { + builder.append(arg).append("\n"); + } + builder.append("-execute\n"); + writeFlush(builder.toString()); + return readResponse(); + } + + public synchronized void writeFlush(String message) throws IOException { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + writer.write(message); + writer.flush(); + } + + public synchronized String readLine() throws IOException { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + return reader.readLine(); + } + + public synchronized Map readResponse() throws IOException { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + ExifTool.log.debug("Reading response back from ExifTool..."); + Map resultMap = new HashMap(500); + String line; + + while ((line = reader.readLine()) != null) { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + String[] pair = ExifTool.TAG_VALUE_PATTERN.split(line, 2); + + if (pair.length == 2) { + resultMap.put(pair[0], pair[1]); + ExifTool.log.debug(String.format( + "\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); + } + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need to + * look for it and break from this loop when we see it otherwise + * this process will hang indefinitely blocking on the input stream + * with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } + } + return resultMap; + } + + public boolean isClosed() { + return closed; + } + + public void close() { + if (!closed) { + closeLock.lock(); + try { + if (!closed) { + closed = true; + try { + ExifTool.log.debug("Closing Read stream..."); + reader.close(); + ExifTool.log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + ExifTool.log + .debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); + writer.write("-stay_open\nFalse\n"); + writer.flush(); + } catch (IOException ex) { + // log.error(ex,ex); + } + + try { + ExifTool.log.debug("Closing Write stream..."); + writer.close(); + ExifTool.log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + ExifTool.log + .debug("Read/Write streams successfully closed."); + + try { + process.destroy(); + } catch (Exception e) { + // + } + // process = null; + + } + } finally { + closeLock.unlock(); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProxy.java new file mode 100644 index 00000000..f30df15b --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProxy.java @@ -0,0 +1,22 @@ +package com.thebuzzmedia.exiftool; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * A Proxy to an Exif Process, will restart if backing exif process died, or run + * new one on every call. + * + * @author Matt Gile, msgile + */ +public interface ExifProxy { + public void startup(); + + public Map execute(long runTimeoutMills, List args) + throws IOException; + + public boolean isRunning(); + + public void shutdown(); +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 0fe9c055..2415da24 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -15,29 +15,21 @@ */ package com.thebuzzmedia.exiftool; -import java.io.BufferedReader; import java.io.File; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; import java.lang.reflect.Array; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; -import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; -import java.util.Timer; -import java.util.TimerTask; import java.util.TreeMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; import org.slf4j.Logger; @@ -271,18 +263,17 @@ public class ExifTool { *

* Default value is "ExifTool Cleanup Thread". */ - private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; + static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; /** * Compiled {@link Pattern} of ": " used to split compact output from * ExifTool evenly into name/value pairs. */ - private static final Pattern TAG_VALUE_PATTERN = Pattern - .compile("\\s*:\\s*"); - private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); + static final String STREAM_CLOSED_MESSAGE = "Stream closed"; private static final String EXIF_DATE_FORMAT = "yyyy:MM:dd HH:mm:ss"; - private static Logger log = LoggerFactory.getLogger(ExifTool.class); + static Logger log = LoggerFactory.getLogger(ExifTool.class); private final Map featureSupportedMap = new HashMap(); private final Set featureEnabledSet = EnumSet @@ -505,13 +496,6 @@ public ExifTool setWriteOptions(WriteOptions options) { return this; } - // ================================================================================ - // OLD API - public static enum Format { - NUMERIC, - HUMAN_READABLE - } - public Map getImageMeta(File image, Tag... tags) throws IllegalArgumentException, SecurityException, IOException { return getImageMeta(image, Format.NUMERIC, tags); @@ -843,979 +827,5 @@ static MetadataTag toTag(String name) { } // ================================================================================ - /** - * Represents an external exif process. Works for both single use and keep - * alive modes. This is the actual process, with streams for reading and - * writing data. - */ - public static final class ExifProcess { - public static VersionNumber readVersion(String exifCmd) { - ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, - "-ver")); - try { - return new VersionNumber(process.readLine()); - } catch (IOException ex) { - throw new RuntimeException(String.format( - "Unable to check version number of ExifTool: %s", - exifCmd)); - } finally { - process.close(); - } - } - - private final ReentrantLock closeLock = new ReentrantLock(false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; - private volatile boolean closed = false; - - public ExifProcess(boolean keepAlive, List args) { - this.keepAlive = keepAlive; - log.debug(String - .format("Attempting to start ExifTool process using args: %s", - args)); - try { - this.process = new ProcessBuilder(args).start(); - this.reader = new BufferedReader(new InputStreamReader( - process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream()); - log.debug("\tSuccessful"); - } catch (Exception e) { - String message = "Unable to start external ExifTool process using the execution arguments: " - + args - + ". Ensure ExifTool is installed correctly and runs using the command path '" - + args.get(0) - + "' as specified by the 'exiftool.path' system property."; - - log.debug(message); - throw new RuntimeException(message, e); - } - } - - public synchronized Map sendToRunning(List args) - throws IOException { - if (!keepAlive) { - throw new IOException("Not KeepAlive Process"); - } - StringBuilder builder = new StringBuilder(); - for (String arg : args) { - builder.append(arg).append("\n"); - } - builder.append("-execute\n"); - writeFlush(builder.toString()); - return readResponse(); - } - - public synchronized void writeFlush(String message) throws IOException { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - writer.write(message); - writer.flush(); - } - - public synchronized String readLine() throws IOException { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - return reader.readLine(); - } - - public synchronized Map readResponse() - throws IOException { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - Map resultMap = new HashMap(500); - String line; - - while ((line = reader.readLine()) != null) { - if (closed) - throw new IOException(STREAM_CLOSED_MESSAGE); - String[] pair = TAG_VALUE_PATTERN.split(line, 2); - - if (pair.length == 2) { - resultMap.put(pair[0], pair[1]); - log.debug(String.format("\tRead Tag [name=%s, value=%s]", - pair[0], pair[1])); - } - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need - * to look for it and break from this loop when we see it - * otherwise this process will hang indefinitely blocking on the - * input stream with no data to read. - */ - if (keepAlive && line.equals("{ready}")) { - break; - } - } - return resultMap; - } - - public boolean isClosed() { - return closed; - } - - public void close() { - if (!closed) { - closeLock.lock(); - try { - if (!closed) { - closed = true; - try { - log.debug("Closing Read stream..."); - reader.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - writer.write("-stay_open\nFalse\n"); - writer.flush(); - } catch (IOException ex) { - // log.error(ex,ex); - } - - try { - log.debug("Closing Write stream..."); - writer.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - log.debug("Read/Write streams successfully closed."); - - try { - process.destroy(); - } catch (Exception e) { - // - } - // process = null; - - } - } finally { - closeLock.unlock(); - } - } - } - } - - /** - * A Proxy to an Exif Process, will restart if backing exif process died, or - * run new one on every call. - * - * @author Matt Gile, msgile - */ - public interface ExifProxy { - public void startup(); - - public Map execute(long runTimeoutMills, - List args) throws IOException; - - public boolean isRunning(); - - public void shutdown(); - } - - /** - * Manages an external exif process in keep alive mode. - */ - public static class KeepAliveExifProxy implements ExifProxy { - private final List startupArgs; - private final AtomicBoolean shuttingDown = new AtomicBoolean(false); - private final Timer cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - private long inactivityTimeout = 0; - private volatile long lastRunStart = 0; - private volatile ExifProcess process; - - public KeepAliveExifProxy(String exifCmd, List baseArgs) { - inactivityTimeout = Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, - DEFAULT_PROCESS_CLEANUP_DELAY); - startupArgs = new ArrayList(baseArgs.size() + 5); - startupArgs.add(exifCmd); - startupArgs.addAll(Arrays.asList("-stay_open", "True")); - startupArgs.addAll(baseArgs); - startupArgs.addAll(Arrays.asList("-@", "-")); - // runs every minute to check if process has been inactive too long - cleanupTimer.schedule(new TimerTask() { - @Override - public void run() { - if (process != null && lastRunStart > 0 - && inactivityTimeout > 0) { - if ((System.currentTimeMillis() - lastRunStart) > inactivityTimeout) { - synchronized (this) { - if (process != null) { - process.close(); - } - } - } - } - } - }, 60 * 1000); // every minute - } - - public void setInactiveTimeout(long mills) { - this.inactivityTimeout = mills; - } - - @Override - public void startup() { - shuttingDown.set(false); - if (process == null || process.isClosed()) { - synchronized (this) { - if (process == null || process.isClosed()) { - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = new ExifProcess(true, startupArgs); - } - } - } - } - - @Override - public Map execute(final long runTimeoutMills, - List args) throws IOException { - lastRunStart = System.currentTimeMillis(); - int attempts = 0; - while (attempts < 3 && !shuttingDown.get()) { - attempts++; - if (process == null || process.isClosed()) { - synchronized (this) { - if (process == null || process.isClosed()) { - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = new ExifProcess(true, startupArgs); - } - } - } - TimerTask attemptTimer = null; - try { - if (runTimeoutMills > 0) { - attemptTimer = new TimerTask() { - @Override - public void run() { - if (process != null && !process.isClosed()) { - log.warn("Process ran too long closing, max " - + runTimeoutMills + " mills"); - process.close(); - } - } - }; - cleanupTimer.schedule(attemptTimer, runTimeoutMills); - } - log.debug("Streaming arguments to ExifTool process..."); - return process.sendToRunning(args); - } catch (IOException ex) { - if (STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) - && !shuttingDown.get()) { - // only catch "Stream Closed" error (happens when - // process has died) - log.warn(String - .format("Caught IOException(\"%s\"), will restart daemon", - STREAM_CLOSED_MESSAGE)); - process.close(); - } else { - throw ex; - } - } finally { - if (attemptTimer != null) - attemptTimer.cancel(); - } - } - if (shuttingDown.get()) { - throw new IOException("Shutting Down"); - } - throw new IOException("Ran out of attempts"); - } - - @Override - public boolean isRunning() { - return process != null && !process.isClosed(); - } - - @Override - public void shutdown() { - shuttingDown.set(true); - } - } - - public static class SingleUseExifProxy implements ExifProxy { - private final Timer cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - private final List baseArgs; - - public SingleUseExifProxy(String exifCmd, List defaultArgs) { - this.baseArgs = new ArrayList(defaultArgs.size() + 1); - this.baseArgs.add(exifCmd); - this.baseArgs.addAll(defaultArgs); - } - - @Override - public Map execute(final long runTimeoutMills, - List args) throws IOException { - List newArgs = new ArrayList(baseArgs.size() - + args.size()); - newArgs.addAll(baseArgs); - newArgs.addAll(args); - final ExifProcess process = new ExifProcess(false, newArgs); - TimerTask attemptTimer = null; - if (runTimeoutMills > 0) { - attemptTimer = new TimerTask() { - @Override - public void run() { - if (!process.isClosed()) { - log.warn("Process ran too long closing, max " - + runTimeoutMills + " mills"); - process.close(); - } - } - }; - cleanupTimer.schedule(attemptTimer, runTimeoutMills); - } - try { - return process.readResponse(); - } finally { - process.close(); - if (attemptTimer != null) - attemptTimer.cancel(); - } - } - - @Override - public void startup() { - ; - } - - @Override - public boolean isRunning() { - return false; - } - - @Override - public void shutdown() { - ; - } - } - - // ================================================================================ - /** - * All the read options, is immutable, copy on change, fluent style "with" - * setters. - */ - public static class ReadOptions { - private final long runTimeoutMills; - private final boolean convertTypes; - private final boolean numericOutput; - private final boolean showDuplicates; - private final boolean showEmptyTags; - - public ReadOptions() { - this(0, false, false, false, false); - } - - private ReadOptions(long runTimeoutMills, boolean convertTypes, - boolean numericOutput, boolean showDuplicates, - boolean showEmptyTags) { - this.runTimeoutMills = runTimeoutMills; - this.convertTypes = convertTypes; - this.numericOutput = numericOutput; - this.showDuplicates = showDuplicates; - this.showEmptyTags = showEmptyTags; - } - - @Override - public String toString() { - return String - .format("%s(runTimeout:%,d convertTypes:%s showDuplicates:%s showEmptyTags:%s)", - getClass().getSimpleName(), runTimeoutMills, - convertTypes, showDuplicates, showEmptyTags); - } - - /** - * Sets the maximum time a process can run - */ - public ReadOptions withRunTimeoutMills(long mills) { - return new ReadOptions(mills, convertTypes, numericOutput, - showDuplicates, showEmptyTags); - } - - /** - * By default all values will be returned as the strings printed by the - * exiftool. If this is enabled then {@link MetadataTag#getType()} is - * used to cast the string into a java type. - */ - public ReadOptions withConvertTypes(boolean enabled) { - return new ReadOptions(runTimeoutMills, enabled, numericOutput, - showDuplicates, showEmptyTags); - } - - /** - * Setting this to true will add the "-n" option causing the ExifTool to - * output of some tags to change. - *

- * ExifTool, via the -n command line arg, is capable of - * returning most values in their raw numeric form (e.g. - * Aperture="2.8010323841") as well as a more human-readable/friendly - * format (e.g. Aperture="2.8"). - *

- * While the {@link Tag}s defined on this class do provide a hint at the - * type of the result (see {@link MetadataTag#getType()}), that hint - * only applies when the numeric value is returned. - *

- * If the caller finds the human-readable format easier to process, Set - * this to false, the default. - *

- * In order to see the types of values that are returned when human - * readable is used (default), you can check the comprehensive - * ExifTool Tag Guide. - *

- * This makes sense with some values like Aperture that in numeric - * format end up returning as 14-decimal-place, high precision values - * that are near the intended value (e.g. "2.79999992203711" instead of - * just returning "2.8"). On the other hand, other values (like - * Orientation) are easier to parse when their numeric value (1-8) is - * returned instead of a much longer friendly name (e.g. - * "Mirror horizontal and rotate 270 CW"). - * - * Attempted from work done by - * - * @author Riyad Kalla (software@thebuzzmedia.com) - */ - public ReadOptions withNumericOutput(boolean enabled) { - return new ReadOptions(runTimeoutMills, convertTypes, enabled, - showDuplicates, showEmptyTags); - } - - /** - * If enabled will show tags which are duplicated between different tag - * regions, relates to the "-a" option in ExifTool. - */ - public ReadOptions withShowDuplicates(boolean enabled) { - return new ReadOptions(runTimeoutMills, convertTypes, - numericOutput, enabled, showEmptyTags); - } - - public ReadOptions withShowEmptyTags(boolean enabled) { - return new ReadOptions(runTimeoutMills, convertTypes, - numericOutput, showDuplicates, enabled); - } - } - - // ================================================================================ - /** - * All the write options, is immutable, copy on change, fluent style "with" - * setters. - */ - public static class WriteOptions { - private final long runTimeoutMills; - private final boolean deleteBackupFile; - - public WriteOptions() { - this(0, false); - } - - private WriteOptions(long runTimeoutMills, boolean deleteBackupFile) { - this.runTimeoutMills = runTimeoutMills; - this.deleteBackupFile = deleteBackupFile; - } - - @Override - public String toString() { - return String.format("%s(runTimeOut:%,d deleteBackupFile:%s)", - getClass().getSimpleName(), runTimeoutMills, - deleteBackupFile); - } - - public WriteOptions withRunTimeoutMills(long mills) { - return new WriteOptions(mills, deleteBackupFile); - } - - /** - * ExifTool automatically makes a backup copy a file before writing - * metadata tags in the form "file.ext_original", by default this tool - * will delete that original file after the writing is done. - */ - public WriteOptions withDeleteBackupFile(boolean enabled) { - return new WriteOptions(runTimeoutMills, enabled); - } - } - - // ================================================================================ - /** - * Enum used to define the different kinds of features in the native - * ExifTool executable that this class can help you take advantage of. - *

- * These flags are different from {@link Tag}s in that a "feature" is - * determined to be a special functionality of the underlying ExifTool - * executable that requires a different code-path in this class to take - * advantage of; for example, -stay_open True support. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Feature { - /** - * Enum used to specify that you wish to launch the underlying ExifTool - * process with -stay_open True support turned on that this - * class can then take advantage of. - *

- * Required ExifTool version is 8.36 or higher. - */ - STAY_OPEN(8, 36), - /** - * Acitves the MWG modules. The Metadata Working Group (MWG) recommends - * techniques to allow certain overlapping EXIF, IPTC and XMP tags to be - * reconciled when reading, and synchronized when writing. The MWG - * Composite tags below are designed to aid in the implementation of - * these recommendations. Will add the args " -use MWG" - * - * @see ExifTool - * MWG Docs !! Note these version numbers are not correct - */ - MWG_MODULE(8, 36), ; - - private VersionNumber requireVersion; - private Feature(int... numbers) { - this.requireVersion = new VersionNumber(numbers); - } - - /** - * Used to get the version of ExifTool required by this feature in order - * to work. - * - * @return the version of ExifTool required by this feature in order to - * work. - */ - VersionNumber getVersion() { - return requireVersion; - } - - boolean isSupported(VersionNumber exifVersionNumber) { - return requireVersion.isBeforeOrEqualTo(exifVersionNumber); - } - } - - // ================================================================================ - /** - * Version Number used to determine if one version is after another. - * - * @author Matt Gile, msgile - */ - static class VersionNumber { - private final int[] numbers; - - public VersionNumber(String str) { - String[] versionParts = str.trim().split("\\."); - this.numbers = new int[versionParts.length]; - for (int i = 0; i < versionParts.length; i++) { - numbers[i] = Integer.parseInt(versionParts[i]); - } - } - - public VersionNumber(int... numbers) { - this.numbers = numbers; - } - - public boolean isBeforeOrEqualTo(VersionNumber other) { - int max = Math.min(this.numbers.length, other.numbers.length); - for (int i = 0; i < max; i++) { - if (this.numbers[i] > other.numbers[i]) { - return false; - } else if (this.numbers[i] < other.numbers[i]) { - return true; - } - } - // assume missing number as zero, so if the current process number - // is more digits it is a higher version - return this.numbers.length <= other.numbers.length; - } - - @Override - public String toString() { - StringBuilder builder = new StringBuilder(); - for (int number : numbers) { - if (builder.length() > 0) { - builder.append("."); - } - builder.append(number); - } - return builder.toString(); - } - } - - // ================================================================================ - /** - * Base type for all "tag" passed to exiftool. The key is the value passed - * to the exiftool like "-creator". The Types is used for automatic type - * conversions. - * - */ - public interface MetadataTag { - /** - * Returns the values passed to exiftool - */ - public String getKey(); - - /** - * The types - */ - public Class getType(); - - public boolean isMapped(); - } - - // ================================================================================ - /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifTool. - *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default humanReadable is false. - *

- * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. - *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. - *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. - *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Tag implements MetadataTag { - // single entry tags - APERTURE("ApertureValue", Double.class), - AUTHOR("XPAuthor", String.class), - COLOR_SPACE("ColorSpace", Integer.class), - COMMENT("XPComment", String.class), - CONTRAST("Contrast", Integer.class), - CREATE_DATE("CreateDate", Date.class), - CREATION_DATE("CreationDate", Date.class), - DATE_CREATED("DateCreated", Date.class), - DATE_TIME_ORIGINAL("DateTimeOriginal", Date.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - FLASH("Flash", Integer.class), - FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), - FNUMBER("FNumber", String.class), - GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), - GPS_DATESTAMP("GPSDateStamp", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), - GPS_LONGITUDE("GPSLongitude", Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), - GPS_SPEED("GPSSpeed", Double.class), - GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), - IMAGE_WIDTH("ImageWidth", Integer.class), - ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), - LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), - MAKE("Make", String.class), - METERING_MODE("MeteringMode", Integer.class), - MODEL("Model", String.class), - ORIENTATION("Orientation", Integer.class), - OWNER_NAME("OwnerName", String.class), - RATING("Rating", Integer.class), - RATING_PERCENT("RatingPercent", Integer.class), - ROTATION("Rotation", Integer.class), - SATURATION("Saturation", Integer.class), - SENSING_METHOD("SensingMethod", Integer.class), - SHARPNESS("Sharpness", Integer.class), - SHUTTER_SPEED("ShutterSpeedValue", Double.class), - SOFTWARE("Software", String.class), - SUBJECT("XPSubject", String.class), - TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), - X_RESOLUTION("XResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), ; - - /** - * Used to get the {@link Tag} identified by the given, case-sensitive, - * tag name. - * - * @param name - * The case-sensitive name of the tag that will be searched - * for. - * - * @return the {@link Tag} identified by the given, case-sensitive, tag - * name or null if one couldn't be found. - */ - public static Tag forName(String name) { - for (Tag tag : Tag.values()) { - if (tag.getKey().equals(name)) { - return tag; - } - } - return null; - } - - public static Map toTagMap(Map values) { - Map tagMap = new EnumMap(Tag.class); - for (Tag tag : Tag.values()) { - if (values.containsKey(tag.getKey())) { - tagMap.put(tag, values.get(tag.getKey())); - } - } - return tagMap; - - } - - /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifTool process) into the type described - * by the associated {@link Tag}. - * - * @param - * The type of the returned value. - * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. - * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). - * - * @throws IllegalArgumentException - * if tag is null. - * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). - * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. - */ - @SuppressWarnings("unchecked") - public T parseValue(String value) throws IllegalArgumentException { - return (T) deserialize(getKey(), value, getType()); - } - - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ - public String getName() { - return name; - } - - /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifTool Tag Guide. - * - * @return a hint for the native type of this tag's value. - */ - @Override - public Class getType() { - return type; - } - - @Override - public String getKey() { - return name; - } - - @Override - public boolean isMapped() { - return true; - } - - private String name; - private Class type; - - private Tag(String name, Class type) { - this.name = name; - this.type = type; - } - } - - // ================================================================================ - public enum MwgTag implements MetadataTag { - LOCATION("Location", String.class), - CITY("City", String.class), - STATE("State", String.class), - COUNTRY("Country", String.class), - - COPYRIGHT("Copyright", String.class), - - DATE_TIME_ORIGINAL("DateTimeOriginal", Date.class), - CREATE_DATE("CreateDate", Date.class), - MODIFY_DATE("ModifyDate", Date.class), - - CREATOR("Creator", String.class), - DESCRIPTION("Description", String.class), - KEYWORDS("Keywords", String[].class), - - ORIENTATION("Orientation", Integer.class), - RATING("Rating", Integer.class), - - ; - - private String name; - private Class type; - - private MwgTag(String name, Class type) { - this.name = name; - this.type = type; - } - - @Override - public String getKey() { - return name; - } - - @Override - public Class getType() { - return type; - } - - @Override - public boolean isMapped() { - return true; - } - - @Override - public String toString() { - return name; - } - } - - // ================================================================================ - - /** - * A Custom Tag that the user defines. Used to cover tags not in the enum. - */ - public static class CustomTag implements MetadataTag { - private final String name; - private final Class type; - private final boolean mapped; - - public CustomTag(String name, Class type) { - this(name, type, !name.trim().endsWith(":all")); - } - - public CustomTag(String name, Class type, boolean mapped) { - this.name = name.trim(); - this.type = type; - this.mapped = mapped; - } - - @Override - public String getKey() { - return name; - } - - @Override - public Class getType() { - return type; - } - - @Override - public boolean isMapped() { - return mapped; - } - - @Override - public String toString() { - return getKey(); - } - } - - // ================================================================================ - public enum TagGroup implements MetadataTag { - EXIF("EXIF", "exif:all"), - IPTC("IPTC", "iptc:all"), - XMP("XMP", "xmp:all"), - ALL("ALL", "all"); - - private final String name; - private final String key; - - private TagGroup(String name, String key) { - this.name = name; - this.key = key; - } - - public String getName() { - return name; - } - - @Override - public String getKey() { - return key; - } - - @Override - public Class getType() { - return Void.class; - } - - @Override - public boolean isMapped() { - return false; - } - - } - - // ================================================================================ - /** - * Class used to define an exception that occurs when the caller attempts to - * use a {@link Feature} that the underlying native ExifTool install does - * not support (i.e. the version isn't new enough). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public class UnsupportedFeatureException extends RuntimeException { - private static final long serialVersionUID = -1332725983656030770L; - - public UnsupportedFeatureException(Feature feature) { - super( - "Use of feature [" - + feature.toString() - + "] requires version " - + feature.getVersion() - + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); - } - } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Feature.java b/src/main/java/com/thebuzzmedia/exiftool/Feature.java new file mode 100644 index 00000000..57e085ff --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Feature.java @@ -0,0 +1,58 @@ +package com.thebuzzmedia.exiftool; + +// ================================================================================ +/** + * Enum used to define the different kinds of features in the native ExifTool + * executable that this class can help you take advantage of. + *

+ * These flags are different from {@link Tag}s in that a "feature" is determined + * to be a special functionality of the underlying ExifTool executable that + * requires a different code-path in this class to take advantage of; for + * example, -stay_open True support. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public enum Feature { + /** + * Enum used to specify that you wish to launch the underlying ExifTool + * process with -stay_open True support turned on that this + * class can then take advantage of. + *

+ * Required ExifTool version is 8.36 or higher. + */ + STAY_OPEN(8, 36), + /** + * Acitves the MWG modules. The Metadata Working Group (MWG) recommends + * techniques to allow certain overlapping EXIF, IPTC and XMP tags to be + * reconciled when reading, and synchronized when writing. The MWG Composite + * tags below are designed to aid in the implementation of these + * recommendations. Will add the args " -use MWG" + * + * @see ExifTool + * MWG Docs !! Note these version numbers are not correct + */ + MWG_MODULE(8, 36), ; + + private VersionNumber requireVersion; + + private Feature(int... numbers) { + this.requireVersion = new VersionNumber(numbers); + } + + /** + * Used to get the version of ExifTool required by this feature in order to + * work. + * + * @return the version of ExifTool required by this feature in order to + * work. + */ + VersionNumber getVersion() { + return requireVersion; + } + + boolean isSupported(VersionNumber exifVersionNumber) { + return requireVersion.isBeforeOrEqualTo(exifVersionNumber); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Format.java b/src/main/java/com/thebuzzmedia/exiftool/Format.java new file mode 100644 index 00000000..aea3ab9a --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Format.java @@ -0,0 +1,8 @@ +package com.thebuzzmedia.exiftool; + +// ================================================================================ +// OLD API +public enum Format { + NUMERIC, + HUMAN_READABLE +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java new file mode 100644 index 00000000..59bc6963 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java @@ -0,0 +1,136 @@ +package com.thebuzzmedia.exiftool; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Manages an external exif process in keep alive mode. + */ +public class KeepAliveExifProxy implements ExifProxy { + private final List startupArgs; + private final AtomicBoolean shuttingDown = new AtomicBoolean(false); + private final Timer cleanupTimer = new Timer(ExifTool.CLEANUP_THREAD_NAME, + true); + private long inactivityTimeout = 0; + private volatile long lastRunStart = 0; + private volatile ExifProcess process; + + public KeepAliveExifProxy(String exifCmd, List baseArgs) { + inactivityTimeout = Long.getLong( + ExifTool.ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, + ExifTool.DEFAULT_PROCESS_CLEANUP_DELAY); + startupArgs = new ArrayList(baseArgs.size() + 5); + startupArgs.add(exifCmd); + startupArgs.addAll(Arrays.asList("-stay_open", "True")); + startupArgs.addAll(baseArgs); + startupArgs.addAll(Arrays.asList("-@", "-")); + // runs every minute to check if process has been inactive too long + cleanupTimer.schedule(new TimerTask() { + @Override + public void run() { + if (process != null && lastRunStart > 0 + && inactivityTimeout > 0) { + if ((System.currentTimeMillis() - lastRunStart) > inactivityTimeout) { + synchronized (this) { + if (process != null) { + process.close(); + } + } + } + } + } + }, 60 * 1000); // every minute + } + + public void setInactiveTimeout(long mills) { + this.inactivityTimeout = mills; + } + + @Override + public void startup() { + shuttingDown.set(false); + if (process == null || process.isClosed()) { + synchronized (this) { + if (process == null || process.isClosed()) { + ExifTool.log + .debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = new ExifProcess(true, startupArgs); + } + } + } + } + + @Override + public Map execute(final long runTimeoutMills, + List args) throws IOException { + lastRunStart = System.currentTimeMillis(); + int attempts = 0; + while (attempts < 3 && !shuttingDown.get()) { + attempts++; + if (process == null || process.isClosed()) { + synchronized (this) { + if (process == null || process.isClosed()) { + ExifTool.log + .debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = new ExifProcess(true, startupArgs); + } + } + } + TimerTask attemptTimer = null; + try { + if (runTimeoutMills > 0) { + attemptTimer = new TimerTask() { + @Override + public void run() { + if (process != null && !process.isClosed()) { + ExifTool.log + .warn("Process ran too long closing, max " + + runTimeoutMills + " mills"); + process.close(); + } + } + }; + cleanupTimer.schedule(attemptTimer, runTimeoutMills); + } + ExifTool.log + .debug("Streaming arguments to ExifTool process..."); + return process.sendToRunning(args); + } catch (IOException ex) { + if (ExifTool.STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) + && !shuttingDown.get()) { + // only catch "Stream Closed" error (happens when + // process has died) + ExifTool.log.warn(String.format( + "Caught IOException(\"%s\"), will restart daemon", + ExifTool.STREAM_CLOSED_MESSAGE)); + process.close(); + } else { + throw ex; + } + } finally { + if (attemptTimer != null) + attemptTimer.cancel(); + } + } + if (shuttingDown.get()) { + throw new IOException("Shutting Down"); + } + throw new IOException("Ran out of attempts"); + } + + @Override + public boolean isRunning() { + return process != null && !process.isClosed(); + } + + @Override + public void shutdown() { + shuttingDown.set(true); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java b/src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java new file mode 100644 index 00000000..8915f8a4 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java @@ -0,0 +1,22 @@ +package com.thebuzzmedia.exiftool; + +// ================================================================================ +/** + * Base type for all "tag" passed to exiftool. The key is the value passed to + * the exiftool like "-creator". The Types is used for automatic type + * conversions. + * + */ +public interface MetadataTag { + /** + * Returns the values passed to exiftool + */ + public String getKey(); + + /** + * The types + */ + public Class getType(); + + public boolean isMapped(); +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java b/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java new file mode 100644 index 00000000..67f4a002 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java @@ -0,0 +1,54 @@ +package com.thebuzzmedia.exiftool; + +import java.util.Date; + +// ================================================================================ +public enum MwgTag implements MetadataTag { + LOCATION("Location", String.class), + CITY("City", String.class), + STATE("State", String.class), + COUNTRY("Country", String.class), + + COPYRIGHT("Copyright", String.class), + + DATE_TIME_ORIGINAL("DateTimeOriginal", Date.class), + CREATE_DATE("CreateDate", Date.class), + MODIFY_DATE("ModifyDate", Date.class), + + CREATOR("Creator", String.class), + DESCRIPTION("Description", String.class), + KEYWORDS("Keywords", String[].class), + + ORIENTATION("Orientation", Integer.class), + RATING("Rating", Integer.class), + + ; + + private String name; + private Class type; + + private MwgTag(String name, Class type) { + this.name = name; + this.type = type; + } + + @Override + public String getKey() { + return name; + } + + @Override + public Class getType() { + return type; + } + + @Override + public boolean isMapped() { + return true; + } + + @Override + public String toString() { + return name; + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ReadOptions.java b/src/main/java/com/thebuzzmedia/exiftool/ReadOptions.java new file mode 100644 index 00000000..189992d5 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/ReadOptions.java @@ -0,0 +1,104 @@ +package com.thebuzzmedia.exiftool; + +// ================================================================================ +/** + * All the read options, is immutable, copy on change, fluent style "with" + * setters. + */ +public class ReadOptions { + final long runTimeoutMills; + final boolean convertTypes; + final boolean numericOutput; + final boolean showDuplicates; + final boolean showEmptyTags; + + public ReadOptions() { + this(0, false, false, false, false); + } + + private ReadOptions(long runTimeoutMills, boolean convertTypes, + boolean numericOutput, boolean showDuplicates, boolean showEmptyTags) { + this.runTimeoutMills = runTimeoutMills; + this.convertTypes = convertTypes; + this.numericOutput = numericOutput; + this.showDuplicates = showDuplicates; + this.showEmptyTags = showEmptyTags; + } + + @Override + public String toString() { + return String + .format("%s(runTimeout:%,d convertTypes:%s showDuplicates:%s showEmptyTags:%s)", + getClass().getSimpleName(), runTimeoutMills, + convertTypes, showDuplicates, showEmptyTags); + } + + /** + * Sets the maximum time a process can run + */ + public ReadOptions withRunTimeoutMills(long mills) { + return new ReadOptions(mills, convertTypes, numericOutput, + showDuplicates, showEmptyTags); + } + + /** + * By default all values will be returned as the strings printed by the + * exiftool. If this is enabled then {@link MetadataTag#getType()} is used + * to cast the string into a java type. + */ + public ReadOptions withConvertTypes(boolean enabled) { + return new ReadOptions(runTimeoutMills, enabled, numericOutput, + showDuplicates, showEmptyTags); + } + + /** + * Setting this to true will add the "-n" option causing the ExifTool to + * output of some tags to change. + *

+ * ExifTool, via the -n command line arg, is capable of + * returning most values in their raw numeric form (e.g. + * Aperture="2.8010323841") as well as a more human-readable/friendly format + * (e.g. Aperture="2.8"). + *

+ * While the {@link Tag}s defined on this class do provide a hint at the + * type of the result (see {@link MetadataTag#getType()}), that hint only + * applies when the numeric value is returned. + *

+ * If the caller finds the human-readable format easier to process, Set this + * to false, the default. + *

+ * In order to see the types of values that are returned when human readable + * is used (default), you can check the comprehensive + * ExifTool Tag Guide. + *

+ * This makes sense with some values like Aperture that in numeric format + * end up returning as 14-decimal-place, high precision values that are near + * the intended value (e.g. "2.79999992203711" instead of just returning + * "2.8"). On the other hand, other values (like Orientation) are easier to + * parse when their numeric value (1-8) is returned instead of a much longer + * friendly name (e.g. "Mirror horizontal and rotate 270 CW"). + * + * Attempted from work done by + * + * @author Riyad Kalla (software@thebuzzmedia.com) + */ + public ReadOptions withNumericOutput(boolean enabled) { + return new ReadOptions(runTimeoutMills, convertTypes, enabled, + showDuplicates, showEmptyTags); + } + + /** + * If enabled will show tags which are duplicated between different tag + * regions, relates to the "-a" option in ExifTool. + */ + public ReadOptions withShowDuplicates(boolean enabled) { + return new ReadOptions(runTimeoutMills, convertTypes, numericOutput, + enabled, showEmptyTags); + } + + public ReadOptions withShowEmptyTags(boolean enabled) { + return new ReadOptions(runTimeoutMills, convertTypes, numericOutput, + showDuplicates, enabled); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java new file mode 100644 index 00000000..dc6e0887 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java @@ -0,0 +1,66 @@ +package com.thebuzzmedia.exiftool; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +public class SingleUseExifProxy implements ExifProxy { + private final Timer cleanupTimer = new Timer(ExifTool.CLEANUP_THREAD_NAME, + true); + private final List baseArgs; + + public SingleUseExifProxy(String exifCmd, List defaultArgs) { + this.baseArgs = new ArrayList(defaultArgs.size() + 1); + this.baseArgs.add(exifCmd); + this.baseArgs.addAll(defaultArgs); + } + + @Override + public Map execute(final long runTimeoutMills, + List args) throws IOException { + List newArgs = new ArrayList(baseArgs.size() + + args.size()); + newArgs.addAll(baseArgs); + newArgs.addAll(args); + final ExifProcess process = new ExifProcess(false, newArgs); + TimerTask attemptTimer = null; + if (runTimeoutMills > 0) { + attemptTimer = new TimerTask() { + @Override + public void run() { + if (!process.isClosed()) { + ExifTool.log.warn("Process ran too long closing, max " + + runTimeoutMills + " mills"); + process.close(); + } + } + }; + cleanupTimer.schedule(attemptTimer, runTimeoutMills); + } + try { + return process.readResponse(); + } finally { + process.close(); + if (attemptTimer != null) + attemptTimer.cancel(); + } + } + + @Override + public void startup() { + ; + } + + @Override + public boolean isRunning() { + return false; + } + + @Override + public void shutdown() { + ; + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Tag.java b/src/main/java/com/thebuzzmedia/exiftool/Tag.java new file mode 100644 index 00000000..cf2ac2ed --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Tag.java @@ -0,0 +1,202 @@ +package com.thebuzzmedia.exiftool; + +import java.util.Date; +import java.util.EnumMap; +import java.util.Map; + +// ================================================================================ +/** + * Enum used to pre-define a convenient list of tags that can be easily + * extracted from images using this class with an external install of ExifTool. + *

+ * Each tag defined also includes a type hint for the parsed value associated + * with it when the default humanReadable is false. + *

+ * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or + * process the returned {@link String} values any way they wish. + *

Tag Support

+ * ExifTool is capable of parsing almost every tag known to man (1000+), but + * this class makes an attempt at pre-defining a convenient list of the most + * common tags for use. + *

+ * This list was determined by looking at the common metadata tag values written + * to images by popular mobile devices (iPhone, Android) as well as cameras like + * simple point and shoots as well as DSLRs. As an additional source of input + * the list of supported/common EXIF formats that Flickr supports was also + * reviewed to ensure the most common/useful tags were being covered here. + *

+ * Please email me or file an issue if + * you think this list is missing a commonly used tag that should be added to + * it. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public enum Tag implements MetadataTag { + // single entry tags + APERTURE("ApertureValue", Double.class), + AUTHOR("XPAuthor", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATE_DATE("CreateDate", Date.class), + CREATION_DATE("CreationDate", Date.class), + DATE_CREATED("DateCreated", Date.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", Date.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + FLASH("Flash", Integer.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + FNUMBER("FNumber", String.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_DATESTAMP("GPSDateStamp", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SENSING_METHOD("SensingMethod", Integer.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), ; + + /** + * Used to get the {@link Tag} identified by the given, case-sensitive, tag + * name. + * + * @param name + * The case-sensitive name of the tag that will be searched for. + * + * @return the {@link Tag} identified by the given, case-sensitive, tag name + * or null if one couldn't be found. + */ + public static Tag forName(String name) { + for (Tag tag : Tag.values()) { + if (tag.getKey().equals(name)) { + return tag; + } + } + return null; + } + + public static Map toTagMap(Map values) { + Map tagMap = new EnumMap(Tag.class); + for (Tag tag : Tag.values()) { + if (values.containsKey(tag.getKey())) { + tagMap.put(tag, values.get(tag.getKey())); + } + } + return tagMap; + + } + + /** + * Convenience method used to convert the given string Tag value (returned + * from the external ExifTool process) into the type described by the + * associated {@link Tag}. + * + * @param + * The type of the returned value. + * @param value + * The {@link String} representation of the tag's value as parsed + * from the image. + * + * @return the given string value converted to a native Java type (e.g. + * Integer, Double, etc.). + * + * @throws IllegalArgumentException + * if tag is null. + * @throws NumberFormatException + * if any exception occurs while trying to parse the given + * value to any of the supported numeric types in + * Java via calls to the respective parseXXX + * methods defined on all the numeric wrapper classes (e.g. + * {@link Integer#parseInt(String)} , + * {@link Double#parseDouble(String)} and so on). + * @throws ClassCastException + * if the type defined by T is incompatible with + * the type defined by {@link Tag#getType()} returned by the + * tag argument passed in. This class performs an + * implicit/unchecked cast to the type T before + * returning the parsed result of the type indicated by + * {@link Tag#getType()}. If the types do not match, a + * ClassCastException will be generated by the VM. + */ + @SuppressWarnings("unchecked") + public T parseValue(String value) throws IllegalArgumentException { + return (T) ExifTool.deserialize(getKey(), value, getType()); + } + + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ + public String getName() { + return name; + } + + /** + * Used to get a hint for the native type of this tag's value as specified + * by Phil Harvey's ExifTool Tag Guide. + * + * @return a hint for the native type of this tag's value. + */ + @Override + public Class getType() { + return type; + } + + @Override + public String getKey() { + return name; + } + + @Override + public boolean isMapped() { + return true; + } + + private String name; + private Class type; + + private Tag(String name, Class type) { + this.name = name; + this.type = type; + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java b/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java new file mode 100644 index 00000000..16d88a8c --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java @@ -0,0 +1,37 @@ +package com.thebuzzmedia.exiftool; + +// ================================================================================ +public enum TagGroup implements MetadataTag { + EXIF("EXIF", "exif:all"), + IPTC("IPTC", "iptc:all"), + XMP("XMP", "xmp:all"), + ALL("ALL", "all"); + + private final String name; + private final String key; + + private TagGroup(String name, String key) { + this.name = name; + this.key = key; + } + + public String getName() { + return name; + } + + @Override + public String getKey() { + return key; + } + + @Override + public Class getType() { + return Void.class; + } + + @Override + public boolean isMapped() { + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java b/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java new file mode 100644 index 00000000..8fe21a33 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java @@ -0,0 +1,23 @@ +package com.thebuzzmedia.exiftool; + +// ================================================================================ +/** + * Class used to define an exception that occurs when the caller attempts to use + * a {@link Feature} that the underlying native ExifTool install does not + * support (i.e. the version isn't new enough). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public class UnsupportedFeatureException extends RuntimeException { + private static final long serialVersionUID = -1332725983656030770L; + + public UnsupportedFeatureException(Feature feature) { + super( + "Use of feature [" + + feature.toString() + + "] requires version " + + feature.getVersion() + + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java b/src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java new file mode 100644 index 00000000..ede4b748 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java @@ -0,0 +1,49 @@ +package com.thebuzzmedia.exiftool; + +// ================================================================================ +/** + * Version Number used to determine if one version is after another. + * + * @author Matt Gile, msgile + */ +class VersionNumber { + private final int[] numbers; + + public VersionNumber(String str) { + String[] versionParts = str.trim().split("\\."); + this.numbers = new int[versionParts.length]; + for (int i = 0; i < versionParts.length; i++) { + numbers[i] = Integer.parseInt(versionParts[i]); + } + } + + public VersionNumber(int... numbers) { + this.numbers = numbers; + } + + public boolean isBeforeOrEqualTo(VersionNumber other) { + int max = Math.min(this.numbers.length, other.numbers.length); + for (int i = 0; i < max; i++) { + if (this.numbers[i] > other.numbers[i]) { + return false; + } else if (this.numbers[i] < other.numbers[i]) { + return true; + } + } + // assume missing number as zero, so if the current process number + // is more digits it is a higher version + return this.numbers.length <= other.numbers.length; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + for (int number : numbers) { + if (builder.length() > 0) { + builder.append("."); + } + builder.append(number); + } + return builder.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/WriteOptions.java b/src/main/java/com/thebuzzmedia/exiftool/WriteOptions.java new file mode 100644 index 00000000..447e16d6 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/WriteOptions.java @@ -0,0 +1,39 @@ +package com.thebuzzmedia.exiftool; + +// ================================================================================ +/** + * All the write options, is immutable, copy on change, fluent style "with" + * setters. + */ +public class WriteOptions { + final long runTimeoutMills; + final boolean deleteBackupFile; + + public WriteOptions() { + this(0, false); + } + + private WriteOptions(long runTimeoutMills, boolean deleteBackupFile) { + this.runTimeoutMills = runTimeoutMills; + this.deleteBackupFile = deleteBackupFile; + } + + @Override + public String toString() { + return String.format("%s(runTimeOut:%,d deleteBackupFile:%s)", + getClass().getSimpleName(), runTimeoutMills, deleteBackupFile); + } + + public WriteOptions withRunTimeoutMills(long mills) { + return new WriteOptions(mills, deleteBackupFile); + } + + /** + * ExifTool automatically makes a backup copy a file before writing metadata + * tags in the form "file.ext_original", by default this tool will delete + * that original file after the writing is done. + */ + public WriteOptions withDeleteBackupFile(boolean enabled) { + return new WriteOptions(runTimeoutMills, enabled); + } +} \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index 8ec7233b..22a94a68 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -6,9 +6,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Tag; - public class Benchmark { public static final int ITERATIONS = 25; diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index 35439204..2d7e0fa1 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -7,9 +7,6 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Format; - public class Example { private static Logger log = LoggerFactory.getLogger(Example.class); @@ -27,9 +24,9 @@ public static void main(String[] args) throws IOException, // list all first-class tags for (File f : images) { log.info("\n[{}]", f.getName()); - Map metadata = tool.getImageMeta(f, - Format.HUMAN_READABLE, ExifTool.Tag.values()); - for (ExifTool.Tag key : metadata.keySet()) { + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, Tag.values()); + for (Tag key : metadata.keySet()) { log.info(String.format("\t\t%s: %s", key.getKey(), metadata.get(key))); } @@ -39,9 +36,9 @@ public static void main(String[] args) throws IOException, // list all XMP, IPTC and XMP tags File f = new File(TEST_FILES_PATH + "/kureckjones_jett_075_02-cropped.tif"); - for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] { - ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, - ExifTool.TagGroup.XMP }) { + for (TagGroup tagGroup : new TagGroup[] { + TagGroup.EXIF, TagGroup.IPTC, + TagGroup.XMP }) { Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, tagGroup); log.info(tagGroup.getKey()); diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 52756adc..468d24fe 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -44,14 +44,14 @@ public void testSingleTool() throws Exception { tool.shutdown(); } - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + tool = new ExifTool(Feature.STAY_OPEN); try { assertTrue(runTests(tool, "")); } finally { tool.shutdown(); } - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + tool = new ExifTool(Feature.STAY_OPEN); try { tool.startup(); assertTrue(runTests(tool, "")); @@ -72,7 +72,7 @@ public void testConcurrent() throws Exception { @Override public void run() { log.info(getName() + ": starting"); - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); try { runTests(tool, getName()); log.info(getName() + ": finished"); @@ -99,7 +99,7 @@ public void run() { @Test public void testManyThreadsOneTool() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + final ExifTool tool = new ExifTool(Feature.STAY_OPEN); try { Thread[] threads = new Thread[20]; for (int i = 0; i < threads.length; i++) { @@ -134,7 +134,7 @@ public void run() { @Test public void testProcessTimeout() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + final ExifTool tool = new ExifTool(Feature.STAY_OPEN); try { tool.setRunTimeout(1); runTests(tool, "will fail"); @@ -149,52 +149,52 @@ public void testProcessTimeout() throws Exception { public boolean runTests(ExifTool tool, String runId) throws IOException, URISyntaxException { - Map metadata; + Map metadata; File imageFile; - Set keys; - ExifTool.Tag tag; + Set keys; + Tag tag; URL url = getClass() .getResource("/kureckjones_jett_075_02-cropped.tif"); imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.values()); + metadata = tool.getImageMeta(imageFile, Format.HUMAN_READABLE, + Tag.values()); assertEquals(22, metadata.size()); keys = metadata.keySet(); - tag = ExifTool.Tag.IMAGE_WIDTH; + tag = Tag.IMAGE_WIDTH; assertTrue(keys.contains(tag)); assertEquals(728, tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.IMAGE_HEIGHT; + tag = Tag.IMAGE_HEIGHT; assertEquals(825, tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.MODEL; + tag = Tag.MODEL; assertEquals("P 45+", tag.parseValue(metadata.get(tag))); log.info(runId + ": finished image 1"); url = getClass().getResource("/nexus-s-electric-cars.jpg"); imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.values()); + metadata = tool.getImageMeta(imageFile, Format.HUMAN_READABLE, + Tag.values()); assertEquals(23, metadata.size()); keys = metadata.keySet(); - tag = ExifTool.Tag.IMAGE_WIDTH; + tag = Tag.IMAGE_WIDTH; assertTrue(keys.contains(tag)); assertEquals(2560, tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.IMAGE_HEIGHT; + tag = Tag.IMAGE_HEIGHT; assertEquals(1920, tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.MODEL; + tag = Tag.MODEL; assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.ISO; + tag = Tag.ISO; assertEquals(50, tag.parseValue(metadata.get(tag))); - tag = ExifTool.Tag.SHUTTER_SPEED; + tag = Tag.SHUTTER_SPEED; assertEquals("1/64", metadata.get(tag)); assertEquals(0.015625, tag.parseValue(metadata.get(tag))); log.info(runId + ": finished image 2"); @@ -203,14 +203,14 @@ public boolean runTests(ExifTool tool, String runId) throws IOException, @Test public void testGroupTags() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); try { Map metadata; URL url = getClass().getResource("/iptc_test-photoshop.jpg"); File f = new File(url.toURI()); - metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, - ExifTool.TagGroup.IPTC); + metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, + TagGroup.IPTC); assertEquals(17, metadata.size()); assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); assertEquals("IPTC Status: Copyright Notice", @@ -228,24 +228,24 @@ public void testGroupTags() throws Exception { @Test public void testTag() { assertEquals("string value", "John Doe", - ExifTool.Tag.AUTHOR.parseValue("John Doe")); - assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); + Tag.AUTHOR.parseValue("John Doe")); + assertEquals("integer value", 200, Tag.ISO.parseValue("200")); assertEquals("double value, from fraction", .25, - ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); + Tag.SHUTTER_SPEED.parseValue("1/4")); assertEquals("double value, from decimal", .25, - ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); + Tag.SHUTTER_SPEED.parseValue(".25")); } @Test public void testVersionNumber() { - assertTrue(new ExifTool.VersionNumber("1.2") - .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); - assertTrue(new ExifTool.VersionNumber(1, 2) - .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); - assertTrue(new ExifTool.VersionNumber(1, 2, 3) - .isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); - assertTrue(new ExifTool.VersionNumber(1, 2, 3) - .isBeforeOrEqualTo(new ExifTool.VersionNumber(2, 1))); + assertTrue(new VersionNumber("1.2") + .isBeforeOrEqualTo(new VersionNumber("1.2.3"))); + assertTrue(new VersionNumber(1, 2) + .isBeforeOrEqualTo(new VersionNumber("1.2"))); + assertTrue(new VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new VersionNumber("1.3"))); + assertTrue(new VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new VersionNumber(2, 1))); } @Test @@ -255,25 +255,25 @@ public void testWriteTagStringNonDaemon() throws Exception { Path imageFile = Paths.get(url.toURI()); // Check the value is correct at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Now change it String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check that it's updated metadata = tool .getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -286,30 +286,30 @@ public void testWriteTagStringNonDaemon() throws Exception { @Test public void testWriteTagString() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Check the value is correct at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Now change it String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check that it's updated metadata = tool .getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -322,20 +322,20 @@ public void testWriteTagString() throws Exception { @Test public void testWriteTagStringInvalidformat() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Check the value is correct at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); String newDate = "2egek opkpgrpok"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); // Now change it to an invalid value which should fail tool.addImageMetadata(imageFile.toFile(), newValues); @@ -343,10 +343,10 @@ public void testWriteTagStringInvalidformat() throws Exception { // Finally check that it's not updated metadata = tool .getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -367,23 +367,23 @@ public void testWriteTagNumberNonDaemon() throws Exception { Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.ORIENTATION); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION); assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); + Map newValues = new HashMap(); + newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check the updated value metadata = tool.getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); + Format.HUMAN_READABLE, Tag.ORIENTATION); assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(ExifTool.Tag.ORIENTATION)); + metadata.get(Tag.ORIENTATION)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -396,28 +396,28 @@ public void testWriteTagNumberNonDaemon() throws Exception { @Test public void testWriteTagNumber() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.ORIENTATION); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION); assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); + Map newValues = new HashMap(); + newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check the updated value metadata = tool.getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); + Format.HUMAN_READABLE, Tag.ORIENTATION); assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(ExifTool.Tag.ORIENTATION)); + metadata.get(Tag.ORIENTATION)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -430,35 +430,35 @@ public void testWriteTagNumber() throws Exception { @Test public void testWriteMultipleTag() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Now change them String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check the updated value metadata = tool.getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Format.HUMAN_READABLE, Tag.ORIENTATION, + Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(ExifTool.Tag.ORIENTATION)); + metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -476,30 +476,30 @@ public void testWriteMultipleTagNonDaemon() throws Exception { Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, - ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Now change them String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); tool.writeMetadata(imageFile.toFile(), newValues); // Finally check the updated value metadata = tool.getImageMeta(imageFile.toFile(), - ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, - ExifTool.Tag.DATE_TIME_ORIGINAL); + Format.HUMAN_READABLE, Tag.ORIENTATION, + Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(ExifTool.Tag.ORIENTATION)); + metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); + metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is not // affected by the change @@ -512,7 +512,7 @@ public void testWriteMultipleTagNonDaemon() throws Exception { @Test public void testWritingWithImplicitTypes() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.MWG_MODULE); + ExifTool tool = new ExifTool(Feature.MWG_MODULE); tool.setReadOptions(tool.getReadOptions().withNumericOutput(true) .withConvertTypes(true)); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); @@ -523,38 +523,38 @@ public void testWritingWithImplicitTypes() throws Exception { "yyyy:MM:dd hh:mm:ss"); Map metadata = tool.readMetadata(imageFile, - ExifTool.Tag.ORIENTATION, - ExifTool.MwgTag.DATE_TIME_ORIGINAL); + Tag.ORIENTATION, + MwgTag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", 1, - metadata.get(ExifTool.Tag.ORIENTATION)); + metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", formatter.parse("2010:12:10 17:07:05"), - metadata.get(ExifTool.MwgTag.DATE_TIME_ORIGINAL)); + metadata.get(MwgTag.DATE_TIME_ORIGINAL)); // Now change them Map data = new HashMap(); Date dateTimeOrig = formatter.parse("2014:01:23 10:07:05"); - data.put(ExifTool.MwgTag.DATE_TIME_ORIGINAL, dateTimeOrig); - data.put(ExifTool.Tag.ORIENTATION, 3); + data.put(MwgTag.DATE_TIME_ORIGINAL, dateTimeOrig); + data.put(Tag.ORIENTATION, 3); Date createDate = formatter.parse("2013:02:21 10:07:05"); - data.put(ExifTool.MwgTag.CREATE_DATE, createDate.getTime()); - data.put(ExifTool.MwgTag.KEYWORDS, new String[] { "a", "b", "c" }); + data.put(MwgTag.CREATE_DATE, createDate.getTime()); + data.put(MwgTag.KEYWORDS, new String[] { "a", "b", "c" }); tool.writeMetadata( tool.getWriteOptions().withDeleteBackupFile(false), imageFile, data); // Finally check the updated value - metadata = tool.readMetadata(imageFile, ExifTool.Tag.ORIENTATION, - imageFile, ExifTool.MwgTag.DATE_TIME_ORIGINAL, - ExifTool.MwgTag.CREATE_DATE, ExifTool.MwgTag.KEYWORDS); + metadata = tool.readMetadata(imageFile, Tag.ORIENTATION, + imageFile, MwgTag.DATE_TIME_ORIGINAL, + MwgTag.CREATE_DATE, MwgTag.KEYWORDS); assertEquals("Orientation tag updated value is wrong", 3, - metadata.get(ExifTool.Tag.ORIENTATION)); + metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, - metadata.get(ExifTool.MwgTag.DATE_TIME_ORIGINAL)); + metadata.get(MwgTag.DATE_TIME_ORIGINAL)); assertEquals("CreateDate tag is wrong", createDate, - metadata.get(ExifTool.MwgTag.CREATE_DATE)); + metadata.get(MwgTag.CREATE_DATE)); assertEquals("Keywords tag is wrong", "a", - ((String[]) metadata.get(ExifTool.MwgTag.KEYWORDS))[0]); + ((String[]) metadata.get(MwgTag.KEYWORDS))[0]); // Finally copy the source file back over so the next test run is // not affected by the change From 99d25eefee62faa5f6b7bff56ef9793ae6646fff Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 14:15:41 +0300 Subject: [PATCH 042/148] - extract classes in new files to ease up the integration process --- .../exiftool/CleanupTimerTask.java | 30 + .../com/thebuzzmedia/exiftool/ExifTool.java | 655 +----------------- .../com/thebuzzmedia/exiftool/Feature.java | 41 ++ .../com/thebuzzmedia/exiftool/Format.java | 41 ++ .../com/thebuzzmedia/exiftool/IOStream.java | 50 ++ .../com/thebuzzmedia/exiftool/Sidecar.java | 216 ++++++ .../java/com/thebuzzmedia/exiftool/Tag.java | 252 +++++++ .../exiftool/UnsupportedFeatureException.java | 28 + .../com/thebuzzmedia/exiftool/Benchmark.java | 3 - .../com/thebuzzmedia/exiftool/Example.java | 4 - 10 files changed, 665 insertions(+), 655 deletions(-) create mode 100644 src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Feature.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Format.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/IOStream.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Sidecar.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Tag.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java diff --git a/src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java b/src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java new file mode 100644 index 00000000..2c9103d3 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java @@ -0,0 +1,30 @@ +package com.thebuzzmedia.exiftool; + +import java.util.Timer; +import java.util.TimerTask; + +/** + * Class used to represent the {@link TimerTask} used by the internal auto + * cleanup {@link Timer} to call {@link ExifTool#close()} after a specified + * interval of inactivity. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +class CleanupTimerTask extends TimerTask { + private ExifTool owner; + + public CleanupTimerTask(ExifTool owner) throws IllegalArgumentException { + if (owner == null) + throw new IllegalArgumentException( + "owner cannot be null and must refer to the ExifTool instance creating this task."); + + this.owner = owner; + } + + @Override + public void run() { + ExifTool.log("\tAuto cleanup task running..."); + owner.close(); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index be279f30..bd2fad39 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -328,7 +328,7 @@ public class ExifTool { * support one time during each run of the VM and never again during the * session of that running VM. */ - protected static final Map FEATURE_SUPPORT_MAP = new HashMap(); + protected static final Map FEATURE_SUPPORT_MAP = new HashMap(); /** * Static list of args used to execute ExifTool using the '-ver' flag in @@ -540,402 +540,20 @@ protected static IOStream startExifToolProcess(List args) return streams; } - /** - * Simple class used to house the read/write streams used to communicate - * with an external ExifTool process as well as the logic used to safely - * close the streams when no longer needed. - *

- * This class is just a convenient way to group and manage the read/write - * streams as opposed to making them dangling member variables off of - * ExifTool directly. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - private static class IOStream { - BufferedReader reader; - OutputStreamWriter writer; - - public IOStream(BufferedReader reader, OutputStreamWriter writer) { - this.reader = reader; - this.writer = writer; - } - - public void close() { - try { - log("\tClosing Read stream..."); - reader.close(); - log("\t\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log("\tClosing Write stream..."); - writer.close(); - log("\t\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - // Null the stream references. - reader = null; - writer = null; - - log("\tRead/Write streams successfully closed."); - } - } - - /** - * Enum used to define the different kinds of features in the native - * ExifTool executable that this class can help you take advantage of. - *

- * These flags are different from {@link Tag}s in that a "feature" is - * determined to be a special functionality of the underlying ExifTool - * executable that requires a different code-path in this class to take - * advantage of; for example, -stay_open True support. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Feature { - /** - * Enum used to specify that you wish to launch the underlying ExifTool - * process with -stay_open True support turned on that this - * class can then take advantage of. - *

- * Required ExifTool version is 8.36 or higher. - */ - STAY_OPEN("8.36"); - - /** - * Used to get the version of ExifTool required by this feature in order - * to work. - * - * @return the version of ExifTool required by this feature in order to - * work. - */ - public String getVersion() { - return version; - } - - private String version; - - private Feature(String version) { - this.version = version; - } - } - - /** - * Enum used to define the 2 different output formats that {@link Tag} - * values can be returned in: numeric or human-readable text. - *

- * ExifTool, via the -n command line arg, is capable of - * returning most values in their raw numeric form (e.g. - * Aperture="2.8010323841") as well as a more human-readable/friendly format - * (e.g. Aperture="2.8"). - *

- * While the {@link Tag}s defined on this class do provide a hint at the - * type of the result (see {@link Tag#getType()}), that hint only applies - * when the {@link Format#NUMERIC} form of the value is returned. - *

- * If the caller finds the human-readable format easier to process, - * {@link Format#HUMAN_READABLE} can be specified when calling - * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned - * {@link String} values processed manually by the caller. - *

- * In order to see the types of values that are returned when - * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive - * ExifTool Tag Guide. - *

- * This makes sense with some values like Aperture that in - * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high - * precision values that are near the intended value (e.g. - * "2.79999992203711" instead of just returning "2.8"). On the other hand, - * other values (like Orientation) are easier to parse when their numeric - * value (1-8) is returned instead of a much longer friendly name (e.g. - * "Mirror horizontal and rotate 270 CW"). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Format { - NUMERIC, - HUMAN_READABLE; - } - - /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifTool. - *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default {@link Format#NUMERIC} value format - * is used. - *

- * All replies from ExifTool are parsed as {@link String}s and using the - * type hint from each {@link Tag} can easily be converted to the correct - * data format by using the provided {@link Tag#parseValue(Tag, String)} - * method. - *

- * This class does not make an attempt at converting the value automatically - * in case the caller decides they would prefer tag values returned in - * {@link Format#HUMAN_READABLE} format and to avoid any compatibility - * issues with future versions of ExifTool if a tag's return value is - * changed. This approach to leaving returned tag values as strings until - * the caller decides they want to parse them is a safer and more robust - * approach. - *

- * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. - *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. - *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. - *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Tag { - APERTURE("ApertureValue", Double.class), - ARTIST("Artist", String.class), - AUTHOR("XPAuthor", String.class), - BODY_SERIAL_NUMBER("BodySerialNumber", String.class), - CAMERA_SERIAL_NUMBER("CameraSerialNumber", String.class), - CAPTION_ABSTRACT("Caption-Abstract", String.class), - COLOR_SPACE("ColorSpace", Integer.class), - COMMENT("XPComment", String.class), - CONTRAST("Contrast", Integer.class), - CREATE_DATE("CreateDate", String.class), - COPYRIGHT("Copyright", String.class), - COPYRIGHT_NOTICE("CopyrightNotice", String.class), - CREATION_DATE("CreationDate", String.class), - CREATOR("Creator", String.class), - DATE_CREATED("DateCreated", String.class), - DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), - DEVICE_SERIAL_NUMBER("DeviceSerialNumber", String.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - EXTENDER_SERIAL_NUMBER("ExtenderSerialNumber", String.class), - FILE_TYPE("FileType", String.class), - FLASH("Flash", Integer.class), - FLASH_SERIAL_NUMBER("FlashSerialNumber", String.class), - FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), - GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), - GPS_DATESTAMP("GPSDateStamp", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), - GPS_LONGITUDE("GPSLongitude", Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), - GPS_SPEED("GPSSpeed", Double.class), - GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), - IMAGE_UNIQUE_ID("ImageUniqueID", String.class), - IMAGE_WIDTH("ImageWidth", Integer.class), - INTERNAL_SERIAL_NUMBER("InternalSerialNumber", String.class), - IPTC_KEYWORDS("Keywords", String.class), - ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), - LENS("Lens", String.class), - LENS_ID("LensID", String.class), - LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), - LENS_SERIAL_NUMBER("LensSerialNumber", String.class), - MAKE("Make", String.class), - METERING_MODE("MeteringMode", Integer.class), - MODEL("Model", String.class), - OBJECT_NAME("ObjectName", String.class), - ORIENTATION("Orientation", Integer.class), - OWNER_NAME("OwnerName", String.class), - RATING("Rating", Integer.class), - RATING_PERCENT("RatingPercent", Integer.class), - ROTATION("Rotation", Integer.class), - SATURATION("Saturation", Integer.class), - SCANNER_SERIAL_NUMBER("ScannerSerialNumber", String.class), - SENSING_METHOD("SensingMethod", Integer.class), - SERIAL_NUMBER("SerialNumber", String.class), - SHARPNESS("Sharpness", Integer.class), - SHUTTER_SPEED("ShutterSpeedValue", Double.class), - SOFTWARE("Software", String.class), - SOURCE_SERIAL_NUMBER("SourceSerialNumber", String.class), - SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), - SUBJECT("XPSubject", String.class), - TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), - X_RESOLUTION("XResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), ; - private static final Map TAG_LOOKUP_MAP; - - /** - * Initializer used to init the static final tag/name - * lookup map used by all instances of this class. - */ - static { - Tag[] values = Tag.values(); - TAG_LOOKUP_MAP = new HashMap( - values.length * 3); - - for (int i = 0; i < values.length; i++) { - Tag tag = values[i]; - TAG_LOOKUP_MAP.put(tag.name, tag); - } - } - - /** - * Used to get the {@link Tag} identified by the given, case-sensitive, - * tag name. - * - * @param name - * The case-sensitive name of the tag that will be searched - * for. - * - * @return the {@link Tag} identified by the given, case-sensitive, tag - * name or null if one couldn't be found. - */ - public static Tag forName(String name) { - return TAG_LOOKUP_MAP.get(name); - } - - /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifTool process) into the type described - * by the associated {@link Tag}. - * - * @param - * The type of the returned value. - * @param tag - * The {@link Tag} whose value this is. The tag's type hint - * will be queried to determine how to convert this string - * value. - * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. - * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). - * - * @throws IllegalArgumentException - * if tag is null. - * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). - * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. - */ - @SuppressWarnings("unchecked") - public static T parseValue(Tag tag, String value) - throws IllegalArgumentException, NumberFormatException { - if (tag == null) - throw new IllegalArgumentException("tag cannot be null"); - - T result = null; - - // Check that there is work to do first. - if (value != null) { - Class type = tag.type; - - if (Boolean.class.isAssignableFrom(type)) - result = (T) Boolean.valueOf(value); - else if (Byte.class.isAssignableFrom(type)) - result = (T) Byte.valueOf(Byte.parseByte(value)); - else if (Integer.class.isAssignableFrom(type)) - result = (T) Integer.valueOf(Integer.parseInt(value)); - else if (Short.class.isAssignableFrom(type)) - result = (T) Short.valueOf(Short.parseShort(value)); - else if (Long.class.isAssignableFrom(type)) - result = (T) Long.valueOf(Long.parseLong(value)); - else if (Float.class.isAssignableFrom(type)) - result = (T) Float.valueOf(Float.parseFloat(value)); - else if (Double.class.isAssignableFrom(type)) - result = (T) Double.valueOf(Double.parseDouble(value)); - else if (Character.class.isAssignableFrom(type)) - result = (T) Character.valueOf(value.charAt(0)); - else if (String.class.isAssignableFrom(type)) - result = (T) value; - } - - return result; - } - - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ - public String getName() { - return name; - } - - /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifTool Tag Guide. - * - * @return a hint for the native type of this tag's value. - */ - public Class getType() { - return type; - } - - private String name; - private Class type; - - private Tag(String name, Class type) { - this.name = name; - this.type = type; - } - } - private Timer cleanupTimer; private TimerTask currentCleanupTask; - private IOStream streams; - private List args; + IOStream streams; + List args; - private Set featureSet; + Set featureSet; public ExifTool() { this((Feature[]) null); } public ExifTool(Feature... features) throws UnsupportedFeatureException { - featureSet = new HashSet(); + featureSet = new HashSet(); if (features != null && features.length > 0) { /* @@ -1117,8 +735,7 @@ public Map getImageMeta(File image, Format format, Tag... tags) * Create a result map big enough to hold results for each of the tags * and avoid collisions while inserting. */ - Map resultMap = new HashMap( - tags.length * 3); + Map resultMap = new HashMap(tags.length * 3); if (DEBUG) log("Querying %d tags from image: %s", tags.length, @@ -1425,7 +1042,7 @@ public void setImageMeta(File image, Format format, Map tags) * It is annoying that we cannot just reset the timer on the task, but that * isn't the way the java.util.Timer class was designed unfortunately. */ - private void resetCleanupTask() { + void resetCleanupTask() { // no-op if the timer was never created. if (cleanupTimer == null) return; @@ -1443,262 +1060,4 @@ private void resetCleanupTask() { log("\t\tSuccessful"); } - - /** - * Class used to represent the {@link TimerTask} used by the internal auto - * cleanup {@link Timer} to call {@link ExifTool#close()} after a specified - * interval of inactivity. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - private class CleanupTimerTask extends TimerTask { - private ExifTool owner; - - public CleanupTimerTask(ExifTool owner) throws IllegalArgumentException { - if (owner == null) - throw new IllegalArgumentException( - "owner cannot be null and must refer to the ExifTool instance creating this task."); - - this.owner = owner; - } - - @Override - public void run() { - log("\tAuto cleanup task running..."); - owner.close(); - } - } - - /** - * Class used to define an exception that occurs when the caller attempts to - * use a {@link Feature} that the underlying native ExifTool install does - * not support (i.e. the version isn't new enough). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public class UnsupportedFeatureException extends RuntimeException { - private static final long serialVersionUID = -1332725983656030770L; - - private Feature feature; - - public UnsupportedFeatureException(Feature feature) { - super( - "Use of feature [" - + feature - + "] requires version " - + feature.version - + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); - } - - public Feature getFeature() { - return feature; - } - } - - /** - * Class used to handle XMP Sidecar files using exiftool. - * - * @author Clinton LaForest (clafore@bgsu.edu) - * @since 1.2_thespiritx - */ - public class Sidecar { - public Sidecar(Feature feature) { - - } - - /** - * Used to merge a XMP Sidecar file with an image. - * - * @param xmp - * The xmp sidecar file. - * - * @param file - * The image file. - * - * @param preserve - * true - preserves name mappings - * false - uses preferred name mappings - * - * @return void - * - */ - public void merge(File xmp, File file, Boolean preserve) { - if (xmp == null) - throw new IllegalArgumentException( - "xmp cannot be null and must be a valid xmp sidecar stream."); - if (file == null) - throw new IllegalArgumentException("file cannot be null"); - if (preserve == null) - preserve = false; - if (!file.canWrite()) - throw new SecurityException( - "Unable to read the given image [" - + file.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); - - long startTime = System.currentTimeMillis(); - - if (DEBUG) - log("Writing %s tags to image: %s", xmp.getAbsolutePath(), - file.getAbsolutePath()); - - long exifToolCallElapsedTime = 0; - - /* - * Using ExifTool in daemon mode (-stay_open True) executes - * different code paths below. So establish the flag for this once - * and it is reused a multitude of times later in this method to - * figure out where to branch to. - */ - boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); - - args.clear(); - - if (stayOpen) { - log("\tUsing ExifTool in daemon mode (-stay_open True)..."); - - // Always reset the cleanup task. - resetCleanupTask(); - - /* - * If this is our first time calling getImageMeta with a - * stayOpen connection, set up the persistent process and run it - * so it is ready to receive commands from us. - */ - if (streams == null) { - log("\tStarting daemon ExifTool process and creating read/write streams (this only happens once)..."); - - args.add(EXIF_TOOL_PATH); - args.add("-stay_open"); - args.add("True"); - args.add("-@"); - args.add("-"); - - // Begin the persistent ExifTool process. - streams = startExifToolProcess(args); - } - - log("\tStreaming arguments to ExifTool process..."); - - try { - streams.writer.write("-tagsfromfile\n"); - - streams.writer.write(file.getAbsolutePath()); - streams.writer.write("\n"); - - if (preserve) { - streams.writer.write("-all:all"); - streams.writer.write("\n"); - } else { - streams.writer.write("-xmp"); - streams.writer.write("\n"); - } - - streams.writer.write(xmp.getAbsolutePath()); - streams.writer.write("\n"); - - log("\tExecuting ExifTool..."); - - // Begin tracking the duration ExifTool takes to respond. - exifToolCallElapsedTime = System.currentTimeMillis(); - - // Run ExifTool on our file with all the given arguments. - streams.writer.write("-execute\n"); - streams.writer.flush(); - - } catch (IOException e) { - log("\tError received in stayopen stream: %s", - e.getMessage()); - } // compact output - } else { - log("\tUsing ExifTool in non-daemon mode (-stay_open False)..."); - - /* - * Since we are not using a stayOpen process, we need to setup - * the execution arguments completely each time. - */ - args.add(EXIF_TOOL_PATH); - - args.add("-tagsfromfile"); // compact output - - args.add(file.getAbsolutePath()); - - if (preserve) { - args.add("-all:all"); - } else { - args.add("-xmp"); - } - - args.add(xmp.getAbsolutePath()); - - // Run the ExifTool with our args. - streams = startExifToolProcess(args); - - // Begin tracking the duration ExifTool takes to respond. - exifToolCallElapsedTime = System.currentTimeMillis(); - } - - log("\tReading response back from ExifTool..."); - - String line = null; - - try { - while ((line = streams.reader.readLine()) != null) { - /* - * When using a persistent ExifTool process, it terminates - * its output to us with a "{ready}" clause on a new line, - * we need to look for it and break from this loop when we - * see it otherwise this process will hang indefinitely - * blocking on the input stream with no data to read. - */ - if (stayOpen && line.equals("{ready}")) - break; - } - } catch (IOException e) { - log("\tError received in response: %d", e.getMessage()); - } - - // Print out how long the call to external ExifTool process took. - log("\tFinished reading ExifTool response in %d ms.", - (System.currentTimeMillis() - exifToolCallElapsedTime)); - - /* - * If we are not using a persistent ExifTool process, then after - * running the command above, the process exited in which case we - * need to clean our streams up since it no longer exists. If we - * were using a persistent ExifTool process, leave the streams open - * for future calls. - */ - if (!stayOpen) - streams.close(); - - if (DEBUG) - log("\tImage Meta Processed in %d ms [write %s tags]", - (System.currentTimeMillis() - startTime), - xmp.getAbsolutePath()); - - } - - /** - * Used to export a XMP Sidecar file from an image. - * - * @param xmp - * The xmp sidecar file. - * - * @param file - * The image file. - * - * @param preserve - * true - preserves name mappings - * false - uses preferred name mappings - * - * @return void - * - */ - public void export(File xmp, File file, boolean preserve) { - - } - } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/Feature.java b/src/main/java/com/thebuzzmedia/exiftool/Feature.java new file mode 100644 index 00000000..9fbe4c1f --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Feature.java @@ -0,0 +1,41 @@ +package com.thebuzzmedia.exiftool; + +/** + * Enum used to define the different kinds of features in the native ExifTool + * executable that this class can help you take advantage of. + *

+ * These flags are different from {@link Tag}s in that a "feature" is determined + * to be a special functionality of the underlying ExifTool executable that + * requires a different code-path in this class to take advantage of; for + * example, -stay_open True support. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public enum Feature { + /** + * Enum used to specify that you wish to launch the underlying ExifTool + * process with -stay_open True support turned on that this + * class can then take advantage of. + *

+ * Required ExifTool version is 8.36 or higher. + */ + STAY_OPEN("8.36"); + + /** + * Used to get the version of ExifTool required by this feature in order to + * work. + * + * @return the version of ExifTool required by this feature in order to + * work. + */ + public String getVersion() { + return version; + } + + String version; + + private Feature(String version) { + this.version = version; + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Format.java b/src/main/java/com/thebuzzmedia/exiftool/Format.java new file mode 100644 index 00000000..90f80db6 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Format.java @@ -0,0 +1,41 @@ +package com.thebuzzmedia.exiftool; + +import java.io.File; + +/** + * Enum used to define the 2 different output formats that {@link Tag} values + * can be returned in: numeric or human-readable text. + *

+ * ExifTool, via the -n command line arg, is capable of returning + * most values in their raw numeric form (e.g. Aperture="2.8010323841") as well + * as a more human-readable/friendly format (e.g. Aperture="2.8"). + *

+ * While the {@link Tag}s defined on this class do provide a hint at the type of + * the result (see {@link Tag#getType()}), that hint only applies when the + * {@link Format#NUMERIC} form of the value is returned. + *

+ * If the caller finds the human-readable format easier to process, + * {@link Format#HUMAN_READABLE} can be specified when calling + * {@link ExifTool#getImageMeta(File, Format, Tag...)} and the returned + * {@link String} values processed manually by the caller. + *

+ * In order to see the types of values that are returned when + * {@link Format#HUMAN_READABLE} is used, you can check the comprehensive + * ExifTool Tag Guide. + *

+ * This makes sense with some values like Aperture that in + * {@link Format#NUMERIC} format end up returning as 14-decimal-place, high + * precision values that are near the intended value (e.g. "2.79999992203711" + * instead of just returning "2.8"). On the other hand, other values (like + * Orientation) are easier to parse when their numeric value (1-8) is returned + * instead of a much longer friendly name (e.g. + * "Mirror horizontal and rotate 270 CW"). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public enum Format { + NUMERIC, + HUMAN_READABLE; +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/IOStream.java b/src/main/java/com/thebuzzmedia/exiftool/IOStream.java new file mode 100644 index 00000000..f06b7b80 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/IOStream.java @@ -0,0 +1,50 @@ +package com.thebuzzmedia.exiftool; + +import java.io.BufferedReader; +import java.io.OutputStreamWriter; + +/** + * Simple class used to house the read/write streams used to communicate with an + * external ExifTool process as well as the logic used to safely close the + * streams when no longer needed. + *

+ * This class is just a convenient way to group and manage the read/write + * streams as opposed to making them dangling member variables off of ExifTool + * directly. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +class IOStream { + BufferedReader reader; + OutputStreamWriter writer; + + public IOStream(BufferedReader reader, OutputStreamWriter writer) { + this.reader = reader; + this.writer = writer; + } + + public void close() { + try { + ExifTool.log("\tClosing Read stream..."); + reader.close(); + ExifTool.log("\t\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + ExifTool.log("\tClosing Write stream..."); + writer.close(); + ExifTool.log("\t\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + // Null the stream references. + reader = null; + writer = null; + + ExifTool.log("\tRead/Write streams successfully closed."); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Sidecar.java b/src/main/java/com/thebuzzmedia/exiftool/Sidecar.java new file mode 100644 index 00000000..8d8b683d --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Sidecar.java @@ -0,0 +1,216 @@ +package com.thebuzzmedia.exiftool; + +import java.io.File; +import java.io.IOException; + +/** + * Class used to handle XMP Sidecar files using exiftool. + * + * @author Clinton LaForest (clafore@bgsu.edu) + * @since 1.2_thespiritx + */ +public class Sidecar { + /** + * + */ + private final ExifTool exifTool; + + public Sidecar(ExifTool exifTool, Feature feature) { + this.exifTool = exifTool; + + } + + /** + * Used to merge a XMP Sidecar file with an image. + * + * @param xmp + * The xmp sidecar file. + * + * @param file + * The image file. + * + * @param preserve + * true - preserves name mappings false + * - uses preferred name mappings + * + * @return void + * + */ + public void merge(File xmp, File file, Boolean preserve) { + if (xmp == null) + throw new IllegalArgumentException( + "xmp cannot be null and must be a valid xmp sidecar stream."); + if (file == null) + throw new IllegalArgumentException("file cannot be null"); + if (preserve == null) + preserve = false; + if (!file.canWrite()) + throw new SecurityException( + "Unable to read the given image [" + + file.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + + long startTime = System.currentTimeMillis(); + + if (ExifTool.DEBUG) + ExifTool.log("Writing %s tags to image: %s", xmp.getAbsolutePath(), + file.getAbsolutePath()); + + long exifToolCallElapsedTime = 0; + + /* + * Using ExifTool in daemon mode (-stay_open True) executes different + * code paths below. So establish the flag for this once and it is + * reused a multitude of times later in this method to figure out where + * to branch to. + */ + boolean stayOpen = this.exifTool.featureSet.contains(Feature.STAY_OPEN); + + this.exifTool.args.clear(); + + if (stayOpen) { + ExifTool.log("\tUsing ExifTool in daemon mode (-stay_open True)..."); + + // Always reset the cleanup task. + this.exifTool.resetCleanupTask(); + + /* + * If this is our first time calling getImageMeta with a stayOpen + * connection, set up the persistent process and run it so it is + * ready to receive commands from us. + */ + if (this.exifTool.streams == null) { + ExifTool.log("\tStarting daemon ExifTool process and creating read/write streams (this only happens once)..."); + + this.exifTool.args.add(ExifTool.EXIF_TOOL_PATH); + this.exifTool.args.add("-stay_open"); + this.exifTool.args.add("True"); + this.exifTool.args.add("-@"); + this.exifTool.args.add("-"); + + // Begin the persistent ExifTool process. + this.exifTool.streams = ExifTool + .startExifToolProcess(this.exifTool.args); + } + + ExifTool.log("\tStreaming arguments to ExifTool process..."); + + try { + this.exifTool.streams.writer.write("-tagsfromfile\n"); + + this.exifTool.streams.writer.write(file.getAbsolutePath()); + this.exifTool.streams.writer.write("\n"); + + if (preserve) { + this.exifTool.streams.writer.write("-all:all"); + this.exifTool.streams.writer.write("\n"); + } else { + this.exifTool.streams.writer.write("-xmp"); + this.exifTool.streams.writer.write("\n"); + } + + this.exifTool.streams.writer.write(xmp.getAbsolutePath()); + this.exifTool.streams.writer.write("\n"); + + ExifTool.log("\tExecuting ExifTool..."); + + // Begin tracking the duration ExifTool takes to respond. + exifToolCallElapsedTime = System.currentTimeMillis(); + + // Run ExifTool on our file with all the given arguments. + this.exifTool.streams.writer.write("-execute\n"); + this.exifTool.streams.writer.flush(); + + } catch (IOException e) { + ExifTool.log("\tError received in stayopen stream: %s", + e.getMessage()); + } // compact output + } else { + ExifTool.log("\tUsing ExifTool in non-daemon mode (-stay_open False)..."); + + /* + * Since we are not using a stayOpen process, we need to setup the + * execution arguments completely each time. + */ + this.exifTool.args.add(ExifTool.EXIF_TOOL_PATH); + + this.exifTool.args.add("-tagsfromfile"); // compact output + + this.exifTool.args.add(file.getAbsolutePath()); + + if (preserve) { + this.exifTool.args.add("-all:all"); + } else { + this.exifTool.args.add("-xmp"); + } + + this.exifTool.args.add(xmp.getAbsolutePath()); + + // Run the ExifTool with our args. + this.exifTool.streams = ExifTool + .startExifToolProcess(this.exifTool.args); + + // Begin tracking the duration ExifTool takes to respond. + exifToolCallElapsedTime = System.currentTimeMillis(); + } + + ExifTool.log("\tReading response back from ExifTool..."); + + String line = null; + + try { + while ((line = this.exifTool.streams.reader.readLine()) != null) { + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need + * to look for it and break from this loop when we see it + * otherwise this process will hang indefinitely blocking on the + * input stream with no data to read. + */ + if (stayOpen && line.equals("{ready}")) + break; + } + } catch (IOException e) { + ExifTool.log("\tError received in response: %d", e.getMessage()); + } + + // Print out how long the call to external ExifTool process took. + ExifTool.log("\tFinished reading ExifTool response in %d ms.", + (System.currentTimeMillis() - exifToolCallElapsedTime)); + + /* + * If we are not using a persistent ExifTool process, then after running + * the command above, the process exited in which case we need to clean + * our streams up since it no longer exists. If we were using a + * persistent ExifTool process, leave the streams open for future calls. + */ + if (!stayOpen) + this.exifTool.streams.close(); + + if (ExifTool.DEBUG) + ExifTool.log("\tImage Meta Processed in %d ms [write %s tags]", + (System.currentTimeMillis() - startTime), + xmp.getAbsolutePath()); + + } + + /** + * Used to export a XMP Sidecar file from an image. + * + * @param xmp + * The xmp sidecar file. + * + * @param file + * The image file. + * + * @param preserve + * true - preserves name mappings false + * - uses preferred name mappings + * + * @return void + * + */ + public void export(File xmp, File file, boolean preserve) { + + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Tag.java b/src/main/java/com/thebuzzmedia/exiftool/Tag.java new file mode 100644 index 00000000..59bc1a67 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Tag.java @@ -0,0 +1,252 @@ +package com.thebuzzmedia.exiftool; + +import java.util.HashMap; +import java.util.Map; + +/** + * Enum used to pre-define a convenient list of tags that can be easily + * extracted from images using this class with an external install of ExifTool. + *

+ * Each tag defined also includes a type hint for the parsed value associated + * with it when the default {@link Format#NUMERIC} value format is used. + *

+ * All replies from ExifTool are parsed as {@link String}s and using the type + * hint from each {@link Tag} can easily be converted to the correct data format + * by using the provided {@link Tag#parseValue(Tag, String)} method. + *

+ * This class does not make an attempt at converting the value automatically in + * case the caller decides they would prefer tag values returned in + * {@link Format#HUMAN_READABLE} format and to avoid any compatibility issues + * with future versions of ExifTool if a tag's return value is changed. This + * approach to leaving returned tag values as strings until the caller decides + * they want to parse them is a safer and more robust approach. + *

+ * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or + * process the returned {@link String} values any way they wish. + *

Tag Support

+ * ExifTool is capable of parsing almost every tag known to man (1000+), but + * this class makes an attempt at pre-defining a convenient list of the most + * common tags for use. + *

+ * This list was determined by looking at the common metadata tag values written + * to images by popular mobile devices (iPhone, Android) as well as cameras like + * simple point and shoots as well as DSLRs. As an additional source of input + * the list of supported/common EXIF formats that Flickr supports was also + * reviewed to ensure the most common/useful tags were being covered here. + *

+ * Please email me or file an issue if + * you think this list is missing a commonly used tag that should be added to + * it. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public enum Tag { + APERTURE("ApertureValue", Double.class), + ARTIST("Artist", String.class), + AUTHOR("XPAuthor", String.class), + BODY_SERIAL_NUMBER("BodySerialNumber", String.class), + CAMERA_SERIAL_NUMBER("CameraSerialNumber", String.class), + CAPTION_ABSTRACT("Caption-Abstract", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATE_DATE("CreateDate", String.class), + COPYRIGHT("Copyright", String.class), + COPYRIGHT_NOTICE("CopyrightNotice", String.class), + CREATION_DATE("CreationDate", String.class), + CREATOR("Creator", String.class), + DATE_CREATED("DateCreated", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), + DEVICE_SERIAL_NUMBER("DeviceSerialNumber", String.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + EXTENDER_SERIAL_NUMBER("ExtenderSerialNumber", String.class), + FILE_TYPE("FileType", String.class), + FLASH("Flash", Integer.class), + FLASH_SERIAL_NUMBER("FlashSerialNumber", String.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_DATESTAMP("GPSDateStamp", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_UNIQUE_ID("ImageUniqueID", String.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + INTERNAL_SERIAL_NUMBER("InternalSerialNumber", String.class), + IPTC_KEYWORDS("Keywords", String.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS("Lens", String.class), + LENS_ID("LensID", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + LENS_SERIAL_NUMBER("LensSerialNumber", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + OBJECT_NAME("ObjectName", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SCANNER_SERIAL_NUMBER("ScannerSerialNumber", String.class), + SENSING_METHOD("SensingMethod", Integer.class), + SERIAL_NUMBER("SerialNumber", String.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SOURCE_SERIAL_NUMBER("SourceSerialNumber", String.class), + SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), ; + private static final Map TAG_LOOKUP_MAP; + + /** + * Initializer used to init the static final tag/name lookup + * map used by all instances of this class. + */ + static { + Tag[] values = Tag.values(); + TAG_LOOKUP_MAP = new HashMap(values.length * 3); + + for (int i = 0; i < values.length; i++) { + Tag tag = values[i]; + TAG_LOOKUP_MAP.put(tag.name, tag); + } + } + + /** + * Used to get the {@link Tag} identified by the given, case-sensitive, tag + * name. + * + * @param name + * The case-sensitive name of the tag that will be searched for. + * + * @return the {@link Tag} identified by the given, case-sensitive, tag name + * or null if one couldn't be found. + */ + public static Tag forName(String name) { + return TAG_LOOKUP_MAP.get(name); + } + + /** + * Convenience method used to convert the given string Tag value (returned + * from the external ExifTool process) into the type described by the + * associated {@link Tag}. + * + * @param + * The type of the returned value. + * @param tag + * The {@link Tag} whose value this is. The tag's type hint will + * be queried to determine how to convert this string value. + * @param value + * The {@link String} representation of the tag's value as parsed + * from the image. + * + * @return the given string value converted to a native Java type (e.g. + * Integer, Double, etc.). + * + * @throws IllegalArgumentException + * if tag is null. + * @throws NumberFormatException + * if any exception occurs while trying to parse the given + * value to any of the supported numeric types in + * Java via calls to the respective parseXXX + * methods defined on all the numeric wrapper classes (e.g. + * {@link Integer#parseInt(String)} , + * {@link Double#parseDouble(String)} and so on). + * @throws ClassCastException + * if the type defined by T is incompatible with + * the type defined by {@link Tag#getType()} returned by the + * tag argument passed in. This class performs an + * implicit/unchecked cast to the type T before + * returning the parsed result of the type indicated by + * {@link Tag#getType()}. If the types do not match, a + * ClassCastException will be generated by the VM. + */ + @SuppressWarnings("unchecked") + public static T parseValue(Tag tag, String value) + throws IllegalArgumentException, NumberFormatException { + if (tag == null) + throw new IllegalArgumentException("tag cannot be null"); + + T result = null; + + // Check that there is work to do first. + if (value != null) { + Class type = tag.type; + + if (Boolean.class.isAssignableFrom(type)) + result = (T) Boolean.valueOf(value); + else if (Byte.class.isAssignableFrom(type)) + result = (T) Byte.valueOf(Byte.parseByte(value)); + else if (Integer.class.isAssignableFrom(type)) + result = (T) Integer.valueOf(Integer.parseInt(value)); + else if (Short.class.isAssignableFrom(type)) + result = (T) Short.valueOf(Short.parseShort(value)); + else if (Long.class.isAssignableFrom(type)) + result = (T) Long.valueOf(Long.parseLong(value)); + else if (Float.class.isAssignableFrom(type)) + result = (T) Float.valueOf(Float.parseFloat(value)); + else if (Double.class.isAssignableFrom(type)) + result = (T) Double.valueOf(Double.parseDouble(value)); + else if (Character.class.isAssignableFrom(type)) + result = (T) Character.valueOf(value.charAt(0)); + else if (String.class.isAssignableFrom(type)) + result = (T) value; + } + + return result; + } + + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ + public String getName() { + return name; + } + + /** + * Used to get a hint for the native type of this tag's value as specified + * by Phil Harvey's ExifTool Tag Guide. + * + * @return a hint for the native type of this tag's value. + */ + public Class getType() { + return type; + } + + String name; + private Class type; + + private Tag(String name, Class type) { + this.name = name; + this.type = type; + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java b/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java new file mode 100644 index 00000000..706a9153 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java @@ -0,0 +1,28 @@ +package com.thebuzzmedia.exiftool; + +/** + * Class used to define an exception that occurs when the caller attempts to use + * a {@link Feature} that the underlying native ExifTool install does not + * support (i.e. the version isn't new enough). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public class UnsupportedFeatureException extends RuntimeException { + private static final long serialVersionUID = -1332725983656030770L; + + private Feature feature; + + public UnsupportedFeatureException(Feature feature) { + super( + "Use of feature [" + + feature + + "] requires version " + + feature.version + + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); + } + + public Feature getFeature() { + return feature; + } +} \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index aa22c00c..c0afd27d 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -3,9 +3,6 @@ import java.io.File; import java.io.IOException; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Tag; - public class Benchmark { public static final int ITERS = 25; public static final Tag[] TAGS = Tag.values(); diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index 2e424db3..4072f122 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -3,10 +3,6 @@ import java.io.File; import java.io.IOException; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Format; -import com.thebuzzmedia.exiftool.ExifTool.Tag; - public class Example { public static final int ITERS = 100; public static final File[] IMAGES = new File("src/test/resources") From 32b028fee2d09326c711b596a691f376255a31ee Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 15:38:12 +0300 Subject: [PATCH 043/148] - extract classes to ease up the integration process --- .../com/thebuzzmedia/exiftool/CustomTag.java | 40 + .../com/thebuzzmedia/exiftool/ExifError.java | 9 +- .../thebuzzmedia/exiftool/ExifProcess.java | 197 ++ .../com/thebuzzmedia/exiftool/ExifProxy.java | 22 + .../com/thebuzzmedia/exiftool/ExifTool.java | 2168 +++++------------ .../com/thebuzzmedia/exiftool/Feature.java | 58 + .../com/thebuzzmedia/exiftool/Format.java | 8 + .../exiftool/KeepAliveExifProxy.java | 136 ++ .../exiftool/LineReaderThread.java | 121 +- .../thebuzzmedia/exiftool/MetadataTag.java | 22 + .../com/thebuzzmedia/exiftool/MwgTag.java | 54 + .../thebuzzmedia/exiftool/ReadOptions.java | 104 + .../exiftool/SingleUseExifProxy.java | 66 + .../java/com/thebuzzmedia/exiftool/Tag.java | 202 ++ .../com/thebuzzmedia/exiftool/TagGroup.java | 37 + .../exiftool/UnsupportedFeatureException.java | 23 + .../thebuzzmedia/exiftool/VersionNumber.java | 49 + .../thebuzzmedia/exiftool/WriteOptions.java | 39 + .../com/thebuzzmedia/exiftool/Benchmark.java | 95 +- .../com/thebuzzmedia/exiftool/Example.java | 79 +- .../thebuzzmedia/exiftool/TestExifTool.java | 984 ++++---- 21 files changed, 2407 insertions(+), 2106 deletions(-) create mode 100644 src/main/java/com/thebuzzmedia/exiftool/CustomTag.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/ExifProxy.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Feature.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Format.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/MwgTag.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/ReadOptions.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/Tag.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/TagGroup.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java create mode 100644 src/main/java/com/thebuzzmedia/exiftool/WriteOptions.java diff --git a/src/main/java/com/thebuzzmedia/exiftool/CustomTag.java b/src/main/java/com/thebuzzmedia/exiftool/CustomTag.java new file mode 100644 index 00000000..076cb40b --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/CustomTag.java @@ -0,0 +1,40 @@ +package com.thebuzzmedia.exiftool; + +/** + * A Custom Tag that the user defines. Used to cover tags not in the enum. + */ +public class CustomTag implements MetadataTag { + private final String name; + private final Class type; + private final boolean mapped; + + public CustomTag(String name, Class type) { + this(name, type, !name.trim().endsWith(":all")); + } + + public CustomTag(String name, Class type, boolean mapped) { + this.name = name.trim(); + this.type = type; + this.mapped = mapped; + } + + @Override + public String getKey() { + return name; + } + + @Override + public Class getType() { + return type; + } + + @Override + public boolean isMapped() { + return mapped; + } + + @Override + public String toString() { + return getKey(); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifError.java b/src/main/java/com/thebuzzmedia/exiftool/ExifError.java index 843b62d6..a3062f38 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifError.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifError.java @@ -4,13 +4,14 @@ /** * Represents an error from the ExifTool + * * @author msgile * @author $LastChangedBy$ - * @version $Revision$ $LastChangedDate$ + * @version $Revision$ $LastChangedDate$ * @since 7/25/14 */ public class ExifError extends IOException { - public ExifError(String message) { - super(message); - } + public ExifError(String message) { + super(message); + } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java new file mode 100644 index 00000000..c6431c1a --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -0,0 +1,197 @@ +package com.thebuzzmedia.exiftool; + +import java.io.BufferedReader; +import java.io.IOException; +import java.io.InputStreamReader; +import java.io.OutputStreamWriter; +import java.util.Arrays; +import java.util.HashMap; +import java.util.List; +import java.util.Map; +import java.util.concurrent.locks.ReentrantLock; +import java.util.regex.Pattern; + +//================================================================================ +/** + * Represents an external exif process. Works for both single use and keep alive + * modes. This is the actual process, with streams for reading and writing data. + */ +public final class ExifProcess { + /** + * Compiled {@link Pattern} of ": " used to split compact output from + * ExifTool evenly into name/value pairs. + */ + private static final Pattern TAG_VALUE_PATTERN = Pattern + .compile("\\s*:\\s*"); + + public static VersionNumber readVersion(String exifCmd) { + ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, + "-ver")); + try { + return new VersionNumber(process.readLine()); + } catch (IOException ex) { + throw new RuntimeException(String.format( + "Unable to check version number of ExifTool: %s", exifCmd)); + } finally { + process.close(); + } + } + + private final ReentrantLock closeLock = new ReentrantLock(false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader out; + private final OutputStreamWriter in; + private final LineReaderThread errReader; + private volatile boolean closed = false; + + public ExifProcess(boolean keepAlive, List args) { + this.keepAlive = keepAlive; + ExifTool.log.debug(String.format( + "Attempting to start ExifTool process using args: %s", args)); + try { + this.process = new ProcessBuilder(args).start(); + this.out = new BufferedReader(new InputStreamReader( + process.getInputStream())); + this.in = new OutputStreamWriter(process.getOutputStream()); + this.errReader = new LineReaderThread("exif-process-err-reader", + new BufferedReader(new InputStreamReader( + process.getErrorStream()))); + errReader.start(); + ExifTool.log.debug("\tSuccessful"); + } catch (Exception e) { + String message = "Unable to start external ExifTool process using the execution arguments: " + + args + + ". Ensure ExifTool is installed correctly and runs using the command path '" + + args.get(0) + + "' as specified by the 'exiftool.path' system property."; + + ExifTool.log.debug(message); + throw new RuntimeException(message, e); + } + } + + public synchronized Map sendToRunning(List args) + throws IOException { + if (!keepAlive) { + throw new IOException("Not KeepAlive Process"); + } + StringBuilder builder = new StringBuilder(); + for (String arg : args) { + builder.append(arg).append("\n"); + } + builder.append("-execute\n"); + writeFlush(builder.toString()); + return readResponse(); + } + + public synchronized void writeFlush(String message) throws IOException { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + in.write(message); + in.flush(); + } + + public synchronized String readLine() throws IOException { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + return out.readLine(); + } + + public synchronized Map readResponse() throws IOException { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + ExifTool.log.debug("Reading response back from ExifTool..."); + Map resultMap = new HashMap(500); + String line; + while ((line = out.readLine()) != null) { + if (closed) + throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); + String[] pair = TAG_VALUE_PATTERN.split(line, 2); + if (pair.length == 2) { + resultMap.put(pair[0], pair[1]); + ExifTool.log.debug(String.format( + "\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); + } + + /* + * When using a persistent ExifTool process, it terminates its + * output to us with a "{ready}" clause on a new line, we need to + * look for it and break from this loop when we see it otherwise + * this process will hang indefinitely blocking on the input stream + * with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } + } + if (errReader.hasLines()) { + for (String error : errReader.takeLines()) { + if (error.toLowerCase().startsWith("error")) { + throw new ExifError(error); + } + } + } + return resultMap; + } + + public boolean isClosed() { + return closed; + } + + public void close() { + if (!closed) { + closeLock.lock(); + try { + if (!closed) { + closed = true; + try { + ExifTool.log.debug("Closing Read stream..."); + out.close(); + ExifTool.log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + ExifTool.log + .debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); + in.write("-stay_open\nFalse\n"); + in.flush(); + } catch (IOException ex) { + // log.error(ex,ex); + } + + try { + ExifTool.log.debug("Closing Write stream..."); + in.close(); + ExifTool.log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + try { + ExifTool.log.debug("Closing Error stream..."); + errReader.close(); + ExifTool.log.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + } + + ExifTool.log + .debug("Read/Write streams successfully closed."); + + try { + process.destroy(); + } catch (Exception e) { + // + } + // process = null; + + } + } finally { + closeLock.unlock(); + } + } + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProxy.java new file mode 100644 index 00000000..f30df15b --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProxy.java @@ -0,0 +1,22 @@ +package com.thebuzzmedia.exiftool; + +import java.io.IOException; +import java.util.List; +import java.util.Map; + +/** + * A Proxy to an Exif Process, will restart if backing exif process died, or run + * new one on every call. + * + * @author Matt Gile, msgile + */ +public interface ExifProxy { + public void startup(); + + public Map execute(long runTimeoutMills, List args) + throws IOException; + + public boolean isRunning(); + + public void shutdown(); +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index b94a5599..b7988019 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -15,38 +15,30 @@ */ package com.thebuzzmedia.exiftool; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.io.BufferedReader; import java.io.File; import java.io.FileNotFoundException; import java.io.IOException; -import java.io.InputStreamReader; -import java.io.OutputStreamWriter; import java.lang.reflect.Array; import java.text.ParseException; import java.text.SimpleDateFormat; import java.util.ArrayList; import java.util.Arrays; import java.util.Date; -import java.util.EnumMap; import java.util.EnumSet; import java.util.HashMap; import java.util.List; import java.util.Map; import java.util.Set; import java.util.StringTokenizer; -import java.util.Timer; -import java.util.TimerTask; import java.util.TreeMap; -import java.util.concurrent.atomic.AtomicBoolean; -import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + /** - * Provide a Java-like interface to Phil Harvey's excellent, - * Perl-based ExifTool. + * Provide a Java-like interface to Phil Harvey's excellent, Perl-based ExifTool. *

* Initial work done by "Riyad Kalla" software@thebuzzmedia.com. *

@@ -70,13 +62,14 @@ * system path or pointed to by {@link #ENV_EXIF_TOOL_PATH}, using this class to * communicate with ExifTool is as simple as creating an instance ( * ExifTool tool = new ExifTool()) and then making calls to - * {@link #readMetadata(ReadOptions,java.io.File, Object...)} (optionally supplying tags or + * {@link #readMetadata(ReadOptions,java.io.File, Object...)} (optionally + * supplying tags or * {@link #writeMetadata(WriteOptions,java.io.File, java.util.Map)} *

- * In this default mode methods will automatically - * start an external ExifTool process to handle the request. After ExifTool has - * parsed the tag values from the file, the external process exits and this - * class parses the result before returning it to the caller. + * In this default mode methods will automatically start an external ExifTool + * process to handle the request. After ExifTool has parsed the tag values from + * the file, the external process exits and this class parses the result before + * returning it to the caller. *

*

ExifTool -stay_open Support

* ExifTool * Because this feature requires ExifTool 8.36 or later, this class will * actually verify support for the feature in the version of ExifTool pointed at - * by {@link #ENV_EXIF_TOOL_PATH} before successfully instantiating the class and - * will notify you via an {@link UnsupportedFeatureException} if the native + * by {@link #ENV_EXIF_TOOL_PATH} before successfully instantiating the class + * and will notify you via an {@link UnsupportedFeatureException} if the native * ExifTool doesn't support the requested feature. *

* In the event of an {@link UnsupportedFeatureException}, the caller can either @@ -120,9 +113,10 @@ * of inactivity to clean up those stray resources. *

* The inactivity period can be controlled by modifying the - * {@link #ENV_EXIF_TOOL_PROCESSCLEANUPDELAY} system variable. A value of 0 or - * less disabled the automatic cleanup process and requires you to cleanup - * ExifTool instances on your own by calling {@link #close()} manually. + * {@link #ENV_EXIF_TOOL_PROCESSCLEANUPDELAY} system variable. A value of + * 0 or less disabled the automatic cleanup process and requires + * you to cleanup ExifTool instances on your own by calling {@link #close()} + * manually. *

* Any class activity by way of calls to getImageMeta will always * reset the inactivity timer, so in a busy system the cleanup thread could @@ -199,1499 +193,661 @@ * written the 2nd most robust image metadata library I have come across: Metadata Extractor * that you might want to look at. - * + * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ public class ExifTool { - /** - * If ExifTool is on your system path and running the command "exiftool" - * successfully executes it, the default value unchanged will work fine on - * any platform. If the ExifTool executable is named something else or not - * in the system path, then this property will need to be set to point at it - * before using this class. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.path=/path/to/exiftool - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * On Windows be sure to double-escape the path to the tool, for example: - * - * -Dexiftool.path=C:\\Tools\\exiftool.exe - * - *

- * Default value is "exiftool". - *

Relative Paths

- * Relative path values (e.g. "bin/tools/exiftool") are executed with - * relation to the base directory the VM process was started in. Essentially - * the directory that new File(".").getAbsolutePath() points at - * during runtime. - */ - public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; - /** - * Interval (in milliseconds) of inactivity before the cleanup thread wakes - * up and cleans up the daemon ExifTool process and the read/write streams - * used to communicate with it when the {@link Feature#STAY_OPEN} feature is - * used. - *

- * Ever time a call to getImageMeta is processed, the timer - * keeping track of cleanup is reset; more specifically, this class has to - * experience no activity for this duration of time before the cleanup - * process is fired up and cleans up the host OS process and the stream - * resources. - *

- * Any subsequent calls to getImageMeta after a cleanup simply - * re-initializes the resources. - *

- * This system property can be set on startup with:
- * - * -Dexiftool.processCleanupDelay=600000 - * or by calling {@link System#setProperty(String, String)} before - * this class is loaded. - *

- * Setting this value to 0 disables the automatic cleanup thread completely - * and the caller will need to manually cleanup the external ExifTool - * process and read/write streams by calling {@link #close()}. - *

- * Default value is zero, no inactivity timeout. - */ - public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; - - /** - * Name used to identify the (optional) cleanup {@link Thread}. - *

- * This is only provided to make debugging and profiling easier for - * implementers making use of this class such that the resources this class - * creates and uses (i.e. Threads) are readily identifiable in a running VM. - *

- * Default value is "ExifTool Cleanup Thread". - */ - private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; - - private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - private static final String EXIF_DATE_FORMAT = "yyyy:MM:dd HH:mm:ss"; - - private static final Logger log = LoggerFactory.getLogger(ExifTool.class); - - private final Map featureSupportedMap = new HashMap(); - private final Set featureEnabledSet = EnumSet.noneOf(Feature.class); - private ReadOptions defReadOptions = new ReadOptions(); - private WriteOptions defWriteOptions = new WriteOptions(); - private final VersionNumber exifVersion; - private final ExifProxy exifProxy; - - public ExifTool(){ - this((Feature[]) null); - } - - /** - * In this constructor, exifToolPath and processCleanupDelay are read from system properties - * exiftool.path and exiftool.processCleanupDelay. processCleanupDelay is optional. If not found, - * the default is used. - */ - public ExifTool (Feature ... features){ - this( - System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), - Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, DEFAULT_PROCESS_CLEANUP_DELAY), - features - ); - } - - /** - * Pass in the absolute path to the ExifTool executable on the host system. - */ - public ExifTool(String exifToolPath) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY); - } - - public ExifTool(String exifToolPath, Feature ... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); - } - - public ExifTool(String exifCmd, long processCleanupDelay, Feature ... features) { - this.exifVersion = ExifProcess.readVersion(exifCmd); - if (features != null && features.length > 0) { - for (Feature feature : features) { - if ( ! feature.isSupported(exifVersion) ) { - throw new UnsupportedFeatureException(feature); - } - this.featureEnabledSet.add(feature); - this.featureSupportedMap.put(feature,true); - } - } - - List baseArgs = new ArrayList(3); - if (featureEnabledSet.contains(Feature.MWG_MODULE) ) { - baseArgs.addAll(Arrays.asList("-use","MWG")); - } - if (featureEnabledSet.contains(Feature.STAY_OPEN) ) { - KeepAliveExifProxy proxy = new KeepAliveExifProxy(exifCmd,baseArgs); - proxy.setInactiveTimeout(processCleanupDelay); - exifProxy = proxy; - } else { - exifProxy = new SingleUseExifProxy(exifCmd,baseArgs); - } - } - - /** - * Limits the amount of time (in mills) an exif operation can take. Setting value to greater than 0 to enable. - */ - public ExifTool setRunTimeout(long mills) { - defReadOptions = defReadOptions.withRunTimeoutMills(mills); - defWriteOptions = defWriteOptions.withRunTimeoutMills(mills); - return this; - } - - /** - * Used to determine if the given {@link Feature} is supported by the - * underlying native install of ExifTool pointed at by - * {@link #ENV_EXIF_TOOL_PATH}. - *

- * If support for the given feature has not been checked for yet, this - * method will automatically call out to ExifTool and ensure the requested - * feature is supported in the current local install. - *

- * The external call to ExifTool to confirm feature support is only ever - * done once per JVM session and stored in a static final - * {@link Map} that all instances of this class share. - * - * @param feature - * The feature to check support for in the underlying ExifTool - * install. - * - * @return true if support for the given {@link Feature} was - * confirmed to work with the currently installed ExifTool or - * false if it is not supported. - * - * @throws IllegalArgumentException - * if feature is null. - * @throws RuntimeException - * if any exception occurs while attempting to start the - * external ExifTool process to verify feature support. - */ - public boolean isFeatureSupported(Feature feature) throws RuntimeException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); - } - - Boolean supported = featureSupportedMap.get(feature); + /** + * If ExifTool is on your system path and running the command "exiftool" + * successfully executes it, the default value unchanged will work fine on + * any platform. If the ExifTool executable is named something else or not + * in the system path, then this property will need to be set to point at it + * before using this class. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.path=/path/to/exiftool + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * On Windows be sure to double-escape the path to the tool, for example: + * + * -Dexiftool.path=C:\\Tools\\exiftool.exe + * + *

+ * Default value is "exiftool". + *

Relative Paths

+ * Relative path values (e.g. "bin/tools/exiftool") are executed with + * relation to the base directory the VM process was started in. Essentially + * the directory that new File(".").getAbsolutePath() points at + * during runtime. + */ + public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + /** + * Interval (in milliseconds) of inactivity before the cleanup thread wakes + * up and cleans up the daemon ExifTool process and the read/write streams + * used to communicate with it when the {@link Feature#STAY_OPEN} feature is + * used. + *

+ * Ever time a call to getImageMeta is processed, the timer + * keeping track of cleanup is reset; more specifically, this class has to + * experience no activity for this duration of time before the cleanup + * process is fired up and cleans up the host OS process and the stream + * resources. + *

+ * Any subsequent calls to getImageMeta after a cleanup simply + * re-initializes the resources. + *

+ * This system property can be set on startup with:
+ * + * -Dexiftool.processCleanupDelay=600000 + * or by calling {@link System#setProperty(String, String)} before + * this class is loaded. + *

+ * Setting this value to 0 disables the automatic cleanup thread completely + * and the caller will need to manually cleanup the external ExifTool + * process and read/write streams by calling {@link #close()}. + *

+ * Default value is zero, no inactivity timeout. + */ + public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + + /** + * Name used to identify the (optional) cleanup {@link Thread}. + *

+ * This is only provided to make debugging and profiling easier for + * implementers making use of this class such that the resources this class + * creates and uses (i.e. Threads) are readily identifiable in a running VM. + *

+ * Default value is "ExifTool Cleanup Thread". + */ + static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; + + static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + private static final String EXIF_DATE_FORMAT = "yyyy:MM:dd HH:mm:ss"; + + static final Logger log = LoggerFactory.getLogger(ExifTool.class); + + private final Map featureSupportedMap = new HashMap(); + private final Set featureEnabledSet = EnumSet + .noneOf(Feature.class); + private ReadOptions defReadOptions = new ReadOptions(); + private WriteOptions defWriteOptions = new WriteOptions(); + private final VersionNumber exifVersion; + private final ExifProxy exifProxy; + + public ExifTool() { + this((Feature[]) null); + } + + /** + * In this constructor, exifToolPath and processCleanupDelay are read from + * system properties exiftool.path and exiftool.processCleanupDelay. + * processCleanupDelay is optional. If not found, the default is used. + */ + public ExifTool(Feature... features) { + this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( + ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, + DEFAULT_PROCESS_CLEANUP_DELAY), features); + } + + /** + * Pass in the absolute path to the ExifTool executable on the host system. + */ + public ExifTool(String exifToolPath) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY); + } + + public ExifTool(String exifToolPath, Feature... features) { + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); + } + + public ExifTool(String exifCmd, long processCleanupDelay, + Feature... features) { + this.exifVersion = ExifProcess.readVersion(exifCmd); + if (features != null && features.length > 0) { + for (Feature feature : features) { + if (!feature.isSupported(exifVersion)) { + throw new UnsupportedFeatureException(feature); + } + this.featureEnabledSet.add(feature); + this.featureSupportedMap.put(feature, true); + } + } + + List baseArgs = new ArrayList(3); + if (featureEnabledSet.contains(Feature.MWG_MODULE)) { + baseArgs.addAll(Arrays.asList("-use", "MWG")); + } + if (featureEnabledSet.contains(Feature.STAY_OPEN)) { + KeepAliveExifProxy proxy = new KeepAliveExifProxy(exifCmd, baseArgs); + proxy.setInactiveTimeout(processCleanupDelay); + exifProxy = proxy; + } else { + exifProxy = new SingleUseExifProxy(exifCmd, baseArgs); + } + } + + /** + * Limits the amount of time (in mills) an exif operation can take. Setting + * value to greater than 0 to enable. + */ + public ExifTool setRunTimeout(long mills) { + defReadOptions = defReadOptions.withRunTimeoutMills(mills); + defWriteOptions = defWriteOptions.withRunTimeoutMills(mills); + return this; + } + + /** + * Used to determine if the given {@link Feature} is supported by the + * underlying native install of ExifTool pointed at by + * {@link #ENV_EXIF_TOOL_PATH}. + *

+ * If support for the given feature has not been checked for yet, this + * method will automatically call out to ExifTool and ensure the requested + * feature is supported in the current local install. + *

+ * The external call to ExifTool to confirm feature support is only ever + * done once per JVM session and stored in a static final + * {@link Map} that all instances of this class share. + * + * @param feature + * The feature to check support for in the underlying ExifTool + * install. + * + * @return true if support for the given {@link Feature} was + * confirmed to work with the currently installed ExifTool or + * false if it is not supported. + * + * @throws IllegalArgumentException + * if feature is null. + * @throws RuntimeException + * if any exception occurs while attempting to start the + * external ExifTool process to verify feature support. + */ + public boolean isFeatureSupported(Feature feature) throws RuntimeException { + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); + } + + Boolean supported = featureSupportedMap.get(feature); /* * If there is no Boolean flag for the feature, support for it hasn't * been checked yet with the native ExifTool install, so we need to do * that. */ - if (supported == null) { - log.debug("Support for feature %s has not been checked yet, checking..."); - supported = feature.isSupported(exifVersion); - featureSupportedMap.put(feature,supported); - } - - return supported; - } - - /** - * Used to determine if the given {@link Feature} has been enabled for this - * particular instance of {@link ExifTool}. - *

- * This method is different from {@link #isFeatureSupported(Feature)}, which - * checks if the given feature is supported by the underlying ExifTool - * install where as this method tells the caller if the given feature has - * been enabled for use in this particular instance. - * - * @param feature - * The feature to check if it has been enabled for us or not on - * this instance. - * - * @return true if the given {@link Feature} is currently - * enabled on this instance of {@link ExifTool}, otherwise returns - * false. - * - * @throws IllegalArgumentException - * if feature is null. - */ - public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException { - if (feature == null){ - throw new IllegalArgumentException("feature cannot be null"); - } - return featureEnabledSet.contains(feature); - } - - /** - * Used to startup the external ExifTool process and open the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. This method has no effect if the stay open feature is not enabled. - */ - public void startup(){ - exifProxy.startup(); - } - - /** - * This is same as {@link #close()}, added for consistency with {@link #startup()} - */ - public void shutdown(){ - close(); - } - - /** - * Used to shutdown the external ExifTool process and close the read/write - * streams used to communicate with it when {@link Feature#STAY_OPEN} is - * enabled. - *

- * NOTE: Calling this method does not preclude this - * instance of {@link ExifTool} from being re-used, it merely disposes of - * the native and internal resources until the next call to - * getImageMeta causes them to be re-instantiated. - *

- * Calling this method on an instance of this class without - * {@link Feature#STAY_OPEN} support enabled has no effect. - */ - public void close() { - exifProxy.shutdown(); - } - - public boolean isStayOpen() { - return featureEnabledSet.contains(Feature.STAY_OPEN); - } - - /** - * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support - * enabled, this method is used to determine if there is currently a running - * ExifTool process associated with this class. - *

- * Any dependent processes and streams can be shutdown using - * {@link #close()} and this class will automatically re-create them on the - * next call to getImageMeta if necessary. - * - * @return true if there is an external ExifTool process in - * daemon mode associated with this class utilizing the - * {@link Feature#STAY_OPEN} feature, otherwise returns - * false. - */ - public boolean isRunning() { - return exifProxy != null && ! exifProxy.isRunning(); - } - - - public ReadOptions getReadOptions() { - return defReadOptions; - } - - public ExifTool setReadOptions(ReadOptions options) { - defReadOptions = options; - return this; - } - - public WriteOptions getWriteOptions() { - return defWriteOptions; - } - - public ExifTool setWriteOptions(WriteOptions options) { - defWriteOptions = options; - return this; - } - //================================================================================ - //OLD API - public static enum Format{NUMERIC, HUMAN_READABLE} - - public Map getImageMeta(File image, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - return getImageMeta(image, Format.NUMERIC, tags); - } - - public Map getImageMeta(File image, Format format, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { - - String [] stringTags = new String[tags.length]; - int i=0; - for (Tag tag : tags){ - stringTags[i++] = tag.getKey(); - } - Map result = getImageMeta(image, format, true, stringTags); - return Tag.toTagMap(result); - } - - public Map getImageMeta(File image, Format format, TagGroup... tags) - throws IllegalArgumentException, SecurityException, IOException { - String [] stringTags = new String[tags.length]; - int i=0; - for (TagGroup tag : tags){ - stringTags[i++] = tag.getKey(); - } - return getImageMeta(image, format, false, stringTags); - } - - public Map getImageMeta(File file, Format format, boolean supressDuplicates, String... tags) throws IOException { - ReadOptions options = defReadOptions.withNumericOutput(format == Format.NUMERIC).withShowDuplicates(!supressDuplicates).withConvertTypes(false); - Map result = readMetadata(options, file, tags); - Map data = new TreeMap(); - for(Map.Entry entry : result.entrySet()) { - data.put(entry.getKey().toString(), entry.getValue()!=null?entry.getValue().toString():""); - } - return data; - } - - public void addImageMetadata(File image, Map values) throws IOException { - writeMetadata(defWriteOptions.withDeleteBackupFile(false),image,values); - } - //================================================================================ - public Map readMetadata(File file, Object... tags) throws IOException { - return readMetadata(defReadOptions,file,tags); - } - /** - * Reads metadata from the file. - */ - public Map readMetadata(ReadOptions options, File file, Object... tags) throws IOException { - if (file == null){ - throw new IllegalArgumentException("file cannot be null and must be a valid stream of image data."); - } - if (!file.canRead()){ - throw new SecurityException("Unable to read the given image ["+file.getAbsolutePath() - + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); - } - - List args = new ArrayList(tags.length+2); - if ( options.numericOutput ) { - args.add("-n"); // numeric output - } - if ( options.showDuplicates) { - args.add("-a"); - } - if ( ! options.showEmptyTags ) { - args.add("-S"); // compact output - } - for(Object tag: tags) { - if ( tag instanceof MetadataTag ) { - args.add("-"+((MetadataTag) tag).getKey()); - } else { - args.add("-" + tag); - } - } - args.add(file.getAbsolutePath()); - - Map resultMap = exifProxy.execute(options.runTimeoutMills,args); - - Map metadata = new HashMap(resultMap.size()); - - for(Object tag: tags) { - MetadataTag metaTag; - if (tag instanceof MetadataTag) { - metaTag = (MetadataTag) tag; - } else { - metaTag = toTag(tag.toString()); - } - if ( metaTag.isMapped() ) { - String input = resultMap.remove(metaTag.getKey()); - if ( ! options.showEmptyTags && (input == null || input.isEmpty()) ) { - continue; - } - Object value = options.convertTypes ? deserialize(metaTag.getKey(), input, metaTag.getType()) : input; - //maps with tag passed in, as caller expects to fetch - metadata.put(tag, value); - } - } - for(Map.Entry entry : resultMap.entrySet()) { - if ( ! options.showEmptyTags && entry.getValue() == null || entry.getValue().isEmpty() ) { - continue; - } - if ( options.convertTypes) { - MetadataTag metaTag = toTag(entry.getKey()); - Object value = deserialize(metaTag.getKey(), entry.getValue(), metaTag.getType()); - metadata.put(entry.getKey(), value); - } else { - metadata.put(entry.getKey(),entry.getValue()); - - } - } - return metadata; - } - - public void writeMetadata(File image, Map values) throws IOException { - writeMetadata(defWriteOptions, image, values); - } - /** - * Takes a map of tags (either (@link Tag) or Strings for keys) and replaces/appends them to the metadata. - */ - public void writeMetadata(WriteOptions options, File file, Map values) throws IOException { - if ( file == null ) throw new NullPointerException("File is null"); - if ( ! file.exists() ) throw new FileNotFoundException(String.format("File \"%s\" does not exits",file.getAbsolutePath())); - if ( ! file.canWrite() ) throw new SecurityException(String.format("File \"%s\" cannot be written to",file.getAbsolutePath())); - - log.info("Adding Tags {} to {}", values, file.getAbsolutePath()); - - List args = new ArrayList(values.size()+3); - for(Map.Entry entry : values.entrySet()) { - args.addAll(serializeToArgs(entry.getKey(),entry.getValue())); - } - args.add(file.getAbsolutePath()); - - //start process - long startTime = System.currentTimeMillis(); - try { - exifProxy.execute(options.runTimeoutMills, args); - } finally { - if ( options.deleteBackupFile ) { - File origBackup = new File(file.getAbsolutePath()+"_original"); - if ( origBackup.exists() ) origBackup.delete(); - } - } - - // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()) log.debug(String.format("Image Meta Processed in %d ms [added %d tags]", (System.currentTimeMillis() - startTime), values.size())); - - } - - public void rebuildMetadata(File file) throws IOException { - rebuildMetadata(getWriteOptions(),file); - } - - /** - * Rewrite all the the metadata tags in a JPEG image. This will not work for TIFF files. - * Use this when the image has some corrupt tags. - * - * @link http://www.sno.phy.queensu.ca/~phil/exiftool/faq.html#Q20 - */ - public void rebuildMetadata(WriteOptions options, File file) throws IOException { - if ( file == null ) throw new NullPointerException("File is null"); - if ( ! file.exists() ) throw new FileNotFoundException(String.format("File \"%s\" does not exits",file.getAbsolutePath())); - if ( ! file.canWrite() ) throw new SecurityException(String.format("File \"%s\" cannot be written to",file.getAbsolutePath())); - - List args = Arrays.asList("-all=", "-tagsfromfile", "@", "-all:all", "-unsafe",file.getAbsolutePath()); - try { - exifProxy.execute(options.runTimeoutMills, args); - } finally { - if ( options.deleteBackupFile ) { - File origBackup = new File(file.getAbsolutePath()+"_original"); - if ( origBackup.exists() ) origBackup.delete(); - } - } - } - //================================================================================ - //STATIC helpers - - static List serializeToArgs(Object tag, Object value) { - final Class tagType; - final String tagName; - if ( tag instanceof MetadataTag ) { - tagName = ((MetadataTag) tag).getKey(); - tagType = ((MetadataTag) tag).getType(); - } else { - tagName = tag.toString(); - tagType = null; - } - - //pre process - if ( value != null ) { - if ( value.getClass().isArray() ) { - //convert array to iterable, this is lame - int len = Array.getLength(value); - List newList = new ArrayList(len); - for (int i = 0; i < len; i++) { - Object item = Array.get(value,i); - newList.add(item); - } - value = newList; - } else if ( value instanceof Number && Date.class.equals(tagType) ) { - //if we know this is a date field and data is a number assume it is unix epoch time - Date date = new Date(((Number) value).longValue()); - value = date; - } - } - - List args = new ArrayList(4); - String arg; - if (value == null ) { - arg = String.format("-%s=",tagName); - } else if ( value instanceof Number ) { - arg = String.format("-%s#=%s",tagName,value); - } else if(value instanceof Date) { - SimpleDateFormat formatter = new SimpleDateFormat(EXIF_DATE_FORMAT); - arg = String.format("-%s=%s",tagName,formatter.format((Date)value)); - } else if (value instanceof Iterable) { - Iterable it = (Iterable) value; - args.add("-sep"); - args.add(","); - StringBuilder itemList = new StringBuilder(); - for(Object item : it) { - if ( itemList.length() > 0 ) { - itemList.append(","); - } - itemList.append(item); - } - arg = String.format("-%s=%s",tagName, itemList); - } else { - if ( tagType != null && tagType.isArray() ) { - args.add("-sep"); - args.add(","); - } - arg = String.format("-%s=%s",tagName,value); - } - args.add(arg); - return args; - } - - static Object deserialize(String tagName, String value, Class expectedType) { - try { - if ( Boolean.class.equals(expectedType) ) { - if ( value == null ) return null; - value = value.trim().toLowerCase(); - switch (value.charAt(0)) { - case 'n': case 'f': case '0': return false; - } - if ( value.equals("off") ) { - return false; - } - return true; - } else if ( Date.class.equals(expectedType) ) { - if ( value == null ) return null; - SimpleDateFormat formatter = new SimpleDateFormat(EXIF_DATE_FORMAT); - return formatter.parse(value); - } else if ( Integer.class.equals(expectedType) ) { - if ( value == null ) return 0; - return Integer.parseInt(value); - } else if ( Long.class.equals(expectedType) ) { - if ( value == null ) return 0; - return Long.parseLong(value); - } else if ( Float.class.equals(expectedType) ) { - if ( value == null ) return 0; - return Float.parseFloat(value); - } else if ( Double.class.equals(expectedType) ) { - if ( value == null ) return 0; - String[] enumeratorAndDivisor = value.split("/"); - if ( enumeratorAndDivisor.length == 2 ) { - return Double.parseDouble(enumeratorAndDivisor[0]) / Double.parseDouble(enumeratorAndDivisor[1]); - } else { - return Double.parseDouble(value); - } - } else if ( String[].class.equals(expectedType) ) { - if ( value == null ) return new String[0]; - return value.split(","); - } else { - return value; - } - } catch (ParseException ex) { - log.warn("Invalid format, Tag:"+tagName); - return null; - } catch (NumberFormatException ex) { - log.warn("Invalid format, Tag:"+tagName); - return null; - } - - } - - static MetadataTag toTag(String name) { - for(Tag tag: Tag.values()) { - if ( tag.getKey().equalsIgnoreCase(name) ) { - return tag; - } - } - for(MwgTag tag: MwgTag.values()) { - if ( tag.getKey().equalsIgnoreCase(name) ) { - return tag; - } - } - return new CustomTag(name,String.class); - } - - //================================================================================ - /** - * Represents an external exif process. Works for both single use and keep alive modes. - * This is the actual process, with streams for reading and writing data. - */ - public static final class ExifProcess { - /** - * Compiled {@link Pattern} of ": " used to split compact output from - * ExifTool evenly into name/value pairs. - */ - private static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); - - public static VersionNumber readVersion(String exifCmd) { - ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, "-ver")); - try { - return new VersionNumber(process.readLine()); - } catch (IOException ex) { - throw new RuntimeException(String.format("Unable to check version number of ExifTool: %s", exifCmd)); - } finally { - process.close(); - } - } - - private final ReentrantLock closeLock = new ReentrantLock(false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader out; - private final OutputStreamWriter in; - private final LineReaderThread errReader; - private volatile boolean closed = false; - - public ExifProcess(boolean keepAlive, List args) { - this.keepAlive = keepAlive; - log.debug(String.format("Attempting to start ExifTool process using args: %s", args)); - try { - this.process = new ProcessBuilder(args).start(); - this.out = new BufferedReader(new InputStreamReader(process.getInputStream())); - this.in = new OutputStreamWriter(process.getOutputStream()); - this.errReader = new LineReaderThread("exif-process-err-reader",new BufferedReader(new InputStreamReader(process.getErrorStream()))); - errReader.start(); - log.debug("\tSuccessful"); - } catch (Exception e) { - String message = "Unable to start external ExifTool process using the execution arguments: " - + args - + ". Ensure ExifTool is installed correctly and runs using the command path '" - + args.get(0) - + "' as specified by the 'exiftool.path' system property."; - - log.debug(message); - throw new RuntimeException(message, e); - } - } - - public synchronized Map sendToRunning(List args) throws IOException { - if (!keepAlive) { - throw new IOException("Not KeepAlive Process"); - } - StringBuilder builder = new StringBuilder(); - for (String arg : args) { - builder.append(arg).append("\n"); - } - builder.append("-execute\n"); - writeFlush(builder.toString()); - return readResponse(); - } - - public synchronized void writeFlush(String message) throws IOException { - if (closed) throw new IOException(STREAM_CLOSED_MESSAGE); - in.write(message); - in.flush(); - } - - public synchronized String readLine() throws IOException { - if (closed) throw new IOException(STREAM_CLOSED_MESSAGE); - return out.readLine(); - } - - public synchronized Map readResponse() throws IOException { - if (closed) throw new IOException(STREAM_CLOSED_MESSAGE); - log.debug("Reading response back from ExifTool..."); - Map resultMap = new HashMap(500); - String line; - while ((line = out.readLine()) != null) { - if (closed) throw new IOException(STREAM_CLOSED_MESSAGE); - String[] pair = TAG_VALUE_PATTERN.split(line, 2); - if (pair.length == 2) { - resultMap.put(pair[0], pair[1]); - log.debug(String.format("\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); - } - - /* - * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need to - * look for it and break from this loop when we see it otherwise - * this process will hang indefinitely blocking on the input stream - * with no data to read. - */ - if (keepAlive && line.equals("{ready}")) { - break; - } - } - if ( errReader.hasLines() ) { - for(String error : errReader.takeLines()) { - if ( error.toLowerCase().startsWith("error") ) { - throw new ExifError(error); - } - } - } - return resultMap; - } - - public boolean isClosed() { - return closed; - } - - public void close() { - if (!closed) { - closeLock.lock(); - try { - if (!closed) { - closed = true; - try { - log.debug("Closing Read stream..."); - out.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log.debug("Attempting to close ExifTool daemon process, issuing '-stay_open\\nFalse\\n' command..."); - in.write("-stay_open\nFalse\n"); - in.flush(); - } catch (IOException ex) { - //log.error(ex,ex); - } - - try { - log.debug("Closing Write stream..."); - in.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - try { - log.debug("Closing Error stream..."); - errReader.close(); - log.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - } - - log.debug("Read/Write streams successfully closed."); - - try { - process.destroy(); - } catch (Exception e) { - // - } - //process = null; - - } - } finally { - closeLock.unlock(); - } - } - } - } - - /** - * A Proxy to an Exif Process, will restart if backing exif process died, or run new one on every call. - * @author Matt Gile, msgile - */ - public interface ExifProxy { - public void startup(); - public Map execute(long runTimeoutMills, List args) throws IOException; - public boolean isRunning(); - public void shutdown(); - } - - /** - * Manages an external exif process in keep alive mode. - */ - public static class KeepAliveExifProxy implements ExifProxy { - private final List startupArgs; - private final AtomicBoolean shuttingDown = new AtomicBoolean(false); - private final Timer cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - private long inactivityTimeout = 0; - private volatile long lastRunStart = 0; - private volatile ExifProcess process; - - public KeepAliveExifProxy(String exifCmd, List baseArgs) { - inactivityTimeout = Long.getLong(ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, DEFAULT_PROCESS_CLEANUP_DELAY); - startupArgs = new ArrayList(baseArgs.size()+5); - startupArgs.add(exifCmd); - startupArgs.addAll(Arrays.asList("-stay_open", "True")); - startupArgs.addAll(baseArgs); - startupArgs.addAll(Arrays.asList("-@", "-")); - //runs every minute to check if process has been inactive too long - cleanupTimer.schedule(new TimerTask() { - @Override - public void run() { - if ( process != null && lastRunStart > 0 && inactivityTimeout > 0 ) { - if ( (System.currentTimeMillis()-lastRunStart) > inactivityTimeout) { - synchronized (this) { - if ( process != null ) { - process.close(); - } - } - } - } - } - },60*1000); //every minute - } - - public void setInactiveTimeout(long mills) { - this.inactivityTimeout = mills; - } - - public void startup() { - shuttingDown.set(false); - if (process ==null || process.isClosed()) { - synchronized (this){ - if (process ==null || process.isClosed() ){ - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = new ExifProcess(true, startupArgs); - } - } - } - } - - public Map execute(final long runTimeoutMills, List args) throws IOException { - lastRunStart = System.currentTimeMillis(); - int attempts = 0; - while (attempts < 3 && ! shuttingDown.get()){ - attempts++; - if (process ==null || process.isClosed()) { - synchronized (this){ - if (process ==null || process.isClosed() ){ - log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = new ExifProcess(true, startupArgs); - } - } - } - TimerTask attemptTimer = null; - try { - if ( runTimeoutMills > 0 ) { - attemptTimer = new TimerTask() { - public void run() { - if (process != null && ! process.isClosed()) { - log.warn("Process ran too long closing, max " + runTimeoutMills + " mills"); - process.close(); - } - } - }; - cleanupTimer.schedule(attemptTimer, runTimeoutMills); - } - log.debug("Streaming arguments to ExifTool process..."); - return process.sendToRunning(args); - } catch (IOException ex){ - if ( STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) && ! shuttingDown.get() ){ - //only catch "Stream Closed" error (happens when process has died) - log.warn(String.format("Caught IOException(\"%s\"), will restart daemon",STREAM_CLOSED_MESSAGE)); - process.close(); - } else { - throw ex; - } - } finally { - if ( attemptTimer != null ) attemptTimer.cancel(); - } - } - if ( shuttingDown.get() ) { - throw new IOException("Shutting Down"); - } - throw new IOException("Ran out of attempts"); - } - - public boolean isRunning() { - return process != null && ! process.isClosed(); - } - - public void shutdown() { - shuttingDown.set(true); - } - } - - public static class SingleUseExifProxy implements ExifProxy { - private final Timer cleanupTimer = new Timer(CLEANUP_THREAD_NAME, true); - private final List baseArgs; - - public SingleUseExifProxy(String exifCmd, List defaultArgs) { - this.baseArgs = new ArrayList(defaultArgs.size()+1); - this.baseArgs.add(exifCmd); - this.baseArgs.addAll(defaultArgs); - } - - public Map execute(final long runTimeoutMills, List args) throws IOException { - List newArgs = new ArrayList(baseArgs.size()+args.size()); - newArgs.addAll(baseArgs); - newArgs.addAll(args); - final ExifProcess process = new ExifProcess(false, newArgs); - TimerTask attemptTimer = null; - if ( runTimeoutMills > 0 ) { - attemptTimer = new TimerTask() { - public void run() { - if ( ! process.isClosed() ) { - log.warn("Process ran too long closing, max " + runTimeoutMills + " mills"); - process.close(); - } - } - }; - cleanupTimer.schedule(attemptTimer, runTimeoutMills); - } - try { - return process.readResponse(); - } finally { - process.close(); - if ( attemptTimer != null ) attemptTimer.cancel(); - } - } - - public void startup() { - ; - } - - public boolean isRunning() { - return false; - } - - public void shutdown() { - ; - } - } - //================================================================================ - /** - * All the read options, is immutable, copy on change, fluent style "with" setters. - */ - public static class ReadOptions { - private final long runTimeoutMills; - private final boolean convertTypes; - private final boolean numericOutput; - private final boolean showDuplicates; - private final boolean showEmptyTags; - - public ReadOptions() { - this(0,false,false,false,false); - } - - private ReadOptions(long runTimeoutMills, boolean convertTypes, boolean numericOutput, boolean showDuplicates, boolean showEmptyTags) { - this.runTimeoutMills = runTimeoutMills; - this.convertTypes = convertTypes; - this.numericOutput = numericOutput; - this.showDuplicates = showDuplicates; - this.showEmptyTags = showEmptyTags; - } - - public String toString() { - return String.format("%s(runTimeout:%,d convertTypes:%s showDuplicates:%s showEmptyTags:%s)", - getClass().getSimpleName(),runTimeoutMills,convertTypes,showDuplicates,showEmptyTags); - } - - /** - * Sets the maximum time a process can run - */ - public ReadOptions withRunTimeoutMills(long mills) { - return new ReadOptions(mills,convertTypes,numericOutput, showDuplicates,showEmptyTags); - } - - /** - * By default all values will be returned as the strings printed by the exiftool. - * If this is enabled then {@link MetadataTag#getType()} is used to cast the string into a java type. - */ - public ReadOptions withConvertTypes(boolean enabled) { - return new ReadOptions(runTimeoutMills,enabled,numericOutput, showDuplicates,showEmptyTags); - } - - /** - * Setting this to true will add the "-n" option causing the ExifTool to output of some tags to change. - *

- * ExifTool, via the -n command line arg, is capable of - * returning most values in their raw numeric form (e.g. - * Aperture="2.8010323841") as well as a more human-readable/friendly format - * (e.g. Aperture="2.8"). - *

- * While the {@link Tag}s defined on this class do provide a hint at the - * type of the result (see {@link MetadataTag#getType()}), that hint only applies - * when the numeric value is returned. - *

- * If the caller finds the human-readable format easier to process, - * Set this to false, the default. - *

- * In order to see the types of values that are returned when human readable - * is used (default), you can check the comprehensive - * ExifTool Tag Guide. - *

- * This makes sense with some values like Aperture that in numeric - * format end up returning as 14-decimal-place, high - * precision values that are near the intended value (e.g. - * "2.79999992203711" instead of just returning "2.8"). On the other hand, - * other values (like Orientation) are easier to parse when their numeric - * value (1-8) is returned instead of a much longer friendly name (e.g. - * "Mirror horizontal and rotate 270 CW"). - * - * Attempted from work done by - * @author Riyad Kalla (software@thebuzzmedia.com) - */ - public ReadOptions withNumericOutput(boolean enabled) { - return new ReadOptions(runTimeoutMills,convertTypes,enabled, showDuplicates,showEmptyTags); - } - - /** - * If enabled will show tags which are duplicated between different tag regions, relates to the "-a" option in ExifTool. - */ - public ReadOptions withShowDuplicates(boolean enabled) { - return new ReadOptions(runTimeoutMills,convertTypes,numericOutput,enabled,showEmptyTags); - } - - public ReadOptions withShowEmptyTags(boolean enabled) { - return new ReadOptions(runTimeoutMills,convertTypes,numericOutput,showDuplicates,enabled); - } - } - - //================================================================================ - /** - * All the write options, is immutable, copy on change, fluent style "with" setters. - */ - public static class WriteOptions { - private final long runTimeoutMills; - private final boolean deleteBackupFile; - - public WriteOptions() { - this(0,false); - } - - private WriteOptions(long runTimeoutMills, boolean deleteBackupFile) { - this.runTimeoutMills = runTimeoutMills; - this.deleteBackupFile = deleteBackupFile; - } - - public String toString() { - return String.format("%s(runTimeOut:%,d deleteBackupFile:%s)",getClass().getSimpleName(),runTimeoutMills,deleteBackupFile); - } - - public WriteOptions withRunTimeoutMills(long mills) { - return new WriteOptions(mills,deleteBackupFile); - } - /** - * ExifTool automatically makes a backup copy a file before writing metadata tags in the form - * "file.ext_original", by default this tool will delete that original file after the writing is done. - */ - public WriteOptions withDeleteBackupFile(boolean enabled) { - return new WriteOptions(runTimeoutMills,enabled); - } - } - - //================================================================================ - /** - * Enum used to define the different kinds of features in the native - * ExifTool executable that this class can help you take advantage of. - *

- * These flags are different from {@link Tag}s in that a "feature" is - * determined to be a special functionality of the underlying ExifTool - * executable that requires a different code-path in this class to take - * advantage of; for example, -stay_open True support. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Feature { - /** - * Enum used to specify that you wish to launch the underlying ExifTool - * process with -stay_open True support turned on that this - * class can then take advantage of. - *

- * Required ExifTool version is 8.36 or higher. - */ - STAY_OPEN(8,36), - /** - * Acitves the MWG modules. The Metadata Working Group (MWG) recommends - * techniques to allow certain overlapping EXIF, IPTC and XMP tags to be - * reconciled when reading, and synchronized when writing. The MWG Composite tags - * below are designed to aid in the implementation of these recommendations. - * Will add the args " -use MWG" - * - * @see ExifTool MWG Docs - * !! Note these version numbers are not correct - */ - MWG_MODULE(8,36), - ; - - - private VersionNumber requireVersion; - private Feature(int... numbers) { - this.requireVersion = new VersionNumber(numbers); - } - /** - * Used to get the version of ExifTool required by this feature in order - * to work. - * - * @return the version of ExifTool required by this feature in order to - * work. - */ - VersionNumber getVersion() { - return requireVersion; - } - - boolean isSupported(VersionNumber exifVersionNumber) { - return requireVersion.isBeforeOrEqualTo(exifVersionNumber); - } - } - - //================================================================================ - /** - * Version Number used to determine if one version is after another. - * @author Matt Gile, msgile - */ - static class VersionNumber { - private final int[] numbers; - - public VersionNumber(String str) { - String[] versionParts = str.trim().split("\\."); - this.numbers = new int[versionParts.length]; - for(int i=0; i other.numbers[i] ) { - return false; - } else if ( this.numbers[i] < other.numbers[i] ) { - return true; - } - } - //assume missing number as zero, so if the current process number is more digits it is a higher version - return this.numbers.length <= other.numbers.length; - } - - public String toString() { - StringBuilder builder = new StringBuilder(); - for (int number : numbers) { - if (builder.length() > 0) { - builder.append("."); - } - builder.append(number); - } - return builder.toString(); - } - } - - - //================================================================================ - /** - * Base type for all "tag" passed to exiftool. - * The key is the value passed to the exiftool like "-creator". - * The Types is used for automatic type conversions. - * - */ - public interface MetadataTag { - /** - * Returns the values passed to exiftool - */ - public String getKey(); - /** - * The types - */ - public Class getType(); - public boolean isMapped(); - } - - //================================================================================ - /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifTool. - *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default humanReadable is false. - *

- * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. - *

Tag Support

- * ExifTool is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. - *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. - *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public enum Tag implements MetadataTag { - //single entry tags - APERTURE("ApertureValue", Double.class), - AUTHOR("XPAuthor", String.class), - COLOR_SPACE("ColorSpace", Integer.class), - COMMENT("XPComment", String.class), - CONTRAST("Contrast", Integer.class), - CREATE_DATE("CreateDate", Date.class), - CREATION_DATE("CreationDate", Date.class), - DATE_CREATED("DateCreated", Date.class), - DATE_TIME_ORIGINAL("DateTimeOriginal", Date.class), - DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - FLASH("Flash", Integer.class), - FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), - FNUMBER("FNumber", String.class), - GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), - GPS_DATESTAMP("GPSDateStamp", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), - GPS_LONGITUDE("GPSLongitude", Double.class), - GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), - GPS_SPEED("GPSSpeed", Double.class), - GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), - IMAGE_WIDTH("ImageWidth", Integer.class), - ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), - LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), - MAKE("Make", String.class), - METERING_MODE("MeteringMode", Integer.class), - MODEL("Model", String.class), - ORIENTATION("Orientation", Integer.class), - OWNER_NAME("OwnerName", String.class), - RATING("Rating", Integer.class), - RATING_PERCENT("RatingPercent", Integer.class), - ROTATION("Rotation", Integer.class), - SATURATION("Saturation", Integer.class), - SENSING_METHOD("SensingMethod", Integer.class), - SHARPNESS("Sharpness", Integer.class), - SHUTTER_SPEED("ShutterSpeedValue", Double.class), - SOFTWARE("Software", String.class), - SUBJECT("XPSubject", String.class), - TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), - X_RESOLUTION("XResolution", Double.class), - Y_RESOLUTION("YResolution", Double.class), - ; - - /** - * Used to get the {@link Tag} identified by the given, case-sensitive, - * tag name. - * - * @param name - * The case-sensitive name of the tag that will be searched - * for. - * - * @return the {@link Tag} identified by the given, case-sensitive, tag - * name or null if one couldn't be found. - */ - public static Tag forName(String name) { - for (Tag tag : Tag.values()){ - if (tag.getKey().equals(name)){ - return tag; - } - } - return null; - } - - public static Map toTagMap(Map values) { - Map tagMap = new EnumMap(Tag.class); - for (Tag tag : Tag.values()){ - if (values.containsKey(tag.getKey())){ - tagMap.put(tag, values.get(tag.getKey())); - } - } - return tagMap; - - } - - /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifTool process) into the type described - * by the associated {@link Tag}. - * - * @param - * The type of the returned value. - * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. - * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). - * - * @throws IllegalArgumentException - * if tag is null. - * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). - * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. - */ - @SuppressWarnings("unchecked") - public T parseValue(String value) throws IllegalArgumentException { - return (T) deserialize(getKey(),value,getType()); - } - - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ - public String getName() { - return name; - } - - /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifTool Tag Guide. - * - * @return a hint for the native type of this tag's value. - */ - public Class getType() { - return type; - } - - public String getKey() { return name; } - public boolean isMapped() { return true; } - - private String name; - private Class type; - - private Tag(String name, Class type) { - this.name = name; - this.type = type; - } - } - //================================================================================ - public enum MwgTag implements MetadataTag { - LOCATION("Location",String.class), - CITY("City",String.class), - STATE("State",String.class), - COUNTRY("Country",String.class), - - COPYRIGHT("Copyright",String.class), - - DATE_TIME_ORIGINAL("DateTimeOriginal",Date.class), - CREATE_DATE("CreateDate",Date.class), - MODIFY_DATE("ModifyDate",Date.class), - - CREATOR("Creator",String.class), - DESCRIPTION("Description",String.class), - KEYWORDS("Keywords",String[].class), - - ORIENTATION("Orientation",Integer.class), - RATING("Rating",Integer.class), - - ; - - - private String name; - private Class type; - private MwgTag(String name, Class type) { - this.name = name; - this.type = type; - } - public String getKey() { return name; } - public Class getType() { return type; } - public boolean isMapped() { return true; } - public String toString() { return name; } - } - - //================================================================================ - - /** - * A Custom Tag that the user defines. Used to cover tags not in the enum. - */ - public static class CustomTag implements MetadataTag { - private final String name; - private final Class type; - private final boolean mapped; - - public CustomTag(String name, Class type) { - this(name,type,!name.trim().endsWith(":all")); - } - public CustomTag(String name, Class type, boolean mapped) { - this.name = name.trim(); - this.type = type; - this.mapped = mapped; - } - - public String getKey() { - return name; - } - - public Class getType() { - return type; - } - - public boolean isMapped() { - return mapped; - } - - public String toString() { - return getKey(); - } - } - - - //================================================================================ - public enum TagGroup implements MetadataTag { - EXIF("EXIF","exif:all"), - IPTC("IPTC","iptc:all"), - XMP("XMP","xmp:all"), - ALL("ALL","all"); - - private final String name; - private final String key; - - private TagGroup(String name, String key) { - this.name = name; - this.key = key; - } - - public String getName() { - return name; - } - public String getKey() { - return key; - } - - public Class getType() { - return Void.class; - } - - public boolean isMapped() { - return false; - } - - } - - - //================================================================================ - /** - * Class used to define an exception that occurs when the caller attempts to - * use a {@link Feature} that the underlying native ExifTool install does - * not support (i.e. the version isn't new enough). - * - * @author Riyad Kalla (software@thebuzzmedia.com) - * @since 1.1 - */ - public class UnsupportedFeatureException extends RuntimeException { - private static final long serialVersionUID = -1332725983656030770L; + if (supported == null) { + log.debug("Support for feature %s has not been checked yet, checking..."); + supported = feature.isSupported(exifVersion); + featureSupportedMap.put(feature, supported); + } + + return supported; + } + + /** + * Used to determine if the given {@link Feature} has been enabled for this + * particular instance of {@link ExifTool}. + *

+ * This method is different from {@link #isFeatureSupported(Feature)}, which + * checks if the given feature is supported by the underlying ExifTool + * install where as this method tells the caller if the given feature has + * been enabled for use in this particular instance. + * + * @param feature + * The feature to check if it has been enabled for us or not on + * this instance. + * + * @return true if the given {@link Feature} is currently + * enabled on this instance of {@link ExifTool}, otherwise returns + * false. + * + * @throws IllegalArgumentException + * if feature is null. + */ + public boolean isFeatureEnabled(Feature feature) + throws IllegalArgumentException { + if (feature == null) { + throw new IllegalArgumentException("feature cannot be null"); + } + return featureEnabledSet.contains(feature); + } + + /** + * Used to startup the external ExifTool process and open the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. This method has no effect if the stay open feature is not + * enabled. + */ + public void startup() { + exifProxy.startup(); + } + + /** + * This is same as {@link #close()}, added for consistency with + * {@link #startup()} + */ + public void shutdown() { + close(); + } + + /** + * Used to shutdown the external ExifTool process and close the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. + *

+ * NOTE: Calling this method does not preclude this + * instance of {@link ExifTool} from being re-used, it merely disposes of + * the native and internal resources until the next call to + * getImageMeta causes them to be re-instantiated. + *

+ * Calling this method on an instance of this class without + * {@link Feature#STAY_OPEN} support enabled has no effect. + */ + public void close() { + exifProxy.shutdown(); + } + + public boolean isStayOpen() { + return featureEnabledSet.contains(Feature.STAY_OPEN); + } + + /** + * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support + * enabled, this method is used to determine if there is currently a running + * ExifTool process associated with this class. + *

+ * Any dependent processes and streams can be shutdown using + * {@link #close()} and this class will automatically re-create them on the + * next call to getImageMeta if necessary. + * + * @return true if there is an external ExifTool process in + * daemon mode associated with this class utilizing the + * {@link Feature#STAY_OPEN} feature, otherwise returns + * false. + */ + public boolean isRunning() { + return exifProxy != null && !exifProxy.isRunning(); + } + + public ReadOptions getReadOptions() { + return defReadOptions; + } + + public ExifTool setReadOptions(ReadOptions options) { + defReadOptions = options; + return this; + } + + public WriteOptions getWriteOptions() { + return defWriteOptions; + } + + public ExifTool setWriteOptions(WriteOptions options) { + defWriteOptions = options; + return this; + } + + public Map getImageMeta(File image, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { + return getImageMeta(image, Format.NUMERIC, tags); + } + + public Map getImageMeta(File image, Format format, Tag... tags) + throws IllegalArgumentException, SecurityException, IOException { + + String[] stringTags = new String[tags.length]; + int i = 0; + for (Tag tag : tags) { + stringTags[i++] = tag.getKey(); + } + Map result = getImageMeta(image, format, true, + stringTags); + return Tag.toTagMap(result); + } + + public Map getImageMeta(File image, Format format, + TagGroup... tags) throws IllegalArgumentException, + SecurityException, IOException { + String[] stringTags = new String[tags.length]; + int i = 0; + for (TagGroup tag : tags) { + stringTags[i++] = tag.getKey(); + } + return getImageMeta(image, format, false, stringTags); + } + + public Map getImageMeta(File file, Format format, + boolean supressDuplicates, String... tags) throws IOException { + ReadOptions options = defReadOptions + .withNumericOutput(format == Format.NUMERIC) + .withShowDuplicates(!supressDuplicates).withConvertTypes(false); + Map result = readMetadata(options, file, tags); + Map data = new TreeMap(); + for (Map.Entry entry : result.entrySet()) { + data.put(entry.getKey().toString(), + entry.getValue() != null ? entry.getValue().toString() : ""); + } + return data; + } + + public void addImageMetadata(File image, Map values) + throws IOException { + writeMetadata(defWriteOptions.withDeleteBackupFile(false), image, + values); + } + + // ================================================================================ + public Map readMetadata(File file, Object... tags) + throws IOException { + return readMetadata(defReadOptions, file, tags); + } + + /** + * Reads metadata from the file. + */ + public Map readMetadata(ReadOptions options, File file, + Object... tags) throws IOException { + if (file == null) { + throw new IllegalArgumentException( + "file cannot be null and must be a valid stream of image data."); + } + if (!file.canRead()) { + throw new SecurityException( + "Unable to read the given image [" + + file.getAbsolutePath() + + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); + } + + List args = new ArrayList(tags.length + 2); + if (options.numericOutput) { + args.add("-n"); // numeric output + } + if (options.showDuplicates) { + args.add("-a"); + } + if (!options.showEmptyTags) { + args.add("-S"); // compact output + } + for (Object tag : tags) { + if (tag instanceof MetadataTag) { + args.add("-" + ((MetadataTag) tag).getKey()); + } else { + args.add("-" + tag); + } + } + args.add(file.getAbsolutePath()); + + Map resultMap = exifProxy.execute( + options.runTimeoutMills, args); + + Map metadata = new HashMap( + resultMap.size()); + + for (Object tag : tags) { + MetadataTag metaTag; + if (tag instanceof MetadataTag) { + metaTag = (MetadataTag) tag; + } else { + metaTag = toTag(tag.toString()); + } + if (metaTag.isMapped()) { + String input = resultMap.remove(metaTag.getKey()); + if (!options.showEmptyTags + && (input == null || input.isEmpty())) { + continue; + } + Object value = options.convertTypes ? deserialize( + metaTag.getKey(), input, metaTag.getType()) : input; + // maps with tag passed in, as caller expects to fetch + metadata.put(tag, value); + } + } + for (Map.Entry entry : resultMap.entrySet()) { + if (!options.showEmptyTags && entry.getValue() == null + || entry.getValue().isEmpty()) { + continue; + } + if (options.convertTypes) { + MetadataTag metaTag = toTag(entry.getKey()); + Object value = deserialize(metaTag.getKey(), entry.getValue(), + metaTag.getType()); + metadata.put(entry.getKey(), value); + } else { + metadata.put(entry.getKey(), entry.getValue()); + + } + } + return metadata; + } + + public void writeMetadata(File image, Map values) + throws IOException { + writeMetadata(defWriteOptions, image, values); + } + + /** + * Takes a map of tags (either (@link Tag) or Strings for keys) and + * replaces/appends them to the metadata. + */ + public void writeMetadata(WriteOptions options, File file, + Map values) throws IOException { + if (file == null) + throw new NullPointerException("File is null"); + if (!file.exists()) + throw new FileNotFoundException(String.format( + "File \"%s\" does not exits", file.getAbsolutePath())); + if (!file.canWrite()) + throw new SecurityException(String.format( + "File \"%s\" cannot be written to", file.getAbsolutePath())); + + log.info("Adding Tags {} to {}", values, file.getAbsolutePath()); + + List args = new ArrayList(values.size() + 3); + for (Map.Entry entry : values.entrySet()) { + args.addAll(serializeToArgs(entry.getKey(), entry.getValue())); + } + args.add(file.getAbsolutePath()); + + // start process + long startTime = System.currentTimeMillis(); + try { + exifProxy.execute(options.runTimeoutMills, args); + } finally { + if (options.deleteBackupFile) { + File origBackup = new File(file.getAbsolutePath() + "_original"); + if (origBackup.exists()) + origBackup.delete(); + } + } + + // Print out how long the call to external ExifTool process took. + if (log.isDebugEnabled()) + log.debug(String.format( + "Image Meta Processed in %d ms [added %d tags]", + (System.currentTimeMillis() - startTime), values.size())); + + } + + public void rebuildMetadata(File file) throws IOException { + rebuildMetadata(getWriteOptions(), file); + } + + /** + * Rewrite all the the metadata tags in a JPEG image. This will not work for + * TIFF files. Use this when the image has some corrupt tags. + * + * @link http://www.sno.phy.queensu.ca/~phil/exiftool/faq.html#Q20 + */ + public void rebuildMetadata(WriteOptions options, File file) + throws IOException { + if (file == null) + throw new NullPointerException("File is null"); + if (!file.exists()) + throw new FileNotFoundException(String.format( + "File \"%s\" does not exits", file.getAbsolutePath())); + if (!file.canWrite()) + throw new SecurityException(String.format( + "File \"%s\" cannot be written to", file.getAbsolutePath())); + + List args = Arrays.asList("-all=", "-tagsfromfile", "@", + "-all:all", "-unsafe", file.getAbsolutePath()); + try { + exifProxy.execute(options.runTimeoutMills, args); + } finally { + if (options.deleteBackupFile) { + File origBackup = new File(file.getAbsolutePath() + "_original"); + if (origBackup.exists()) + origBackup.delete(); + } + } + } + + // ================================================================================ + // STATIC helpers + + static List serializeToArgs(Object tag, Object value) { + final Class tagType; + final String tagName; + if (tag instanceof MetadataTag) { + tagName = ((MetadataTag) tag).getKey(); + tagType = ((MetadataTag) tag).getType(); + } else { + tagName = tag.toString(); + tagType = null; + } + + // pre process + if (value != null) { + if (value.getClass().isArray()) { + // convert array to iterable, this is lame + int len = Array.getLength(value); + List newList = new ArrayList(len); + for (int i = 0; i < len; i++) { + Object item = Array.get(value, i); + newList.add(item); + } + value = newList; + } else if (value instanceof Number && Date.class.equals(tagType)) { + // if we know this is a date field and data is a number assume + // it is unix epoch time + Date date = new Date(((Number) value).longValue()); + value = date; + } + } + + List args = new ArrayList(4); + String arg; + if (value == null) { + arg = String.format("-%s=", tagName); + } else if (value instanceof Number) { + arg = String.format("-%s#=%s", tagName, value); + } else if (value instanceof Date) { + SimpleDateFormat formatter = new SimpleDateFormat(EXIF_DATE_FORMAT); + arg = String.format("-%s=%s", tagName, + formatter.format((Date) value)); + } else if (value instanceof Iterable) { + Iterable it = (Iterable) value; + args.add("-sep"); + args.add(","); + StringBuilder itemList = new StringBuilder(); + for (Object item : it) { + if (itemList.length() > 0) { + itemList.append(","); + } + itemList.append(item); + } + arg = String.format("-%s=%s", tagName, itemList); + } else { + if (tagType != null && tagType.isArray()) { + args.add("-sep"); + args.add(","); + } + arg = String.format("-%s=%s", tagName, value); + } + args.add(arg); + return args; + } + + static Object deserialize(String tagName, String value, Class expectedType) { + try { + if (Boolean.class.equals(expectedType)) { + if (value == null) + return null; + value = value.trim().toLowerCase(); + switch (value.charAt(0)) { + case 'n': + case 'f': + case '0': + return false; + } + if (value.equals("off")) { + return false; + } + return true; + } else if (Date.class.equals(expectedType)) { + if (value == null) + return null; + SimpleDateFormat formatter = new SimpleDateFormat( + EXIF_DATE_FORMAT); + return formatter.parse(value); + } else if (Integer.class.equals(expectedType)) { + if (value == null) + return 0; + return Integer.parseInt(value); + } else if (Long.class.equals(expectedType)) { + if (value == null) + return 0; + return Long.parseLong(value); + } else if (Float.class.equals(expectedType)) { + if (value == null) + return 0; + return Float.parseFloat(value); + } else if (Double.class.equals(expectedType)) { + if (value == null) + return 0; + String[] enumeratorAndDivisor = value.split("/"); + if (enumeratorAndDivisor.length == 2) { + return Double.parseDouble(enumeratorAndDivisor[0]) + / Double.parseDouble(enumeratorAndDivisor[1]); + } else { + return Double.parseDouble(value); + } + } else if (String[].class.equals(expectedType)) { + if (value == null) + return new String[0]; + return value.split(","); + } else { + return value; + } + } catch (ParseException ex) { + log.warn("Invalid format, Tag:" + tagName); + return null; + } catch (NumberFormatException ex) { + log.warn("Invalid format, Tag:" + tagName); + return null; + } + + } + + static MetadataTag toTag(String name) { + for (Tag tag : Tag.values()) { + if (tag.getKey().equalsIgnoreCase(name)) { + return tag; + } + } + for (MwgTag tag : MwgTag.values()) { + if (tag.getKey().equalsIgnoreCase(name)) { + return tag; + } + } + return new CustomTag(name, String.class); + } + + // ================================================================================ - public UnsupportedFeatureException(Feature feature) { - super( - "Use of feature [" - + feature.toString() - + "] requires version " - + feature.getVersion() - + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); - } - } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Feature.java b/src/main/java/com/thebuzzmedia/exiftool/Feature.java new file mode 100644 index 00000000..123b8530 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Feature.java @@ -0,0 +1,58 @@ +package com.thebuzzmedia.exiftool; + +//================================================================================ +/** + * Enum used to define the different kinds of features in the native ExifTool + * executable that this class can help you take advantage of. + *

+ * These flags are different from {@link Tag}s in that a "feature" is determined + * to be a special functionality of the underlying ExifTool executable that + * requires a different code-path in this class to take advantage of; for + * example, -stay_open True support. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public enum Feature { + /** + * Enum used to specify that you wish to launch the underlying ExifTool + * process with -stay_open True support turned on that this + * class can then take advantage of. + *

+ * Required ExifTool version is 8.36 or higher. + */ + STAY_OPEN(8, 36), + /** + * Acitves the MWG modules. The Metadata Working Group (MWG) recommends + * techniques to allow certain overlapping EXIF, IPTC and XMP tags to be + * reconciled when reading, and synchronized when writing. The MWG Composite + * tags below are designed to aid in the implementation of these + * recommendations. Will add the args " -use MWG" + * + * @see ExifTool + * MWG Docs !! Note these version numbers are not correct + */ + MWG_MODULE(8, 36), ; + + private VersionNumber requireVersion; + + private Feature(int... numbers) { + this.requireVersion = new VersionNumber(numbers); + } + + /** + * Used to get the version of ExifTool required by this feature in order to + * work. + * + * @return the version of ExifTool required by this feature in order to + * work. + */ + VersionNumber getVersion() { + return requireVersion; + } + + boolean isSupported(VersionNumber exifVersionNumber) { + return requireVersion.isBeforeOrEqualTo(exifVersionNumber); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Format.java b/src/main/java/com/thebuzzmedia/exiftool/Format.java new file mode 100644 index 00000000..4eda8150 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Format.java @@ -0,0 +1,8 @@ +package com.thebuzzmedia.exiftool; + +//================================================================================ +//OLD API +public enum Format { + NUMERIC, + HUMAN_READABLE +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java new file mode 100644 index 00000000..7aeda2fc --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java @@ -0,0 +1,136 @@ +package com.thebuzzmedia.exiftool; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; +import java.util.concurrent.atomic.AtomicBoolean; + +/** + * Manages an external exif process in keep alive mode. + */ +public class KeepAliveExifProxy implements ExifProxy { + private final List startupArgs; + private final AtomicBoolean shuttingDown = new AtomicBoolean(false); + private final Timer cleanupTimer = new Timer(ExifTool.CLEANUP_THREAD_NAME, + true); + private long inactivityTimeout = 0; + private volatile long lastRunStart = 0; + private volatile ExifProcess process; + + public KeepAliveExifProxy(String exifCmd, List baseArgs) { + inactivityTimeout = Long.getLong( + ExifTool.ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, + ExifTool.DEFAULT_PROCESS_CLEANUP_DELAY); + startupArgs = new ArrayList(baseArgs.size() + 5); + startupArgs.add(exifCmd); + startupArgs.addAll(Arrays.asList("-stay_open", "True")); + startupArgs.addAll(baseArgs); + startupArgs.addAll(Arrays.asList("-@", "-")); + // runs every minute to check if process has been inactive too long + cleanupTimer.schedule(new TimerTask() { + @Override + public void run() { + if (process != null && lastRunStart > 0 + && inactivityTimeout > 0) { + if ((System.currentTimeMillis() - lastRunStart) > inactivityTimeout) { + synchronized (this) { + if (process != null) { + process.close(); + } + } + } + } + } + }, 60 * 1000); // every minute + } + + public void setInactiveTimeout(long mills) { + this.inactivityTimeout = mills; + } + + @Override + public void startup() { + shuttingDown.set(false); + if (process == null || process.isClosed()) { + synchronized (this) { + if (process == null || process.isClosed()) { + ExifTool.log + .debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = new ExifProcess(true, startupArgs); + } + } + } + } + + @Override + public Map execute(final long runTimeoutMills, + List args) throws IOException { + lastRunStart = System.currentTimeMillis(); + int attempts = 0; + while (attempts < 3 && !shuttingDown.get()) { + attempts++; + if (process == null || process.isClosed()) { + synchronized (this) { + if (process == null || process.isClosed()) { + ExifTool.log + .debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); + process = new ExifProcess(true, startupArgs); + } + } + } + TimerTask attemptTimer = null; + try { + if (runTimeoutMills > 0) { + attemptTimer = new TimerTask() { + @Override + public void run() { + if (process != null && !process.isClosed()) { + ExifTool.log + .warn("Process ran too long closing, max " + + runTimeoutMills + " mills"); + process.close(); + } + } + }; + cleanupTimer.schedule(attemptTimer, runTimeoutMills); + } + ExifTool.log + .debug("Streaming arguments to ExifTool process..."); + return process.sendToRunning(args); + } catch (IOException ex) { + if (ExifTool.STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) + && !shuttingDown.get()) { + // only catch "Stream Closed" error (happens when process + // has died) + ExifTool.log.warn(String.format( + "Caught IOException(\"%s\"), will restart daemon", + ExifTool.STREAM_CLOSED_MESSAGE)); + process.close(); + } else { + throw ex; + } + } finally { + if (attemptTimer != null) + attemptTimer.cancel(); + } + } + if (shuttingDown.get()) { + throw new IOException("Shutting Down"); + } + throw new IOException("Ran out of attempts"); + } + + @Override + public boolean isRunning() { + return process != null && !process.isClosed(); + } + + @Override + public void shutdown() { + shuttingDown.set(true); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java b/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java index c875892c..c7701fac 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java +++ b/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java @@ -8,78 +8,81 @@ import java.util.concurrent.BlockingQueue; /** - * A Thread which reads lines from a BufferedReader and puts them in a queue, so they can be read from with out blocking. - * This is used when reading from a process.err input. - * + * A Thread which reads lines from a BufferedReader and puts them in a queue, so + * they can be read from with out blocking. This is used when reading from a + * process.err input. + * * Remember to start thread!! - * + * * @author msgile * @author $LastChangedBy$ - * @version $Revision$ $LastChangedDate$ + * @version $Revision$ $LastChangedDate$ * @since 7/25/14 */ public class LineReaderThread extends Thread { - private BufferedReader reader; - private BlockingQueue lineBuffer = new ArrayBlockingQueue(10,true); + private BufferedReader reader; + private BlockingQueue lineBuffer = new ArrayBlockingQueue( + 10, true); - public LineReaderThread(String name, BufferedReader reader) { - super(name); - this.reader = reader; - } - public LineReaderThread(ThreadGroup group, String name, BufferedReader reader) { - super(group, name); - this.reader = reader; - } + public LineReaderThread(String name, BufferedReader reader) { + super(name); + this.reader = reader; + } - @Override - public void run() { - String line; - try { - while((line = reader.readLine()) != null) { - line = line.trim(); - if ( ! line.isEmpty() ) { - lineBuffer.put(line); - } - } - } catch (IOException ex) { - //exit - } catch (InterruptedException ignored) { - //exit - } - } + public LineReaderThread(ThreadGroup group, String name, + BufferedReader reader) { + super(group, name); + this.reader = reader; + } - public boolean isEmpty() { - return lineBuffer.isEmpty(); - } + @Override + public void run() { + String line; + try { + while ((line = reader.readLine()) != null) { + line = line.trim(); + if (!line.isEmpty()) { + lineBuffer.put(line); + } + } + } catch (IOException ex) { + // exit + } catch (InterruptedException ignored) { + // exit + } + } - public boolean hasLines() { - return ! lineBuffer.isEmpty(); - } + public boolean isEmpty() { + return lineBuffer.isEmpty(); + } - /** - * Takes all lines from the buffer or returns empty list. - */ - public List takeLines() { - List lines = new ArrayList(lineBuffer.size()); - lineBuffer.drainTo(lines); - return lines; - } + public boolean hasLines() { + return !lineBuffer.isEmpty(); + } - /** - * Reads line without blocking, will return Null if no lines in buffer. - */ - public String readLine() { - return lineBuffer.poll(); - } + /** + * Takes all lines from the buffer or returns empty list. + */ + public List takeLines() { + List lines = new ArrayList(lineBuffer.size()); + lineBuffer.drainTo(lines); + return lines; + } - public void close() { - interrupt(); - try { - reader.close(); - } catch (IOException ignored) { - ; - } - } + /** + * Reads line without blocking, will return Null if no lines in buffer. + */ + public String readLine() { + return lineBuffer.poll(); + } + public void close() { + interrupt(); + try { + reader.close(); + } catch (IOException ignored) { + ; + } + } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java b/src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java new file mode 100644 index 00000000..eb52a4df --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java @@ -0,0 +1,22 @@ +package com.thebuzzmedia.exiftool; + +//================================================================================ +/** + * Base type for all "tag" passed to exiftool. The key is the value passed to + * the exiftool like "-creator". The Types is used for automatic type + * conversions. + * + */ +public interface MetadataTag { + /** + * Returns the values passed to exiftool + */ + public String getKey(); + + /** + * The types + */ + public Class getType(); + + public boolean isMapped(); +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java b/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java new file mode 100644 index 00000000..f77e29da --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java @@ -0,0 +1,54 @@ +package com.thebuzzmedia.exiftool; + +import java.util.Date; + +//================================================================================ +public enum MwgTag implements MetadataTag { + LOCATION("Location", String.class), + CITY("City", String.class), + STATE("State", String.class), + COUNTRY("Country", String.class), + + COPYRIGHT("Copyright", String.class), + + DATE_TIME_ORIGINAL("DateTimeOriginal", Date.class), + CREATE_DATE("CreateDate", Date.class), + MODIFY_DATE("ModifyDate", Date.class), + + CREATOR("Creator", String.class), + DESCRIPTION("Description", String.class), + KEYWORDS("Keywords", String[].class), + + ORIENTATION("Orientation", Integer.class), + RATING("Rating", Integer.class), + + ; + + private String name; + private Class type; + + private MwgTag(String name, Class type) { + this.name = name; + this.type = type; + } + + @Override + public String getKey() { + return name; + } + + @Override + public Class getType() { + return type; + } + + @Override + public boolean isMapped() { + return true; + } + + @Override + public String toString() { + return name; + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ReadOptions.java b/src/main/java/com/thebuzzmedia/exiftool/ReadOptions.java new file mode 100644 index 00000000..b22b7abb --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/ReadOptions.java @@ -0,0 +1,104 @@ +package com.thebuzzmedia.exiftool; + +//================================================================================ +/** + * All the read options, is immutable, copy on change, fluent style "with" + * setters. + */ +public class ReadOptions { + final long runTimeoutMills; + final boolean convertTypes; + final boolean numericOutput; + final boolean showDuplicates; + final boolean showEmptyTags; + + public ReadOptions() { + this(0, false, false, false, false); + } + + private ReadOptions(long runTimeoutMills, boolean convertTypes, + boolean numericOutput, boolean showDuplicates, boolean showEmptyTags) { + this.runTimeoutMills = runTimeoutMills; + this.convertTypes = convertTypes; + this.numericOutput = numericOutput; + this.showDuplicates = showDuplicates; + this.showEmptyTags = showEmptyTags; + } + + @Override + public String toString() { + return String + .format("%s(runTimeout:%,d convertTypes:%s showDuplicates:%s showEmptyTags:%s)", + getClass().getSimpleName(), runTimeoutMills, + convertTypes, showDuplicates, showEmptyTags); + } + + /** + * Sets the maximum time a process can run + */ + public ReadOptions withRunTimeoutMills(long mills) { + return new ReadOptions(mills, convertTypes, numericOutput, + showDuplicates, showEmptyTags); + } + + /** + * By default all values will be returned as the strings printed by the + * exiftool. If this is enabled then {@link MetadataTag#getType()} is used + * to cast the string into a java type. + */ + public ReadOptions withConvertTypes(boolean enabled) { + return new ReadOptions(runTimeoutMills, enabled, numericOutput, + showDuplicates, showEmptyTags); + } + + /** + * Setting this to true will add the "-n" option causing the ExifTool to + * output of some tags to change. + *

+ * ExifTool, via the -n command line arg, is capable of + * returning most values in their raw numeric form (e.g. + * Aperture="2.8010323841") as well as a more human-readable/friendly format + * (e.g. Aperture="2.8"). + *

+ * While the {@link Tag}s defined on this class do provide a hint at the + * type of the result (see {@link MetadataTag#getType()}), that hint only + * applies when the numeric value is returned. + *

+ * If the caller finds the human-readable format easier to process, Set this + * to false, the default. + *

+ * In order to see the types of values that are returned when human readable + * is used (default), you can check the comprehensive + * ExifTool Tag Guide. + *

+ * This makes sense with some values like Aperture that in numeric format + * end up returning as 14-decimal-place, high precision values that are near + * the intended value (e.g. "2.79999992203711" instead of just returning + * "2.8"). On the other hand, other values (like Orientation) are easier to + * parse when their numeric value (1-8) is returned instead of a much longer + * friendly name (e.g. "Mirror horizontal and rotate 270 CW"). + * + * Attempted from work done by + * + * @author Riyad Kalla (software@thebuzzmedia.com) + */ + public ReadOptions withNumericOutput(boolean enabled) { + return new ReadOptions(runTimeoutMills, convertTypes, enabled, + showDuplicates, showEmptyTags); + } + + /** + * If enabled will show tags which are duplicated between different tag + * regions, relates to the "-a" option in ExifTool. + */ + public ReadOptions withShowDuplicates(boolean enabled) { + return new ReadOptions(runTimeoutMills, convertTypes, numericOutput, + enabled, showEmptyTags); + } + + public ReadOptions withShowEmptyTags(boolean enabled) { + return new ReadOptions(runTimeoutMills, convertTypes, numericOutput, + showDuplicates, enabled); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java new file mode 100644 index 00000000..dc6e0887 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java @@ -0,0 +1,66 @@ +package com.thebuzzmedia.exiftool; + +import java.io.IOException; +import java.util.ArrayList; +import java.util.List; +import java.util.Map; +import java.util.Timer; +import java.util.TimerTask; + +public class SingleUseExifProxy implements ExifProxy { + private final Timer cleanupTimer = new Timer(ExifTool.CLEANUP_THREAD_NAME, + true); + private final List baseArgs; + + public SingleUseExifProxy(String exifCmd, List defaultArgs) { + this.baseArgs = new ArrayList(defaultArgs.size() + 1); + this.baseArgs.add(exifCmd); + this.baseArgs.addAll(defaultArgs); + } + + @Override + public Map execute(final long runTimeoutMills, + List args) throws IOException { + List newArgs = new ArrayList(baseArgs.size() + + args.size()); + newArgs.addAll(baseArgs); + newArgs.addAll(args); + final ExifProcess process = new ExifProcess(false, newArgs); + TimerTask attemptTimer = null; + if (runTimeoutMills > 0) { + attemptTimer = new TimerTask() { + @Override + public void run() { + if (!process.isClosed()) { + ExifTool.log.warn("Process ran too long closing, max " + + runTimeoutMills + " mills"); + process.close(); + } + } + }; + cleanupTimer.schedule(attemptTimer, runTimeoutMills); + } + try { + return process.readResponse(); + } finally { + process.close(); + if (attemptTimer != null) + attemptTimer.cancel(); + } + } + + @Override + public void startup() { + ; + } + + @Override + public boolean isRunning() { + return false; + } + + @Override + public void shutdown() { + ; + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Tag.java b/src/main/java/com/thebuzzmedia/exiftool/Tag.java new file mode 100644 index 00000000..f9be48ab --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/Tag.java @@ -0,0 +1,202 @@ +package com.thebuzzmedia.exiftool; + +import java.util.Date; +import java.util.EnumMap; +import java.util.Map; + +//================================================================================ +/** + * Enum used to pre-define a convenient list of tags that can be easily + * extracted from images using this class with an external install of ExifTool. + *

+ * Each tag defined also includes a type hint for the parsed value associated + * with it when the default humanReadable is false. + *

+ * The types provided by each tag are merely a hint based on the ExifTool Tag Guide by Phil Harvey; the caller is free to parse or + * process the returned {@link String} values any way they wish. + *

Tag Support

+ * ExifTool is capable of parsing almost every tag known to man (1000+), but + * this class makes an attempt at pre-defining a convenient list of the most + * common tags for use. + *

+ * This list was determined by looking at the common metadata tag values written + * to images by popular mobile devices (iPhone, Android) as well as cameras like + * simple point and shoots as well as DSLRs. As an additional source of input + * the list of supported/common EXIF formats that Flickr supports was also + * reviewed to ensure the most common/useful tags were being covered here. + *

+ * Please email me or file an issue if + * you think this list is missing a commonly used tag that should be added to + * it. + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public enum Tag implements MetadataTag { + // single entry tags + APERTURE("ApertureValue", Double.class), + AUTHOR("XPAuthor", String.class), + COLOR_SPACE("ColorSpace", Integer.class), + COMMENT("XPComment", String.class), + CONTRAST("Contrast", Integer.class), + CREATE_DATE("CreateDate", Date.class), + CREATION_DATE("CreationDate", Date.class), + DATE_CREATED("DateCreated", Date.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", Date.class), + DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), + EXIF_VERSION("ExifVersion", String.class), + EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), + EXPOSURE_PROGRAM("ExposureProgram", Integer.class), + EXPOSURE_TIME("ExposureTime", Double.class), + FLASH("Flash", Integer.class), + FOCAL_LENGTH("FocalLength", Double.class), + FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + FNUMBER("FNumber", String.class), + GPS_ALTITUDE("GPSAltitude", Double.class), + GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), + GPS_BEARING("GPSDestBearing", Double.class), + GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_DATESTAMP("GPSDateStamp", String.class), + GPS_LATITUDE("GPSLatitude", Double.class), + GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LONGITUDE("GPSLongitude", Double.class), + GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), + GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_SPEED("GPSSpeed", Double.class), + GPS_SPEED_REF("GPSSpeedRef", String.class), + GPS_TIMESTAMP("GPSTimeStamp", String.class), + IMAGE_HEIGHT("ImageHeight", Integer.class), + IMAGE_WIDTH("ImageWidth", Integer.class), + ISO("ISO", Integer.class), + KEYWORDS("XPKeywords", String.class), + LENS_MAKE("LensMake", String.class), + LENS_MODEL("LensModel", String.class), + MAKE("Make", String.class), + METERING_MODE("MeteringMode", Integer.class), + MODEL("Model", String.class), + ORIENTATION("Orientation", Integer.class), + OWNER_NAME("OwnerName", String.class), + RATING("Rating", Integer.class), + RATING_PERCENT("RatingPercent", Integer.class), + ROTATION("Rotation", Integer.class), + SATURATION("Saturation", Integer.class), + SENSING_METHOD("SensingMethod", Integer.class), + SHARPNESS("Sharpness", Integer.class), + SHUTTER_SPEED("ShutterSpeedValue", Double.class), + SOFTWARE("Software", String.class), + SUBJECT("XPSubject", String.class), + TITLE("XPTitle", String.class), + WHITE_BALANCE("WhiteBalance", Integer.class), + X_RESOLUTION("XResolution", Double.class), + Y_RESOLUTION("YResolution", Double.class), ; + + /** + * Used to get the {@link Tag} identified by the given, case-sensitive, tag + * name. + * + * @param name + * The case-sensitive name of the tag that will be searched for. + * + * @return the {@link Tag} identified by the given, case-sensitive, tag name + * or null if one couldn't be found. + */ + public static Tag forName(String name) { + for (Tag tag : Tag.values()) { + if (tag.getKey().equals(name)) { + return tag; + } + } + return null; + } + + public static Map toTagMap(Map values) { + Map tagMap = new EnumMap(Tag.class); + for (Tag tag : Tag.values()) { + if (values.containsKey(tag.getKey())) { + tagMap.put(tag, values.get(tag.getKey())); + } + } + return tagMap; + + } + + /** + * Convenience method used to convert the given string Tag value (returned + * from the external ExifTool process) into the type described by the + * associated {@link Tag}. + * + * @param + * The type of the returned value. + * @param value + * The {@link String} representation of the tag's value as parsed + * from the image. + * + * @return the given string value converted to a native Java type (e.g. + * Integer, Double, etc.). + * + * @throws IllegalArgumentException + * if tag is null. + * @throws NumberFormatException + * if any exception occurs while trying to parse the given + * value to any of the supported numeric types in + * Java via calls to the respective parseXXX + * methods defined on all the numeric wrapper classes (e.g. + * {@link Integer#parseInt(String)} , + * {@link Double#parseDouble(String)} and so on). + * @throws ClassCastException + * if the type defined by T is incompatible with + * the type defined by {@link Tag#getType()} returned by the + * tag argument passed in. This class performs an + * implicit/unchecked cast to the type T before + * returning the parsed result of the type indicated by + * {@link Tag#getType()}. If the types do not match, a + * ClassCastException will be generated by the VM. + */ + @SuppressWarnings("unchecked") + public T parseValue(String value) throws IllegalArgumentException { + return (T) ExifTool.deserialize(getKey(), value, getType()); + } + + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ + public String getName() { + return name; + } + + /** + * Used to get a hint for the native type of this tag's value as specified + * by Phil Harvey's ExifTool Tag Guide. + * + * @return a hint for the native type of this tag's value. + */ + @Override + public Class getType() { + return type; + } + + @Override + public String getKey() { + return name; + } + + @Override + public boolean isMapped() { + return true; + } + + private String name; + private Class type; + + private Tag(String name, Class type) { + this.name = name; + this.type = type; + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java b/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java new file mode 100644 index 00000000..1346004c --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java @@ -0,0 +1,37 @@ +package com.thebuzzmedia.exiftool; + +//================================================================================ +public enum TagGroup implements MetadataTag { + EXIF("EXIF", "exif:all"), + IPTC("IPTC", "iptc:all"), + XMP("XMP", "xmp:all"), + ALL("ALL", "all"); + + private final String name; + private final String key; + + private TagGroup(String name, String key) { + this.name = name; + this.key = key; + } + + public String getName() { + return name; + } + + @Override + public String getKey() { + return key; + } + + @Override + public Class getType() { + return Void.class; + } + + @Override + public boolean isMapped() { + return false; + } + +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java b/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java new file mode 100644 index 00000000..b7699997 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/UnsupportedFeatureException.java @@ -0,0 +1,23 @@ +package com.thebuzzmedia.exiftool; + +//================================================================================ +/** + * Class used to define an exception that occurs when the caller attempts to use + * a {@link Feature} that the underlying native ExifTool install does not + * support (i.e. the version isn't new enough). + * + * @author Riyad Kalla (software@thebuzzmedia.com) + * @since 1.1 + */ +public class UnsupportedFeatureException extends RuntimeException { + private static final long serialVersionUID = -1332725983656030770L; + + public UnsupportedFeatureException(Feature feature) { + super( + "Use of feature [" + + feature.toString() + + "] requires version " + + feature.getVersion() + + " or higher of the native ExifTool program. The version of ExifTool referenced by the system property 'exiftool.path' is not high enough. You can either upgrade the install of ExifTool or avoid using this feature to workaround this exception."); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java b/src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java new file mode 100644 index 00000000..c6131b2c --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/VersionNumber.java @@ -0,0 +1,49 @@ +package com.thebuzzmedia.exiftool; + +//================================================================================ +/** + * Version Number used to determine if one version is after another. + * + * @author Matt Gile, msgile + */ +class VersionNumber { + private final int[] numbers; + + public VersionNumber(String str) { + String[] versionParts = str.trim().split("\\."); + this.numbers = new int[versionParts.length]; + for (int i = 0; i < versionParts.length; i++) { + numbers[i] = Integer.parseInt(versionParts[i]); + } + } + + public VersionNumber(int... numbers) { + this.numbers = numbers; + } + + public boolean isBeforeOrEqualTo(VersionNumber other) { + int max = Math.min(this.numbers.length, other.numbers.length); + for (int i = 0; i < max; i++) { + if (this.numbers[i] > other.numbers[i]) { + return false; + } else if (this.numbers[i] < other.numbers[i]) { + return true; + } + } + // assume missing number as zero, so if the current process number is + // more digits it is a higher version + return this.numbers.length <= other.numbers.length; + } + + @Override + public String toString() { + StringBuilder builder = new StringBuilder(); + for (int number : numbers) { + if (builder.length() > 0) { + builder.append("."); + } + builder.append(number); + } + return builder.toString(); + } +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/WriteOptions.java b/src/main/java/com/thebuzzmedia/exiftool/WriteOptions.java new file mode 100644 index 00000000..68a1c97f --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/WriteOptions.java @@ -0,0 +1,39 @@ +package com.thebuzzmedia.exiftool; + +//================================================================================ +/** + * All the write options, is immutable, copy on change, fluent style "with" + * setters. + */ +public class WriteOptions { + final long runTimeoutMills; + final boolean deleteBackupFile; + + public WriteOptions() { + this(0, false); + } + + private WriteOptions(long runTimeoutMills, boolean deleteBackupFile) { + this.runTimeoutMills = runTimeoutMills; + this.deleteBackupFile = deleteBackupFile; + } + + @Override + public String toString() { + return String.format("%s(runTimeOut:%,d deleteBackupFile:%s)", + getClass().getSimpleName(), runTimeoutMills, deleteBackupFile); + } + + public WriteOptions withRunTimeoutMills(long mills) { + return new WriteOptions(mills, deleteBackupFile); + } + + /** + * ExifTool automatically makes a backup copy a file before writing metadata + * tags in the form "file.ext_original", by default this tool will delete + * that original file after the writing is done. + */ + public WriteOptions withDeleteBackupFile(boolean enabled) { + return new WriteOptions(runTimeoutMills, enabled); + } +} \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index 6145f0a7..22a94a68 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -1,76 +1,75 @@ package com.thebuzzmedia.exiftool; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Tag; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.io.IOException; -public class Benchmark { +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; - public static final int ITERATIONS = 25; - private static Logger log = LoggerFactory.getLogger(Benchmark.class); +public class Benchmark { + public static final int ITERATIONS = 25; + private static Logger log = LoggerFactory.getLogger(Benchmark.class); - public static void main(String[] args) throws IOException, InterruptedException { + public static void main(String[] args) throws IOException, + InterruptedException { - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); - final Tag[] tags = Tag.values(); - final File[] images = new File("src/test/resources").listFiles(); + final Tag[] tags = Tag.values(); + final File[] images = new File("src/test/resources").listFiles(); - log.info("Benchmark [tags=" + tags.length + ", images=" - + images.length + ", iterations=" + ITERATIONS + "]"); - log.info("\t" + (images.length * ITERATIONS) - + " ExifTool process calls, " - + (tags.length * images.length * ITERATIONS) - + " total operations.\n"); + log.info("Benchmark [tags=" + tags.length + ", images=" + images.length + + ", iterations=" + ITERATIONS + "]"); + log.info("\t" + (images.length * ITERATIONS) + + " ExifTool process calls, " + + (tags.length * images.length * ITERATIONS) + + " total operations.\n"); - ExifTool tool = new ExifTool(); - ExifTool toolSO = new ExifTool(Feature.STAY_OPEN); + ExifTool tool = new ExifTool(); + ExifTool toolSO = new ExifTool(Feature.STAY_OPEN); /* * -stay_open False */ - log.info("\t[-stay_open False]"); - long elapsedTime = 0; + log.info("\t[-stay_open False]"); + long elapsedTime = 0; - for (int i = 1; i <= ITERATIONS; i++){ - log.info(String.format("iteration %s of %s", i, ITERATIONS)); - elapsedTime += run(tool, images, tags); - } + for (int i = 1; i <= ITERATIONS; i++) { + log.info(String.format("iteration %s of %s", i, ITERATIONS)); + elapsedTime += run(tool, images, tags); + } - log.info("\t\tElapsed Time: " + elapsedTime + " ms (" - + ((double) elapsedTime / 1000) + " secs)"); + log.info("\t\tElapsed Time: " + elapsedTime + " ms (" + + ((double) elapsedTime / 1000) + " secs)"); /* * -stay_open True */ - log.info("\n\t[-stay_open True]"); - long elapsedTimeSO = 0; + log.info("\n\t[-stay_open True]"); + long elapsedTimeSO = 0; - for (int i = 1; i <= ITERATIONS; i++) { - log.info(String.format("iteration %s of %s", i, ITERATIONS)); - elapsedTimeSO += run(toolSO, images, tags); - } + for (int i = 1; i <= ITERATIONS; i++) { + log.info(String.format("iteration %s of %s", i, ITERATIONS)); + elapsedTimeSO += run(toolSO, images, tags); + } - log.info("\t\tElapsed Time: " + elapsedTimeSO + " ms (" - + ((double) elapsedTimeSO / 1000) + " secs - " - + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); + log.info("\t\tElapsed Time: " + elapsedTimeSO + " ms (" + + ((double) elapsedTimeSO / 1000) + " secs - " + + ((float) elapsedTime / (float) elapsedTimeSO) + "x faster)"); - // Shut down the running exiftool proc. - toolSO.close(); - } + // Shut down the running exiftool proc. + toolSO.close(); + } - private static long run(ExifTool tool, File[] images, Tag[] tags) - throws IllegalArgumentException, SecurityException, IOException { - long startTime = System.currentTimeMillis(); + private static long run(ExifTool tool, File[] images, Tag[] tags) + throws IllegalArgumentException, SecurityException, IOException { + long startTime = System.currentTimeMillis(); - for (File image : images){ - tool.getImageMeta(image, tags); - } + for (File image : images) { + tool.getImageMeta(image, tags); + } - return (System.currentTimeMillis() - startTime); - } + return (System.currentTimeMillis() - startTime); + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index 27e536e7..0920f586 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -1,46 +1,51 @@ package com.thebuzzmedia.exiftool; -import com.thebuzzmedia.exiftool.ExifTool.Feature; -import com.thebuzzmedia.exiftool.ExifTool.Format; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - import java.io.File; import java.io.IOException; import java.util.Map; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + public class Example { - private static Logger log = LoggerFactory.getLogger(Example.class); - private static final String TEST_FILES_PATH = "src/test/resources"; - - public static void main(String[] args) throws IOException, InterruptedException { - - //System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, "D:\\Tools\\exiftool.exe"); - ExifTool tool = new ExifTool(Feature.STAY_OPEN); - - File[] images = new File(TEST_FILES_PATH).listFiles(); - - //list all first-class tags - for (File f : images) { - log.info("\n[{}]", f.getName()); - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, ExifTool.Tag.values()); - for (ExifTool.Tag key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key.getKey(), metadata.get(key))); - } - } - - log.info("\n\n** GET TAGS BY GROUP"); - //list all XMP, IPTC and XMP tags - File f = new File(TEST_FILES_PATH + "/kureckjones_jett_075_02-cropped.tif"); - for (ExifTool.TagGroup tagGroup : new ExifTool.TagGroup[] {ExifTool.TagGroup.EXIF, ExifTool.TagGroup.IPTC, ExifTool.TagGroup.XMP}){ - Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, tagGroup); - log.info(tagGroup.getKey()); - for (String key : metadata.keySet()){ - log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - } - } - - tool.close(); - } + private static Logger log = LoggerFactory.getLogger(Example.class); + private static final String TEST_FILES_PATH = "src/test/resources"; + + public static void main(String[] args) throws IOException, + InterruptedException { + + // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, + // "D:\\Tools\\exiftool.exe"); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + + File[] images = new File(TEST_FILES_PATH).listFiles(); + + // list all first-class tags + for (File f : images) { + log.info("\n[{}]", f.getName()); + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, Tag.values()); + for (Tag key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key.getKey(), + metadata.get(key))); + } + } + + log.info("\n\n** GET TAGS BY GROUP"); + // list all XMP, IPTC and XMP tags + File f = new File(TEST_FILES_PATH + + "/kureckjones_jett_075_02-cropped.tif"); + for (TagGroup tagGroup : new TagGroup[] { TagGroup.EXIF, TagGroup.IPTC, + TagGroup.XMP }) { + Map metadata = tool.getImageMeta(f, + Format.HUMAN_READABLE, tagGroup); + log.info(tagGroup.getKey()); + for (String key : metadata.keySet()) { + log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + } + } + + tool.close(); + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 5fdfd815..4c5f9ffb 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -1,8 +1,8 @@ package com.thebuzzmedia.exiftool; -import org.junit.Test; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; @@ -20,460 +20,540 @@ import java.util.Map; import java.util.Set; -import static org.junit.Assert.*; +import org.junit.Test; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** - * TestMetadata

- * + * TestMetadata + *

+ * * @author Michael Rush (michaelrush@gmail.com) * @since Initially created 8/8/13 */ public class TestExifTool { - private static Logger log = LoggerFactory.getLogger(TestExifTool.class); - - @Test - public void testSingleTool() throws Exception { - ExifTool tool = new ExifTool(); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - - tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.startup(); - assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); - } - } - - @Test - public void testConcurrent() throws Exception { - - int toolCount = 5; - - List threads = new ArrayList(toolCount); - for (int i=1; i <= toolCount; i++){ - String toolName = "tool"+i; - Thread t = new Thread(toolName){ - @Override - public void run() { - log.info(getName() + ": starting"); - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - runTests(tool,getName()); - log.info(getName() + ": finished"); - } catch (IOException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } catch (URISyntaxException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } finally { - tool.shutdown(); - } - log.info(getName() + ": finished"); - } - }; - t.start(); - threads.add(t); - } - - for (Thread t : threads){ - t.run(); - } - } - - @Test - public void testManyThreadsOneTool() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Thread[] threads = new Thread[20]; - for(int i=0; i < threads.length; i++) { - final String label = "run "+i; - threads[i] = new Thread(new Runnable() { - public void run() { - try { - for(int j=0; j<5; j++) { - runTests(tool,label); - } - log.info("DONE: "+label+" success!"); - } catch (IOException ex) { - fail(label); - } catch (URISyntaxException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } - } - },label); - } - for(Thread thread : threads) { - thread.start(); - } - for(Thread thread : threads) { - thread.join(); - } - } finally { - tool.shutdown(); - } - } - - @Test - public void testProcessTimeout() throws Exception { - final ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - tool.setRunTimeout(1); - runTests(tool,"will fail"); - fail("should have failed"); - } catch (IOException ex) { - ; - } finally { - tool.shutdown(); - } - } - - public boolean runTests(ExifTool tool, String runId) throws IOException, URISyntaxException { - - Map metadata; - File imageFile; - Set keys; - ExifTool.Tag tag; - - URL url = getClass().getResource("/kureckjones_jett_075_02-cropped.tif"); - imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(22, metadata.size()); - - keys = metadata.keySet(); - - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(728, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(825, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("P 45+", tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 1"); - - - url = getClass().getResource("/nexus-s-electric-cars.jpg"); - imageFile = new File(url.toURI()); - metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(23, metadata.size()); - - keys = metadata.keySet(); - tag = ExifTool.Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(2560, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.IMAGE_HEIGHT; - assertEquals(1920, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.MODEL; - assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.ISO; - assertEquals(50, tag.parseValue(metadata.get(tag))); - - tag = ExifTool.Tag.SHUTTER_SPEED; - assertEquals("1/64", metadata.get(tag)); - assertEquals(0.015625, tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 2"); - return true; - } - - @Test - public void testGroupTags() throws Exception { - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - try { - Map metadata; - - URL url = getClass().getResource("/iptc_test-photoshop.jpg"); - File f = new File(url.toURI()); - metadata = tool.getImageMeta(f, ExifTool.Format.HUMAN_READABLE, ExifTool.TagGroup.IPTC); - assertEquals(17, metadata.size()); - assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); - assertEquals("IPTC Status: Copyright Notice", metadata.get("CopyrightNotice")); - assertEquals("IPTC Content: Description Writer", metadata.get("Writer-Editor")); - //for (String key : metadata.keySet()){ - // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - //} - } finally { - tool.shutdown(); - } - } - - @Test - public void testTag(){ - assertEquals("string value", "John Doe", ExifTool.Tag.AUTHOR.parseValue("John Doe")); - assertEquals("integer value", 200, ExifTool.Tag.ISO.parseValue("200")); - assertEquals("double value, from fraction", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue("1/4")); - assertEquals("double value, from decimal", .25, ExifTool.Tag.SHUTTER_SPEED.parseValue(".25")); - } - - @Test - public void testVersionNumber() { - assertTrue(new ExifTool.VersionNumber("1.2").isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2.3"))); - assertTrue(new ExifTool.VersionNumber(1,2).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.2"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber("1.3"))); - assertTrue(new ExifTool.VersionNumber(1,2,3).isBeforeOrEqualTo(new ExifTool.VersionNumber(2,1))); - } - - @Test - public void testWriteTagStringNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteTagString() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteTagStringInvalidformat() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - String newDate = "2egek opkpgrpok"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - - // Now change it to an invalid value which should fail - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's not updated - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - // might not exist - if(backup_url != null) { - Path backupFile = Paths.get(backup_url.toURI()); - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - } - - @Test - public void testWriteTagNumberNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteTagNumber() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Now change it - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteMultipleTag() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWriteMultipleTagNonDaemon() throws Exception{ - ExifTool tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(ExifTool.Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(ExifTool.Tag.ORIENTATION, 3); - - tool.writeMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.ORIENTATION, ExifTool.Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(ExifTool.Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not affected by the change - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - } - - @Test - public void testWritingWithImplicitTypes() throws Exception{ - ExifTool tool = new ExifTool(ExifTool.Feature.MWG_MODULE); - tool.setReadOptions(tool.getReadOptions().withNumericOutput(true).withConvertTypes(true)); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - File imageFile = Paths.get(url.toURI()).toFile(); - try { - // Test what orientation value is at the start - SimpleDateFormat formatter = new SimpleDateFormat("yyyy:MM:dd hh:mm:ss"); - - Map metadata = tool.readMetadata(imageFile, ExifTool.Tag.ORIENTATION, ExifTool.MwgTag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", 1, metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("Wrong starting value", formatter.parse("2010:12:10 17:07:05"), metadata.get(ExifTool.MwgTag.DATE_TIME_ORIGINAL)); - - // Now change them - Map data = new HashMap(); - Date dateTimeOrig = formatter.parse("2014:01:23 10:07:05"); - data.put(ExifTool.MwgTag.DATE_TIME_ORIGINAL, dateTimeOrig); - data.put(ExifTool.Tag.ORIENTATION, 3); - Date createDate = formatter.parse("2013:02:21 10:07:05"); - data.put(ExifTool.MwgTag.CREATE_DATE, createDate.getTime()); - data.put(ExifTool.MwgTag.KEYWORDS, new String[]{"a", "b", "c"}); - tool.writeMetadata(tool.getWriteOptions().withDeleteBackupFile(false),imageFile, data); - - // Finally check the updated value - metadata = tool.readMetadata(imageFile, ExifTool.Tag.ORIENTATION, imageFile, ExifTool.MwgTag.DATE_TIME_ORIGINAL, ExifTool.MwgTag.CREATE_DATE, ExifTool.MwgTag.KEYWORDS); - assertEquals("Orientation tag updated value is wrong", 3, metadata.get(ExifTool.Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, metadata.get(ExifTool.MwgTag.DATE_TIME_ORIGINAL)); - assertEquals("CreateDate tag is wrong", createDate, metadata.get(ExifTool.MwgTag.CREATE_DATE)); - assertEquals("Keywords tag is wrong", "a", ((String[]) metadata.get(ExifTool.MwgTag.KEYWORDS))[0]); - - // Finally copy the source file back over so the next test run is not affected by the change - - } finally { - URL backup_url = getClass().getResource("/nexus-s-electric-cars.jpg_original"); - if ( backup_url != null ) { - Path backupFile = Paths.get(backup_url.toURI()); - Files.move(backupFile, imageFile.toPath(), StandardCopyOption.REPLACE_EXISTING); - } - - } - } - - //todo TEST automatic daemon restart by killing perl process + private static Logger log = LoggerFactory.getLogger(TestExifTool.class); + + @Test + public void testSingleTool() throws Exception { + ExifTool tool = new ExifTool(); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(Feature.STAY_OPEN); + try { + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + + tool = new ExifTool(Feature.STAY_OPEN); + try { + tool.startup(); + assertTrue(runTests(tool, "")); + } finally { + tool.shutdown(); + } + } + + @Test + public void testConcurrent() throws Exception { + + int toolCount = 5; + + List threads = new ArrayList(toolCount); + for (int i = 1; i <= toolCount; i++) { + String toolName = "tool" + i; + Thread t = new Thread(toolName) { + @Override + public void run() { + log.info(getName() + ": starting"); + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + try { + runTests(tool, getName()); + log.info(getName() + ": finished"); + } catch (IOException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } catch (URISyntaxException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } finally { + tool.shutdown(); + } + log.info(getName() + ": finished"); + } + }; + t.start(); + threads.add(t); + } + + for (Thread t : threads) { + t.run(); + } + } + + @Test + public void testManyThreadsOneTool() throws Exception { + final ExifTool tool = new ExifTool(Feature.STAY_OPEN); + try { + Thread[] threads = new Thread[20]; + for (int i = 0; i < threads.length; i++) { + final String label = "run " + i; + threads[i] = new Thread(new Runnable() { + @Override + public void run() { + try { + for (int j = 0; j < 5; j++) { + runTests(tool, label); + } + log.info("DONE: " + label + " success!"); + } catch (IOException ex) { + fail(label); + } catch (URISyntaxException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } + } + }, label); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + } finally { + tool.shutdown(); + } + } + + @Test + public void testProcessTimeout() throws Exception { + final ExifTool tool = new ExifTool(Feature.STAY_OPEN); + try { + tool.setRunTimeout(1); + runTests(tool, "will fail"); + fail("should have failed"); + } catch (IOException ex) { + ; + } finally { + tool.shutdown(); + } + } + + public boolean runTests(ExifTool tool, String runId) throws IOException, + URISyntaxException { + + Map metadata; + File imageFile; + Set keys; + Tag tag; + + URL url = getClass() + .getResource("/kureckjones_jett_075_02-cropped.tif"); + imageFile = new File(url.toURI()); + metadata = tool.getImageMeta(imageFile, Format.HUMAN_READABLE, + Tag.values()); + assertEquals(22, metadata.size()); + + keys = metadata.keySet(); + + tag = Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(728, tag.parseValue(metadata.get(tag))); + + tag = Tag.IMAGE_HEIGHT; + assertEquals(825, tag.parseValue(metadata.get(tag))); + + tag = Tag.MODEL; + assertEquals("P 45+", tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 1"); + + url = getClass().getResource("/nexus-s-electric-cars.jpg"); + imageFile = new File(url.toURI()); + metadata = tool.getImageMeta(imageFile, Format.HUMAN_READABLE, + Tag.values()); + assertEquals(23, metadata.size()); + + keys = metadata.keySet(); + tag = Tag.IMAGE_WIDTH; + assertTrue(keys.contains(tag)); + assertEquals(2560, tag.parseValue(metadata.get(tag))); + + tag = Tag.IMAGE_HEIGHT; + assertEquals(1920, tag.parseValue(metadata.get(tag))); + + tag = Tag.MODEL; + assertEquals("Nexus S", tag.parseValue(metadata.get(tag))); + + tag = Tag.ISO; + assertEquals(50, tag.parseValue(metadata.get(tag))); + + tag = Tag.SHUTTER_SPEED; + assertEquals("1/64", metadata.get(tag)); + assertEquals(0.015625, tag.parseValue(metadata.get(tag))); + log.info(runId + ": finished image 2"); + return true; + } + + @Test + public void testGroupTags() throws Exception { + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + try { + Map metadata; + + URL url = getClass().getResource("/iptc_test-photoshop.jpg"); + File f = new File(url.toURI()); + metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, + TagGroup.IPTC); + assertEquals(17, metadata.size()); + assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); + assertEquals("IPTC Status: Copyright Notice", + metadata.get("CopyrightNotice")); + assertEquals("IPTC Content: Description Writer", + metadata.get("Writer-Editor")); + // for (String key : metadata.keySet()){ + // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + // } + } finally { + tool.shutdown(); + } + } + + @Test + public void testTag() { + assertEquals("string value", "John Doe", + Tag.AUTHOR.parseValue("John Doe")); + assertEquals("integer value", 200, Tag.ISO.parseValue("200")); + assertEquals("double value, from fraction", .25, + Tag.SHUTTER_SPEED.parseValue("1/4")); + assertEquals("double value, from decimal", .25, + Tag.SHUTTER_SPEED.parseValue(".25")); + } + + @Test + public void testVersionNumber() { + assertTrue(new VersionNumber("1.2") + .isBeforeOrEqualTo(new VersionNumber("1.2.3"))); + assertTrue(new VersionNumber(1, 2).isBeforeOrEqualTo(new VersionNumber( + "1.2"))); + assertTrue(new VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new VersionNumber("1.3"))); + assertTrue(new VersionNumber(1, 2, 3) + .isBeforeOrEqualTo(new VersionNumber(2, 1))); + } + + @Test + public void testWriteTagStringNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's updated + metadata = tool.getImageMeta(imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteTagString() throws Exception { + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's updated + metadata = tool.getImageMeta(imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteTagStringInvalidformat() throws Exception { + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + String newDate = "2egek opkpgrpok"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + + // Now change it to an invalid value which should fail + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's not updated + metadata = tool.getImageMeta(imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + // might not exist + if (backup_url != null) { + Path backupFile = Paths.get(backup_url.toURI()); + Files.move(backupFile, imageFile, + StandardCopyOption.REPLACE_EXISTING); + } + } + + @Test + public void testWriteTagNumberNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.ORIENTATION); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + + // Now change it + Map newValues = new HashMap(); + newValues.put(Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(Tag.ORIENTATION)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteTagNumber() throws Exception { + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.ORIENTATION); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + + // Now change it + Map newValues = new HashMap(); + newValues.put(Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(Tag.ORIENTATION)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteMultipleTag() throws Exception { + ExifTool tool = new ExifTool(Feature.STAY_OPEN); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWriteMultipleTagNonDaemon() throws Exception { + ExifTool tool = new ExifTool(); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); + + tool.writeMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", + metadata.get(Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + + Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } + + @Test + public void testWritingWithImplicitTypes() throws Exception { + ExifTool tool = new ExifTool(Feature.MWG_MODULE); + tool.setReadOptions(tool.getReadOptions().withNumericOutput(true) + .withConvertTypes(true)); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + File imageFile = Paths.get(url.toURI()).toFile(); + try { + // Test what orientation value is at the start + SimpleDateFormat formatter = new SimpleDateFormat( + "yyyy:MM:dd hh:mm:ss"); + + Map metadata = tool.readMetadata(imageFile, + Tag.ORIENTATION, MwgTag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", 1, + metadata.get(Tag.ORIENTATION)); + assertEquals("Wrong starting value", + formatter.parse("2010:12:10 17:07:05"), + metadata.get(MwgTag.DATE_TIME_ORIGINAL)); + + // Now change them + Map data = new HashMap(); + Date dateTimeOrig = formatter.parse("2014:01:23 10:07:05"); + data.put(MwgTag.DATE_TIME_ORIGINAL, dateTimeOrig); + data.put(Tag.ORIENTATION, 3); + Date createDate = formatter.parse("2013:02:21 10:07:05"); + data.put(MwgTag.CREATE_DATE, createDate.getTime()); + data.put(MwgTag.KEYWORDS, new String[] { "a", "b", "c" }); + tool.writeMetadata( + tool.getWriteOptions().withDeleteBackupFile(false), + imageFile, data); + + // Finally check the updated value + metadata = tool.readMetadata(imageFile, Tag.ORIENTATION, imageFile, + MwgTag.DATE_TIME_ORIGINAL, MwgTag.CREATE_DATE, + MwgTag.KEYWORDS); + assertEquals("Orientation tag updated value is wrong", 3, + metadata.get(Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, + metadata.get(MwgTag.DATE_TIME_ORIGINAL)); + assertEquals("CreateDate tag is wrong", createDate, + metadata.get(MwgTag.CREATE_DATE)); + assertEquals("Keywords tag is wrong", "a", + ((String[]) metadata.get(MwgTag.KEYWORDS))[0]); + + // Finally copy the source file back over so the next test run is + // not affected by the change + + } finally { + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + if (backup_url != null) { + Path backupFile = Paths.get(backup_url.toURI()); + Files.move(backupFile, imageFile.toPath(), + StandardCopyOption.REPLACE_EXISTING); + } + + } + } + + // todo TEST automatic daemon restart by killing perl process } From a16f62f41e31bd458516a2304a566d019451df9d Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 15:38:34 +0300 Subject: [PATCH 044/148] - ignore eclipse files --- .gitignore | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/.gitignore b/.gitignore index 50756ce4..70ce0736 100644 --- a/.gitignore +++ b/.gitignore @@ -5,4 +5,9 @@ bin workspace.xml *.iml .idea -out \ No newline at end of file +out +/.classpath + +/.project + +/.settings From d4f03a13d893559f093de6b81843d96ff30706f4 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 17:30:41 +0300 Subject: [PATCH 045/148] - formatted --- pom.xml | 11 ++--------- 1 file changed, 2 insertions(+), 9 deletions(-) diff --git a/pom.xml b/pom.xml index ab9c0c34..6d9c02c6 100644 --- a/pom.xml +++ b/pom.xml @@ -3,22 +3,18 @@ xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> 4.0.0 - com.thebuzzmedia.exiftool exiftool-lib jar - 2.2.0 - https://github.com/thebuzzmedia/exiftool - + 2.3.0 + https://github.com/raisercostin/exiftool Riyad Kalla software@thebuzzmedia.com - - @@ -32,7 +28,6 @@ - commons-io @@ -45,14 +40,12 @@ 1.7.5 compile - junit junit 4.11 test - org.slf4j From 1e37c03bf1acc8c08662a551861fec1f49d59789 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 18:10:55 +0300 Subject: [PATCH 046/148] - fix compilation error --- src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java index 2541ad5a..fb4b1714 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java @@ -16,6 +16,7 @@ package com.thebuzzmedia.exiftool; import java.io.File; +import java.io.FileNotFoundException; import java.io.IOException; import java.lang.reflect.Array; import java.text.ParseException; @@ -266,7 +267,7 @@ public class ExifToolNew { static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - private static final String EXIF_DATE_FORMAT = "yyyy:MM:dd HH:mm:ss"; + static final String EXIF_DATE_FORMAT = "yyyy:MM:dd HH:mm:ss"; static final Logger log = LoggerFactory.getLogger(ExifTool.class); From 9f77fd2094912402b0d885d11a37477844bb9b2f Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 26 Jul 2014 18:46:45 +0300 Subject: [PATCH 047/148] - released in maven --- README | 6 ++++++ pom.xml | 36 +++++++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/README b/README index 0868be33..779bccb3 100644 --- a/README +++ b/README @@ -211,3 +211,9 @@ Contact ------- If you have questions, comments or bug reports for this software please contact us at: software@thebuzzmedia.com + + +Maven +- create deliverables: mvn install -Prelease -DskipTests=true +- release in svn: svn import -m "release" C:\Users\costin\.m2\repository\com https://raisercostin.googlecode.com/svn/maven2/com --force +- current release: 2.3.0 - at http://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/2.3.0/ \ No newline at end of file diff --git a/pom.xml b/pom.xml index 6d9c02c6..7a0031a0 100644 --- a/pom.xml +++ b/pom.xml @@ -23,7 +23,7 @@ 3.0 1.7 - 1.5 + 1.7 @@ -54,4 +54,38 @@ test + + + release + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.7 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + + From a096d1a82d79ee08a103ca39f7f538404592a952 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 12:24:04 +0300 Subject: [PATCH 048/148] - refactor to prepare for ExifTool interface extraction --- .../com/thebuzzmedia/exiftool/ExifTool.java | 30 ++++++++++--------- .../thebuzzmedia/exiftool/ExifToolNew.java | 12 ++++---- .../thebuzzmedia/exiftool/TestExifTool.java | 5 ++-- 3 files changed, 24 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index a2e0b8d2..306a94a6 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -304,7 +304,12 @@ public class ExifTool { private TimerTask currentCleanupTask = null; private AtomicBoolean shuttingDown = new AtomicBoolean(false); private volatile ExifProcess process; - private int timeoutWhenKeepAlive = 0; + /** + * Limits the amount of time (in mills) an exif operation can take. Setting + * value to greater than 0 to enable. + */ + private final int timeoutWhenKeepAlive; + private static final int DEFAULT_TIMEOUT_WHEN_KEEP_ALIVE = 0; public ExifTool() { this((Feature[]) null); @@ -316,24 +321,30 @@ public ExifTool() { * processCleanupDelay is optional. If not found, the default is used. */ public ExifTool(Feature... features) { + this(DEFAULT_TIMEOUT_WHEN_KEEP_ALIVE,features); + } + + public ExifTool(int timeoutWhenKeepAliveInMillis, Feature... features) { this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, - DEFAULT_PROCESS_CLEANUP_DELAY), features); + DEFAULT_PROCESS_CLEANUP_DELAY), timeoutWhenKeepAliveInMillis, features); } + public ExifTool(String exifToolPath) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, (Feature[]) null); + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, DEFAULT_TIMEOUT_WHEN_KEEP_ALIVE, (Feature[]) null); } public ExifTool(String exifToolPath, Feature... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, DEFAULT_TIMEOUT_WHEN_KEEP_ALIVE, features); } - public ExifTool(String exifCmd, long processCleanupDelay, + public ExifTool(String exifCmd, long processCleanupDelay, int timeoutWhenKeepAliveInMillis, Feature... features) { this.exifCmd = exifCmd; this.processCleanupDelay = processCleanupDelay; this.exifVersion = ExifProcess.readVersion(exifCmd); + this.timeoutWhenKeepAlive = timeoutWhenKeepAliveInMillis; if (features != null && features.length > 0) { for (Feature feature : features) { if (!feature.isSupported(exifVersion)) { @@ -355,15 +366,6 @@ public ExifTool(String exifCmd, long processCleanupDelay, } } - /** - * Limits the amount of time (in mills) an exif operation can take. Setting - * value to greater than 0 to enable. - */ - public ExifTool setRunTimeout(int mills) { - timeoutWhenKeepAlive = mills; - return this; - } - /** * Used to determine if the given {@link Feature} is supported by the * underlying native install of ExifTool pointed at by {@link #exifCmd}. diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java index fb4b1714..ef4ee58e 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java @@ -224,7 +224,7 @@ public class ExifToolNew { * the directory that new File(".").getAbsolutePath() points at * during runtime. */ - public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + private static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; /** * Interval (in milliseconds) of inactivity before the cleanup thread wakes * up and cleans up the daemon ExifTool process and the read/write streams @@ -252,8 +252,8 @@ public class ExifToolNew { *

* Default value is zero, no inactivity timeout. */ - public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + private static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + private static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; /** * Name used to identify the (optional) cleanup {@link Thread}. @@ -264,12 +264,12 @@ public class ExifToolNew { *

* Default value is "ExifTool Cleanup Thread". */ - static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; + private static final String CLEANUP_THREAD_NAME = "ExifTool Cleanup Thread"; - static final String STREAM_CLOSED_MESSAGE = "Stream closed"; + private static final String STREAM_CLOSED_MESSAGE = "Stream closed"; static final String EXIF_DATE_FORMAT = "yyyy:MM:dd HH:mm:ss"; - static final Logger log = LoggerFactory.getLogger(ExifTool.class); + private static final Logger log = LoggerFactory.getLogger(ExifTool.class); private final Map featureSupportedMap = new HashMap(); private final Set featureEnabledSet = EnumSet diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 651eeb47..1fe24427 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -136,9 +136,8 @@ public void run() { @Test public void testProcessTimeout() throws Exception { - final ExifTool tool = new ExifTool(Feature.STAY_OPEN); + final ExifTool tool = new ExifTool(1,Feature.STAY_OPEN); try { - tool.setRunTimeout(1); runTests(tool, "will fail"); fail("should have failed"); } catch (IOException ex) { @@ -161,7 +160,7 @@ public boolean runTests(ExifTool tool, String runId) throws IOException, imageFile = new File(url.toURI()); metadata = tool.getImageMeta(imageFile, Format.HUMAN_READABLE, Tag.values()); - assertEquals(25, metadata.size()); + assertEquals(31, metadata.size()); keys = metadata.keySet(); From cba9d78eca38c8c0c0a398dcf66539d2f5434961 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 13:45:37 +0300 Subject: [PATCH 049/148] - extract interface ExifToolService --- .../com/thebuzzmedia/exiftool/ExifTool.java | 103 +++++++-- .../thebuzzmedia/exiftool/ExifToolNew.java | 93 +++++--- .../thebuzzmedia/exiftool/ExifToolNew2.java | 124 ++++++++++- .../exiftool/ExifToolService.java | 210 ++++++++++++++++++ .../exiftool/KeepAliveExifProxy.java | 4 +- .../java/com/thebuzzmedia/exiftool/Tag.java | 22 +- .../com/thebuzzmedia/exiftool/Benchmark.java | 6 +- .../com/thebuzzmedia/exiftool/Example.java | 6 +- .../thebuzzmedia/exiftool/TestExifTool.java | 62 +++--- 9 files changed, 523 insertions(+), 107 deletions(-) create mode 100644 src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 306a94a6..1f4be8f2 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -210,11 +210,11 @@ * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ -public class ExifTool { +public class ExifTool implements ExifToolService { - public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; - public static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - public static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + private static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + private static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + private static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; /** * Name used to identify the (optional) cleanup {@link Thread}. @@ -321,26 +321,28 @@ public ExifTool() { * processCleanupDelay is optional. If not found, the default is used. */ public ExifTool(Feature... features) { - this(DEFAULT_TIMEOUT_WHEN_KEEP_ALIVE,features); + this(DEFAULT_TIMEOUT_WHEN_KEEP_ALIVE, features); } public ExifTool(int timeoutWhenKeepAliveInMillis, Feature... features) { this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, - DEFAULT_PROCESS_CLEANUP_DELAY), timeoutWhenKeepAliveInMillis, features); + DEFAULT_PROCESS_CLEANUP_DELAY), timeoutWhenKeepAliveInMillis, + features); } - public ExifTool(String exifToolPath) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, DEFAULT_TIMEOUT_WHEN_KEEP_ALIVE, (Feature[]) null); + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, + DEFAULT_TIMEOUT_WHEN_KEEP_ALIVE, (Feature[]) null); } public ExifTool(String exifToolPath, Feature... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, DEFAULT_TIMEOUT_WHEN_KEEP_ALIVE, features); + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, + DEFAULT_TIMEOUT_WHEN_KEEP_ALIVE, features); } - public ExifTool(String exifCmd, long processCleanupDelay, int timeoutWhenKeepAliveInMillis, - Feature... features) { + public ExifTool(String exifCmd, long processCleanupDelay, + int timeoutWhenKeepAliveInMillis, Feature... features) { this.exifCmd = exifCmd; this.processCleanupDelay = processCleanupDelay; this.exifVersion = ExifProcess.readVersion(exifCmd); @@ -392,6 +394,7 @@ public ExifTool(String exifCmd, long processCleanupDelay, int timeoutWhenKeepAli * if any exception occurs while attempting to start the * external ExifTool process to verify feature support. */ + @Override public boolean isFeatureSupported(Feature feature) throws RuntimeException { if (feature == null) { throw new IllegalArgumentException("feature cannot be null"); @@ -419,6 +422,7 @@ public boolean isFeatureSupported(Feature feature) throws RuntimeException { * enabled. This method has no effect if the stay open feature is not * enabled. */ + @Override public void startup() { if (featureSet.contains(Feature.STAY_OPEN)) { shuttingDown.set(false); @@ -457,6 +461,7 @@ public void run() { * This is same as {@link #close()}, added for consistency with * {@link #startup()} */ + @Override public void shutdown() { close(); } @@ -477,6 +482,7 @@ public void shutdown() { * Calling this method on an instance of this class without * {@link Feature#STAY_OPEN} support enabled has no effect. */ + @Override public synchronized void close() { shuttingDown.set(true); if (process != null) { @@ -488,6 +494,7 @@ public synchronized void close() { } } + @Override public boolean isStayOpen() { return featureSet.contains(Feature.STAY_OPEN); } @@ -506,6 +513,7 @@ public boolean isStayOpen() { * {@link Feature#STAY_OPEN} feature, otherwise returns * false. */ + @Override public boolean isRunning() { return process != null && !process.isClosed(); } @@ -530,6 +538,7 @@ public boolean isRunning() { * @throws IllegalArgumentException * if feature is null. */ + @Override public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException { if (feature == null) { @@ -538,25 +547,27 @@ public boolean isFeatureEnabled(Feature feature) return featureSet.contains(feature); } - public Map getImageMeta(File image, Tag... tags) + @Override + public Map getImageMeta(File image, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { - return getImageMeta(image, Format.NUMERIC, tags); } - public Map getImageMeta(File image, Format format, Tag... tags) + @Override + public Map getImageMeta(File image, Format format, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { String[] stringTags = new String[tags.length]; int i = 0; - for (Tag tag : tags) { - stringTags[i++] = tag.getName(); + for (MetadataTag tag : tags) { + stringTags[i++] = tag.getKey(); } Map result = getImageMeta(image, format, true, stringTags); return Tag.toTagMap(result); } + @Override public Map getImageMeta(File image, Format format, TagGroup... tags) throws IllegalArgumentException, SecurityException, IOException { @@ -568,7 +579,7 @@ public Map getImageMeta(File image, Format format, return getImageMeta(image, format, false, stringTags); } - private Map getImageMeta(final File image, + public Map getImageMeta(final File image, final Format format, final boolean suppressDuplicates, final String... tags) throws IllegalArgumentException, SecurityException, IOException { @@ -635,8 +646,11 @@ private Map getImageMeta(final File image, return resultMap; } - public void addImageMetadata(File image, Map values) + @Override + public void addImageMetadata(File image, Map values) throws IOException { + // public void addImageMetadata(File image, Map values) + // throws IOException { final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); @@ -680,17 +694,18 @@ public void addImageMetadata(File image, Map values) } } - private List createCommandList(String filename, - Map values) { + private List createCommandList(String filename, + Map values) { List args = new ArrayList(64); - for (Map.Entry entry : values.entrySet()) { - Tag tag = entry.getKey(); + for (Map.Entry entry : values.entrySet()) { + //works only for Tags + Tag tag = (Tag)entry.getKey(); Object value = entry.getValue(); StringBuilder arg = new StringBuilder(); - arg.append("-").append(tag.getName()); + arg.append("-").append(tag.getKey()); if (value instanceof Number) { arg.append("#"); } @@ -720,6 +735,7 @@ private List createCommandList(String filename, * @throws IOException * Signals that an I/O exception has occurred. */ + @Override public String getImageMetadataXml(File input, boolean includeBinary) throws IOException { List args = new ArrayList(); @@ -741,6 +757,7 @@ public String getImageMetadataXml(File input, boolean includeBinary) * @throws IOException * Signals that an I/O exception has occurred. */ + @Override public void getImageMetadataXml(File input, File output, boolean includeBinary) throws IOException { @@ -763,6 +780,7 @@ public void getImageMetadataXml(File input, File output, * @throws IOException * Signals that an I/O exception has occurred. */ + @Override public String extractImageIccProfile(File input, File output) throws IOException { @@ -790,13 +808,14 @@ public String extractImageIccProfile(File input, File output) * @throws IOException * Signals that an I/O exception has occurred. */ + @Override public File extractThumbnail(File input, Tag tag) throws IOException { List args = new ArrayList(); String suffix = ".thumb.jpg"; String thumbname = FilenameUtils.getBaseName(input.getName()) + suffix; - args.add("-" + tag.getName()); + args.add("-" + tag.getKey()); args.add(input.getAbsolutePath()); args.add("-b"); args.add("-w"); @@ -886,4 +905,40 @@ public void run() { protected static void log(String message, Object... params) { log.debug(message, params); } + + @Override + public Map getImageMeta2(File image, MetadataTag... tags) + throws IllegalArgumentException, SecurityException, IOException { + // TODO Auto-generated method stub + return null; + } + + @Override + public void rebuildMetadata(File file) throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public void rebuildMetadata(WriteOptions options, File file) + throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public Map readMetadata(File file, Object... tags) + throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public Map readMetadata(ReadOptions options, File file, + Object... tags) throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public void writeMetadata(WriteOptions options, File image, + Map values) throws IOException { + throw new RuntimeException("Not implemented."); + } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java index ef4ee58e..78841c0d 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java @@ -197,7 +197,7 @@ * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ -public class ExifToolNew { +public class ExifToolNew implements ExifToolService { /** * If ExifTool is on your system path and running the command "exiftool" @@ -252,8 +252,8 @@ public class ExifToolNew { *

* Default value is zero, no inactivity timeout. */ - private static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; - private static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; + static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; + static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; /** * Name used to identify the (optional) cleanup {@link Thread}. @@ -274,7 +274,7 @@ public class ExifToolNew { private final Map featureSupportedMap = new HashMap(); private final Set featureEnabledSet = EnumSet .noneOf(Feature.class); - private ReadOptions defReadOptions = new ReadOptions(); + private final ReadOptions defReadOptions; private WriteOptions defWriteOptions = new WriteOptions(); private final VersionNumber exifVersion; private final ExifProxy exifProxy; @@ -289,25 +289,30 @@ public ExifToolNew() { * processCleanupDelay is optional. If not found, the default is used. */ public ExifToolNew(Feature... features) { + this(new ReadOptions(), features); + } + + public ExifToolNew(ReadOptions readOptions, Feature...features) { this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, - DEFAULT_PROCESS_CLEANUP_DELAY), features); + DEFAULT_PROCESS_CLEANUP_DELAY), readOptions, features); } /** * Pass in the absolute path to the ExifTool executable on the host system. */ public ExifToolNew(String exifToolPath) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY); + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, new ReadOptions()); } public ExifToolNew(String exifToolPath, Feature... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, features); + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, new ReadOptions(), features); } public ExifToolNew(String exifCmd, long processCleanupDelay, - Feature... features) { + ReadOptions readOptions, Feature... features) { this.exifVersion = ExifProcess.readVersion(exifCmd); + this.defReadOptions = readOptions; if (features != null && features.length > 0) { for (Feature feature : features) { if (!feature.isSupported(exifVersion)) { @@ -330,16 +335,16 @@ public ExifToolNew(String exifCmd, long processCleanupDelay, exifProxy = new SingleUseExifProxy(exifCmd, baseArgs); } } - - /** - * Limits the amount of time (in mills) an exif operation can take. Setting - * value to greater than 0 to enable. - */ - public ExifToolNew setRunTimeout(long mills) { - defReadOptions = defReadOptions.withRunTimeoutMills(mills); - defWriteOptions = defWriteOptions.withRunTimeoutMills(mills); - return this; - } +// +// /** +// * Limits the amount of time (in mills) an exif operation can take. Setting +// * value to greater than 0 to enable. +// */ +// public ExifToolNew setRunTimeout(long mills) { +// defReadOptions = defReadOptions.withRunTimeoutMills(mills); +// defWriteOptions = defWriteOptions.withRunTimeoutMills(mills); +// return this; +// } /** * Used to determine if the given {@link Feature} is supported by the @@ -478,11 +483,6 @@ public ReadOptions getReadOptions() { return defReadOptions; } - public ExifToolNew setReadOptions(ReadOptions options) { - defReadOptions = options; - return this; - } - public WriteOptions getWriteOptions() { return defWriteOptions; } @@ -492,12 +492,12 @@ public ExifToolNew setWriteOptions(WriteOptions options) { return this; } - public Map getImageMeta(File image, Tag... tags) + public Map getImageMeta(File image, Tag... tags) throws IllegalArgumentException, SecurityException, IOException { return getImageMeta(image, Format.NUMERIC, tags); } - public Map getImageMeta(File image, Format format, Tag... tags) + public Map getImageMeta(File image, Format format, Tag... tags) throws IllegalArgumentException, SecurityException, IOException { String[] stringTags = new String[tags.length]; @@ -683,6 +683,7 @@ public void writeMetadata(WriteOptions options, File image, (System.currentTimeMillis() - startTime), values.size())); } } + public void rebuildMetadata(File file) throws IOException { rebuildMetadata(getWriteOptions(), file); } @@ -797,6 +798,46 @@ static MetadataTag toTag(String name) { return new CustomTag(name, String.class); } - // ================================================================================ + @Override + public String getImageMetadataXml(File input, boolean includeBinary) + throws IOException { + throw new RuntimeException("Not implemented."); + } + @Override + public void getImageMetadataXml(File input, File output, + boolean includeBinary) throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public String extractImageIccProfile(File input, File output) + throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public File extractThumbnail(File input, Tag tag) throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public Map getImageMeta(File image, + MetadataTag... tags) throws IllegalArgumentException, + SecurityException, IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public Map getImageMeta2(File image, MetadataTag... tags) + throws IllegalArgumentException, SecurityException, IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public Map getImageMeta(File image, Format format, + MetadataTag... tags) throws IllegalArgumentException, + SecurityException, IOException { + throw new RuntimeException("Not implemented."); + } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java index b5950fa7..f4cb8780 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java @@ -206,7 +206,7 @@ * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ -public class ExifToolNew2 { +public class ExifToolNew2 implements ExifToolService { /** * Flag used to indicate if debugging output has been enabled by setting the * "exiftool.debug" system property to true. This @@ -374,7 +374,9 @@ public class ExifToolNew2 { * if any exception occurs while attempting to start the * external ExifTool process to verify feature support. */ - public static boolean isFeatureSupported(Feature feature) + + @Override + public boolean isFeatureSupported(Feature feature) throws IllegalArgumentException, RuntimeException { if (feature == null) throw new IllegalArgumentException("feature cannot be null"); @@ -492,7 +494,8 @@ protected static void checkFeatureSupport(Feature... features) } // Ensure the version found is >= the required version. - if (ver != null && ver.compareTo(feature.getVersion().toString()) >= 0) { + if (ver != null + && ver.compareTo(feature.getVersion().toString()) >= 0) { supported = Boolean.TRUE; log("\t\tFound ExifTool version %s, feature %s is SUPPORTED.", ver, feature); @@ -749,7 +752,7 @@ public Map getImageMeta(File image, Format format, Tag... tags) * reused a multitude of times later in this method to figure out where * to branch to. */ - boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + boolean stayOpen = isStayOpen(); // Clear process args args.clear(); @@ -848,7 +851,8 @@ public Map getImageMeta(File image, Format format, Tag... tags) */ if (tag != null) { resultMap.put(tag, pair[1]); - log("\t\tRead Tag [name=%s, value=%s]", tag.getKey(), pair[1]); + log("\t\tRead Tag [name=%s, value=%s]", tag.getKey(), + pair[1]); } } @@ -989,8 +993,8 @@ public void setImageMeta(File image, Format format, Map tags) args.add("-S"); // compact output for (Entry entry : tags.entrySet()) - args.add("-" + entry.getKey().getKey() + "='" + entry.getValue() - + "'"); + args.add("-" + entry.getKey().getKey() + "='" + + entry.getValue() + "'"); args.add(image.getAbsolutePath()); @@ -1060,4 +1064,110 @@ void resetCleanupTask() { log("\t\tSuccessful"); } + + @Override + public void startup() { + resetCleanupTask(); + } + + @Override + public void shutdown() { + shutdownCleanupTask(); + } + + @Override + public boolean isStayOpen() { + return featureSet.contains(Feature.STAY_OPEN); + } + + @Override + public Map getImageMeta(File image, Format format, + TagGroup... tags) throws IllegalArgumentException, + SecurityException, IOException { + return getImageMeta(image, format, tags); + } + + @Override + public void addImageMetadata(File image, Map values) + throws IOException { + setImageMeta(image, (Map) values); + } + + @Override + public String getImageMetadataXml(File input, boolean includeBinary) + throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public void getImageMetadataXml(File input, File output, + boolean includeBinary) throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public String extractImageIccProfile(File input, File output) + throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public File extractThumbnail(File input, Tag tag) throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public Map getImageMeta(File file, Format format, + boolean supressDuplicates, String... tags) throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public Map getImageMeta(File image, + MetadataTag... tags) throws IllegalArgumentException, + SecurityException, IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public Map getImageMeta2(File image, MetadataTag... tags) + throws IllegalArgumentException, SecurityException, IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public Map getImageMeta(File image, Format format, + MetadataTag... tags) throws IllegalArgumentException, + SecurityException, IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public void rebuildMetadata(File file) throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public void rebuildMetadata(WriteOptions options, File file) + throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public Map readMetadata(File file, Object... tags) + throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public Map readMetadata(ReadOptions options, File file, + Object... tags) throws IOException { + throw new RuntimeException("Not implemented."); + } + + @Override + public void writeMetadata(WriteOptions options, File image, + Map values) throws IOException { + throw new RuntimeException("Not implemented."); + } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java new file mode 100644 index 00000000..62aa08b1 --- /dev/null +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java @@ -0,0 +1,210 @@ +package com.thebuzzmedia.exiftool; + +import java.io.File; +import java.io.IOException; +import java.util.Map; + +public interface ExifToolService { + + /** + * Used to determine if the given {@link Feature} is supported by the + * underlying native install of ExifTool pointed at by {@link #exifCmd}. + *

+ * If support for the given feature has not been checked for yet, this + * method will automatically call out to ExifTool and ensure the requested + * feature is supported in the current local install. + *

+ * The external call to ExifTool to confirm feature support is only ever + * done once per JVM session and stored in a static final + * {@link Map} that all instances of this class share. + * + * @param feature + * The feature to check support for in the underlying ExifTool + * install. + * + * @return true if support for the given {@link Feature} was + * confirmed to work with the currently installed ExifTool or + * false if it is not supported. + * + * @throws IllegalArgumentException + * if feature is null. + * @throws RuntimeException + * if any exception occurs while attempting to start the + * external ExifTool process to verify feature support. + */ + boolean isFeatureSupported(Feature feature) throws RuntimeException; + + /** + * Used to startup the external ExifTool process and open the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. This method has no effect if the stay open feature is not + * enabled. + */ + void startup(); + + /** + * This is same as {@link #close()}, added for consistency with + * {@link #startup()} + */ + void shutdown(); + + /** + * Used to shutdown the external ExifTool process and close the read/write + * streams used to communicate with it when {@link Feature#STAY_OPEN} is + * enabled. + *

+ * NOTE: Calling this method does not preclude this + * instance of {@link ExifTool} from being re-used, it merely disposes of + * the native and internal resources until the next call to + * getImageMeta causes them to be re-instantiated. + *

+ * The cleanup thread will automatically call this after an interval of + * inactivity defined by {@link #processCleanupDelay}. + *

+ * Calling this method on an instance of this class without + * {@link Feature#STAY_OPEN} support enabled has no effect. + */ + void close(); + + /** + * Using ExifTool in daemon mode (-stay_open True) executes different code + * paths below. So establish the flag for this once and it is reused a + * multitude of times later in this method to figure out where to branch to. + */ + boolean isStayOpen(); + + /** + * For {@link ExifTool} instances with {@link Feature#STAY_OPEN} support + * enabled, this method is used to determine if there is currently a running + * ExifTool process associated with this class. + *

+ * Any dependent processes and streams can be shutdown using + * {@link #close()} and this class will automatically re-create them on the + * next call to getImageMeta if necessary. + * + * @return true if there is an external ExifTool process in + * daemon mode associated with this class utilizing the + * {@link Feature#STAY_OPEN} feature, otherwise returns + * false. + */ + boolean isRunning(); + + /** + * Used to determine if the given {@link Feature} has been enabled for this + * particular instance of {@link ExifTool}. + *

+ * This method is different from {@link #isFeatureSupported(Feature)}, which + * checks if the given feature is supported by the underlying ExifTool + * install where as this method tells the caller if the given feature has + * been enabled for use in this particular instance. + * + * @param feature + * The feature to check if it has been enabled for us or not on + * this instance. + * + * @return true if the given {@link Feature} is currently + * enabled on this instance of {@link ExifTool}, otherwise returns + * false. + * + * @throws IllegalArgumentException + * if feature is null. + */ + boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException; + + Map getImageMeta(File file, Format format, + boolean supressDuplicates, String... tags) throws IOException; + Map getImageMeta(File image, MetadataTag... tags) + throws IllegalArgumentException, SecurityException, IOException; + + Map getImageMeta2(File image, MetadataTag... tags) + throws IllegalArgumentException, SecurityException, IOException; + Map getImageMeta(File image, Format format, MetadataTag... tags) + throws IllegalArgumentException, SecurityException, IOException; + Map getImageMeta(File image, Format format, + TagGroup... tags) throws IllegalArgumentException, + SecurityException, IOException; + + public void addImageMetadata(File image, Map values) + throws IOException; + + /** + * extract image metadata to exiftool's internal xml format. + * + * @param input + * the input file + * @return command output as xml string + * @throws IOException + * Signals that an I/O exception has occurred. + */ + String getImageMetadataXml(File input, boolean includeBinary) + throws IOException; + + /** + * extract image metadata to exiftool's internal xml format. + * + * @param input + * the input file + * @param output + * the output file + * @throws IOException + * Signals that an I/O exception has occurred. + */ + void getImageMetadataXml(File input, File output, boolean includeBinary) + throws IOException; + + /** + * output icc profile from input to output. + * + * @param input + * the input file + * @param output + * the output file for icc data + * @return the command result from standard output e.g. + * "1 output files created" + * @throws IOException + * Signals that an I/O exception has occurred. + */ + String extractImageIccProfile(File input, File output) throws IOException; + + /** + * Extract thumbnail from the given tag. + * + * @param input + * the input file + * @param tag + * the tag containing binary data PhotoshopThumbnail or + * ThumbnailImage + * @return the thumbnail file created. it is in the same folder as the input + * file because of the syntax of exiftool and has the suffix + * ".thumb.jpg" + * @throws IOException + * Signals that an I/O exception has occurred. + */ + File extractThumbnail(File input, Tag tag) throws IOException; + + void rebuildMetadata(File file) throws IOException; + + /** + * Rewrite all the the metadata tags in a JPEG image. This will not work for + * TIFF files. Use this when the image has some corrupt tags. + * + * @link http://www.sno.phy.queensu.ca/~phil/exiftool/faq.html#Q20 + */ + void rebuildMetadata(WriteOptions options, File file) throws IOException; + + Map readMetadata(File file, Object... tags) + throws IOException; + + /** + * Reads metadata from the file. + */ + Map readMetadata(ReadOptions options, File file, + Object... tags) throws IOException; + + /** + * Takes a map of tags (either (@link Tag) or Strings for keys) and + * replaces/appends them to the metadata. + */ + void writeMetadata(WriteOptions options, File image, + Map values) throws IOException; +} \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java index 59bc6963..75258210 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java +++ b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java @@ -23,8 +23,8 @@ public class KeepAliveExifProxy implements ExifProxy { public KeepAliveExifProxy(String exifCmd, List baseArgs) { inactivityTimeout = Long.getLong( - ExifTool.ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, - ExifTool.DEFAULT_PROCESS_CLEANUP_DELAY); + ExifToolNew.ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, + ExifToolNew.DEFAULT_PROCESS_CLEANUP_DELAY); startupArgs = new ArrayList(baseArgs.size() + 5); startupArgs.add(exifCmd); startupArgs.addAll(Arrays.asList("-stay_open", "True")); diff --git a/src/main/java/com/thebuzzmedia/exiftool/Tag.java b/src/main/java/com/thebuzzmedia/exiftool/Tag.java index 4987c63d..f297dc17 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/Tag.java +++ b/src/main/java/com/thebuzzmedia/exiftool/Tag.java @@ -151,7 +151,7 @@ public enum Tag implements MetadataTag { for (int i = 0; i < values.length; i++) { Tag tag = values[i]; - TAG_LOOKUP_MAP.put(tag.getName(), tag); + TAG_LOOKUP_MAP.put(tag.getKey(), tag); } } @@ -168,14 +168,14 @@ public enum Tag implements MetadataTag { public static Tag forName(String name) { return TAG_LOOKUP_MAP.get(name); } - public static Map toTagMap(Map values) { + public static Map toTagMap(Map values) { return mapByTag(values); } - private static Map mapByTag(Map stringMap) { - Map tagMap = new HashMap(Tag.values().length); + private static Map mapByTag(Map stringMap) { + Map tagMap = new HashMap(Tag.values().length); for (Tag tag : Tag.values()) { - if (stringMap.containsKey(tag.getName())) { - tagMap.put(tag, stringMap.get(tag.getName())); + if (stringMap.containsKey(tag.getKey())) { + tagMap.put(tag, stringMap.get(tag.getKey())); } } return tagMap; @@ -350,11 +350,6 @@ public static Object deserialize(String tagName, String value, Class expectedTyp } - /** - * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). - * - * @return the name of the tag (e.g. "Orientation", "ISO", etc.). - */ @Deprecated public String getName() { return getKey(); @@ -373,6 +368,11 @@ public Class getType() { return type; } + /** + * Used to get the name of the tag (e.g. "Orientation", "ISO", etc.). + * + * @return the name of the tag (e.g. "Orientation", "ISO", etc.). + */ @Override public String getKey() { return key; diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index 22a94a68..e8ccf155 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -27,8 +27,8 @@ public static void main(String[] args) throws IOException, + (tags.length * images.length * ITERATIONS) + " total operations.\n"); - ExifTool tool = new ExifTool(); - ExifTool toolSO = new ExifTool(Feature.STAY_OPEN); + ExifToolService tool = new ExifTool(); + ExifToolService toolSO = new ExifTool(Feature.STAY_OPEN); /* * -stay_open False @@ -62,7 +62,7 @@ public static void main(String[] args) throws IOException, toolSO.close(); } - private static long run(ExifTool tool, File[] images, Tag[] tags) + private static long run(ExifToolService tool, File[] images, Tag[] tags) throws IllegalArgumentException, SecurityException, IOException { long startTime = System.currentTimeMillis(); diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index 2d7e0fa1..0589616b 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -17,16 +17,16 @@ public static void main(String[] args) throws IOException, // System.setProperty(ExifTool.ENV_EXIF_TOOL_PATH, // "D:\\Tools\\exiftool.exe"); - ExifTool tool = new ExifTool(Feature.STAY_OPEN); + ExifToolService tool = new ExifTool(Feature.STAY_OPEN); File[] images = new File(TEST_FILES_PATH).listFiles(); // list all first-class tags for (File f : images) { log.info("\n[{}]", f.getName()); - Map metadata = tool.getImageMeta(f, + Map metadata = tool.getImageMeta(f, Format.HUMAN_READABLE, Tag.values()); - for (Tag key : metadata.keySet()) { + for (MetadataTag key : metadata.keySet()) { log.info(String.format("\t\t%s: %s", key.getKey(), metadata.get(key))); } diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 1fe24427..6eb7913c 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -39,7 +39,7 @@ public class TestExifTool { @Test public void testSingleTool() throws Exception { - ExifTool tool = new ExifTool(); + ExifToolService tool = new ExifTool(); try { assertTrue(runTests(tool, "")); } finally { @@ -74,7 +74,7 @@ public void testConcurrent() throws Exception { @Override public void run() { log.info(getName() + ": starting"); - ExifTool tool = new ExifTool(Feature.STAY_OPEN); + ExifToolService tool = new ExifTool(Feature.STAY_OPEN); try { runTests(tool, getName()); log.info(getName() + ": finished"); @@ -101,7 +101,7 @@ public void run() { @Test public void testManyThreadsOneTool() throws Exception { - final ExifTool tool = new ExifTool(Feature.STAY_OPEN); + final ExifToolService tool = new ExifTool(Feature.STAY_OPEN); try { Thread[] threads = new Thread[20]; for (int i = 0; i < threads.length; i++) { @@ -136,7 +136,7 @@ public void run() { @Test public void testProcessTimeout() throws Exception { - final ExifTool tool = new ExifTool(1,Feature.STAY_OPEN); + final ExifToolService tool = new ExifTool(1,Feature.STAY_OPEN); try { runTests(tool, "will fail"); fail("should have failed"); @@ -147,12 +147,12 @@ public void testProcessTimeout() throws Exception { } } - public boolean runTests(ExifTool tool, String runId) throws IOException, + public boolean runTests(ExifToolService tool, String runId) throws IOException, URISyntaxException { - Map metadata; + Map metadata; File imageFile; - Set keys; + Set keys; Tag tag; URL url = getClass() @@ -179,7 +179,7 @@ public boolean runTests(ExifTool tool, String runId) throws IOException, imageFile = new File(url.toURI()); metadata = tool.getImageMeta(imageFile, Format.HUMAN_READABLE, Tag.values()); - assertEquals(24, metadata.size()); + assertEquals(25, metadata.size()); keys = metadata.keySet(); tag = Tag.IMAGE_WIDTH; @@ -204,7 +204,7 @@ public boolean runTests(ExifTool tool, String runId) throws IOException, @Test public void testGroupTags() throws Exception { - ExifTool tool = new ExifTool(Feature.STAY_OPEN); + ExifToolService tool = new ExifTool(Feature.STAY_OPEN); try { Map metadata; @@ -251,12 +251,12 @@ public void testVersionNumber() { @Test public void testWriteTagStringNonDaemon() throws Exception { - ExifTool tool = new ExifTool(); + ExifToolService tool = new ExifTool(); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Check the value is correct at the start - Map metadata = tool.getImageMeta( + Map metadata = tool.getImageMeta( imageFile.toFile(), Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); assertEquals("Wrong starting value", "2010:12:10 17:07:05", @@ -288,12 +288,12 @@ public void testWriteTagStringNonDaemon() throws Exception { @Test public void testWriteTagString() throws Exception { - ExifTool tool = new ExifTool(Feature.STAY_OPEN); + ExifToolService tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Check the value is correct at the start - Map metadata = tool.getImageMeta( + Map metadata = tool.getImageMeta( imageFile.toFile(), Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); assertEquals("Wrong starting value", "2010:12:10 17:07:05", @@ -324,12 +324,12 @@ public void testWriteTagString() throws Exception { @Test public void testWriteTagStringInvalidformat() throws Exception { - ExifTool tool = new ExifTool(Feature.STAY_OPEN); + ExifToolService tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Check the value is correct at the start - Map metadata = tool.getImageMeta( + Map metadata = tool.getImageMeta( imageFile.toFile(), Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); assertEquals("Wrong starting value", "2010:12:10 17:07:05", @@ -364,12 +364,12 @@ public void testWriteTagStringInvalidformat() throws Exception { @Test public void testWriteTagNumberNonDaemon() throws Exception { - ExifTool tool = new ExifTool(); + ExifToolService tool = new ExifTool(); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( + Map metadata = tool.getImageMeta( imageFile.toFile(), Format.HUMAN_READABLE, Tag.ORIENTATION); assertEquals("Orientation tag starting value is wrong", @@ -399,12 +399,12 @@ public void testWriteTagNumberNonDaemon() throws Exception { @Test public void testWriteTagNumber() throws Exception { - ExifTool tool = new ExifTool(Feature.STAY_OPEN); + ExifToolService tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( + Map metadata = tool.getImageMeta( imageFile.toFile(), Format.HUMAN_READABLE, Tag.ORIENTATION); assertEquals("Orientation tag starting value is wrong", @@ -434,12 +434,12 @@ public void testWriteTagNumber() throws Exception { @Test public void testWriteMulipleTag() throws Exception { - ExifTool tool = new ExifTool(Feature.STAY_OPEN); + ExifToolService tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( + Map metadata = tool.getImageMeta( imageFile.toFile(), Format.HUMAN_READABLE, Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", @@ -476,12 +476,12 @@ public void testWriteMulipleTag() throws Exception { @Test public void testWriteMulipleTagNonDaemon() throws Exception { - ExifTool tool = new ExifTool(); + ExifToolService tool = new ExifTool(); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( + Map metadata = tool.getImageMeta( imageFile.toFile(), Format.HUMAN_READABLE, Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", @@ -519,12 +519,12 @@ public void testWriteMulipleTagNonDaemon() throws Exception { @Test public void testWriteMultipleTagNonDaemon2() throws Exception { - ExifToolNew tool = new ExifToolNew(); + ExifToolService tool = new ExifToolNew(); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start - Map metadata = tool.getImageMeta( + Map metadata = tool.getImageMeta( imageFile.toFile(), Format.HUMAN_READABLE, Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", @@ -538,7 +538,8 @@ public void testWriteMultipleTagNonDaemon2() throws Exception { newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); newValues.put(Tag.ORIENTATION, 3); - tool.writeMetadata(imageFile.toFile(), newValues); + //tool.writeMetadata(imageFile.toFile(), newValues); + tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check the updated value metadata = tool.getImageMeta(imageFile.toFile(), @@ -559,9 +560,8 @@ public void testWriteMultipleTagNonDaemon2() throws Exception { } @Test public void testWritingWithImplicitTypes() throws Exception { - ExifToolNew tool = new ExifToolNew(Feature.MWG_MODULE); - tool.setReadOptions(tool.getReadOptions().withNumericOutput(true) - .withConvertTypes(true)); + ExifToolService tool = new ExifToolNew(new ReadOptions().withNumericOutput(true) + .withConvertTypes(true),Feature.MWG_MODULE); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); File imageFile = Paths.get(url.toURI()).toFile(); try { @@ -569,7 +569,7 @@ public void testWritingWithImplicitTypes() throws Exception { SimpleDateFormat formatter = new SimpleDateFormat( "yyyy:MM:dd hh:mm:ss"); - Map metadata = tool.readMetadata(imageFile, + Map metadata = tool.getImageMeta2(imageFile, Tag.ORIENTATION, MwgTag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", 1, @@ -587,7 +587,7 @@ public void testWritingWithImplicitTypes() throws Exception { data.put(MwgTag.CREATE_DATE, createDate.getTime()); data.put(MwgTag.KEYWORDS, new String[] { "a", "b", "c" }); tool.writeMetadata( - tool.getWriteOptions().withDeleteBackupFile(false), + new WriteOptions().withDeleteBackupFile(false), imageFile, data); // Finally check the updated value From d3d12b479d8984def6f1bf636755c053b8584e10 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 15:29:23 +0300 Subject: [PATCH 050/148] - fixed memory leaks due to not properly closing the ExifTool/ExifProcess by -- making ExifTool implement AutoCloseable to simplify the instantiation with try(ExifTool tool = new ExifTool()){ .... } pattern -- register in ExifProcess all the launched processes and force a clean on them on JVM shutdown to destroy the child exiftool processes - all 14/16 test pass --- .../thebuzzmedia/exiftool/ExifProcess.java | 85 +++- .../com/thebuzzmedia/exiftool/ExifTool.java | 9 +- .../thebuzzmedia/exiftool/ExifToolNew.java | 57 +-- .../thebuzzmedia/exiftool/ExifToolNew2.java | 6 + .../exiftool/ExifToolService.java | 14 +- .../thebuzzmedia/exiftool/TestExifTool.java | 396 +++++++++--------- 6 files changed, 310 insertions(+), 257 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index bca02381..218309b9 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -4,11 +4,17 @@ import java.io.IOException; import java.io.InputStreamReader; import java.io.OutputStreamWriter; +import java.io.PrintWriter; +import java.io.StringWriter; +import java.lang.reflect.InvocationTargetException; import java.util.ArrayList; import java.util.Arrays; +import java.util.Collections; import java.util.HashMap; import java.util.List; import java.util.Map; +import java.util.Map.Entry; +import java.util.TreeMap; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; @@ -18,6 +24,30 @@ * modes. This is the actual process, with streams for reading and writing data. */ public final class ExifProcess { + private static class Pair{ + final P1 _1; + final P2 _2; + public Pair(P1 _1, P2 _2){ + this._1 = _1; + this._2 = _2; + } + @Override + public String toString() { + return "Pair("+_1+","+_2+")"; + } + } + private static final Map> all = Collections.synchronizedMap(new TreeMap>()); + static{ + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + ExifTool.log.info("Close all remaining processes:" + all.keySet()); + for(Entry> item : all.entrySet()){ + ExifTool.log.info("Close leaked process " + item); + item.getValue()._2.close(); + } + } + }); + } /** * Compiled {@link Pattern} of ": " used to split compact output from * ExifTool evenly into name/value pairs. @@ -26,7 +56,8 @@ public final class ExifProcess { .compile("\\s*:\\s*"); public static VersionNumber readVersion(String exifCmd) { - ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, "-ver")); + ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, + "-ver")); try { return new VersionNumber(process.readLine()); } catch (IOException ex) { @@ -38,7 +69,7 @@ public static VersionNumber readVersion(String exifCmd) { } public static ExifProcess _execute(boolean keepAlive, List args) { - return new ExifProcess(keepAlive,args); + return new ExifProcess(keepAlive, args); } public static Map executeToResults(String exifCmd, @@ -68,8 +99,8 @@ public static String executeToString(String exifCmd, List args) } public static ExifProcess startup(String exifCmd) { - List args = Arrays.asList(exifCmd, "-stay_open", "True", - "-@", "-"); + List args = Arrays.asList(exifCmd, "-stay_open", "True", "-@", + "-"); return _execute(true, args); } @@ -87,6 +118,7 @@ public ExifProcess(boolean keepAlive, List args) { "Attempting to start ExifTool process using args: %s", args)); try { this.process = new ProcessBuilder(args).start(); + all.put(process.toString(), new Pair(toString(new RuntimeException("start of "+process)),this)); this.reader = new BufferedReader(new InputStreamReader( process.getInputStream())); this.writer = new OutputStreamWriter(process.getOutputStream()); @@ -94,7 +126,7 @@ public ExifProcess(boolean keepAlive, List args) { new BufferedReader(new InputStreamReader( process.getErrorStream()))); errReader.start(); - ExifTool.log.debug("\tSuccessful"); + ExifTool.log.debug("\tSuccessful " + process + " started."); } catch (Exception e) { String message = "Unable to start external ExifTool process using the execution arguments: " + args @@ -106,11 +138,20 @@ public ExifProcess(boolean keepAlive, List args) { throw new RuntimeException(message, e); } } - public synchronized Map sendToRunning(List args) throws IOException { + + private String toString(Throwable throwable) { + StringWriter sw = new StringWriter(); + throwable.printStackTrace(new PrintWriter(sw)); + return sw.getBuffer().toString(); + } + + public synchronized Map sendToRunning(List args) + throws IOException { return sendArgs(args); } - public synchronized Map sendArgs(List args) throws IOException { + public synchronized Map sendArgs(List args) + throws IOException { if (!keepAlive) { throw new IOException("Not KeepAlive Process"); } @@ -155,10 +196,10 @@ public synchronized Map readResponse() throws IOException { /* * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need - * to look for it and break from this loop when we see it - * otherwise this process will hang indefinitely blocking on the - * input stream with no data to read. + * output to us with a "{ready}" clause on a new line, we need to + * look for it and break from this loop when we see it otherwise + * this process will hang indefinitely blocking on the input stream + * with no data to read. */ if (keepAlive && line.equals("{ready}")) { break; @@ -186,10 +227,10 @@ public synchronized String readResponseString() throws IOException { /* * When using a persistent ExifTool process, it terminates its - * output to us with a "{ready}" clause on a new line, we need - * to look for it and break from this loop when we see it - * otherwise this process will hang indefinitely blocking on the - * input stream with no data to read. + * output to us with a "{ready}" clause on a new line, we need to + * look for it and break from this loop when we see it otherwise + * this process will hang indefinitely blocking on the input stream + * with no data to read. */ if (keepAlive && line.equals("{ready}")) { break; @@ -242,12 +283,17 @@ public void close() { // no-op, just try to close it. } - ExifTool.log.debug("Read/Write streams successfully closed."); + ExifTool.log + .debug("Read/Write streams successfully closed."); try { + ExifTool.log.debug("\tDestroy process " + process + "..."); process.destroy(); + all.remove(process.toString()); + ExifTool.log.debug("\tDestroy process " + process + " done => "+all.keySet()); } catch (Exception e) { // + ExifTool.log.debug("", e); } // process = null; @@ -257,4 +303,11 @@ public void close() { } } } + + @Override + protected void finalize() throws Throwable { + ExifTool.log.debug("\tFinalize process " + process + "."); + close(); + super.finalize(); + } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 1f4be8f2..2954c024 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -16,6 +16,7 @@ package com.thebuzzmedia.exiftool; +import java.io.Closeable; import java.io.File; import java.io.FileWriter; import java.io.IOException; @@ -210,7 +211,7 @@ * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 */ -public class ExifTool implements ExifToolService { +public class ExifTool implements ExifToolService, AutoCloseable { private static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; private static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; @@ -941,4 +942,10 @@ public void writeMetadata(WriteOptions options, File image, Map values) throws IOException { throw new RuntimeException("Not implemented."); } + @Override + protected void finalize() throws Throwable { + log.info("ExifTool not used anymore shutdown the exiftool process..."); + shutdown(); + super.finalize(); + } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java index 78841c0d..549603c5 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java @@ -292,7 +292,7 @@ public ExifToolNew(Feature... features) { this(new ReadOptions(), features); } - public ExifToolNew(ReadOptions readOptions, Feature...features) { + public ExifToolNew(ReadOptions readOptions, Feature... features) { this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, DEFAULT_PROCESS_CLEANUP_DELAY), readOptions, features); @@ -306,7 +306,8 @@ public ExifToolNew(String exifToolPath) { } public ExifToolNew(String exifToolPath, Feature... features) { - this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, new ReadOptions(), features); + this(exifToolPath, DEFAULT_PROCESS_CLEANUP_DELAY, new ReadOptions(), + features); } public ExifToolNew(String exifCmd, long processCleanupDelay, @@ -335,16 +336,18 @@ public ExifToolNew(String exifCmd, long processCleanupDelay, exifProxy = new SingleUseExifProxy(exifCmd, baseArgs); } } -// -// /** -// * Limits the amount of time (in mills) an exif operation can take. Setting -// * value to greater than 0 to enable. -// */ -// public ExifToolNew setRunTimeout(long mills) { -// defReadOptions = defReadOptions.withRunTimeoutMills(mills); -// defWriteOptions = defWriteOptions.withRunTimeoutMills(mills); -// return this; -// } + + // + // /** + // * Limits the amount of time (in mills) an exif operation can take. + // Setting + // * value to greater than 0 to enable. + // */ + // public ExifToolNew setRunTimeout(long mills) { + // defReadOptions = defReadOptions.withRunTimeoutMills(mills); + // defWriteOptions = defWriteOptions.withRunTimeoutMills(mills); + // return this; + // } /** * Used to determine if the given {@link Feature} is supported by the @@ -497,8 +500,9 @@ public Map getImageMeta(File image, Tag... tags) return getImageMeta(image, Format.NUMERIC, tags); } - public Map getImageMeta(File image, Format format, Tag... tags) - throws IllegalArgumentException, SecurityException, IOException { + public Map getImageMeta(File image, Format format, + Tag... tags) throws IllegalArgumentException, SecurityException, + IOException { String[] stringTags = new String[tags.length]; int i = 0; @@ -547,11 +551,8 @@ public Map readMetadata(File file, Object... tags) return readMetadata(defReadOptions, file, tags); } - /** - * Reads metadata from the file. - */ - public Map readMetadata(ReadOptions options, File file, - Object... tags) throws IOException { + public Map readMetadata(ReadOptions options, + File file, Object... tags) throws IOException { if (file == null) { throw new IllegalArgumentException( "file cannot be null and must be a valid stream of image data."); @@ -604,7 +605,7 @@ public Map readMetadata(ReadOptions options, File file, Object value = options.convertTypes ? Tag.deserialize( metaTag.getKey(), input, metaTag.getType()) : input; // maps with tag passed in, as caller expects to fetch - metadata.put(tag, value); + metadata.put(metaTag, value); } } for (Map.Entry entry : resultMap.entrySet()) { @@ -829,15 +830,23 @@ public Map getImageMeta(File image, } @Override - public Map getImageMeta2(File image, MetadataTag... tags) + public Map getImageMeta2(File file, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { - throw new RuntimeException("Not implemented."); + return readMetadata(file, tags); } @Override - public Map getImageMeta(File image, Format format, + public Map getImageMeta(File file, Format format, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { - throw new RuntimeException("Not implemented."); + Map result = readMetadata(file, tags); + //since meta tags are passed we will have a proper Map result + return (Map)result; + } + @Override + protected void finalize() throws Throwable { + log.info("ExifTool not used anymore shutdown the exiftool process..."); + shutdown(); + super.finalize(); } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java index f4cb8780..60527bdc 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java @@ -1170,4 +1170,10 @@ public void writeMetadata(WriteOptions options, File image, Map values) throws IOException { throw new RuntimeException("Not implemented."); } + @Override + protected void finalize() throws Throwable { + ExifTool.log.info("ExifTool not used anymore shutdown the exiftool process..."); + shutdown(); + super.finalize(); + } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java index 62aa08b1..1e84fc53 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java @@ -4,7 +4,7 @@ import java.io.IOException; import java.util.Map; -public interface ExifToolService { +public interface ExifToolService extends AutoCloseable{ /** * Used to determine if the given {@link Feature} is supported by the @@ -113,18 +113,18 @@ public interface ExifToolService { Map getImageMeta(File file, Format format, boolean supressDuplicates, String... tags) throws IOException; - Map getImageMeta(File image, MetadataTag... tags) + Map getImageMeta(File file, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException; - Map getImageMeta2(File image, MetadataTag... tags) + Map getImageMeta2(File file, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException; - Map getImageMeta(File image, Format format, MetadataTag... tags) + Map getImageMeta(File file, Format format, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException; - Map getImageMeta(File image, Format format, + Map getImageMeta(File file, Format format, TagGroup... tags) throws IllegalArgumentException, SecurityException, IOException; - public void addImageMetadata(File image, Map values) + public void addImageMetadata(File file, Map values) throws IOException; /** @@ -205,6 +205,6 @@ Map readMetadata(ReadOptions options, File file, * Takes a map of tags (either (@link Tag) or Strings for keys) and * replaces/appends them to the metadata. */ - void writeMetadata(WriteOptions options, File image, + void writeMetadata(WriteOptions options, File file, Map values) throws IOException; } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 6eb7913c..9d453bb7 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -39,26 +39,17 @@ public class TestExifTool { @Test public void testSingleTool() throws Exception { - ExifToolService tool = new ExifTool(); - try { + try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); } - tool = new ExifTool(Feature.STAY_OPEN); - try { + try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); } - tool = new ExifTool(Feature.STAY_OPEN); - try { + try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { tool.startup(); assertTrue(runTests(tool, "")); - } finally { - tool.shutdown(); } } @@ -74,8 +65,7 @@ public void testConcurrent() throws Exception { @Override public void run() { log.info(getName() + ": starting"); - ExifToolService tool = new ExifTool(Feature.STAY_OPEN); - try { + try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { runTests(tool, getName()); log.info(getName() + ": finished"); } catch (IOException e) { @@ -84,8 +74,6 @@ public void run() { } catch (URISyntaxException e) { log.error(e.getMessage(), e); fail(e.getMessage()); - } finally { - tool.shutdown(); } log.info(getName() + ": finished"); } @@ -101,8 +89,7 @@ public void run() { @Test public void testManyThreadsOneTool() throws Exception { - final ExifToolService tool = new ExifTool(Feature.STAY_OPEN); - try { + try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { Thread[] threads = new Thread[20]; for (int i = 0; i < threads.length; i++) { final String label = "run " + i; @@ -129,26 +116,21 @@ public void run() { for (Thread thread : threads) { thread.join(); } - } finally { - tool.shutdown(); } } @Test public void testProcessTimeout() throws Exception { - final ExifToolService tool = new ExifTool(1,Feature.STAY_OPEN); - try { + try (ExifToolService tool = new ExifTool(1, Feature.STAY_OPEN)) { runTests(tool, "will fail"); fail("should have failed"); } catch (IOException ex) { ; - } finally { - tool.shutdown(); } } - public boolean runTests(ExifToolService tool, String runId) throws IOException, - URISyntaxException { + public boolean runTests(ExifToolService tool, String runId) + throws IOException, URISyntaxException { Map metadata; File imageFile; @@ -204,8 +186,7 @@ public boolean runTests(ExifToolService tool, String runId) throws IOException, @Test public void testGroupTags() throws Exception { - ExifToolService tool = new ExifTool(Feature.STAY_OPEN); - try { + try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { Map metadata; URL url = getClass().getResource("/iptc_test-photoshop.jpg"); @@ -221,8 +202,6 @@ public void testGroupTags() throws Exception { // for (String key : metadata.keySet()){ // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); // } - } finally { - tool.shutdown(); } } @@ -241,8 +220,8 @@ public void testTag() { public void testVersionNumber() { assertTrue(new VersionNumber("1.2") .isBeforeOrEqualTo(new VersionNumber("1.2.3"))); - assertTrue(new VersionNumber(1, 2) - .isBeforeOrEqualTo(new VersionNumber("1.2"))); + assertTrue(new VersionNumber(1, 2).isBeforeOrEqualTo(new VersionNumber( + "1.2"))); assertTrue(new VersionNumber(1, 2, 3) .isBeforeOrEqualTo(new VersionNumber("1.3"))); assertTrue(new VersionNumber(1, 2, 3) @@ -251,197 +230,199 @@ public void testVersionNumber() { @Test public void testWriteTagStringNonDaemon() throws Exception { - ExifToolService tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + try (ExifToolService tool = new ExifTool()) { + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's updated + metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(Tag.DATE_TIME_ORIGINAL)); - // Check the value is correct at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), Format.HUMAN_READABLE, - Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's updated - metadata = tool - .getImageMeta(imageFile.toFile(), - Format.HUMAN_READABLE, - Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not - // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + // Finally copy the source file back over so the next test run is + // not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + Files.move(backupFile, imageFile, + StandardCopyOption.REPLACE_EXISTING); + } } @Test public void testWriteTagString() throws Exception { ExifToolService tool = new ExifTool(Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's updated + metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", newDate, + metadata.get(Tag.DATE_TIME_ORIGINAL)); - // Check the value is correct at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), Format.HUMAN_READABLE, - Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's updated - metadata = tool - .getImageMeta(imageFile.toFile(), - Format.HUMAN_READABLE, - Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not - // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + // Finally copy the source file back over so the next test run is + // not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + Files.move(backupFile, imageFile, + StandardCopyOption.REPLACE_EXISTING); + } @Test public void testWriteTagStringInvalidformat() throws Exception { - ExifToolService tool = new ExifTool(Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), Format.HUMAN_READABLE, - Tag.DATE_TIME_ORIGINAL); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(Tag.DATE_TIME_ORIGINAL)); + try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, + Tag.DATE_TIME_ORIGINAL); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", + metadata.get(Tag.DATE_TIME_ORIGINAL)); + + String newDate = "2egek opkpgrpok"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + + // Now change it to an invalid value which should fail + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check that it's not updated + metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", + "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); - String newDate = "2egek opkpgrpok"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - - // Now change it to an invalid value which should fail - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check that it's not updated - metadata = tool - .getImageMeta(imageFile.toFile(), - Format.HUMAN_READABLE, - Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", - metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not - // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - // might not exist - if (backup_url != null) { - Path backupFile = Paths.get(backup_url.toURI()); - Files.move(backupFile, imageFile, - StandardCopyOption.REPLACE_EXISTING); + // Finally copy the source file back over so the next test run is + // not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + // might not exist + if (backup_url != null) { + Path backupFile = Paths.get(backup_url.toURI()); + Files.move(backupFile, imageFile, + StandardCopyOption.REPLACE_EXISTING); + } } } @Test public void testWriteTagNumberNonDaemon() throws Exception { - ExifToolService tool = new ExifTool(); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + try (ExifToolService tool = new ExifTool()) { + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); - // Test what orientation value is at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), Format.HUMAN_READABLE, - Tag.ORIENTATION); - assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, Tag.ORIENTATION); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); - // Now change it - Map newValues = new HashMap(); - newValues.put(Tag.ORIENTATION, 3); + // Now change it + Map newValues = new HashMap(); + newValues.put(Tag.ORIENTATION, 3); - tool.addImageMetadata(imageFile.toFile(), newValues); + tool.addImageMetadata(imageFile.toFile(), newValues); - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), - Format.HUMAN_READABLE, Tag.ORIENTATION); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is not - // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.ORIENTATION); + assertEquals("Orientation tag updated value is wrong", + "Rotate 180", metadata.get(Tag.ORIENTATION)); - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + // Finally copy the source file back over so the next test run is + // not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + Files.move(backupFile, imageFile, + StandardCopyOption.REPLACE_EXISTING); + } } @Test public void testWriteTagNumber() throws Exception { - ExifToolService tool = new ExifTool(Feature.STAY_OPEN); - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get(url.toURI()); - // Test what orientation value is at the start - Map metadata = tool.getImageMeta( - imageFile.toFile(), Format.HUMAN_READABLE, - Tag.ORIENTATION); - assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + // Test what orientation value is at the start + Map metadata = tool.getImageMeta( + imageFile.toFile(), Format.HUMAN_READABLE, Tag.ORIENTATION); + assertEquals("Orientation tag starting value is wrong", + "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); - // Now change it - Map newValues = new HashMap(); - newValues.put(Tag.ORIENTATION, 3); + // Now change it + Map newValues = new HashMap(); + newValues.put(Tag.ORIENTATION, 3); - tool.addImageMetadata(imageFile.toFile(), newValues); + tool.addImageMetadata(imageFile.toFile(), newValues); - // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), - Format.HUMAN_READABLE, Tag.ORIENTATION); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is not - // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); + // Finally check the updated value + metadata = tool.getImageMeta(imageFile.toFile(), + Format.HUMAN_READABLE, Tag.ORIENTATION); + assertEquals("Orientation tag updated value is wrong", + "Rotate 180", metadata.get(Tag.ORIENTATION)); - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + // Finally copy the source file back over so the next test run is + // not + // affected by the change + URL backup_url = getClass().getResource( + "/nexus-s-electric-cars.jpg_original"); + Path backupFile = Paths.get(backup_url.toURI()); + Files.move(backupFile, imageFile, + StandardCopyOption.REPLACE_EXISTING); + } } @Test public void testWriteMulipleTag() throws Exception { - ExifToolService tool = new ExifTool(Feature.STAY_OPEN); + try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start Map metadata = tool.getImageMeta( - imageFile.toFile(), Format.HUMAN_READABLE, - Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + imageFile.toFile(), Format.HUMAN_READABLE, Tag.ORIENTATION, + Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", "2010:12:10 17:07:05", @@ -456,9 +437,8 @@ public void testWriteMulipleTag() throws Exception { tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), - Format.HUMAN_READABLE, Tag.ORIENTATION, - Tag.DATE_TIME_ORIGINAL); + metadata = tool.getImageMeta(imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, @@ -471,19 +451,19 @@ public void testWriteMulipleTag() throws Exception { Path backupFile = Paths.get(backup_url.toURI()); Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - + } } @Test public void testWriteMulipleTagNonDaemon() throws Exception { - ExifToolService tool = new ExifTool(); + try (ExifToolService tool = new ExifTool()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start Map metadata = tool.getImageMeta( - imageFile.toFile(), Format.HUMAN_READABLE, - Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + imageFile.toFile(), Format.HUMAN_READABLE, Tag.ORIENTATION, + Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", "2010:12:10 17:07:05", @@ -498,9 +478,8 @@ public void testWriteMulipleTagNonDaemon() throws Exception { tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), - Format.HUMAN_READABLE, Tag.ORIENTATION, - Tag.DATE_TIME_ORIGINAL); + metadata = tool.getImageMeta(imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, @@ -513,20 +492,19 @@ public void testWriteMulipleTagNonDaemon() throws Exception { Path backupFile = Paths.get(backup_url.toURI()); Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); - + } } @Test public void testWriteMultipleTagNonDaemon2() throws Exception { - - ExifToolService tool = new ExifToolNew(); + try (ExifToolService tool = new ExifToolNew()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get(url.toURI()); // Test what orientation value is at the start Map metadata = tool.getImageMeta( - imageFile.toFile(), Format.HUMAN_READABLE, - Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + imageFile.toFile(), Format.HUMAN_READABLE, Tag.ORIENTATION, + Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", "2010:12:10 17:07:05", @@ -538,13 +516,12 @@ public void testWriteMultipleTagNonDaemon2() throws Exception { newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); newValues.put(Tag.ORIENTATION, 3); - //tool.writeMetadata(imageFile.toFile(), newValues); + // tool.writeMetadata(imageFile.toFile(), newValues); tool.addImageMetadata(imageFile.toFile(), newValues); // Finally check the updated value - metadata = tool.getImageMeta(imageFile.toFile(), - Format.HUMAN_READABLE, Tag.ORIENTATION, - Tag.DATE_TIME_ORIGINAL); + metadata = tool.getImageMeta(imageFile.toFile(), Format.HUMAN_READABLE, + Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, @@ -557,11 +534,14 @@ public void testWriteMultipleTagNonDaemon2() throws Exception { Path backupFile = Paths.get(backup_url.toURI()); Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + } } + @Test public void testWritingWithImplicitTypes() throws Exception { - ExifToolService tool = new ExifToolNew(new ReadOptions().withNumericOutput(true) - .withConvertTypes(true),Feature.MWG_MODULE); + try (ExifToolService tool = new ExifToolNew(new ReadOptions() + .withNumericOutput(true).withConvertTypes(true), + Feature.MWG_MODULE)){ URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); File imageFile = Paths.get(url.toURI()).toFile(); try { @@ -570,8 +550,7 @@ public void testWritingWithImplicitTypes() throws Exception { "yyyy:MM:dd hh:mm:ss"); Map metadata = tool.getImageMeta2(imageFile, - Tag.ORIENTATION, - MwgTag.DATE_TIME_ORIGINAL); + Tag.ORIENTATION, MwgTag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", 1, metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", @@ -586,14 +565,13 @@ public void testWritingWithImplicitTypes() throws Exception { Date createDate = formatter.parse("2013:02:21 10:07:05"); data.put(MwgTag.CREATE_DATE, createDate.getTime()); data.put(MwgTag.KEYWORDS, new String[] { "a", "b", "c" }); - tool.writeMetadata( - new WriteOptions().withDeleteBackupFile(false), + tool.writeMetadata(new WriteOptions().withDeleteBackupFile(false), imageFile, data); // Finally check the updated value - metadata = tool.readMetadata(imageFile, Tag.ORIENTATION, - imageFile, MwgTag.DATE_TIME_ORIGINAL, - MwgTag.CREATE_DATE, MwgTag.KEYWORDS); + metadata = tool.readMetadata(imageFile, Tag.ORIENTATION, imageFile, + MwgTag.DATE_TIME_ORIGINAL, MwgTag.CREATE_DATE, + MwgTag.KEYWORDS); assertEquals("Orientation tag updated value is wrong", 3, metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, @@ -614,7 +592,7 @@ public void testWritingWithImplicitTypes() throws Exception { Files.move(backupFile, imageFile.toPath(), StandardCopyOption.REPLACE_EXISTING); } - + } } } From 893d8ecb267df7f3b8b138902cf12c90c8df8d7b Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 15:43:09 +0300 Subject: [PATCH 051/148] - tests should not modify the original resource --- .../thebuzzmedia/exiftool/TestExifTool.java | 142 ++++++++++-------- 1 file changed, 76 insertions(+), 66 deletions(-) diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 9d453bb7..0a3ed497 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -232,7 +232,8 @@ public void testVersionNumber() { public void testWriteTagStringNonDaemon() throws Exception { try (ExifToolService tool = new ExifTool()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); // Check the value is correct at the start Map metadata = tool.getImageMeta( @@ -256,12 +257,12 @@ public void testWriteTagStringNonDaemon() throws Exception { // Finally copy the source file back over so the next test run is // not // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, - StandardCopyOption.REPLACE_EXISTING); +// URL backup_url = getClass().getResource( +// "/nexus-s-electric-cars.jpg_original"); +// Path backupFile = Paths.get(backup_url.toURI()); +// +// Files.move(backupFile, imageFile, +// StandardCopyOption.REPLACE_EXISTING); } } @@ -269,7 +270,8 @@ public void testWriteTagStringNonDaemon() throws Exception { public void testWriteTagString() throws Exception { ExifToolService tool = new ExifTool(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); // Check the value is correct at the start Map metadata = tool.getImageMeta( @@ -293,19 +295,20 @@ public void testWriteTagString() throws Exception { // Finally copy the source file back over so the next test run is // not // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - Files.move(backupFile, imageFile, - StandardCopyOption.REPLACE_EXISTING); - +// URL backup_url = getClass().getResource( +// "/nexus-s-electric-cars.jpg_original"); +// Path backupFile = Paths.get(backup_url.toURI()); +// Files.move(backupFile, imageFile, +// StandardCopyOption.REPLACE_EXISTING); +// } @Test public void testWriteTagStringInvalidformat() throws Exception { try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); // Check the value is correct at the start Map metadata = tool.getImageMeta( @@ -330,14 +333,14 @@ public void testWriteTagStringInvalidformat() throws Exception { // Finally copy the source file back over so the next test run is // not // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - // might not exist - if (backup_url != null) { - Path backupFile = Paths.get(backup_url.toURI()); - Files.move(backupFile, imageFile, - StandardCopyOption.REPLACE_EXISTING); - } +// URL backup_url = getClass().getResource( +// "/nexus-s-electric-cars.jpg_original"); +// // might not exist +// if (backup_url != null) { +// Path backupFile = Paths.get(backup_url.toURI()); +// Files.move(backupFile, imageFile, +// StandardCopyOption.REPLACE_EXISTING); +// } } } @@ -345,7 +348,8 @@ public void testWriteTagStringInvalidformat() throws Exception { public void testWriteTagNumberNonDaemon() throws Exception { try (ExifToolService tool = new ExifTool()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); // Test what orientation value is at the start Map metadata = tool.getImageMeta( @@ -368,12 +372,12 @@ public void testWriteTagNumberNonDaemon() throws Exception { // Finally copy the source file back over so the next test run is // not // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, - StandardCopyOption.REPLACE_EXISTING); +// URL backup_url = getClass().getResource( +// "/nexus-s-electric-cars.jpg_original"); +// Path backupFile = Paths.get(backup_url.toURI()); +// +// Files.move(backupFile, imageFile, +// StandardCopyOption.REPLACE_EXISTING); } } @@ -381,7 +385,8 @@ public void testWriteTagNumberNonDaemon() throws Exception { public void testWriteTagNumber() throws Exception { try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); // Test what orientation value is at the start Map metadata = tool.getImageMeta( @@ -404,12 +409,12 @@ public void testWriteTagNumber() throws Exception { // Finally copy the source file back over so the next test run is // not // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, - StandardCopyOption.REPLACE_EXISTING); +// URL backup_url = getClass().getResource( +// "/nexus-s-electric-cars.jpg_original"); +// Path backupFile = Paths.get(backup_url.toURI()); +// +// Files.move(backupFile, imageFile, +// StandardCopyOption.REPLACE_EXISTING); } } @@ -417,7 +422,8 @@ public void testWriteTagNumber() throws Exception { public void testWriteMulipleTag() throws Exception { try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); // Test what orientation value is at the start Map metadata = tool.getImageMeta( @@ -446,11 +452,11 @@ public void testWriteMulipleTag() throws Exception { // Finally copy the source file back over so the next test run is not // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); +// URL backup_url = getClass().getResource( +// "/nexus-s-electric-cars.jpg_original"); +// Path backupFile = Paths.get(backup_url.toURI()); +// +// Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); } } @@ -458,7 +464,8 @@ public void testWriteMulipleTag() throws Exception { public void testWriteMulipleTagNonDaemon() throws Exception { try (ExifToolService tool = new ExifTool()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); // Test what orientation value is at the start Map metadata = tool.getImageMeta( @@ -487,11 +494,11 @@ public void testWriteMulipleTagNonDaemon() throws Exception { // Finally copy the source file back over so the next test run is not // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); +// URL backup_url = getClass().getResource( +// "/nexus-s-electric-cars.jpg_original"); +// Path backupFile = Paths.get(backup_url.toURI()); +// +// Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); } } @@ -499,7 +506,8 @@ public void testWriteMulipleTagNonDaemon() throws Exception { public void testWriteMultipleTagNonDaemon2() throws Exception { try (ExifToolService tool = new ExifToolNew()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get(url.toURI()); + Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); // Test what orientation value is at the start Map metadata = tool.getImageMeta( @@ -529,11 +537,11 @@ public void testWriteMultipleTagNonDaemon2() throws Exception { // Finally copy the source file back over so the next test run is not // affected by the change - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - Path backupFile = Paths.get(backup_url.toURI()); - - Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); +// URL backup_url = getClass().getResource( +// "/nexus-s-electric-cars.jpg_original"); +// Path backupFile = Paths.get(backup_url.toURI()); +// +// Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); } } @@ -543,8 +551,10 @@ public void testWritingWithImplicitTypes() throws Exception { .withNumericOutput(true).withConvertTypes(true), Feature.MWG_MODULE)){ URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - File imageFile = Paths.get(url.toURI()).toFile(); - try { + Path imagePath = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()),imagePath, StandardCopyOption.REPLACE_EXISTING); + File imageFile = imagePath.toFile(); +// try { // Test what orientation value is at the start SimpleDateFormat formatter = new SimpleDateFormat( "yyyy:MM:dd hh:mm:ss"); @@ -584,15 +594,15 @@ public void testWritingWithImplicitTypes() throws Exception { // Finally copy the source file back over so the next test run is // not affected by the change - } finally { - URL backup_url = getClass().getResource( - "/nexus-s-electric-cars.jpg_original"); - if (backup_url != null) { - Path backupFile = Paths.get(backup_url.toURI()); - Files.move(backupFile, imageFile.toPath(), - StandardCopyOption.REPLACE_EXISTING); - } - } +// } finally { +// URL backup_url = getClass().getResource( +// "/nexus-s-electric-cars.jpg_original"); +// if (backup_url != null) { +// Path backupFile = Paths.get(backup_url.toURI()); +// Files.move(backupFile, imageFile.toPath(), +// StandardCopyOption.REPLACE_EXISTING); +// } + } } From afe45239332167a03375cc3171900a46f07fe3f5 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 17:01:51 +0300 Subject: [PATCH 052/148] - fix bug in ExifTool --- .../thebuzzmedia/exiftool/ExifProcess.java | 9 +++++ .../com/thebuzzmedia/exiftool/ExifTool.java | 39 ++++++++++--------- .../thebuzzmedia/exiftool/ExifToolNew.java | 25 +++++++----- 3 files changed, 45 insertions(+), 28 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index 218309b9..702ec4a5 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -80,10 +80,19 @@ public static Map executeToResults(String exifCmd, ExifProcess process = _execute(false, newArgs); try { return process.readResponse(); + }catch(Throwable e){ + throw new RuntimeException(String.format("When executing %s we got %s",toCmd(newArgs),e.getMessage()),e); } finally { process.close(); } } + private static String toCmd(List args){ + StringBuilder sb = new StringBuilder(); + for(String arg:args){ + sb.append(arg).append(" "); + } + return sb.toString(); + } public static String executeToString(String exifCmd, List args) throws IOException { diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 2954c024..d23eabd1 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -653,8 +653,6 @@ public void addImageMetadata(File image, Map values) // public void addImageMetadata(File image, Map values) // throws IOException { - final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); - if (image == null) { throw new IllegalArgumentException( "image cannot be null and must be a valid stream of image data."); @@ -673,20 +671,11 @@ public void addImageMetadata(File image, Map values) log.info("Adding Tags {} to {}", values, image.getAbsolutePath()); - Map resultMap; - if (stayOpen) { - log.debug("Using ExifTool in daemon mode (-stay_open True)..."); - resultMap = processStayOpen(createCommandList( - image.getAbsolutePath(), values)); - } else { - log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd, - createCommandList(image.getAbsolutePath(), values)); - } - // start process long startTime = System.currentTimeMillis(); + execute(null, image, values); + // Print out how long the call to external ExifTool process took. if (log.isDebugEnabled()) { log.debug(String.format( @@ -695,8 +684,22 @@ public void addImageMetadata(File image, Map values) } } + private void execute(WriteOptions options, File image, Map values) throws IOException { + final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + Map resultMap; + if (stayOpen) { + log.debug("Using ExifTool in daemon mode (-stay_open True)..."); + resultMap = processStayOpen(createCommandList( + image.getAbsolutePath(), values,stayOpen)); + } else { + log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); + resultMap = ExifProcess.executeToResults(exifCmd, + createCommandList(image.getAbsolutePath(), values,stayOpen)); + } + } + private List createCommandList(String filename, - Map values) { + Map values, boolean stayOpen) { List args = new ArrayList(64); @@ -712,11 +715,11 @@ private List createCommandList(String filename, } arg.append("="); if (value != null) { - if (value instanceof String) { - arg.append("\"").append(value.toString()).append("\""); - } else { +// if (value instanceof String && !stayOpen) { +// arg.append("\"").append(value.toString()).append("\""); +// } else { arg.append(value.toString()); - } +// } } args.add(arg.toString()); diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java index 549603c5..e38c8863 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java @@ -655,17 +655,29 @@ public void writeMetadata(WriteOptions options, File image, + image.getAbsolutePath() + "], ensure that the image exists at the given path and that the executing Java process has permissions to write to it."); } - log.info("Adding Tags {} to {}", values, image.getAbsolutePath()); + // start process + long startTime = System.currentTimeMillis(); + execute(options, image, values); + + // Print out how long the call to external ExifTool process took. + if (log.isDebugEnabled()) { + log.debug(String.format( + "Image Meta Processed in %d ms [added %d tags]", + (System.currentTimeMillis() - startTime), values.size())); + } + } + + private void execute(WriteOptions options, File image, + Map values) throws IOException { List args = new ArrayList(values.size() + 3); for (Map.Entry entry : values.entrySet()) { args.addAll(serializeToArgs(entry.getKey(), entry.getValue())); } args.add(image.getAbsolutePath()); + System.out.println(args.toString()); - // start process - long startTime = System.currentTimeMillis(); try { exifProxy.execute(options.runTimeoutMills, args); } finally { @@ -676,13 +688,6 @@ public void writeMetadata(WriteOptions options, File image, origBackup.delete(); } } - - // Print out how long the call to external ExifTool process took. - if (log.isDebugEnabled()) { - log.debug(String.format( - "Image Meta Processed in %d ms [added %d tags]", - (System.currentTimeMillis() - startTime), values.size())); - } } public void rebuildMetadata(File file) throws IOException { From 52386f2e0c17b8bc510a6d222acefd9ba8e02d49 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 20:13:07 +0300 Subject: [PATCH 053/148] - 15 tests passed for ExifTool failed: testWritingWithImplicitTypes - ExifToolNew still has some leaks and one failed test: testProcessTimeout - ExifToolNew2 still has many failed tests --- .../thebuzzmedia/exiftool/ExifProcess.java | 3 +- .../thebuzzmedia/exiftool/ExifToolNew.java | 18 ++++--- .../thebuzzmedia/exiftool/ExifToolNew2.java | 41 +++++++-------- .../exiftool/ExifToolService.java | 40 ++++++++++++--- .../exiftool/KeepAliveExifProxy.java | 44 +++++++++------- .../thebuzzmedia/exiftool/TestExifTool.java | 50 ++++++++++++------- 6 files changed, 127 insertions(+), 69 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index 702ec4a5..9043ce12 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -11,6 +11,7 @@ import java.util.Arrays; import java.util.Collections; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Map.Entry; @@ -41,7 +42,7 @@ public String toString() { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { ExifTool.log.info("Close all remaining processes:" + all.keySet()); - for(Entry> item : all.entrySet()){ + for(Entry> item : new HashSet>>(all.entrySet())){ ExifTool.log.info("Close leaked process " + item); item.getValue()._2.close(); } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java index e38c8863..6d211b81 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java @@ -291,11 +291,16 @@ public ExifToolNew() { public ExifToolNew(Feature... features) { this(new ReadOptions(), features); } - + public ExifToolNew(long cleanupDelayInMillis, Feature... features) { + this(new ReadOptions(), cleanupDelayInMillis, features); + } public ExifToolNew(ReadOptions readOptions, Feature... features) { - this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), Long.getLong( + this(readOptions,Long.getLong( ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, - DEFAULT_PROCESS_CLEANUP_DELAY), readOptions, features); + DEFAULT_PROCESS_CLEANUP_DELAY), features); + } + public ExifToolNew(ReadOptions readOptions, long cleanupDelayInMillis, Feature... features) { + this(System.getProperty(ENV_EXIF_TOOL_PATH, "exiftool"), cleanupDelayInMillis, readOptions, features); } /** @@ -329,10 +334,12 @@ public ExifToolNew(String exifCmd, long processCleanupDelay, baseArgs.addAll(Arrays.asList("-use", "MWG")); } if (featureEnabledSet.contains(Feature.STAY_OPEN)) { - KeepAliveExifProxy proxy = new KeepAliveExifProxy(exifCmd, baseArgs); - proxy.setInactiveTimeout(processCleanupDelay); + KeepAliveExifProxy proxy = new KeepAliveExifProxy(exifCmd, baseArgs,processCleanupDelay); exifProxy = proxy; } else { + if(processCleanupDelay!=0){ + throw new RuntimeException("The processCleanupDelay parameter should be 0 if no stay_open parameter is used. Was "+processCleanupDelay); + } exifProxy = new SingleUseExifProxy(exifCmd, baseArgs); } } @@ -676,7 +683,6 @@ private void execute(WriteOptions options, File image, args.addAll(serializeToArgs(entry.getKey(), entry.getValue())); } args.add(image.getAbsolutePath()); - System.out.println(args.toString()); try { exifProxy.execute(options.runTimeoutMills, args); diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java index 60527bdc..5c81a0c7 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java @@ -426,7 +426,7 @@ public boolean isFeatureSupported(Feature feature) */ protected static void log(String message, Object... params) { if (DEBUG) - System.out.printf(LOG_PREFIX + message + '\n', params); + ExifTool.log.debug(LOG_PREFIX + message + '\n', params); } /** @@ -711,12 +711,12 @@ public boolean isFeatureEnabled(Feature feature) return featureSet.contains(feature); } - public Map getImageMeta(File image, Tag... tags) + private Map getImageMeta2(File image, Tag... tags) throws IllegalArgumentException, SecurityException, IOException { - return getImageMeta(image, Format.NUMERIC, tags); + return getImageMeta2(image, Format.NUMERIC, tags); } - public Map getImageMeta(File image, Format format, Tag... tags) + private Map getImageMeta2(File image, Format format, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { if (image == null) throw new IllegalArgumentException( @@ -738,7 +738,7 @@ public Map getImageMeta(File image, Format format, Tag... tags) * Create a result map big enough to hold results for each of the tags * and avoid collisions while inserting. */ - Map resultMap = new HashMap(tags.length * 3); + Map resultMap = new HashMap(tags.length * 3); if (DEBUG) log("Querying %d tags from image: %s", tags.length, @@ -1084,7 +1084,8 @@ public boolean isStayOpen() { public Map getImageMeta(File image, Format format, TagGroup... tags) throws IllegalArgumentException, SecurityException, IOException { - return getImageMeta(image, format, tags); + //return getImageMeta2(image, format, tags); + throw new RuntimeException("Not implemented."); } @Override @@ -1093,79 +1094,79 @@ public void addImageMetadata(File image, Map values) setImageMeta(image, (Map) values); } - @Override + @Override @Deprecated public String getImageMetadataXml(File input, boolean includeBinary) throws IOException { throw new RuntimeException("Not implemented."); } - @Override + @Override @Deprecated public void getImageMetadataXml(File input, File output, boolean includeBinary) throws IOException { throw new RuntimeException("Not implemented."); } - @Override + @Override @Deprecated public String extractImageIccProfile(File input, File output) throws IOException { throw new RuntimeException("Not implemented."); } - @Override + @Override @Deprecated public File extractThumbnail(File input, Tag tag) throws IOException { throw new RuntimeException("Not implemented."); } - @Override + @Override @Deprecated public Map getImageMeta(File file, Format format, boolean supressDuplicates, String... tags) throws IOException { throw new RuntimeException("Not implemented."); } - @Override + @Override @Deprecated public Map getImageMeta(File image, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { throw new RuntimeException("Not implemented."); } - @Override + @Override @Deprecated public Map getImageMeta2(File image, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { throw new RuntimeException("Not implemented."); } - @Override + @Override @Deprecated public Map getImageMeta(File image, Format format, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { - throw new RuntimeException("Not implemented."); + return getImageMeta2(image, format, tags); } - @Override + @Override @Deprecated public void rebuildMetadata(File file) throws IOException { throw new RuntimeException("Not implemented."); } - @Override + @Override @Deprecated public void rebuildMetadata(WriteOptions options, File file) throws IOException { throw new RuntimeException("Not implemented."); } - @Override + @Override @Deprecated public Map readMetadata(File file, Object... tags) throws IOException { throw new RuntimeException("Not implemented."); } - @Override + @Override @Deprecated public Map readMetadata(ReadOptions options, File file, Object... tags) throws IOException { throw new RuntimeException("Not implemented."); } - @Override + @Override @Deprecated public void writeMetadata(WriteOptions options, File image, Map values) throws IOException { throw new RuntimeException("Not implemented."); diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java index 1e84fc53..3cc6f75e 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java @@ -4,7 +4,32 @@ import java.io.IOException; import java.util.Map; -public interface ExifToolService extends AutoCloseable{ +public interface ExifToolService extends AutoCloseable { + /** + * Factory method with "best" ExifToolService implementation. + * + * @author raisercostin + */ + public static class Factory { + public static ExifToolService create(Feature... features) { + return new ExifTool(features); + // return new ExifToolNew2(features); + // return new ExifToolNew(features); + } + + public static ExifToolService create(int timeoutWhenKeepAliveInMillis, + Feature... features) { + return new ExifTool(timeoutWhenKeepAliveInMillis, features); + // return new ExifToolNew(timeoutWhenKeepAliveInMillis, features); + // return new ExifToolNew2(timeoutWhenKeepAliveInMillis, features); + } + + public static ExifToolService create(ReadOptions readOptions, + Feature... features) { + //ignore readOptions + return new ExifTool(features); + } + } /** * Used to determine if the given {@link Feature} is supported by the @@ -113,17 +138,20 @@ public interface ExifToolService extends AutoCloseable{ Map getImageMeta(File file, Format format, boolean supressDuplicates, String... tags) throws IOException; + Map getImageMeta(File file, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException; - + Map getImageMeta2(File file, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException; - Map getImageMeta(File file, Format format, MetadataTag... tags) - throws IllegalArgumentException, SecurityException, IOException; - Map getImageMeta(File file, Format format, - TagGroup... tags) throws IllegalArgumentException, + + Map getImageMeta(File file, Format format, + MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException; + Map getImageMeta(File file, Format format, TagGroup... tags) + throws IllegalArgumentException, SecurityException, IOException; + public void addImageMetadata(File file, Map values) throws IOException; diff --git a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java index 75258210..573d55c9 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java +++ b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java @@ -8,6 +8,7 @@ import java.util.Timer; import java.util.TimerTask; import java.util.concurrent.atomic.AtomicBoolean; +import java.util.concurrent.atomic.AtomicLong; /** * Manages an external exif process in keep alive mode. @@ -17,39 +18,46 @@ public class KeepAliveExifProxy implements ExifProxy { private final AtomicBoolean shuttingDown = new AtomicBoolean(false); private final Timer cleanupTimer = new Timer(ExifTool.CLEANUP_THREAD_NAME, true); - private long inactivityTimeout = 0; + private final long inactivityTimeout; private volatile long lastRunStart = 0; private volatile ExifProcess process; public KeepAliveExifProxy(String exifCmd, List baseArgs) { - inactivityTimeout = Long.getLong( + this(exifCmd, baseArgs, Long.getLong( ExifToolNew.ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, - ExifToolNew.DEFAULT_PROCESS_CLEANUP_DELAY); + ExifToolNew.DEFAULT_PROCESS_CLEANUP_DELAY)); + } + + public KeepAliveExifProxy(String exifCmd, List baseArgs, + long inactivityTimeoutParam) { + this.inactivityTimeout = inactivityTimeoutParam; startupArgs = new ArrayList(baseArgs.size() + 5); startupArgs.add(exifCmd); startupArgs.addAll(Arrays.asList("-stay_open", "True")); startupArgs.addAll(baseArgs); startupArgs.addAll(Arrays.asList("-@", "-")); // runs every minute to check if process has been inactive too long - cleanupTimer.schedule(new TimerTask() { - @Override - public void run() { - if (process != null && lastRunStart > 0 - && inactivityTimeout > 0) { - if ((System.currentTimeMillis() - lastRunStart) > inactivityTimeout) { - synchronized (this) { - if (process != null) { - process.close(); + if (inactivityTimeout != 0) { + cleanupTimer.schedule(new TimerTask() { + @Override + public void run() { + if (process != null && lastRunStart > 0 + && inactivityTimeout > 0) { + if ((System.currentTimeMillis() - lastRunStart) > inactivityTimeout) { + synchronized (this) { + if (process != null) { + process.close(); + } } } + } else if (lastRunStart == 0) { + shutdown(); } } - } - }, 60 * 1000); // every minute - } - - public void setInactiveTimeout(long mills) { - this.inactivityTimeout = mills; + }, inactivityTimeout + // 60 * 1000// every minute + ); + } } @Override diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 0a3ed497..060449ed 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -33,21 +33,33 @@ */ public class TestExifTool { - private static final String TEST_FILES_PATH = "src/test/resources"; private static Logger log = LoggerFactory.getLogger(TestExifTool.class); + private static ExifToolService create(Feature... features){ + return ExifToolService.Factory.create(features); + //return new ExifToolNew2(features); + //return new ExifToolNew(features); + } + private static ExifToolService create(int timeoutWhenKeepAliveInMillis, Feature... features){ + return ExifToolService.Factory.create(timeoutWhenKeepAliveInMillis, features); + //return new ExifToolNew(timeoutWhenKeepAliveInMillis, features); + //return new ExifToolNew2(timeoutWhenKeepAliveInMillis, features); + } + private ExifToolService create(ReadOptions readOptions,Feature...features) { + return ExifToolService.Factory.create(readOptions, features); + } @Test public void testSingleTool() throws Exception { - try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { assertTrue(runTests(tool, "")); } - try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { assertTrue(runTests(tool, "")); } - try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { tool.startup(); assertTrue(runTests(tool, "")); } @@ -65,7 +77,7 @@ public void testConcurrent() throws Exception { @Override public void run() { log.info(getName() + ": starting"); - try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { runTests(tool, getName()); log.info(getName() + ": finished"); } catch (IOException e) { @@ -89,7 +101,7 @@ public void run() { @Test public void testManyThreadsOneTool() throws Exception { - try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { Thread[] threads = new Thread[20]; for (int i = 0; i < threads.length; i++) { final String label = "run " + i; @@ -121,9 +133,11 @@ public void run() { @Test public void testProcessTimeout() throws Exception { - try (ExifToolService tool = new ExifTool(1, Feature.STAY_OPEN)) { + try (ExifToolService tool = create(1, Feature.STAY_OPEN)) { + long start = System.currentTimeMillis(); runTests(tool, "will fail"); - fail("should have failed"); + long end = System.currentTimeMillis(); + fail("should have failed. passed "+(end-start)+" miliseconds."); } catch (IOException ex) { ; } @@ -186,7 +200,7 @@ public boolean runTests(ExifToolService tool, String runId) @Test public void testGroupTags() throws Exception { - try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { Map metadata; URL url = getClass().getResource("/iptc_test-photoshop.jpg"); @@ -230,7 +244,7 @@ public void testVersionNumber() { @Test public void testWriteTagStringNonDaemon() throws Exception { - try (ExifToolService tool = new ExifTool()) { + try (ExifToolService tool = create()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); @@ -268,7 +282,7 @@ public void testWriteTagStringNonDaemon() throws Exception { @Test public void testWriteTagString() throws Exception { - ExifToolService tool = new ExifTool(Feature.STAY_OPEN); + ExifToolService tool = create(Feature.STAY_OPEN); URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); @@ -305,7 +319,7 @@ public void testWriteTagString() throws Exception { @Test public void testWriteTagStringInvalidformat() throws Exception { - try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); @@ -346,7 +360,7 @@ public void testWriteTagStringInvalidformat() throws Exception { @Test public void testWriteTagNumberNonDaemon() throws Exception { - try (ExifToolService tool = new ExifTool()) { + try (ExifToolService tool = create()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); @@ -383,7 +397,7 @@ public void testWriteTagNumberNonDaemon() throws Exception { @Test public void testWriteTagNumber() throws Exception { - try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); @@ -420,7 +434,7 @@ public void testWriteTagNumber() throws Exception { @Test public void testWriteMulipleTag() throws Exception { - try (ExifToolService tool = new ExifTool(Feature.STAY_OPEN)) { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); @@ -462,7 +476,7 @@ public void testWriteMulipleTag() throws Exception { @Test public void testWriteMulipleTagNonDaemon() throws Exception { - try (ExifToolService tool = new ExifTool()) { + try (ExifToolService tool = create()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); @@ -504,7 +518,7 @@ public void testWriteMulipleTagNonDaemon() throws Exception { @Test public void testWriteMultipleTagNonDaemon2() throws Exception { - try (ExifToolService tool = new ExifToolNew()) { + try (ExifToolService tool = create()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); @@ -547,7 +561,7 @@ public void testWriteMultipleTagNonDaemon2() throws Exception { @Test public void testWritingWithImplicitTypes() throws Exception { - try (ExifToolService tool = new ExifToolNew(new ReadOptions() + try (ExifToolService tool = create(new ReadOptions() .withNumericOutput(true).withConvertTypes(true), Feature.MWG_MODULE)){ URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); From 12f9c9c9a5d761040fbd372c9b99c5b6f1eed3f9 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 20:13:50 +0300 Subject: [PATCH 054/148] - release 2.3.1 --- pom.xml | 2 +- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 3 +-- 2 files changed, 2 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 7a0031a0..cba80a15 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.0 + 2.3.1 https://github.com/raisercostin/exiftool diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index d23eabd1..8da4b8db 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -913,8 +913,7 @@ protected static void log(String message, Object... params) { @Override public Map getImageMeta2(File image, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { - // TODO Auto-generated method stub - return null; + return (Map)getImageMeta(image, tags); } @Override From fc8a18e5ab50a8dc49b816898cce92597624388e Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 20:21:15 +0300 Subject: [PATCH 055/148] - release next version --- README | 8 ++++++-- pom.xml | 2 +- 2 files changed, 7 insertions(+), 3 deletions(-) diff --git a/README b/README index 779bccb3..9318385d 100644 --- a/README +++ b/README @@ -214,6 +214,10 @@ us at: software@thebuzzmedia.com Maven +- current release: 2.3.1 - at http://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/2.3.1/ - create deliverables: mvn install -Prelease -DskipTests=true -- release in svn: svn import -m "release" C:\Users\costin\.m2\repository\com https://raisercostin.googlecode.com/svn/maven2/com --force -- current release: 2.3.0 - at http://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/2.3.0/ \ No newline at end of file +- release in svn: + svn import -m "release" C:\Users\costin\.m2\repository\com https://raisercostin.googlecode.com/svn/maven2/com --force +- release in svn subsequent releases: + svn import -m "release 2.3.1" C:\Users\costin\.m2\repository\com\thebuzzmedia\exiftool\exiftool-lib\2.3.1 https://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/ex +iftool/exiftool-lib/2.3.1 --force diff --git a/pom.xml b/pom.xml index cba80a15..06383d46 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.1 + 2.3.2-SNAPSHOT https://github.com/raisercostin/exiftool From f883a08f458ae74912a24a73f3afc40d6c96c75f Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 20:31:30 +0300 Subject: [PATCH 056/148] - rename --- README => README.md | 24 +++++++++++++++--------- 1 file changed, 15 insertions(+), 9 deletions(-) rename README => README.md (92%) diff --git a/README b/README.md similarity index 92% rename from README rename to README.md index 9318385d..716dd5c0 100644 --- a/README +++ b/README.md @@ -201,23 +201,29 @@ them. Just remember to be consistent. -Reference ---------- +## Reference ExifTool by Phil Harvey - http://www.sno.phy.queensu.ca/~phil/exiftool/ imgscalr - http://www.thebuzzmedia.com/software/imgscalr-java-image-scaling-library/ -Contact -------- +## Contact If you have questions, comments or bug reports for this software please contact us at: software@thebuzzmedia.com -Maven -- current release: 2.3.1 - at http://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/2.3.1/ -- create deliverables: mvn install -Prelease -DskipTests=true +## Maven +- current release: 2.3.1 +- at `http://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/2.3.1/` +- create deliverables: + `mvn install -Prelease -DskipTests=true` - release in svn: - svn import -m "release" C:\Users\costin\.m2\repository\com https://raisercostin.googlecode.com/svn/maven2/com --force + `svn import -m "release" C:\Users\costin\.m2\repository\com https://raisercostin.googlecode.com/svn/maven2/com --force` - release in svn subsequent releases: - svn import -m "release 2.3.1" C:\Users\costin\.m2\repository\com\thebuzzmedia\exiftool\exiftool-lib\2.3.1 https://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/ex + `svn import -m "release 2.3.1" C:\Users\costin\.m2\repository\com\thebuzzmedia\exiftool\exiftool-lib\2.3.1 https://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/ex` iftool/exiftool-lib/2.3.1 --force + +## Sbt Configuration +build.sbt + + resolvers += "raisercostin" at "https://raisercostin.googlecode.com/svn/maven2" + libraryDependencies += "com.thebuzzmedia.exiftool" % "exiftool-lib" % "2.3.1" From 7f4b1b1d2246c363e609fb67db38dbe8582878ed Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 20:59:50 +0300 Subject: [PATCH 057/148] - return all tags if no specific tag is requested --- .../java/com/thebuzzmedia/exiftool/ExifTool.java | 15 +++++++++------ .../com/thebuzzmedia/exiftool/ExifToolNew.java | 10 +++++++++- .../com/thebuzzmedia/exiftool/ExifToolNew2.java | 4 +++- .../thebuzzmedia/exiftool/ExifToolService.java | 1 + 4 files changed, 22 insertions(+), 8 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 8da4b8db..417620d8 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -557,7 +557,9 @@ public Map getImageMeta(File image, MetadataTag... tags) @Override public Map getImageMeta(File image, Format format, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { - + if (tags == null) { + tags = new MetadataTag[0]; + } String[] stringTags = new String[tags.length]; int i = 0; for (MetadataTag tag : tags) { @@ -572,6 +574,9 @@ public Map getImageMeta(File image, Format format, Metadata public Map getImageMeta(File image, Format format, TagGroup... tags) throws IllegalArgumentException, SecurityException, IOException { + if (tags == null) { + tags = new TagGroup[0]; + } String[] stringTags = new String[tags.length]; int i = 0; for (TagGroup tag : tags) { @@ -582,7 +587,7 @@ public Map getImageMeta(File image, Format format, public Map getImageMeta(final File image, final Format format, final boolean suppressDuplicates, - final String... tags) throws IllegalArgumentException, + String... tags) throws IllegalArgumentException, SecurityException, IOException { // Validate input and create Arg Array @@ -597,10 +602,8 @@ public Map getImageMeta(final File image, args.add("-a"); // suppress duplicates } args.add("-S"); // compact output - - if (tags == null || tags.length == 0) { - throw new IllegalArgumentException( - "tags cannot be null and must contain 1 or more Tag to query the image for."); + if (tags == null) { + tags = new String[0]; } for (String tag : tags) { args.add("-" + tag); diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java index 6d211b81..c94c0b06 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java @@ -510,7 +510,9 @@ public Map getImageMeta(File image, Tag... tags) public Map getImageMeta(File image, Format format, Tag... tags) throws IllegalArgumentException, SecurityException, IOException { - + if (tags == null) { + tags = new Tag[0]; + } String[] stringTags = new String[tags.length]; int i = 0; for (Tag tag : tags) { @@ -524,6 +526,9 @@ public Map getImageMeta(File image, Format format, public Map getImageMeta(File image, Format format, TagGroup... tags) throws IllegalArgumentException, SecurityException, IOException { + if (tags == null) { + tags = new TagGroup[0]; + } String[] stringTags = new String[tags.length]; int i = 0; for (TagGroup tag : tags) { @@ -570,6 +575,9 @@ public Map readMetadata(ReadOptions options, + file.getAbsolutePath() + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); } + if (tags == null) { + tags = new TagGroup[0]; + } List args = new ArrayList(tags.length + 2); if (options.numericOutput) { diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java index 5c81a0c7..1564b130 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java @@ -733,7 +733,9 @@ private Map getImageMeta2(File image, Format format, Metada + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); long startTime = System.currentTimeMillis(); - + if (tags == null) { + tags = new MetadataTag[0]; + } /* * Create a result map big enough to hold results for each of the tags * and avoid collisions while inserting. diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java index 3cc6f75e..0ee576a3 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java @@ -136,6 +136,7 @@ public static ExifToolService create(ReadOptions readOptions, */ boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException; + /** If no tags are given return all tags.*/ Map getImageMeta(File file, Format format, boolean supressDuplicates, String... tags) throws IOException; From c92225e8de847d6523f5f7db7585752f998df29e Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 21:00:08 +0300 Subject: [PATCH 058/148] new release 2.3.2 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 06383d46..2ca03387 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.2-SNAPSHOT + 2.3.2 https://github.com/raisercostin/exiftool From de8835b531ab91f4e612a34abc19756f7e3582ed Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 21:02:36 +0300 Subject: [PATCH 059/148] - next snapshot version --- README.md | 9 ++++----- pom.xml | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/README.md b/README.md index 716dd5c0..3a0a14a1 100644 --- a/README.md +++ b/README.md @@ -212,18 +212,17 @@ us at: software@thebuzzmedia.com ## Maven -- current release: 2.3.1 -- at `http://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/2.3.1/` +- current release: 2.3.2 +- at `http://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/` - create deliverables: `mvn install -Prelease -DskipTests=true` - release in svn: `svn import -m "release" C:\Users\costin\.m2\repository\com https://raisercostin.googlecode.com/svn/maven2/com --force` - release in svn subsequent releases: - `svn import -m "release 2.3.1" C:\Users\costin\.m2\repository\com\thebuzzmedia\exiftool\exiftool-lib\2.3.1 https://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/ex` -iftool/exiftool-lib/2.3.1 --force + `svn import -m "release 2.3.1" C:\Users\costin\.m2\repository\com\thebuzzmedia\exiftool\exiftool-lib\2.3.1 https://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/2.3.1 --force` ## Sbt Configuration build.sbt resolvers += "raisercostin" at "https://raisercostin.googlecode.com/svn/maven2" - libraryDependencies += "com.thebuzzmedia.exiftool" % "exiftool-lib" % "2.3.1" + libraryDependencies += "com.thebuzzmedia.exiftool" % "exiftool-lib" % "2.3.2" diff --git a/pom.xml b/pom.xml index 2ca03387..dc8efec4 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.2 + 2.3.3-SNAPSHOT https://github.com/raisercostin/exiftool From 2a91a10507357b580d7ea785e96a3629d1424efb Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 27 Jul 2014 22:33:45 +0300 Subject: [PATCH 060/148] - fix reading all tags --- .../com/thebuzzmedia/exiftool/ExifTool.java | 5 ++- .../thebuzzmedia/exiftool/ExifToolNew.java | 20 ++++++++--- .../exiftool/ExifToolService.java | 33 ++++++++++--------- 3 files changed, 36 insertions(+), 22 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 417620d8..a4366798 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -567,7 +567,10 @@ public Map getImageMeta(File image, Format format, Metadata } Map result = getImageMeta(image, format, true, stringTags); - return Tag.toTagMap(result); + ReadOptions readOptions = new ReadOptions().withConvertTypes(true).withNumericOutput(format.equals(Format.NUMERIC)); + return (Map)ExifToolNew.convertToMetadataTags(readOptions,result,tags); + //map only known values? + //return Tag.toTagMap(result); } @Override diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java index c94c0b06..27aa855e 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java @@ -562,9 +562,17 @@ public Map readMetadata(File file, Object... tags) throws IOException { return readMetadata(defReadOptions, file, tags); } - public Map readMetadata(ReadOptions options, File file, Object... tags) throws IOException { + if (tags == null) { + tags = new TagGroup[0]; + } + Map resultMap = getImageMeta(options, file, tags); + return convertToMetadataTags(options, resultMap, tags); + } + + private Map getImageMeta(ReadOptions options, File file, + Object... tags) throws IOException { if (file == null) { throw new IllegalArgumentException( "file cannot be null and must be a valid stream of image data."); @@ -575,9 +583,6 @@ public Map readMetadata(ReadOptions options, + file.getAbsolutePath() + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); } - if (tags == null) { - tags = new TagGroup[0]; - } List args = new ArrayList(tags.length + 2); if (options.numericOutput) { @@ -600,7 +605,11 @@ public Map readMetadata(ReadOptions options, Map resultMap = exifProxy.execute( options.runTimeoutMills, args); + return resultMap; + } + public static Map convertToMetadataTags(ReadOptions options, + Map resultMap, Object... tags) { Map metadata = new HashMap( resultMap.size()); @@ -632,7 +641,8 @@ public Map readMetadata(ReadOptions options, MetadataTag metaTag = toTag(entry.getKey()); Object value = Tag.deserialize(metaTag.getKey(), entry.getValue(), metaTag.getType()); - metadata.put(entry.getKey(), value); + //metadata.put(entry.getKey(), value); + metadata.put(metaTag, value); } else { metadata.put(entry.getKey(), entry.getValue()); diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java index 0ee576a3..1db29fe2 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolService.java @@ -153,9 +153,26 @@ Map getImageMeta(File file, Format format, Map getImageMeta(File file, Format format, TagGroup... tags) throws IllegalArgumentException, SecurityException, IOException; + Map readMetadata(File file, Object... tags) + throws IOException; + + /** + * Reads metadata from the file. + */ + Map readMetadata(ReadOptions options, File file, + Object... tags) throws IOException; + + public void addImageMetadata(File file, Map values) throws IOException; + /** + * Takes a map of tags (either (@link Tag) or Strings for keys) and + * replaces/appends them to the metadata. + */ + void writeMetadata(WriteOptions options, File file, + Map values) throws IOException; + /** * extract image metadata to exiftool's internal xml format. * @@ -220,20 +237,4 @@ void getImageMetadataXml(File input, File output, boolean includeBinary) * @link http://www.sno.phy.queensu.ca/~phil/exiftool/faq.html#Q20 */ void rebuildMetadata(WriteOptions options, File file) throws IOException; - - Map readMetadata(File file, Object... tags) - throws IOException; - - /** - * Reads metadata from the file. - */ - Map readMetadata(ReadOptions options, File file, - Object... tags) throws IOException; - - /** - * Takes a map of tags (either (@link Tag) or Strings for keys) and - * replaces/appends them to the metadata. - */ - void writeMetadata(WriteOptions options, File file, - Map values) throws IOException; } \ No newline at end of file From 10f428a842d8d83ca40ac0dc981cb64c6daf1d46 Mon Sep 17 00:00:00 2001 From: Michael Rush Date: Mon, 28 Jul 2014 12:32:50 -0700 Subject: [PATCH 061/148] updated README, added simple code example --- README | 23 ++++++++++++++++++++--- 1 file changed, 20 insertions(+), 3 deletions(-) diff --git a/README b/README index d64caa94..3b869989 100644 --- a/README +++ b/README @@ -1,5 +1,22 @@ -ExifTool - Enhanced Java Integration for Phil Harvey's ExifTool. +## ExifTool -http://www.thebuzzmedia.com/software/exiftool-enhanced-java-integration-for-exiftool/ +ExifTool is a Java integration library for [Phil Harvey's (perl) ExifTool](http://www.sno.phy.queensu.ca/~phil/exiftool/), providing an easy way to read and write EXIF, IPTC, XMP and other metadata from image files. For example: -Forked from https://github.com/thebuzzmedia/exiftool for use with DF Studio (www.dfstudio.com) + ExifTool tool = new ExifTool(); + File imageFile = new File("/path/to/image.jpg"); + + //Read Metadata + Map metadata = tool.getImageMeta(imageFile, + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); + String cameraModel = metadata.get(ExifTool.Tag.MODEL); + + ExifTool.Tag tag = ExifTool.Tag.IMAGE_HEIGHT; + int imageWidth = tag.parseValue(metadata.get(tag)); + + //Write Metadata + Map data = new HashMap(); + data.put(ExifTool.MwgTag.KEYWORDS, new String[]{"portrait", "nature", "flower"}); + tool.writeMetadata(imageFile, data); + + +ExifTool was originally developed by [The Buzz Media](http://www.thebuzzmedia.com/software/exiftool-enhanced-java-integration-for-exiftool/ "Read more about the description and goals of the original project"). This repository is forked from the [original project](https://github.com/thebuzzmedia/exiftool) for use with [DF Studio](www.dfstudio.com "DF Studio is a cloud-based photo storage solution for professional and enterprise photography management and workflow, with features for organization, collaboration, storage and delivery of photographic assets."). From 2b3162bf4368caa026e51ecea608ff9010481e6a Mon Sep 17 00:00:00 2001 From: Michael Rush Date: Mon, 28 Jul 2014 13:49:03 -0700 Subject: [PATCH 062/148] README -> README.md --- README => README.md | 0 1 file changed, 0 insertions(+), 0 deletions(-) rename README => README.md (100%) diff --git a/README b/README.md similarity index 100% rename from README rename to README.md From 860f0fbd8183363578f7c48974b867b2e4506792 Mon Sep 17 00:00:00 2001 From: Michael Rush Date: Mon, 28 Jul 2014 14:13:43 -0700 Subject: [PATCH 063/148] readme text --- README.md | 1 + 1 file changed, 1 insertion(+) diff --git a/README.md b/README.md index 3b869989..88888a4f 100644 --- a/README.md +++ b/README.md @@ -18,5 +18,6 @@ ExifTool is a Java integration library for [Phil Harvey's (perl) ExifTool](http: data.put(ExifTool.MwgTag.KEYWORDS, new String[]{"portrait", "nature", "flower"}); tool.writeMetadata(imageFile, data); +See the included unit tests for more examples. ExifTool was originally developed by [The Buzz Media](http://www.thebuzzmedia.com/software/exiftool-enhanced-java-integration-for-exiftool/ "Read more about the description and goals of the original project"). This repository is forked from the [original project](https://github.com/thebuzzmedia/exiftool) for use with [DF Studio](www.dfstudio.com "DF Studio is a cloud-based photo storage solution for professional and enterprise photography management and workflow, with features for organization, collaboration, storage and delivery of photographic assets."). From 9a8a0ae92527a849c62796a3bb9aaa0e5eac89cd Mon Sep 17 00:00:00 2001 From: Michael Rush Date: Mon, 28 Jul 2014 14:15:47 -0700 Subject: [PATCH 064/148] readme text --- README.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/README.md b/README.md index 88888a4f..cb949cb7 100644 --- a/README.md +++ b/README.md @@ -20,4 +20,4 @@ ExifTool is a Java integration library for [Phil Harvey's (perl) ExifTool](http: See the included unit tests for more examples. -ExifTool was originally developed by [The Buzz Media](http://www.thebuzzmedia.com/software/exiftool-enhanced-java-integration-for-exiftool/ "Read more about the description and goals of the original project"). This repository is forked from the [original project](https://github.com/thebuzzmedia/exiftool) for use with [DF Studio](www.dfstudio.com "DF Studio is a cloud-based photo storage solution for professional and enterprise photography management and workflow, with features for organization, collaboration, storage and delivery of photographic assets."). +ExifTool was originally developed by [The Buzz Media](http://www.thebuzzmedia.com/software/exiftool-enhanced-java-integration-for-exiftool/ "Read more about the description and goals of the original project"). This repository is forked from the [original project](https://github.com/thebuzzmedia/exiftool) for use with [DF Studio](http://www.dfstudio.com "DF Studio is a cloud-based photo storage solution for professional and enterprise photography management and workflow, with features for organization, collaboration, storage and delivery of photographic assets."). From 2ce655d0e71acd46876748e5397e87a568d505d7 Mon Sep 17 00:00:00 2001 From: Michael Rush Date: Mon, 28 Jul 2014 15:39:46 -0700 Subject: [PATCH 065/148] - merge tag constants from thebuzzmedia branch - add license info to readme --- README.md | 4 ++ .../com/thebuzzmedia/exiftool/ExifTool.java | 59 +++++++++++-------- 2 files changed, 37 insertions(+), 26 deletions(-) diff --git a/README.md b/README.md index cb949cb7..26b8a92f 100644 --- a/README.md +++ b/README.md @@ -21,3 +21,7 @@ ExifTool is a Java integration library for [Phil Harvey's (perl) ExifTool](http: See the included unit tests for more examples. ExifTool was originally developed by [The Buzz Media](http://www.thebuzzmedia.com/software/exiftool-enhanced-java-integration-for-exiftool/ "Read more about the description and goals of the original project"). This repository is forked from the [original project](https://github.com/thebuzzmedia/exiftool) for use with [DF Studio](http://www.dfstudio.com "DF Studio is a cloud-based photo storage solution for professional and enterprise photography management and workflow, with features for organization, collaboration, storage and delivery of photographic assets."). + +License +------- +This library is released under the Apache 2 License. See LICENSE. \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index b94a5599..5bb61987 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -1411,58 +1411,65 @@ public interface MetadataTag { public enum Tag implements MetadataTag { //single entry tags APERTURE("ApertureValue", Double.class), - AUTHOR("XPAuthor", String.class), + ARTIST("Artist", String.class), + AUTHOR( "XPAuthor", String.class), + CAPTION_ABSTRACT("Caption-Abstract", String.class), COLOR_SPACE("ColorSpace", Integer.class), COMMENT("XPComment", String.class), CONTRAST("Contrast", Integer.class), - CREATE_DATE("CreateDate", Date.class), - CREATION_DATE("CreationDate", Date.class), - DATE_CREATED("DateCreated", Date.class), - DATE_TIME_ORIGINAL("DateTimeOriginal", Date.class), + COPYRIGHT("Copyright", String.class), + COPYRIGHT_NOTICE("CopyrightNotice", String.class), + CREATION_DATE("CreationDate", String.class), + CREATOR("Creator", String.class), + DATE_TIME_ORIGINAL("DateTimeOriginal", String.class), DIGITAL_ZOOM_RATIO("DigitalZoomRatio", Double.class), - EXIF_VERSION("ExifVersion", String.class), - EXPOSURE_COMPENSATION("ExposureCompensation", Double.class), - EXPOSURE_PROGRAM("ExposureProgram", Integer.class), - EXPOSURE_TIME("ExposureTime", Double.class), - FLASH("Flash", Integer.class), + EXIF_VERSION("ExifVersion",String.class), + EXPOSURE_COMPENSATION( "ExposureCompensation", Double.class), + EXPOSURE_PROGRAM( "ExposureProgram", Integer.class), + EXPOSURE_TIME( "ExposureTime", Double.class), + FLASH( "Flash", Integer.class), FOCAL_LENGTH("FocalLength", Double.class), - FOCAL_LENGTH_35MM("FocalLengthIn35mmFormat", Integer.class), + FOCAL_LENGTH_35MM( "FocalLengthIn35mmFormat", Integer.class), FNUMBER("FNumber", String.class), GPS_ALTITUDE("GPSAltitude", Double.class), - GPS_ALTITUDE_REF("GPSAltitudeRef", Integer.class), - GPS_BEARING("GPSDestBearing", Double.class), - GPS_BEARING_REF("GPSDestBearingRef", String.class), + GPS_ALTITUDE_REF( "GPSAltitudeRef", Integer.class), + GPS_BEARING( "GPSDestBearing", Double.class), + GPS_BEARING_REF( "GPSDestBearingRef", String.class), GPS_DATESTAMP("GPSDateStamp", String.class), - GPS_LATITUDE("GPSLatitude", Double.class), - GPS_LATITUDE_REF("GPSLatitudeRef", String.class), + GPS_LATITUDE( "GPSLatitude", Double.class), + GPS_LATITUDE_REF( "GPSLatitudeRef", String.class), GPS_LONGITUDE("GPSLongitude", Double.class), GPS_LONGITUDE_REF("GPSLongitudeRef", String.class), - GPS_PROCESS_METHOD("GPSProcessingMethod", String.class), + GPS_PROCESS_METHOD( "GPSProcessingMethod", String.class), GPS_SPEED("GPSSpeed", Double.class), GPS_SPEED_REF("GPSSpeedRef", String.class), - GPS_TIMESTAMP("GPSTimeStamp", String.class), - IMAGE_HEIGHT("ImageHeight", Integer.class), + GPS_TIMESTAMP( "GPSTimeStamp", String.class), + IMAGE_HEIGHT( "ImageHeight", Integer.class), IMAGE_WIDTH("ImageWidth", Integer.class), + IPTC_KEYWORDS("Keywords", String.class), ISO("ISO", Integer.class), - KEYWORDS("XPKeywords", String.class), + KEYWORDS( "XPKeywords", String.class), + LENS_ID("LensID",String.class), LENS_MAKE("LensMake", String.class), - LENS_MODEL("LensModel", String.class), + LENS_MODEL( "LensModel", String.class), MAKE("Make", String.class), METERING_MODE("MeteringMode", Integer.class), MODEL("Model", String.class), + OBJECT_NAME("ObjectName", String.class), ORIENTATION("Orientation", Integer.class), OWNER_NAME("OwnerName", String.class), - RATING("Rating", Integer.class), + RATING( "Rating", Integer.class), RATING_PERCENT("RatingPercent", Integer.class), - ROTATION("Rotation", Integer.class), + ROTATION("Rotation",Integer.class), SATURATION("Saturation", Integer.class), - SENSING_METHOD("SensingMethod", Integer.class), - SHARPNESS("Sharpness", Integer.class), + SENSING_METHOD( "SensingMethod", Integer.class), + SHARPNESS( "Sharpness", Integer.class), SHUTTER_SPEED("ShutterSpeedValue", Double.class), SOFTWARE("Software", String.class), SUBJECT("XPSubject", String.class), + SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), TITLE("XPTitle", String.class), - WHITE_BALANCE("WhiteBalance", Integer.class), + WHITE_BALANCE( "WhiteBalance", Integer.class), X_RESOLUTION("XResolution", Double.class), Y_RESOLUTION("YResolution", Double.class), ; From d0e43a4c8fb64852921966242e3e90b9c63ac458 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 5 Aug 2014 19:10:25 +0300 Subject: [PATCH 066/148] - report entire error output in case no error word is present - added charset to properly communicate with exiftool via stay_open feature (on windows use WINDOWS feature to enable charset windows-1252 --- .../exiftool/CleanupTimerTask.java | 42 ++++++++++++++++++ .../thebuzzmedia/exiftool/ExifProcess.java | 27 ++++++----- .../com/thebuzzmedia/exiftool/ExifTool.java | 39 ++++++++++------ .../thebuzzmedia/exiftool/ExifToolNew.java | 4 +- .../com/thebuzzmedia/exiftool/Feature.java | 7 ++- .../exiftool/KeepAliveExifProxy.java | 13 +++--- .../exiftool/SingleUseExifProxy.java | 7 ++- .../thebuzzmedia/exiftool/TestExifTool.java | 13 +++++- ...303\226stliche Zubringerstra\303\237e.png" | Bin 0 -> 320660 bytes 9 files changed, 117 insertions(+), 35 deletions(-) create mode 100644 "src/test/resources/20140502_152336_\303\226stliche Zubringerstra\303\237e.png" diff --git a/src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java b/src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java index df63bd99..cbf4fd7b 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java +++ b/src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java @@ -2,6 +2,10 @@ import java.util.Timer; import java.util.TimerTask; +import java.util.Vector; +import java.util.List; +import java.io.IOException; + /** * Class used to represent the {@link TimerTask} used by the internal auto @@ -27,4 +31,42 @@ public void run() { ExifTool.log.info("\tAuto cleanup task running..."); owner.close(); } + public static class RecruitTest { + + private List getTokens(char[] sentence) throws IllegalArgumentException { + if (sentence == null) throw new IllegalArgumentException ("Sentence argument should not be null."); + List tokens = new Vector(); + StringBuffer tmp = new StringBuffer(); + for (int i = 0; i < sentence.length; i++) { + if (sentence[i] != ' ') { + tmp.append(sentence[i]); + } + else { + if(tmp.length()>0){ + tokens.add(tmp.toString()); + } + tmp = new StringBuffer(""); + } + } + if(tmp.length()>0){ + tokens.add(tmp.toString()); + } + return tokens; + } + + public static void main(String[] args) { + RecruitTest rt = new RecruitTest(); + char[] myString = {' ','h','e','l','l','o',' ','w','o','r','l','d',' ','a'}; + List result = rt.getTokens(myString); + System.out.println("Number of words: " + result.size()); + for (String token: result){ + System.out.println(token); + } + } + + } + public static void main(String[] args) { + RecruitTest.main(args); + } + } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index 9043ce12..b77ae3d8 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -7,6 +7,7 @@ import java.io.PrintWriter; import java.io.StringWriter; import java.lang.reflect.InvocationTargetException; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.Collections; @@ -58,7 +59,7 @@ public void run() { public static VersionNumber readVersion(String exifCmd) { ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, - "-ver")); + "-ver"),Charset.defaultCharset()); try { return new VersionNumber(process.readLine()); } catch (IOException ex) { @@ -69,16 +70,16 @@ public static VersionNumber readVersion(String exifCmd) { } } - public static ExifProcess _execute(boolean keepAlive, List args) { - return new ExifProcess(keepAlive, args); + public static ExifProcess _execute(boolean keepAlive, List args, Charset charset) { + return new ExifProcess(keepAlive, args,charset); } public static Map executeToResults(String exifCmd, - List args) throws IOException { + List args, Charset charset) throws IOException { List newArgs = new ArrayList(args.size() + 1); newArgs.add(exifCmd); newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); + ExifProcess process = _execute(false, newArgs,charset); try { return process.readResponse(); }catch(Throwable e){ @@ -95,12 +96,12 @@ private static String toCmd(List args){ return sb.toString(); } - public static String executeToString(String exifCmd, List args) + public static String executeToString(String exifCmd, List args, Charset charset) throws IOException { List newArgs = new ArrayList(args.size() + 1); newArgs.add(exifCmd); newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs); + ExifProcess process = _execute(false, newArgs,charset); try { return process.readResponseString(); } finally { @@ -108,10 +109,10 @@ public static String executeToString(String exifCmd, List args) } } - public static ExifProcess startup(String exifCmd) { + public static ExifProcess startup(String exifCmd, Charset charset) { List args = Arrays.asList(exifCmd, "-stay_open", "True", "-@", "-"); - return _execute(true, args); + return _execute(true, args,charset); } private final ReentrantLock closeLock = new ReentrantLock(false); @@ -122,7 +123,7 @@ public static ExifProcess startup(String exifCmd) { private final LineReaderThread errReader; private volatile boolean closed = false; - public ExifProcess(boolean keepAlive, List args) { + public ExifProcess(boolean keepAlive, List args, Charset charset) { this.keepAlive = keepAlive; ExifTool.log.debug(String.format( "Attempting to start ExifTool process using args: %s", args)); @@ -131,7 +132,7 @@ public ExifProcess(boolean keepAlive, List args) { all.put(process.toString(), new Pair(toString(new RuntimeException("start of "+process)),this)); this.reader = new BufferedReader(new InputStreamReader( process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream()); + this.writer = new OutputStreamWriter(process.getOutputStream(),charset); this.errReader = new LineReaderThread("exif-process-err-reader", new BufferedReader(new InputStreamReader( process.getErrorStream()))); @@ -179,6 +180,7 @@ public synchronized void writeFlush(String message) throws IOException { throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); writer.write(message); writer.flush(); + System.out.println(message); } public synchronized String readLine() throws IOException { @@ -216,11 +218,14 @@ public synchronized Map readResponse() throws IOException { } } if (errReader.hasLines()) { + StringBuffer sb = new StringBuffer(); for (String error : errReader.takeLines()) { if (error.toLowerCase().startsWith("error")) { throw new ExifError(error); } + sb.append(error); } + throw new ExifError(sb.toString()); } return resultMap; } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index a4366798..95831b87 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -13,16 +13,20 @@ * See the License for the specific language governing permissions and * limitations under the License. */ - package com.thebuzzmedia.exiftool; import java.io.Closeable; import java.io.File; import java.io.FileWriter; import java.io.IOException; +import java.nio.charset.Charset; import java.util.ArrayList; +import java.util.Arrays; +import java.util.Collection; +import java.util.Collections; import java.util.EnumSet; import java.util.HashMap; +import java.util.HashSet; import java.util.List; import java.util.Map; import java.util.Set; @@ -38,10 +42,11 @@ import org.slf4j.LoggerFactory; /** - * Class used to provide a Java-like interface to Phil Harvey's excellent, - * Perl-based ExifTool. *

+ * Initial work done by "Riyad Kalla" software@thebuzzmedia.com. + *

* There are a number of other basic Java wrappers to ExifTool available online, * but most of them only abstract out the actual Java-external-process execution * logic and do no additional work to make integration with the external @@ -66,10 +71,10 @@ * {@link #getImageMeta(File, Format, Tag...)} with a list of {@link Tag}s you * want to pull values for from the given image. *

- * In this default mode, calls to getImageMeta will automatically - * start an external ExifTool process to handle the request. After ExifTool has - * parsed the tag values from the file, the external process exits and this - * class parses the result before returning it to the caller. + * In this default mode methods will automatically start an external ExifTool + * process to handle the request. After ExifTool has parsed the tag values from + * the file, the external process exits and this class parses the result before + * returning it to the caller. *

* Results from calls to getImageMeta are returned in a {@link Map} * with the {@link Tag} values as the keys and {@link String} values for every @@ -305,6 +310,7 @@ public class ExifTool implements ExifToolService, AutoCloseable { private TimerTask currentCleanupTask = null; private AtomicBoolean shuttingDown = new AtomicBoolean(false); private volatile ExifProcess process; + private final Charset charset; /** * Limits the amount of time (in mills) an exif operation can take. Setting * value to greater than 0 to enable. @@ -367,6 +373,7 @@ public ExifTool(String exifCmd, long processCleanupDelay, } else { cleanupTimer = null; } + charset = computeDefaultCharset(Arrays.asList(features)); } /** @@ -436,7 +443,7 @@ private void ensureProcessRunning() { synchronized (this) { if (process == null || process.isClosed()) { log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = ExifProcess.startup(exifCmd); + process = ExifProcess.startup(exifCmd,charset); } } } @@ -639,7 +646,7 @@ public Map getImageMeta(final File image, resultMap = processStayOpen(args); } else { log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd, args); + resultMap = ExifProcess.executeToResults(exifCmd, args,charset); } // Print out how long the call to external ExifTool process took. @@ -700,7 +707,7 @@ private void execute(WriteOptions options, File image, Map values } else { log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); resultMap = ExifProcess.executeToResults(exifCmd, - createCommandList(image.getAbsolutePath(), values,stayOpen)); + createCommandList(image.getAbsolutePath(), values,stayOpen),charset); } } @@ -754,7 +761,7 @@ public String getImageMetadataXml(File input, boolean includeBinary) args.add("-b"); args.add(input.getAbsolutePath()); - return ExifProcess.executeToString(exifCmd, args); + return ExifProcess.executeToString(exifCmd, args,charset); } /** @@ -801,7 +808,7 @@ public String extractImageIccProfile(File input, File output) args.add("-o"); args.add(output.getAbsolutePath()); - return ExifProcess.executeToString(exifCmd, args); + return ExifProcess.executeToString(exifCmd, args,charset); } /** @@ -830,7 +837,7 @@ public File extractThumbnail(File input, Tag tag) throws IOException { args.add("-b"); args.add("-w"); args.add(suffix); - String result = ExifProcess.executeToString(exifCmd, args); + String result = ExifProcess.executeToString(exifCmd, args,charset); File thumbnail = new File(input.getParent() + File.separator + thumbname); if (!thumbnail.exists()) @@ -956,4 +963,10 @@ protected void finalize() throws Throwable { shutdown(); super.finalize(); } + + public static Charset computeDefaultCharset(Collection features) { + if(features.contains(Feature.WINDOWS)) + return Charset.forName("windows-1252"); + return Charset.defaultCharset(); + } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java index 27aa855e..82945eaf 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java @@ -334,13 +334,13 @@ public ExifToolNew(String exifCmd, long processCleanupDelay, baseArgs.addAll(Arrays.asList("-use", "MWG")); } if (featureEnabledSet.contains(Feature.STAY_OPEN)) { - KeepAliveExifProxy proxy = new KeepAliveExifProxy(exifCmd, baseArgs,processCleanupDelay); + KeepAliveExifProxy proxy = new KeepAliveExifProxy(exifCmd, baseArgs,processCleanupDelay,ExifTool.computeDefaultCharset(featureEnabledSet)); exifProxy = proxy; } else { if(processCleanupDelay!=0){ throw new RuntimeException("The processCleanupDelay parameter should be 0 if no stay_open parameter is used. Was "+processCleanupDelay); } - exifProxy = new SingleUseExifProxy(exifCmd, baseArgs); + exifProxy = new SingleUseExifProxy(exifCmd, baseArgs,ExifTool.computeDefaultCharset(featureEnabledSet)); } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/Feature.java b/src/main/java/com/thebuzzmedia/exiftool/Feature.java index 37b74231..142873b5 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/Feature.java +++ b/src/main/java/com/thebuzzmedia/exiftool/Feature.java @@ -33,7 +33,12 @@ public enum Feature { * href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/MWG.html">ExifTool * MWG Docs !! Note these version numbers are not correct */ - MWG_MODULE(8, 36), ; + MWG_MODULE(8, 36), + /** + * Enable charset windows-1252 to be able to properly pass file names in windows with keep alive + */ + WINDOWS(8, 36), + ; private VersionNumber requireVersion; diff --git a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java index 573d55c9..f64c5c1d 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java +++ b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java @@ -1,6 +1,7 @@ package com.thebuzzmedia.exiftool; import java.io.IOException; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.Arrays; import java.util.List; @@ -21,21 +22,23 @@ public class KeepAliveExifProxy implements ExifProxy { private final long inactivityTimeout; private volatile long lastRunStart = 0; private volatile ExifProcess process; + private final Charset charset; - public KeepAliveExifProxy(String exifCmd, List baseArgs) { + public KeepAliveExifProxy(String exifCmd, List baseArgs, Charset charset) { this(exifCmd, baseArgs, Long.getLong( ExifToolNew.ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, - ExifToolNew.DEFAULT_PROCESS_CLEANUP_DELAY)); + ExifToolNew.DEFAULT_PROCESS_CLEANUP_DELAY),charset); } public KeepAliveExifProxy(String exifCmd, List baseArgs, - long inactivityTimeoutParam) { + long inactivityTimeoutParam, Charset charset) { this.inactivityTimeout = inactivityTimeoutParam; startupArgs = new ArrayList(baseArgs.size() + 5); startupArgs.add(exifCmd); startupArgs.addAll(Arrays.asList("-stay_open", "True")); startupArgs.addAll(baseArgs); startupArgs.addAll(Arrays.asList("-@", "-")); + this.charset = charset; // runs every minute to check if process has been inactive too long if (inactivityTimeout != 0) { cleanupTimer.schedule(new TimerTask() { @@ -68,7 +71,7 @@ public void startup() { if (process == null || process.isClosed()) { ExifTool.log .debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = new ExifProcess(true, startupArgs); + process = new ExifProcess(true, startupArgs,charset); } } } @@ -86,7 +89,7 @@ public Map execute(final long runTimeoutMills, if (process == null || process.isClosed()) { ExifTool.log .debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = new ExifProcess(true, startupArgs); + process = new ExifProcess(true, startupArgs,charset); } } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java index dc6e0887..264f69d3 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java +++ b/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java @@ -1,6 +1,7 @@ package com.thebuzzmedia.exiftool; import java.io.IOException; +import java.nio.charset.Charset; import java.util.ArrayList; import java.util.List; import java.util.Map; @@ -11,11 +12,13 @@ public class SingleUseExifProxy implements ExifProxy { private final Timer cleanupTimer = new Timer(ExifTool.CLEANUP_THREAD_NAME, true); private final List baseArgs; + private final Charset charset; - public SingleUseExifProxy(String exifCmd, List defaultArgs) { + public SingleUseExifProxy(String exifCmd, List defaultArgs, Charset charset) { this.baseArgs = new ArrayList(defaultArgs.size() + 1); this.baseArgs.add(exifCmd); this.baseArgs.addAll(defaultArgs); + this.charset = charset; } @Override @@ -25,7 +28,7 @@ public Map execute(final long runTimeoutMills, + args.size()); newArgs.addAll(baseArgs); newArgs.addAll(args); - final ExifProcess process = new ExifProcess(false, newArgs); + final ExifProcess process = new ExifProcess(false, newArgs,charset); TimerTask attemptTimer = null; if (runTimeoutMills > 0) { attemptTimer = new TimerTask() { diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 060449ed..dc1a0714 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -620,5 +620,16 @@ public void testWritingWithImplicitTypes() throws Exception { } } - // todo TEST automatic daemon restart by killing perl process + @Test + public void testReadingUtf8Names() throws Exception { + try (ExifToolService tool = create(new ReadOptions() + .withNumericOutput(true).withConvertTypes(true), + Feature.MWG_MODULE)){ + URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); + File imageFile = new File(url.toURI()); + System.out.println(imageFile.getAbsolutePath()); + Map metadata = tool.getImageMeta(imageFile); + assertEquals("", metadata.toString()); + } + } } diff --git "a/src/test/resources/20140502_152336_\303\226stliche Zubringerstra\303\237e.png" "b/src/test/resources/20140502_152336_\303\226stliche Zubringerstra\303\237e.png" new file mode 100644 index 0000000000000000000000000000000000000000..e8485dbc989f3922c1306de3b4971e9bdbaff857 GIT binary patch literal 320660 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�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 z

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

ROc8Ud@-h_sgDllKE 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 LhUz8c Date: Tue, 5 Aug 2014 19:16:00 +0300 Subject: [PATCH 067/148] - add tests on windows --- .../thebuzzmedia/exiftool/ExifProcess.java | 1 - .../thebuzzmedia/exiftool/TestExifTool.java | 45 +++++++++++++++---- 2 files changed, 36 insertions(+), 10 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index b77ae3d8..26640945 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -180,7 +180,6 @@ public synchronized void writeFlush(String message) throws IOException { throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); writer.write(message); writer.flush(); - System.out.println(message); } public synchronized String readLine() throws IOException { diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index dc1a0714..bbc1e7f6 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -620,16 +620,43 @@ public void testWritingWithImplicitTypes() throws Exception { } } + @Test(expected=ExifError.class) + public void testReadingUtf8NamesWithStayOpen() throws Exception { + try (ExifToolService tool = create( + new ReadOptions().withNumericOutput(true) + .withConvertTypes(true), Feature.STAY_OPEN)) { + URL url = getClass().getResource( + "/20140502_152336_Östliche Zubringerstraße.png"); + File imageFile = new File(url.toURI()); + System.out.println(imageFile.getAbsolutePath()); + Map metadata = tool.getImageMeta(imageFile); + } + } + @Test - public void testReadingUtf8Names() throws Exception { - try (ExifToolService tool = create(new ReadOptions() - .withNumericOutput(true).withConvertTypes(true), - Feature.MWG_MODULE)){ - URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); - File imageFile = new File(url.toURI()); - System.out.println(imageFile.getAbsolutePath()); - Map metadata = tool.getImageMeta(imageFile); - assertEquals("", metadata.toString()); + public void testReadingUtf8NamesWithoutStayOpen() throws Exception { + try (ExifToolService tool = create( + new ReadOptions().withNumericOutput(true) + .withConvertTypes(true))) { + URL url = getClass().getResource( + "/20140502_152336_Östliche Zubringerstraße.png"); + File imageFile = new File(url.toURI()); + System.out.println(imageFile.getAbsolutePath()); + Map metadata = tool.getImageMeta(imageFile); + assertEquals(19, metadata.size()); + } + } + @Test + public void testReadingUtf8NamesWithStayOpenAndWindows() throws Exception { + try (ExifToolService tool = create( + new ReadOptions().withNumericOutput(true) + .withConvertTypes(true), Feature.STAY_OPEN,Feature.WINDOWS)) { + URL url = getClass().getResource( + "/20140502_152336_Östliche Zubringerstraße.png"); + File imageFile = new File(url.toURI()); + System.out.println(imageFile.getAbsolutePath()); + Map metadata = tool.getImageMeta(imageFile); + assertEquals(19, metadata.size()); } } } From 53624be9f0884dccc7646dc2fcc2c9cec77a4ed0 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 5 Aug 2014 19:16:51 +0300 Subject: [PATCH 068/148] 2.3.3 release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index dc8efec4..750224b8 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.3-SNAPSHOT + 2.3.3 https://github.com/raisercostin/exiftool From 669daea058c50c75252de7d23325e5be853e9b2c Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 5 Aug 2014 19:18:11 +0300 Subject: [PATCH 069/148] next snapshot version --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 750224b8..968ce4b3 100644 --- a/pom.xml +++ b/pom.xml @@ -7,7 +7,7 @@ com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.3 + 2.3.4-SNAPSHOT https://github.com/raisercostin/exiftool From ce22b25eb63225f4e4f80954e8510c73f28fda6f Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 19:04:08 +0300 Subject: [PATCH 070/148] - add guava dependency to detect charset - improve error reporting in case no file is found - fix the interface to exiftool that in windows cannot address filenames in UTF-8 format: -- @link(http://perlmaven.com/unicode-filename-support-suggested-solution) -- @link(http://stackoverflow.com/questions/18893284/how-to-get-short-filenames-in-windows-using-java) - switch logger to info - add a test for UTF-8 filenames in windows -? still to be done: windows detection --- pom.xml | 114 +++++++++--------- .../thebuzzmedia/exiftool/ExifProcess.java | 14 ++- .../com/thebuzzmedia/exiftool/ExifTool.java | 110 ++++++++++++----- .../exiftool/SingleUseExifProxy.java | 2 +- .../thebuzzmedia/exiftool/TestExifTool.java | 13 ++ ...0131231_230955_Strada Frumoas\304\203.png" | Bin 0 -> 320660 bytes src/test/resources/simplelogger.properties | 2 +- 7 files changed, 165 insertions(+), 90 deletions(-) create mode 100644 "src/test/resources/20131231_230955_Strada Frumoas\304\203.png" diff --git a/pom.xml b/pom.xml index 968ce4b3..f8925e53 100644 --- a/pom.xml +++ b/pom.xml @@ -1,59 +1,63 @@ - - 4.0.0 - - com.thebuzzmedia.exiftool - exiftool-lib - jar - 2.3.4-SNAPSHOT - https://github.com/raisercostin/exiftool - - - Riyad Kalla - software@thebuzzmedia.com - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.0 - - 1.7 - 1.7 - - - - - - - commons-io - commons-io - 2.2 - - - org.slf4j - slf4j-api - 1.7.5 - compile - - - junit - junit - 4.11 - test - - - - org.slf4j - slf4j-simple - 1.7.5 - test - - + 4.0.0 + + com.thebuzzmedia.exiftool + exiftool-lib + jar + 2.3.4-SNAPSHOT + https://github.com/raisercostin/exiftool + + + Riyad Kalla + software@thebuzzmedia.com + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.0 + + 1.7 + 1.7 + + + + + + + commons-io + commons-io + 2.2 + + + org.slf4j + slf4j-api + 1.7.5 + compile + + + com.google.guava + guava + 17.0 + + + junit + junit + 4.11 + test + + + + org.slf4j + slf4j-simple + 1.7.5 + test + + release diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index 26640945..6194c5de 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -81,7 +81,7 @@ public static Map executeToResults(String exifCmd, newArgs.addAll(args); ExifProcess process = _execute(false, newArgs,charset); try { - return process.readResponse(); + return process.readResponse(args); }catch(Throwable e){ throw new RuntimeException(String.format("When executing %s we got %s",toCmd(newArgs),e.getMessage()),e); } finally { @@ -172,7 +172,7 @@ public synchronized Map sendArgs(List args) } builder.append("-execute\n"); writeFlush(builder.toString()); - return readResponse(); + return readResponse(args); } public synchronized void writeFlush(String message) throws IOException { @@ -188,7 +188,7 @@ public synchronized String readLine() throws IOException { return reader.readLine(); } - public synchronized Map readResponse() throws IOException { + public synchronized Map readResponse(List args) throws IOException { if (closed) throw new IOException(ExifTool.STREAM_CLOSED_MESSAGE); ExifTool.log.debug("Reading response back from ExifTool..."); @@ -224,7 +224,13 @@ public synchronized Map readResponse() throws IOException { } sb.append(error); } - throw new ExifError(sb.toString()); + String result = sb.toString(); + String message = result+". ["+resultMap.size()+"] tags for exiftool with args ["+args+"]."; + if(result.contains("No matching files")){ + throw new ExifError(message); + }else{ + ExifTool.log.info(message); + } } return resultMap; } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 95831b87..61a11f53 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -41,6 +41,8 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.CharMatcher; + /** * Provide a Java-like interface to Phil Harvey's excellent, Perl-based ExifTool. @@ -443,7 +445,7 @@ private void ensureProcessRunning() { synchronized (this) { if (process == null || process.isClosed()) { log.debug("Starting daemon ExifTool process and creating read/write streams (this only happens once)..."); - process = ExifProcess.startup(exifCmd,charset); + process = ExifProcess.startup(exifCmd, charset); } } } @@ -556,14 +558,16 @@ public boolean isFeatureEnabled(Feature feature) } @Override - public Map getImageMeta(File image, MetadataTag... tags) - throws IllegalArgumentException, SecurityException, IOException { + public Map getImageMeta(File image, + MetadataTag... tags) throws IllegalArgumentException, + SecurityException, IOException { return getImageMeta(image, Format.NUMERIC, tags); } @Override - public Map getImageMeta(File image, Format format, MetadataTag... tags) - throws IllegalArgumentException, SecurityException, IOException { + public Map getImageMeta(File image, Format format, + MetadataTag... tags) throws IllegalArgumentException, + SecurityException, IOException { if (tags == null) { tags = new MetadataTag[0]; } @@ -574,10 +578,12 @@ public Map getImageMeta(File image, Format format, Metadata } Map result = getImageMeta(image, format, true, stringTags); - ReadOptions readOptions = new ReadOptions().withConvertTypes(true).withNumericOutput(format.equals(Format.NUMERIC)); - return (Map)ExifToolNew.convertToMetadataTags(readOptions,result,tags); - //map only known values? - //return Tag.toTagMap(result); + ReadOptions readOptions = new ReadOptions().withConvertTypes(true) + .withNumericOutput(format.equals(Format.NUMERIC)); + return (Map) ExifToolNew.convertToMetadataTags(readOptions, result, + tags); + // map only known values? + // return Tag.toTagMap(result); } @Override @@ -597,8 +603,8 @@ public Map getImageMeta(File image, Format format, public Map getImageMeta(final File image, final Format format, final boolean suppressDuplicates, - String... tags) throws IllegalArgumentException, - SecurityException, IOException { + String... tags) throws IllegalArgumentException, SecurityException, + IOException { // Validate input and create Arg Array final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); @@ -628,7 +634,7 @@ public Map getImageMeta(final File image, + image.getAbsolutePath() + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); } - args.add(image.getAbsolutePath()); + args.add(getAbsoluteFileName(image)); // start process long startTime = System.currentTimeMillis(); @@ -646,7 +652,7 @@ public Map getImageMeta(final File image, resultMap = processStayOpen(args); } else { log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd, args,charset); + resultMap = ExifProcess.executeToResults(exifCmd, args, charset); } // Print out how long the call to external ExifTool process took. @@ -659,6 +665,47 @@ public Map getImageMeta(final File image, return resultMap; } + public String getAbsoluteFileName(File file){ + if(!CharMatcher.ASCII.matchesAllOf(file.getAbsolutePath()) && featureSet.contains(Feature.WINDOWS)) + return getMSDOSName(file); + else + return file.getAbsolutePath(); + } + + /** + * There is a bug that prevents exiftool to read unicode file names. We can get the windows filename if necessary with getMSDOSName + * @link(http://perlmaven.com/unicode-filename-support-suggested-solution) + * @link(http://stackoverflow.com/questions/18893284/how-to-get-short-filenames-in-windows-using-java) + */ + public static String getMSDOSName(File file) { + try { + String path = getAbsolutePath(file); + Process process = Runtime.getRuntime().exec( + "cmd /c for %I in (\"" + + file.getAbsolutePath() + + "\") do @echo %~fsI"); + process.waitFor(); + byte[] data = new byte[65536]; + int size = process.getInputStream().read(data); + if (size > 0) + path = new String(data, 0, size).replaceAll("\\r\\n", ""); + return path; + } catch (IOException e) { + throw new RuntimeException(e); + } catch (InterruptedException e) { + throw new RuntimeException(e); + } + } + + public static String getAbsolutePath(File file) throws IOException { + String path = file.getAbsolutePath(); + if (file.exists() == false) + file = new File(path); + path = file.getCanonicalPath(); + if (file.isDirectory() && (path.endsWith(File.separator) == false)) + path += File.separator; + return path; + } @Override public void addImageMetadata(File image, Map values) @@ -697,17 +744,21 @@ public void addImageMetadata(File image, Map values) } } - private void execute(WriteOptions options, File image, Map values) throws IOException { + private void execute(WriteOptions options, File image, + Map values) throws IOException { final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); Map resultMap; if (stayOpen) { log.debug("Using ExifTool in daemon mode (-stay_open True)..."); resultMap = processStayOpen(createCommandList( - image.getAbsolutePath(), values,stayOpen)); + image.getAbsolutePath(), values, stayOpen)); } else { log.debug("Using ExifTool in non-daemon mode (-stay_open False)..."); - resultMap = ExifProcess.executeToResults(exifCmd, - createCommandList(image.getAbsolutePath(), values,stayOpen),charset); + resultMap = ExifProcess + .executeToResults( + exifCmd, + createCommandList(image.getAbsolutePath(), values, + stayOpen), charset); } } @@ -717,8 +768,8 @@ private List createCommandList(String filename, List args = new ArrayList(64); for (Map.Entry entry : values.entrySet()) { - //works only for Tags - Tag tag = (Tag)entry.getKey(); + // works only for Tags + Tag tag = (Tag) entry.getKey(); Object value = entry.getValue(); StringBuilder arg = new StringBuilder(); @@ -728,11 +779,11 @@ private List createCommandList(String filename, } arg.append("="); if (value != null) { -// if (value instanceof String && !stayOpen) { -// arg.append("\"").append(value.toString()).append("\""); -// } else { - arg.append(value.toString()); -// } + // if (value instanceof String && !stayOpen) { + // arg.append("\"").append(value.toString()).append("\""); + // } else { + arg.append(value.toString()); + // } } args.add(arg.toString()); @@ -761,7 +812,7 @@ public String getImageMetadataXml(File input, boolean includeBinary) args.add("-b"); args.add(input.getAbsolutePath()); - return ExifProcess.executeToString(exifCmd, args,charset); + return ExifProcess.executeToString(exifCmd, args, charset); } /** @@ -808,7 +859,7 @@ public String extractImageIccProfile(File input, File output) args.add("-o"); args.add(output.getAbsolutePath()); - return ExifProcess.executeToString(exifCmd, args,charset); + return ExifProcess.executeToString(exifCmd, args, charset); } /** @@ -837,7 +888,7 @@ public File extractThumbnail(File input, Tag tag) throws IOException { args.add("-b"); args.add("-w"); args.add(suffix); - String result = ExifProcess.executeToString(exifCmd, args,charset); + String result = ExifProcess.executeToString(exifCmd, args, charset); File thumbnail = new File(input.getParent() + File.separator + thumbname); if (!thumbnail.exists()) @@ -926,7 +977,7 @@ protected static void log(String message, Object... params) { @Override public Map getImageMeta2(File image, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { - return (Map)getImageMeta(image, tags); + return (Map) getImageMeta(image, tags); } @Override @@ -957,6 +1008,7 @@ public void writeMetadata(WriteOptions options, File image, Map values) throws IOException { throw new RuntimeException("Not implemented."); } + @Override protected void finalize() throws Throwable { log.info("ExifTool not used anymore shutdown the exiftool process..."); @@ -965,7 +1017,7 @@ protected void finalize() throws Throwable { } public static Charset computeDefaultCharset(Collection features) { - if(features.contains(Feature.WINDOWS)) + if (features.contains(Feature.WINDOWS)) return Charset.forName("windows-1252"); return Charset.defaultCharset(); } diff --git a/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java index 264f69d3..ec2eda54 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java +++ b/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java @@ -44,7 +44,7 @@ public void run() { cleanupTimer.schedule(attemptTimer, runTimeoutMills); } try { - return process.readResponse(); + return process.readResponse(args); } finally { process.close(); if (attemptTimer != null) diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index bbc1e7f6..d321371d 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -659,4 +659,17 @@ public void testReadingUtf8NamesWithStayOpenAndWindows() throws Exception { assertEquals(19, metadata.size()); } } + @Test + public void testReadingUtf8NamesOnWindows() throws Exception { + try (ExifToolService tool = create( + new ReadOptions().withNumericOutput(true) + .withConvertTypes(true), Feature.STAY_OPEN,Feature.WINDOWS)) { + URL url = getClass().getResource( + "/20131231_230955_Strada Frumoasă.png"); + File imageFile = new File(url.toURI()); + System.out.println(imageFile.getAbsolutePath()); + Map metadata = tool.getImageMeta(imageFile); + assertEquals(19, metadata.size()); + } + } } diff --git "a/src/test/resources/20131231_230955_Strada Frumoas\304\203.png" "b/src/test/resources/20131231_230955_Strada Frumoas\304\203.png" new file mode 100644 index 0000000000000000000000000000000000000000..e8485dbc989f3922c1306de3b4971e9bdbaff857 GIT binary patch literal 320660 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�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 z

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

ROc8Ud@-h_sgDllKE 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 LhUz8c Date: Wed, 6 Aug 2014 19:09:27 +0300 Subject: [PATCH 071/148] - add scm --- pom.xml | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/pom.xml b/pom.xml index f8925e53..4fa5d198 100644 --- a/pom.xml +++ b/pom.xml @@ -13,7 +13,16 @@ Riyad Kalla software@thebuzzmedia.com + + raisercostin + raisercostin@gmail.com + + + scm:git:git@github.com:raisercostin/exiftool.git + scm:git:git@github.com:raisercostin/exiftool.git + scm:git:git@github.com:raisercostin/exiftool.git + From b301e5519c0aebd205ab40bca9167dc33f860602 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 20:21:16 +0300 Subject: [PATCH 072/148] - add git scm --- pom.xml | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 4fa5d198..6ba5b701 100644 --- a/pom.xml +++ b/pom.xml @@ -19,9 +19,11 @@ + scm:git:git@github.com:raisercostin/exiftool.git - scm:git:git@github.com:raisercostin/exiftool.git scm:git:git@github.com:raisercostin/exiftool.git + git@github.com:raisercostin/exiftool.git + HEAD @@ -34,6 +36,11 @@ 1.7 + + org.apache.maven.plugins + maven-release-plugin + 2.5 + From db4de5b74286e8b455b08d5164a5d8260e092642 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 20:21:38 +0300 Subject: [PATCH 073/148] [maven-release-plugin] prepare release exiftool-lib-2.3.4 --- pom.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 6ba5b701..7818f49a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,10 @@ - + 4.0.0 com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.4-SNAPSHOT + 2.3.4 https://github.com/raisercostin/exiftool @@ -23,7 +21,7 @@ scm:git:git@github.com:raisercostin/exiftool.git scm:git:git@github.com:raisercostin/exiftool.git git@github.com:raisercostin/exiftool.git - HEAD + exiftool-lib-2.3.4 From e10c346d9ba23be4f921f54bec64165f049fd28a Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 20:22:45 +0300 Subject: [PATCH 074/148] [maven-release-plugin] rollback the release of exiftool-lib-2.3.4 --- pom.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 7818f49a..6ba5b701 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,12 @@ - + 4.0.0 com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.4 + 2.3.4-SNAPSHOT https://github.com/raisercostin/exiftool @@ -21,7 +23,7 @@ scm:git:git@github.com:raisercostin/exiftool.git scm:git:git@github.com:raisercostin/exiftool.git git@github.com:raisercostin/exiftool.git - exiftool-lib-2.3.4 + HEAD From d36cdbecacd6973d11428a9932dc3c0fd76851e6 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 20:23:57 +0300 Subject: [PATCH 075/148] -pom --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 6ba5b701..739dd5b1 100644 --- a/pom.xml +++ b/pom.xml @@ -22,7 +22,7 @@ scm:git:git@github.com:raisercostin/exiftool.git scm:git:git@github.com:raisercostin/exiftool.git - git@github.com:raisercostin/exiftool.git + https://github.com/raisercostin/exiftool.git HEAD From 49b76f91d3a927a5129fbf7877b236d2a1969135 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 20:26:07 +0300 Subject: [PATCH 076/148] pom --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 739dd5b1..171019b2 100644 --- a/pom.xml +++ b/pom.xml @@ -20,8 +20,8 @@ - scm:git:git@github.com:raisercostin/exiftool.git - scm:git:git@github.com:raisercostin/exiftool.git + scm:git:https://github.com/raisercostin/exiftool.git + scm:git:https://github.com/raisercostin/exiftool.git https://github.com/raisercostin/exiftool.git HEAD From b769a5cbfe8d47d0695325889e76f9952d9e6b67 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 20:26:31 +0300 Subject: [PATCH 077/148] [maven-release-plugin] prepare release exiftool-lib-2.3.4 --- pom.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 171019b2..80e423e8 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,10 @@ - + 4.0.0 com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.4-SNAPSHOT + 2.3.4 https://github.com/raisercostin/exiftool @@ -23,7 +21,7 @@ scm:git:https://github.com/raisercostin/exiftool.git scm:git:https://github.com/raisercostin/exiftool.git https://github.com/raisercostin/exiftool.git - HEAD + exiftool-lib-2.3.4 From 226685f23356665ce845aeb05da9cc6212aa49f1 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 20:27:33 +0300 Subject: [PATCH 078/148] [maven-release-plugin] rollback the release of exiftool-lib-2.3.4 --- pom.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 80e423e8..171019b2 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,12 @@ - + 4.0.0 com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.4 + 2.3.4-SNAPSHOT https://github.com/raisercostin/exiftool @@ -21,7 +23,7 @@ scm:git:https://github.com/raisercostin/exiftool.git scm:git:https://github.com/raisercostin/exiftool.git https://github.com/raisercostin/exiftool.git - exiftool-lib-2.3.4 + HEAD From b38ca1b8ba13364860b74159b7218200d3afb7ff Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 20:28:36 +0300 Subject: [PATCH 079/148] [maven-release-plugin] prepare release exiftool-lib-2.3.4 --- pom.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 171019b2..80e423e8 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,10 @@ - + 4.0.0 com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.4-SNAPSHOT + 2.3.4 https://github.com/raisercostin/exiftool @@ -23,7 +21,7 @@ scm:git:https://github.com/raisercostin/exiftool.git scm:git:https://github.com/raisercostin/exiftool.git https://github.com/raisercostin/exiftool.git - HEAD + exiftool-lib-2.3.4 From e09060dab693e7ab18f15eb80560d91274c6d299 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 20:28:49 +0300 Subject: [PATCH 080/148] [maven-release-plugin] rollback the release of exiftool-lib-2.3.4 --- pom.xml | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 80e423e8..171019b2 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,12 @@ - + 4.0.0 com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.4 + 2.3.4-SNAPSHOT https://github.com/raisercostin/exiftool @@ -21,7 +23,7 @@ scm:git:https://github.com/raisercostin/exiftool.git scm:git:https://github.com/raisercostin/exiftool.git https://github.com/raisercostin/exiftool.git - exiftool-lib-2.3.4 + HEAD From a79dfc63fa7445f9e43a35ef4607e25f19f80729 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 20:29:37 +0300 Subject: [PATCH 081/148] [maven-release-plugin] prepare release exiftool-lib-2.3.4 --- pom.xml | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/pom.xml b/pom.xml index 171019b2..80e423e8 100644 --- a/pom.xml +++ b/pom.xml @@ -1,12 +1,10 @@ - + 4.0.0 com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.4-SNAPSHOT + 2.3.4 https://github.com/raisercostin/exiftool @@ -23,7 +21,7 @@ scm:git:https://github.com/raisercostin/exiftool.git scm:git:https://github.com/raisercostin/exiftool.git https://github.com/raisercostin/exiftool.git - HEAD + exiftool-lib-2.3.4 From e04095cc2b478f9e9ff39629c1240d2d7db3442f Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 20:29:44 +0300 Subject: [PATCH 082/148] [maven-release-plugin] prepare for next development iteration --- pom.xml | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/pom.xml b/pom.xml index 80e423e8..a509ea6e 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,10 @@ - + 4.0.0 com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.4 + 2.3.5-SNAPSHOT https://github.com/raisercostin/exiftool @@ -21,7 +21,7 @@ scm:git:https://github.com/raisercostin/exiftool.git scm:git:https://github.com/raisercostin/exiftool.git https://github.com/raisercostin/exiftool.git - exiftool-lib-2.3.4 + HEAD From 4f1d6c185f750bcb0837f1dcf8104e7fe2995061 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 22:02:16 +0300 Subject: [PATCH 083/148] - configure distribution Management to use googlecode svn --- README.md | 11 +++++++++++ pom.xml | 16 ++++++++++++++++ 2 files changed, 27 insertions(+) diff --git a/README.md b/README.md index 3a0a14a1..b0b758f6 100644 --- a/README.md +++ b/README.md @@ -220,6 +220,17 @@ us at: software@thebuzzmedia.com `svn import -m "release" C:\Users\costin\.m2\repository\com https://raisercostin.googlecode.com/svn/maven2/com --force` - release in svn subsequent releases: `svn import -m "release 2.3.1" C:\Users\costin\.m2\repository\com\thebuzzmedia\exiftool\exiftool-lib\2.3.1 https://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/2.3.1 --force` +- release with standard maven process + mvn release:prepare -Prelease -DskipTests -Darguments="-DskipTests -Prelease" + mvn release:perform -Prelease -DskipTests -Darguments="-DskipTests -Prelease" +- configure your ~/.m2/settings.xml as + + + exiftool.releases + deployment + deployment123 + + ## Sbt Configuration build.sbt diff --git a/pom.xml b/pom.xml index a509ea6e..8c6efbf3 100644 --- a/pom.xml +++ b/pom.xml @@ -23,6 +23,22 @@ https://github.com/raisercostin/exiftool.git HEAD + + + exiftool.releases + svn:https://raisercostin.googlecode.com/svn/maven2/ + + + From 76876037a9d9af087f2dcfae708cffc68790466c Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 6 Aug 2014 22:04:53 +0300 Subject: [PATCH 084/148] - fix formatting --- README.md | 22 +++++++++++++--------- 1 file changed, 13 insertions(+), 9 deletions(-) diff --git a/README.md b/README.md index b0b758f6..4ea25280 100644 --- a/README.md +++ b/README.md @@ -221,16 +221,20 @@ us at: software@thebuzzmedia.com - release in svn subsequent releases: `svn import -m "release 2.3.1" C:\Users\costin\.m2\repository\com\thebuzzmedia\exiftool\exiftool-lib\2.3.1 https://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/2.3.1 --force` - release with standard maven process - mvn release:prepare -Prelease -DskipTests -Darguments="-DskipTests -Prelease" - mvn release:perform -Prelease -DskipTests -Darguments="-DskipTests -Prelease" + + mvn release:prepare -Prelease -DskipTests -Darguments="-DskipTests -Prelease" + mvn release:perform -Prelease -DskipTests -Darguments="-DskipTests -Prelease" + - configure your ~/.m2/settings.xml as - - - exiftool.releases - deployment - deployment123 - - + + + + exiftool.releases + deployment + deployment123 + + +- see last release [https://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/](https://raisercostin.googlecode.com/svn/maven2/com/thebuzzmedia/exiftool/exiftool-lib/) ## Sbt Configuration build.sbt From 6d2a565dc22023838d79c03e898872e64141f26a Mon Sep 17 00:00:00 2001 From: msgile Date: Fri, 8 Aug 2014 11:30:27 -0700 Subject: [PATCH 085/148] Added WriteOption '-ignoreMinorError' --- .../com/thebuzzmedia/exiftool/ExifTool.java | 21 ++++++++++++++----- .../thebuzzmedia/exiftool/TestExifTool.java | 4 ++-- 2 files changed, 18 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 5bb61987..3fb399f5 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -624,6 +624,11 @@ public void writeMetadata(WriteOptions options, File file, Map va log.info("Adding Tags {} to {}", values, file.getAbsolutePath()); List args = new ArrayList(values.size()+3); + + if ( options.ignoreMinorErrors ) { + args.add("-ignoreMinorErrors"); + } + for(Map.Entry entry : values.entrySet()) { args.addAll(serializeToArgs(entry.getKey(),entry.getValue())); } @@ -1228,29 +1233,35 @@ public ReadOptions withShowEmptyTags(boolean enabled) { public static class WriteOptions { private final long runTimeoutMills; private final boolean deleteBackupFile; + private final boolean ignoreMinorErrors; public WriteOptions() { - this(0,false); + this(0,false, false); } - private WriteOptions(long runTimeoutMills, boolean deleteBackupFile) { + private WriteOptions(long runTimeoutMills, boolean deleteBackupFile, boolean ignoreMinorErrors) { this.runTimeoutMills = runTimeoutMills; this.deleteBackupFile = deleteBackupFile; + this.ignoreMinorErrors = ignoreMinorErrors; } public String toString() { - return String.format("%s(runTimeOut:%,d deleteBackupFile:%s)",getClass().getSimpleName(),runTimeoutMills,deleteBackupFile); + return String.format("%s(runTimeOut:%,d deleteBackupFile:%s ignoreMinorErrors:%s)",getClass().getSimpleName(),runTimeoutMills,deleteBackupFile,ignoreMinorErrors); } public WriteOptions withRunTimeoutMills(long mills) { - return new WriteOptions(mills,deleteBackupFile); + return new WriteOptions(mills,deleteBackupFile, ignoreMinorErrors); } /** * ExifTool automatically makes a backup copy a file before writing metadata tags in the form * "file.ext_original", by default this tool will delete that original file after the writing is done. */ public WriteOptions withDeleteBackupFile(boolean enabled) { - return new WriteOptions(runTimeoutMills,enabled); + return new WriteOptions(runTimeoutMills,enabled, ignoreMinorErrors); + } + + public WriteOptions withIgnoreMinorErrors(boolean enabled) { + return new WriteOptions(runTimeoutMills,deleteBackupFile, enabled); } } diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 5fdfd815..d7dd771b 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -153,7 +153,7 @@ public boolean runTests(ExifTool tool, String runId) throws IOException, URISynt URL url = getClass().getResource("/kureckjones_jett_075_02-cropped.tif"); imageFile = new File(url.toURI()); metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(22, metadata.size()); + assertEquals(25, metadata.size()); keys = metadata.keySet(); @@ -172,7 +172,7 @@ public boolean runTests(ExifTool tool, String runId) throws IOException, URISynt url = getClass().getResource("/nexus-s-electric-cars.jpg"); imageFile = new File(url.toURI()); metadata = tool.getImageMeta(imageFile, ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); - assertEquals(23, metadata.size()); + assertEquals(22, metadata.size()); keys = metadata.keySet(); tag = ExifTool.Tag.IMAGE_WIDTH; From 702a662c07e164556a1b80edf67507b6ffab7719 Mon Sep 17 00:00:00 2001 From: Jamie Tsao Date: Sun, 10 Aug 2014 15:49:19 -0700 Subject: [PATCH 086/148] Added SubSecDateTimeOriginal, CreateDate, ContentCreateDate Tag enums --- .gitignore | 4 ++++ build.xml | 2 +- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 5 ++++- 3 files changed, 9 insertions(+), 2 deletions(-) create mode 100644 .gitignore diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..a4c5fa5f --- /dev/null +++ b/.gitignore @@ -0,0 +1,4 @@ +.classpath +.project +/bin +/dist diff --git a/build.xml b/build.xml index 1bd6c84a..7bf30748 100644 --- a/build.xml +++ b/build.xml @@ -35,7 +35,7 @@ limitations under the License. - + diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 435e0597..7fa998a6 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -749,9 +749,12 @@ public enum Tag { EXIF_VERSION("ExifVersion",String.class), LENS_ID("LensID",String.class), COPYRIGHT("Copyright", String.class), ARTIST("Artist", String.class), SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), + SUB_SEC_DATE_TIME_ORIGINAL("SubSecDateTimeOriginal", Integer.class), OBJECT_NAME("ObjectName", String.class), CAPTION_ABSTRACT("Caption-Abstract", String.class), CREATOR("Creator", String.class), IPTC_KEYWORDS("Keywords", - String.class), COPYRIGHT_NOTICE("CopyrightNotice", String.class); + String.class), COPYRIGHT_NOTICE("CopyrightNotice", String.class), + CREATE_DATE("CreateDate", Integer.class), + CONTENT_CREATION_DATE("ContentCreateDate", Integer.class); private static final Map TAG_LOOKUP_MAP; From 64dd975dca2e753dd15e22c9f850d01018c4ab25 Mon Sep 17 00:00:00 2001 From: David Turner Date: Tue, 30 Sep 2014 20:00:56 -0700 Subject: [PATCH 087/148] Added FileType and AvgBitrate tags --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 435e0597..6f443fb2 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -751,7 +751,8 @@ public enum Tag { SUB_SEC_TIME_ORIGINAL("SubSecTimeOriginal", Integer.class), OBJECT_NAME("ObjectName", String.class), CAPTION_ABSTRACT("Caption-Abstract", String.class), CREATOR("Creator", String.class), IPTC_KEYWORDS("Keywords", - String.class), COPYRIGHT_NOTICE("CopyrightNotice", String.class); + String.class), COPYRIGHT_NOTICE("CopyrightNotice", String.class), + FILE_TYPE("FileType", String.class),AVG_BITRATE("AvgBitrate", String.class); private static final Map TAG_LOOKUP_MAP; From 48416e5ece3a82d7b079e78e3807fe0736d4ff28 Mon Sep 17 00:00:00 2001 From: David Turner Date: Fri, 3 Oct 2014 09:50:45 -0700 Subject: [PATCH 088/148] added MIMEType tag --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 6f443fb2..3382e7ef 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -752,7 +752,8 @@ public enum Tag { OBJECT_NAME("ObjectName", String.class), CAPTION_ABSTRACT("Caption-Abstract", String.class), CREATOR("Creator", String.class), IPTC_KEYWORDS("Keywords", String.class), COPYRIGHT_NOTICE("CopyrightNotice", String.class), - FILE_TYPE("FileType", String.class),AVG_BITRATE("AvgBitrate", String.class); + FILE_TYPE("FileType", String.class), AVG_BITRATE("AvgBitrate", String.class), + MIME_TYPE("MIMEType", String.class); private static final Map TAG_LOOKUP_MAP; From cc0d3aeffb8575444a315f28cc628e74b70c810e Mon Sep 17 00:00:00 2001 From: David Turner Date: Mon, 24 Nov 2014 13:52:21 -0800 Subject: [PATCH 089/148] bumped the version to 1.2.1 and added support for tag "Comment" --- build.xml | 5 +++-- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 3 ++- 2 files changed, 5 insertions(+), 3 deletions(-) diff --git a/build.xml b/build.xml index 1bd6c84a..4b1240ad 100644 --- a/build.xml +++ b/build.xml @@ -21,6 +21,7 @@ limitations under the License. + @@ -57,7 +58,7 @@ limitations under the License. - + @@ -72,4 +73,4 @@ limitations under the License. - \ No newline at end of file + diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 3382e7ef..b2855703 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -753,7 +753,8 @@ public enum Tag { String.class), CREATOR("Creator", String.class), IPTC_KEYWORDS("Keywords", String.class), COPYRIGHT_NOTICE("CopyrightNotice", String.class), FILE_TYPE("FileType", String.class), AVG_BITRATE("AvgBitrate", String.class), - MIME_TYPE("MIMEType", String.class); + MIME_TYPE("MIMEType", String.class),COMMENTS("Comment", String.class), + ; private static final Map TAG_LOOKUP_MAP; From 6c866357c9be6130cf0d4dbb994f6c6a774516a8 Mon Sep 17 00:00:00 2001 From: Brian Storoe Date: Mon, 15 Dec 2014 15:54:32 -0800 Subject: [PATCH 090/148] Add pom.xml to maven-ify. --- .gitignore | 2 ++ pom.xml | 7 +++++++ 2 files changed, 9 insertions(+) create mode 100644 .gitignore create mode 100644 pom.xml diff --git a/.gitignore b/.gitignore new file mode 100644 index 00000000..7f995f33 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +*.iml +target/ diff --git a/pom.xml b/pom.xml new file mode 100644 index 00000000..9cce2ef2 --- /dev/null +++ b/pom.xml @@ -0,0 +1,7 @@ + + 4.0.0 + com.thebuzzmedia + exiftool + 1.2.1 + \ No newline at end of file From 03065fc3b410bb88f0d47b72f46a13940edaf91a Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 20 Dec 2014 11:46:04 +0200 Subject: [PATCH 091/148] - fix NPE bugs --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 6 +++--- src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java | 6 +++--- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index 61a11f53..b69fb4f4 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -608,6 +608,9 @@ public Map getImageMeta(final File image, // Validate input and create Arg Array final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); + if (tags == null) { + tags = new String[0]; + } List args = new ArrayList(tags.length + 4); if (format == null) { throw new IllegalArgumentException("format cannot be null"); @@ -618,9 +621,6 @@ public Map getImageMeta(final File image, args.add("-a"); // suppress duplicates } args.add("-S"); // compact output - if (tags == null) { - tags = new String[0]; - } for (String tag : tags) { args.add("-" + tag); } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java index 1564b130..a732d744 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java @@ -723,6 +723,9 @@ private Map getImageMeta2(File image, Format format, Metada "image cannot be null and must be a valid stream of image data."); if (format == null) throw new IllegalArgumentException("format cannot be null"); +// if (tags == null) { +// tags = new MetadataTag[0]; +// } if (tags == null || tags.length == 0) throw new IllegalArgumentException( "tags cannot be null and must contain 1 or more Tag to query the image for."); @@ -733,9 +736,6 @@ private Map getImageMeta2(File image, Format format, Metada + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); long startTime = System.currentTimeMillis(); - if (tags == null) { - tags = new MetadataTag[0]; - } /* * Create a result map big enough to hold results for each of the tags * and avoid collisions while inserting. From 4a73c8c1bd9c586f43e0eaafb7527182ee14dc36 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 20 Dec 2014 11:48:20 +0200 Subject: [PATCH 092/148] - one option --- build.xml | 1 + 1 file changed, 1 insertion(+) diff --git a/build.xml b/build.xml index 1bd6c84a..89adc8be 100644 --- a/build.xml +++ b/build.xml @@ -35,6 +35,7 @@ limitations under the License. + From b9a9d1e89d278f7debaadccb36b6784529f1e48d Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 20 Dec 2014 15:10:38 +0200 Subject: [PATCH 093/148] - fix compilation error --- src/main/java/com/thebuzzmedia/exiftool/ExifTool.java | 1 - 1 file changed, 1 deletion(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index b97e1542..6f17df50 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -757,7 +757,6 @@ public enum Tag { MIME_TYPE("MIMEType", String.class),COMMENTS("Comment", String.class), CREATE_DATE("CreateDate", Integer.class), CONTENT_CREATION_DATE("ContentCreateDate", Integer.class); - } private static final Map TAG_LOOKUP_MAP; From 1807cf8851e3af30e3b8750ccb2cf9a3be3c7578 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sun, 21 Dec 2014 13:47:31 +0200 Subject: [PATCH 094/148] - fix test --- src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index d321371d..fd430f3a 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -156,12 +156,13 @@ public boolean runTests(ExifToolService tool, String runId) imageFile = new File(url.toURI()); metadata = tool.getImageMeta(imageFile, Format.HUMAN_READABLE, Tag.values()); - assertEquals(31, metadata.size()); + assertEquals(32, metadata.size()); keys = metadata.keySet(); tag = Tag.IMAGE_WIDTH; assertTrue(keys.contains(tag)); + Object a = metadata.get(tag); assertEquals(728, tag.parseValue(metadata.get(tag))); tag = Tag.IMAGE_HEIGHT; From 6c352a626d284afd09c934c10f919306206b587c Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 22 Dec 2014 21:29:20 +0200 Subject: [PATCH 095/148] - samples --- README.md | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/README.md b/README.md index 4ea25280..ceba901e 100644 --- a/README.md +++ b/README.md @@ -241,3 +241,23 @@ build.sbt resolvers += "raisercostin" at "https://raisercostin.googlecode.com/svn/maven2" libraryDependencies += "com.thebuzzmedia.exiftool" % "exiftool-lib" % "2.3.2" + +## Samples + + ExifTool tool = new ExifTool(); + File imageFile = new File("/path/to/image.jpg"); + + //Read Metadata + Map metadata = tool.getImageMeta(imageFile, + ExifTool.Format.HUMAN_READABLE, ExifTool.Tag.values()); + String cameraModel = metadata.get(ExifTool.Tag.MODEL); + + ExifTool.Tag tag = ExifTool.Tag.IMAGE_HEIGHT; + int imageWidth = tag.parseValue(metadata.get(tag)); + + //Write Metadata + Map data = new HashMap(); + data.put(ExifTool.MwgTag.KEYWORDS, new String[]{"portrait", "nature", "flower"}); + tool.writeMetadata(imageFile, data); + +See the included unit tests for more examples. \ No newline at end of file From c203dd3117790766c91d3bb586a0e9041640e897 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 23 Dec 2014 10:08:09 +0200 Subject: [PATCH 096/148] - fix test --- .../java/com/thebuzzmedia/exiftool/Tag.java | 36 +++-- .../exiftool/adapters/ExifToolService.java | 62 ++++---- .../com/thebuzzmedia/exiftool/Example.java | 3 +- .../thebuzzmedia/exiftool/TestExifTool.java | 149 +++++++----------- 4 files changed, 107 insertions(+), 143 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/Tag.java b/src/main/java/com/thebuzzmedia/exiftool/Tag.java index 3584e35d..2808aba7 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/Tag.java +++ b/src/main/java/com/thebuzzmedia/exiftool/Tag.java @@ -246,9 +246,14 @@ public T parseValue(String value) throws IllegalArgumentException { } return null; } + + public String getRawValue(Map metadata) { + return metadata.get(this); + } + @SuppressWarnings("unchecked") - public T getValue(Map metadata) { - return (T)parseValue(this,metadata.get(this)); + public T getValue(Map metadata) { + return (T) parseValue(this, metadata.get(this)); } @SuppressWarnings("unchecked") public static T parseValue(Tag tag, Object value) @@ -261,9 +266,9 @@ public static T parseValue(Tag tag, Object value) // Check that there is work to do first. if (value != null) { Class type = tag.type; - if(type == value.getClass()){ - result = (T)value; - }else if (Boolean.class.isAssignableFrom(type)) + if (type == value.getClass()) { + result = (T) value; + } else if (Boolean.class.isAssignableFrom(type)) result = (T) Boolean.valueOf(value.toString()); else if (Byte.class.isAssignableFrom(type)) result = (T) Byte.valueOf(Byte.parseByte(value.toString())); @@ -274,9 +279,9 @@ else if (Short.class.isAssignableFrom(type)) else if (Long.class.isAssignableFrom(type)) result = (T) Long.valueOf(Long.parseLong(value.toString())); else if (Float.class.isAssignableFrom(type)) - result = (T) Float.valueOf(Float.parseFloat(value.toString())); + result = (T) new Float(parseDouble(value.toString()).floatValue()); else if (Double.class.isAssignableFrom(type)) - result = (T) Double.valueOf(Double.parseDouble(value.toString())); + result = (T) parseDouble(value.toString()); else if (Character.class.isAssignableFrom(type)) result = (T) Character.valueOf(value.toString().charAt(0)); else if (String.class.isAssignableFrom(type)) @@ -286,15 +291,16 @@ else if (String.class.isAssignableFrom(type)) return result; } - private Double parseDouble(String in) { + private static Double parseDouble(String in) { if (in.contains("/")) { String[] enumeratorAndDivisor = in.split("/"); return Double.parseDouble(enumeratorAndDivisor[0]) - / Double.parseDouble(enumeratorAndDivisor[1]); + / Double.parseDouble(enumeratorAndDivisor[1]); } else { return Double.parseDouble(in); } } + @SuppressWarnings("unchecked") public T parseValue2(String value) throws IllegalArgumentException { return (T) deserialize(getKey(), value, getType()); @@ -319,8 +325,7 @@ public static Object deserialize(String tagName, String value, Class expectedTyp } else if (Date.class.equals(expectedType)) { if (value == null) return null; - SimpleDateFormat formatter = new SimpleDateFormat( - ExifToolNew.EXIF_DATE_FORMAT); + SimpleDateFormat formatter = new SimpleDateFormat(ExifToolNew.EXIF_DATE_FORMAT); return formatter.parse(value); } else if (Integer.class.equals(expectedType)) { if (value == null) @@ -339,8 +344,7 @@ public static Object deserialize(String tagName, String value, Class expectedTyp return 0; String[] enumeratorAndDivisor = value.split("/"); if (enumeratorAndDivisor.length == 2) { - return Double.parseDouble(enumeratorAndDivisor[0]) - / Double.parseDouble(enumeratorAndDivisor[1]); + return Double.parseDouble(enumeratorAndDivisor[0]) / Double.parseDouble(enumeratorAndDivisor[1]); } else { return Double.parseDouble(value); } @@ -367,10 +371,8 @@ public String getName() { } /** - * Used to get a hint for the native type of this tag's value as - * specified by Phil Harvey's ExifToolNew3 Tag Guide. + * Used to get a hint for the native type of this tag's value as specified by Phil Harvey's ExifToolNew3 Tag Guide. * * @return a hint for the native type of this tag's value. */ diff --git a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java index 251a0945..8cc254bc 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java +++ b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java @@ -15,7 +15,7 @@ @SuppressWarnings("deprecation") public class ExifToolService extends RawExifToolAdapter implements Closeable { private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ExifToolService.class); - + public ExifToolService(RawExifTool exifTool) { super(exifTool); } @@ -26,8 +26,8 @@ public ExifToolService(RawExifTool exifTool) { // } public Map getImageMeta2(File image, ReadOptions options, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { - Map all = getImageMeta(image,options,toKeys(tags)); - return (Map)toMetadataTagKeys(all); + Map all = getImageMeta(image, options, toKeys(tags)); + return (Map) toMetadataTagKeys(all); } public Map getImageMeta2c(File file, ReadOptions options, MetadataTag... tags) @@ -42,14 +42,14 @@ public Map getImageMeta2b(File image, ReadOptions options, Metad public Map getImageMeta3(File image, ReadOptions options, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { - return getImageMeta4(image, options, Format.NUMERIC, tags); + return getImageMeta4d(image, new ReadOptions().withNumericOutput(Format.NUMERIC), tags); } - public Map getImageMeta4(File image, ReadOptions options, - Format format, MetadataTag... tags) throws IllegalArgumentException, - SecurityException, IOException { - return toMetadataTagKeys(getImageMeta(image,new ReadOptions().withNumericOutput(format), toKeys(tags))); + public Map getImageMeta4d(File image, ReadOptions options, MetadataTag... tags) + throws IllegalArgumentException, SecurityException, IOException { + return toMetadataTagKeys(getImageMeta(image, options, toKeys(tags))); } + public Map getImageMeta4c(File file, ReadOptions options, Format format, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { Map result = getImageMeta6(file, options, tags); @@ -68,7 +68,7 @@ public Map getImageMeta4b(File image, ReadOptions options, stringTags[i++] = tag.getKey(); } Map result = exifTool.getImageMeta(image, new ReadOptions().withNumericOutput(format) - .withShowDuplicates(!true),stringTags); + .withShowDuplicates(!true), stringTags); ReadOptions readOptions = new ReadOptions().withConvertTypes(true).withNumericOutput( format.equals(Format.NUMERIC)); return (Map) convertToMetadataTags(readOptions, result, tags); @@ -86,7 +86,8 @@ public Map getImageMeta5(File image, ReadOptions options, Format for (TagGroup tag : tags) { stringTags[i++] = tag.getValue(); } - return exifTool.getImageMeta(image, new ReadOptions().withNumericOutput(format).withShowDuplicates(!false),stringTags); + return exifTool.getImageMeta(image, new ReadOptions().withNumericOutput(format).withShowDuplicates(!false), + stringTags); } // @@ -287,7 +288,7 @@ public static Map convertToMetadataTags(ReadOptions options, Map } static MetadataTag toTag(String name) { - //Tag.forName( + // Tag.forName( for (Tag tag : Tag.values()) { if (tag.getKey().equalsIgnoreCase(name)) { return tag; @@ -303,38 +304,42 @@ static MetadataTag toTag(String name) { private Map toMetadataTagKeys(Map all) { Map result = new HashMap(); - for (Entry entry : all.entrySet()){ + for (Entry entry : all.entrySet()) { MetadataTag tag = toTag(entry.getKey()); - if(tag!=null){ - result.put(tag,entry.getValue()); + if (tag != null) { + result.put(tag, entry.getValue()); } } return result; } + private String[] toKeys(MetadataTag... tags) { - return Lists.transform(Arrays.asList(tags),new Function(){ + return Lists.transform(Arrays.asList(tags), new Function() { @Override public String apply(MetadataTag input) { return input.getKey(); - }}).toArray(new String[0]); + } + }).toArray(new String[0]); } + // -// @Override @Deprecated -// public Map getImageMeta(File file, Format format, -// boolean supressDuplicates, String... tags) throws IOException { -// return getImageMeta(file,format.withSuppressDuplicates(),tags); -// } -// -// @Override @Deprecated -// public Map getImageMeta(File file, ReadOptions options, -// boolean supressDuplicates, String... tags) throws IOException { -// return getImageMeta10(file,options,tags); -// } - + // @Override @Deprecated + // public Map getImageMeta(File file, Format format, + // boolean supressDuplicates, String... tags) throws IOException { + // return getImageMeta(file,format.withSuppressDuplicates(),tags); + // } + // + // @Override @Deprecated + // public Map getImageMeta(File file, ReadOptions options, + // boolean supressDuplicates, String... tags) throws IOException { + // return getImageMeta10(file,options,tags); + // } + @Override public void close() { super.close(); } + /** * Compiled {@link Pattern} of ": " used to split compact output from ExifToolNew3 evenly into name/value pairs. */ @@ -343,6 +348,7 @@ public void close() { public static String toResponse(List results) { return Joiner.on('\n').join(results); } + public static Map toMap(List all) { Map resultMap = new HashMap(500); for (String line : all) { diff --git a/src/test/java/com/thebuzzmedia/exiftool/Example.java b/src/test/java/com/thebuzzmedia/exiftool/Example.java index 5cc791bd..d4c64990 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Example.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Example.java @@ -26,8 +26,7 @@ public static void main(String[] args) throws IOException, // list all first-class tags for (File f : images) { log.info("\n[{}]", f.getName()); - Map metadata = tool.getImageMeta4(f, - new ReadOptions(), Format.HUMAN_READABLE, Tag.values()); + Map metadata = tool.getImageMeta4d(f, new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.values()); for (MetadataTag key : metadata.keySet()) { log.info(String.format("\t\t%s: %s", key.getKey(), metadata.get(key))); diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index d08a4f2f..04850db9 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -49,14 +49,14 @@ public void testSingleTool() throws Exception { assertTrue(runTests(tool, "")); } - try (ExifToolService tool = create(Feature.STAY_OPEN)) { + try (ExifToolService tool = create(/*Feature.STAY_OPEN*/)) { assertTrue(runTests(tool, "")); } - try (ExifToolService tool = create(Feature.STAY_OPEN)) { - tool.startup(); - assertTrue(runTests(tool, "")); - } +// try (ExifToolService tool = create(Feature.STAY_OPEN)) { +// tool.startup(); +// assertTrue(runTests(tool, "")); +// } } @Test @@ -125,73 +125,35 @@ public void run() { } } - @Test + @Test(expected=IOException.class) public void testProcessTimeout() throws Exception { try (ExifToolService tool = create(1, Feature.STAY_OPEN)) { long start = System.currentTimeMillis(); runTests(tool, "will fail"); long end = System.currentTimeMillis(); fail("should have failed. passed "+(end-start)+" miliseconds."); - } catch (IOException ex) { - ; } } public boolean runTests(ExifToolService tool, String runId) throws IOException, URISyntaxException { - - Map metadata; - File imageFile; - Set keys; - Tag tag; - - URL url = getClass() - .getResource("/kureckjones_jett_075_02-cropped.tif"); - imageFile = new File(url.toURI()); - metadata = tool.getImageMeta4(imageFile, options , - Format.HUMAN_READABLE, Tag.values()); - assertEquals(32, metadata.size()); - - keys = metadata.keySet(); - - tag = Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - Object a = metadata.get(tag); - assertEquals(728, tag.getValue(metadata)); - - tag = Tag.IMAGE_HEIGHT; - assertEquals(825, tag.getValue(metadata)); - - tag = Tag.MODEL; - assertEquals("P 45+", tag.parseValue(metadata.get(tag))); - log.info(runId + ": finished image 1"); - - url = getClass().getResource("/nexus-s-electric-cars.jpg"); - imageFile = new File(url.toURI()); - metadata = tool.getImageMeta4(imageFile, options, - Format.HUMAN_READABLE, Tag.values()); - assertEquals(27, metadata.size()); - - keys = metadata.keySet(); - tag = Tag.IMAGE_WIDTH; - assertTrue(keys.contains(tag)); - assertEquals(2560, tag.getValue(metadata)); - - tag = Tag.IMAGE_HEIGHT; - assertEquals(1920, tag.getValue(metadata)); - - tag = Tag.MODEL; - assertEquals("Nexus S", tag.getValue(metadata)); - - tag = Tag.ISO; - assertEquals(50, tag.getValue(metadata)); - - tag = Tag.SHUTTER_SPEED; - assertEquals("1/64", metadata.get(tag)); - assertEquals(0.015625, tag.getValue(metadata)); - log.info(runId + ": finished image 2"); + testFile(tool, "/kureckjones_jett_075_02-cropped.tif",32,728,825,"P 45+",100,"1/6",0.16666); + testFile(tool, "/nexus-s-electric-cars.jpg",27,2560,1920,"Nexus S",50,"1/64",0.015625); +// Map rawMetadata = tool.getImageMeta(imageFile, new ReadOptions().withNumericOutput(Format.HUMAN_READABLE)); +// assertEquals(231, rawMetadata.size()); return true; } + private void testFile(ExifToolService tool, String resource, int size, int width, int height, String model, int iso, String shutterRaw, double shutter) throws URISyntaxException, IOException { + File imageFile = new File(getClass().getResource(resource).toURI()); + Map metadata = tool.getImageMeta4d(imageFile, new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.values()); + assertEquals(size, metadata.size()); + assertEquals(width, Tag.IMAGE_WIDTH.getValue(metadata)); + assertEquals(height, Tag.IMAGE_HEIGHT.getValue(metadata)); + assertEquals(model, Tag.MODEL.getValue(metadata)); + assertEquals(iso, Tag.ISO.getValue(metadata)); + assertEquals(shutterRaw, Tag.SHUTTER_SPEED.getRawValue(metadata)); + assertEquals(shutter, (Double)Tag.SHUTTER_SPEED.getValue(metadata),1e-5); + } @Test public void testGroupTags() throws Exception { @@ -243,11 +205,10 @@ public void testWriteTagStringNonDaemon() throws Exception { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.DATE_TIME_ORIGINAL }; // Check the value is correct at the start - Map metadata = tool.getImageMeta4( - imageFile.toFile(), options, - Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); @@ -256,10 +217,10 @@ public void testWriteTagStringNonDaemon() throws Exception { Map newValues = new HashMap(); newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.DATE_TIME_ORIGINAL }; // Finally check that it's updated - metadata = tool.getImageMeta4(imageFile.toFile(), - options, Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); @@ -281,11 +242,10 @@ public void testWriteTagString() throws Exception { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.DATE_TIME_ORIGINAL }; // Check the value is correct at the start - Map metadata = tool.getImageMeta4( - imageFile.toFile(), options, - Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); @@ -294,10 +254,10 @@ public void testWriteTagString() throws Exception { Map newValues = new HashMap(); newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.DATE_TIME_ORIGINAL }; // Finally check that it's updated - metadata = tool.getImageMeta4(imageFile.toFile(), - options, Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); @@ -318,11 +278,10 @@ public void testWriteTagStringInvalidformat() throws Exception { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.DATE_TIME_ORIGINAL }; // Check the value is correct at the start - Map metadata = tool.getImageMeta4( - imageFile.toFile(), options, - Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); @@ -332,10 +291,10 @@ public void testWriteTagStringInvalidformat() throws Exception { // Now change it to an invalid value which should fail tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.DATE_TIME_ORIGINAL }; // Finally check that it's not updated - metadata = tool.getImageMeta4(imageFile.toFile(), - options, Format.HUMAN_READABLE, Tag.DATE_TIME_ORIGINAL); + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); @@ -359,10 +318,10 @@ public void testWriteTagNumberNonDaemon() throws Exception { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION }; // Test what orientation value is at the start - Map metadata = tool.getImageMeta4( - imageFile.toFile(), options, Format.HUMAN_READABLE, Tag.ORIENTATION); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); @@ -371,10 +330,10 @@ public void testWriteTagNumberNonDaemon() throws Exception { newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION }; // Finally check the updated value - metadata = tool.getImageMeta4(imageFile.toFile(), - options, Format.HUMAN_READABLE, Tag.ORIENTATION); + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); @@ -396,10 +355,10 @@ public void testWriteTagNumber() throws Exception { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION }; // Test what orientation value is at the start - Map metadata = tool.getImageMeta4( - imageFile.toFile(), options, Format.HUMAN_READABLE, Tag.ORIENTATION); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); @@ -408,10 +367,10 @@ public void testWriteTagNumber() throws Exception { newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION }; // Finally check the updated value - metadata = tool.getImageMeta4(imageFile.toFile(), - options, Format.HUMAN_READABLE, Tag.ORIENTATION); + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); @@ -433,11 +392,10 @@ public void testWriteMulipleTag() throws Exception { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; // Test what orientation value is at the start - Map metadata = tool.getImageMeta4( - imageFile.toFile(), options,Format.HUMAN_READABLE, - Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", "2010:12:10 17:07:05", @@ -450,9 +408,10 @@ public void testWriteMulipleTag() throws Exception { newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; // Finally check the updated value - metadata = tool.getImageMeta4(imageFile.toFile(), options,Format.HUMAN_READABLE, Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, @@ -474,11 +433,10 @@ public void testWriteMulipleTagNonDaemon() throws Exception { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; // Test what orientation value is at the start - Map metadata = tool.getImageMeta4( - imageFile.toFile(), options, Format.HUMAN_READABLE, - Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", "2010:12:10 17:07:05", @@ -491,10 +449,10 @@ public void testWriteMulipleTagNonDaemon() throws Exception { newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; // Finally check the updated value - metadata = tool.getImageMeta4(imageFile.toFile(), options,Format.HUMAN_READABLE, - Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, @@ -516,11 +474,10 @@ public void testWriteMultipleTagNonDaemon2() throws Exception { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; // Test what orientation value is at the start - Map metadata = tool.getImageMeta4( - imageFile.toFile(), options,Format.HUMAN_READABLE, - Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); assertEquals("Wrong starting value", "2010:12:10 17:07:05", @@ -534,10 +491,10 @@ public void testWriteMultipleTagNonDaemon2() throws Exception { // tool.writeMetadata(imageFile.toFile(), newValues); tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; // Finally check the updated value - metadata = tool.getImageMeta4(imageFile.toFile(), options,Format.HUMAN_READABLE, - Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, From 48303b9fd460ea697d14b83eb2db6c3f9fdea2ff Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 23 Dec 2014 10:13:23 +0200 Subject: [PATCH 097/148] - comment out some not used methods in facade --- .../exiftool/adapters/ExifToolService.java | 96 +++++++++---------- 1 file changed, 48 insertions(+), 48 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java index 8cc254bc..19d3e949 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java +++ b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java @@ -29,16 +29,16 @@ public Map getImageMeta2(File image, ReadOptions options, Metada Map all = getImageMeta(image, options, toKeys(tags)); return (Map) toMetadataTagKeys(all); } - - public Map getImageMeta2c(File file, ReadOptions options, MetadataTag... tags) - throws IllegalArgumentException, SecurityException, IOException { - return getImageMeta6(file, options, tags); - } - - public Map getImageMeta2b(File image, ReadOptions options, MetadataTag... tags) - throws IllegalArgumentException, SecurityException, IOException { - return (Map) getImageMeta3(image, options, tags); - } +// +// public Map getImageMeta2c(File file, ReadOptions options, MetadataTag... tags) +// throws IllegalArgumentException, SecurityException, IOException { +// return getImageMeta6(file, options, tags); +// } +// +// public Map getImageMeta2b(File image, ReadOptions options, MetadataTag... tags) +// throws IllegalArgumentException, SecurityException, IOException { +// return (Map) getImageMeta3(image, options, tags); +// } public Map getImageMeta3(File image, ReadOptions options, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { @@ -49,32 +49,32 @@ public Map getImageMeta4d(File image, ReadOptions options, throws IllegalArgumentException, SecurityException, IOException { return toMetadataTagKeys(getImageMeta(image, options, toKeys(tags))); } - - public Map getImageMeta4c(File file, ReadOptions options, Format format, MetadataTag... tags) - throws IllegalArgumentException, SecurityException, IOException { - Map result = getImageMeta6(file, options, tags); - // since meta tags are passed we will have a proper Map result - return (Map) result; - } - - public Map getImageMeta4b(File image, ReadOptions options, Format format, MetadataTag... tags) - throws IllegalArgumentException, SecurityException, IOException { - if (tags == null) { - tags = new MetadataTag[0]; - } - String[] stringTags = new String[tags.length]; - int i = 0; - for (MetadataTag tag : tags) { - stringTags[i++] = tag.getKey(); - } - Map result = exifTool.getImageMeta(image, new ReadOptions().withNumericOutput(format) - .withShowDuplicates(!true), stringTags); - ReadOptions readOptions = new ReadOptions().withConvertTypes(true).withNumericOutput( - format.equals(Format.NUMERIC)); - return (Map) convertToMetadataTags(readOptions, result, tags); - // map only known values? - // return Tag.toTagMap(result); - } +// +// public Map getImageMeta4c(File file, ReadOptions options, Format format, MetadataTag... tags) +// throws IllegalArgumentException, SecurityException, IOException { +// Map result = getImageMeta6(file, options, tags); +// // since meta tags are passed we will have a proper Map result +// return (Map) result; +// } +// +// public Map getImageMeta4b(File image, ReadOptions options, Format format, MetadataTag... tags) +// throws IllegalArgumentException, SecurityException, IOException { +// if (tags == null) { +// tags = new MetadataTag[0]; +// } +// String[] stringTags = new String[tags.length]; +// int i = 0; +// for (MetadataTag tag : tags) { +// stringTags[i++] = tag.getKey(); +// } +// Map result = exifTool.getImageMeta(image, new ReadOptions().withNumericOutput(format) +// .withShowDuplicates(!true), stringTags); +// ReadOptions readOptions = new ReadOptions().withConvertTypes(true).withNumericOutput( +// format.equals(Format.NUMERIC)); +// return (Map) convertToMetadataTags(readOptions, result, tags); +// // map only known values? +// // return Tag.toTagMap(result); +// } public Map getImageMeta5(File image, ReadOptions options, Format format, TagGroup... tags) throws IllegalArgumentException, SecurityException, IOException { @@ -120,18 +120,18 @@ public Map getImageMeta5(File image, ReadOptions options, Format // } // @Override - public Map getImageMeta5b(File image, ReadOptions options, Format format, TagGroup... tags) - throws IllegalArgumentException, SecurityException, IOException { - if (tags == null) { - tags = new TagGroup[0]; - } - String[] stringTags = new String[tags.length]; - int i = 0; - for (TagGroup tag : tags) { - stringTags[i++] = tag.getKey(); - } - return exifTool.getImageMeta(image, options.withNumericOutput(format).withShowDuplicates(false), stringTags); - } +// public Map getImageMeta5b(File image, ReadOptions options, Format format, TagGroup... tags) +// throws IllegalArgumentException, SecurityException, IOException { +// if (tags == null) { +// tags = new TagGroup[0]; +// } +// String[] stringTags = new String[tags.length]; +// int i = 0; +// for (TagGroup tag : tags) { +// stringTags[i++] = tag.getKey(); +// } +// return exifTool.getImageMeta(image, options.withNumericOutput(format).withShowDuplicates(false), stringTags); +// } public Map getImageMeta6(File file, ReadOptions options, Object... tags) throws IOException { return getImageMeta7(file, options, tags); From 5cd7426236f473abce596492e6a4f3def6a8cd93 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 23 Dec 2014 11:45:26 +0200 Subject: [PATCH 098/148] - refactor logging - fix duplicates bug - better exception handling - fix all tests but 2 --- .../thebuzzmedia/exiftool/ExifProcess.java | 59 +- .../thebuzzmedia/exiftool/ExifToolNew3.java | 14 +- .../exiftool/KeepAliveExifProxy.java | 4 +- .../exiftool/LineReaderThread.java | 6 +- .../exiftool/SingleUseExifProxy.java | 3 +- .../exiftool/adapters/ExifToolService.java | 8 +- .../thebuzzmedia/exiftool/TestExifTool.java | 559 +++++++++--------- ...303\226stliche_Zubringerstra\303\237e.png" | Bin 0 -> 320660 bytes 8 files changed, 331 insertions(+), 322 deletions(-) create mode 100644 "src/test/resources/20140502_152336_\303\226stliche_Zubringerstra\303\237e.png" diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index 23fbf399..e16196d7 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -31,6 +31,8 @@ * streams for reading and writing data. */ public final class ExifProcess { + private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ExifProcess.class); + private static class Pair { final P1 _1; final P2 _2; @@ -51,11 +53,13 @@ public String toString() { static { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { - ExifToolNew3.log.info("Close all remaining processes:" + all.keySet()); - for (Entry> item : new HashSet>>( - all.entrySet())) { - ExifToolNew3.log.info("Close leaked process " + item); - item.getValue()._2.close(); + if (!all.isEmpty()) { + ExifToolNew3.log.warn("Close all leaked processes:" + all.keySet()); + for (Entry> item : new HashSet>>( + all.entrySet())) { + ExifToolNew3.log.warn("Close leaked process " + item, new RuntimeException()); + item.getValue()._2.close(); + } } } }); @@ -76,8 +80,7 @@ public static ExifProcess _execute(boolean keepAlive, List args, Charset return new ExifProcess(keepAlive, args, charset); } - public static List executeToResults(String exifCmd, List args, Charset charset) - throws IOException { + public static List executeToResults(String exifCmd, List args, Charset charset) throws IOException { List newArgs = new ArrayList(args.size() + 1); newArgs.add(exifCmd); newArgs.addAll(args); @@ -98,11 +101,12 @@ private static String toCmd(List args) { } return sb.toString(); } -// -// public static String executeToString(String exifCmd, List args, Charset charset) throws IOException { -// return ExifProxy.$.toResponse(executeToResults(exifCmd,args,charset)); -// } -// + + // + // public static String executeToString(String exifCmd, List args, Charset charset) throws IOException { + // return ExifProxy.$.toResponse(executeToResults(exifCmd,args,charset)); + // } + // public static ExifProcess startup(String exifCmd, Charset charset) { List args = Arrays.asList(exifCmd, "-stay_open", "True", "-@", "-"); return _execute(true, args, charset); @@ -158,6 +162,7 @@ public synchronized List sendArgs(List args) throws IOException builder.append(arg).append("\n"); } builder.append("-execute\n"); + LOG.debug("sendArgs(\n" + builder.toString() + "\n)"); writeFlush(builder.toString()); return readResponse(args); } @@ -174,6 +179,7 @@ public synchronized String readLine() throws IOException { throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); return reader.readLine(); } + public synchronized List readResponse(List args) throws IOException { if (closed) throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); @@ -182,15 +188,16 @@ public synchronized List readResponse(List args) throws IOExcept List all = new ArrayList(); while ((line = reader.readLine()) != null) { - if (closed) + if (closed) { + ExifToolNew3.log.info("stream closed message"); throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); + } + ExifToolNew3.log.debug("stream line read [" + line + "]"); all.add(line); /* - * When using a persistent ExifToolNew3 process, it terminates its - * output to us with a "{ready}" clause on a new line, we need to - * look for it and break from this loop when we see it otherwise - * this process will hang indefinitely blocking on the input stream - * with no data to read. + * When using a persistent ExifToolNew3 process, it terminates its output to us with a "{ready}" clause on a + * new line, we need to look for it and break from this loop when we see it otherwise this process will hang + * indefinitely blocking on the input stream with no data to read. */ if (keepAlive && line.equals("{ready}")) { break; @@ -205,12 +212,16 @@ public synchronized List readResponse(List args) throws IOExcept sb.append(error); } String result = sb.toString(); - String message = result+". ["+all.size()+"] tags for exiftool with args ["+args+"]."; - if(result.contains("No matching files")){ - throw new ExifError(message); - }else{ - ExifToolNew3.log.info(message); - } + String message = result + ". " + all.size() + " lines where read [" + all + "] for exiftool with args [" + + args + "]."; + // if(result.contains("No matching files")){ + throw new ExifError(message); + // }else{ + // ExifToolNew3.log.info(message); + // } + } + if (all.isEmpty()) { + throw new RuntimeException("Didn't get anything back from exiftool with args [" + args + "]."); } return all; } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java index 8be0ec34..8cccd17c 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java @@ -42,6 +42,7 @@ import org.slf4j.LoggerFactory; import com.google.common.base.CharMatcher; +import com.google.common.base.Joiner; import com.thebuzzmedia.exiftool.adapters.ExifToolService; /** @@ -493,10 +494,12 @@ public Map getImageMeta(File file, ReadOptions readOptions, Stri } else if (readOptions.numericOutput) { args.add("-n"); // numeric output } - if (!readOptions.showDuplicates) { - args.add("-a"); // suppress duplicates + if (readOptions.showDuplicates) { + // args.add("-a"); + args.add("-duplicates"); // allow duplicates to be shown } - args.add("-S"); // compact output + // -S or -veryShort + args.add("-veryShort"); // compact output for (String tag : tags) { args.add("-" + tag); } @@ -514,6 +517,7 @@ public Map getImageMeta(File file, ReadOptions readOptions, Stri // start process long startTime = System.currentTimeMillis(); log.debug(String.format("Querying %d tags from image: %s", tags.length, file.getAbsolutePath())); + log.info("call stayOpen="+stayOpen +" exiftool "+ Joiner.on(" ").join(args)); /* * Using ExifToolNew3 in daemon mode (-stay_open True) executes different code paths below. So establish the * flag for this once and it is reused a multitude of times later in this method to figure out where to branch @@ -741,7 +745,7 @@ public void writeMetadata(WriteOptions options, File image, Map v @Override protected void finalize() throws Throwable { - log.info("ExifToolNew3 not used anymore shutdown the exiftool process..."); + log.debug("Shutdown on finalize ..."); shutdown(); super.finalize(); } @@ -755,7 +759,7 @@ public static Charset computeDefaultCharset(Collection features) { @Override public List execute(List args) { try { - return ExifProcess.executeToResults(exifCmd,args,charset); + return ExifProcess.executeToResults(exifCmd, args, charset); } catch (IOException e) { throw new RuntimeException(e); } diff --git a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java index 800d9e4e..a2ea99cd 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java +++ b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java @@ -9,6 +9,7 @@ * Manages an external exif process in keep alive mode. */ public class KeepAliveExifProxy implements ExifProxy { + private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(KeepAliveExifProxy.class); private final List startupArgs; private final AtomicBoolean shuttingDown = new AtomicBoolean(false); private final Timer cleanupTimer = new Timer(ExifToolNew3.CLEANUP_THREAD_NAME, true); @@ -61,8 +62,7 @@ public void startup() { if (process == null || process.isClosed()) { synchronized (this) { if (process == null || process.isClosed()) { - ExifToolNew3.log - .debug("Starting daemon ExifToolNew3 process and creating read/write streams (this only happens once)..."); + LOG.debug("Starting daemon ExifToolNew3 process and creating read/write streams (this only happens once)..."); process = new ExifProcess(true, startupArgs, charset); } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java b/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java index c7701fac..215a2348 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java +++ b/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java @@ -22,7 +22,7 @@ public class LineReaderThread extends Thread { private BufferedReader reader; private BlockingQueue lineBuffer = new ArrayBlockingQueue( - 10, true); + 50, true); public LineReaderThread(String name, BufferedReader reader) { super(name); @@ -46,9 +46,9 @@ public void run() { } } } catch (IOException ex) { - // exit + ExifToolNew3.log.warn("Error in LineReaderThread.",ex); } catch (InterruptedException ignored) { - // exit + ExifToolNew3.log.debug("er:",ignored); } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java index 469b312a..f0254adb 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java +++ b/src/main/java/com/thebuzzmedia/exiftool/SingleUseExifProxy.java @@ -5,6 +5,7 @@ import java.util.*; public class SingleUseExifProxy implements ExifProxy { + private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(SingleUseExifProxy.class); private final Timer cleanupTimer = new Timer(ExifToolNew3.CLEANUP_THREAD_NAME, true); private final List baseArgs; private final Charset charset; @@ -32,7 +33,7 @@ public List execute(final long runTimeoutMills, List args) { @Override public void run() { if (!process.isClosed()) { - ExifToolNew3.log.warn("Process ran too long closing, max " + runTimeoutMills + " mills"); + LOG.warn("Process ran too long closing, max " + runTimeoutMills + " mills"); process.close(); } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java index 19d3e949..1be1c5cb 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java +++ b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java @@ -86,7 +86,7 @@ public Map getImageMeta5(File image, ReadOptions options, Format for (TagGroup tag : tags) { stringTags[i++] = tag.getValue(); } - return exifTool.getImageMeta(image, new ReadOptions().withNumericOutput(format).withShowDuplicates(!false), + return exifTool.getImageMeta(image, new ReadOptions().withNumericOutput(format).withShowDuplicates(true), stringTags); } @@ -306,9 +306,9 @@ private Map toMetadataTagKeys(Map all) { Map result = new HashMap(); for (Entry entry : all.entrySet()) { MetadataTag tag = toTag(entry.getKey()); - if (tag != null) { - result.put(tag, entry.getValue()); - } + //if (tag != null) { + result.put(tag, entry.getValue()); + //} } return result; } diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 04850db9..9533ad9d 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -27,17 +27,20 @@ public class TestExifTool { private static final String TEST_FILES_PATH = "src/test/resources"; private static Logger log = LoggerFactory.getLogger(TestExifTool.class); - private static ExifToolService create(Feature... features){ + + private static ExifToolService create(Feature... features) { return RawExifTool.Factory.create(features); - //return new ExifToolNew2(features); - //return new ExifToolNew(features); + // return new ExifToolNew2(features); + // return new ExifToolNew(features); } - private static ExifToolService create(int timeoutWhenKeepAliveInMillis, Feature... features){ + + private static ExifToolService create(int timeoutWhenKeepAliveInMillis, Feature... features) { return RawExifTool.Factory.create(timeoutWhenKeepAliveInMillis, features); - //return new ExifToolNew(timeoutWhenKeepAliveInMillis, features); - //return new ExifToolNew2(timeoutWhenKeepAliveInMillis, features); + // return new ExifToolNew(timeoutWhenKeepAliveInMillis, features); + // return new ExifToolNew2(timeoutWhenKeepAliveInMillis, features); } - private ExifToolService create(ReadOptions readOptions,Feature...features) { + + private ExifToolService create(ReadOptions readOptions, Feature... features) { return RawExifTool.Factory.create(readOptions, features); } @@ -49,14 +52,14 @@ public void testSingleTool() throws Exception { assertTrue(runTests(tool, "")); } - try (ExifToolService tool = create(/*Feature.STAY_OPEN*/)) { + try (ExifToolService tool = create(/* Feature.STAY_OPEN */)) { assertTrue(runTests(tool, "")); } -// try (ExifToolService tool = create(Feature.STAY_OPEN)) { -// tool.startup(); -// assertTrue(runTests(tool, "")); -// } + // try (ExifToolService tool = create(Feature.STAY_OPEN)) { + // tool.startup(); + // assertTrue(runTests(tool, "")); + // } } @Test @@ -70,18 +73,18 @@ public void testConcurrent() throws Exception { Thread t = new Thread(toolName) { @Override public void run() { - log.info(getName() + ": starting"); + log.debug(getName() + ": starting"); try (ExifToolService tool = create(Feature.STAY_OPEN)) { runTests(tool, getName()); - log.info(getName() + ": finished"); } catch (IOException e) { log.error(e.getMessage(), e); fail(e.getMessage()); } catch (URISyntaxException e) { log.error(e.getMessage(), e); fail(e.getMessage()); + } finally { + log.debug(getName() + ": finished"); } - log.info(getName() + ": finished"); } }; t.start(); @@ -125,34 +128,37 @@ public void run() { } } - @Test(expected=IOException.class) + @Test(expected = IOException.class) public void testProcessTimeout() throws Exception { try (ExifToolService tool = create(1, Feature.STAY_OPEN)) { long start = System.currentTimeMillis(); runTests(tool, "will fail"); long end = System.currentTimeMillis(); - fail("should have failed. passed "+(end-start)+" miliseconds."); + fail("should have failed. passed " + (end - start) + " miliseconds."); } } - public boolean runTests(ExifToolService tool, String runId) - throws IOException, URISyntaxException { - testFile(tool, "/kureckjones_jett_075_02-cropped.tif",32,728,825,"P 45+",100,"1/6",0.16666); - testFile(tool, "/nexus-s-electric-cars.jpg",27,2560,1920,"Nexus S",50,"1/64",0.015625); -// Map rawMetadata = tool.getImageMeta(imageFile, new ReadOptions().withNumericOutput(Format.HUMAN_READABLE)); -// assertEquals(231, rawMetadata.size()); + public boolean runTests(ExifToolService tool, String runId) throws IOException, URISyntaxException { + testFile(tool, "/kureckjones_jett_075_02-cropped.tif", 32, 728, 825, "P 45+", 100, "1/6", 0.16666); + testFile(tool, "/nexus-s-electric-cars.jpg", 27, 2560, 1920, "Nexus S", 50, "1/64", 0.015625); + // Map rawMetadata = tool.getImageMeta(imageFile, new + // ReadOptions().withNumericOutput(Format.HUMAN_READABLE)); + // assertEquals(231, rawMetadata.size()); return true; } - private void testFile(ExifToolService tool, String resource, int size, int width, int height, String model, int iso, String shutterRaw, double shutter) throws URISyntaxException, IOException { + + private void testFile(ExifToolService tool, String resource, int size, int width, int height, String model, + int iso, String shutterRaw, double shutter) throws URISyntaxException, IOException { File imageFile = new File(getClass().getResource(resource).toURI()); - Map metadata = tool.getImageMeta4d(imageFile, new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.values()); + Map metadata = tool.getImageMeta4d(imageFile, + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.values()); assertEquals(size, metadata.size()); assertEquals(width, Tag.IMAGE_WIDTH.getValue(metadata)); assertEquals(height, Tag.IMAGE_HEIGHT.getValue(metadata)); assertEquals(model, Tag.MODEL.getValue(metadata)); assertEquals(iso, Tag.ISO.getValue(metadata)); assertEquals(shutterRaw, Tag.SHUTTER_SPEED.getRawValue(metadata)); - assertEquals(shutter, (Double)Tag.SHUTTER_SPEED.getValue(metadata),1e-5); + assertEquals(shutter, (Double) Tag.SHUTTER_SPEED.getValue(metadata), 1e-5); } @Test @@ -162,14 +168,11 @@ public void testGroupTags() throws Exception { URL url = getClass().getResource("/iptc_test-photoshop.jpg"); File f = new File(url.toURI()); - metadata = tool.getImageMeta5(f, options, - Format.HUMAN_READABLE, TagGroup.IPTC); + metadata = tool.getImageMeta5(f, options, Format.HUMAN_READABLE, TagGroup.IPTC); assertEquals(17, metadata.size()); assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); - assertEquals("IPTC Status: Copyright Notice", - metadata.get("CopyrightNotice")); - assertEquals("IPTC Content: Description Writer", - metadata.get("Writer-Editor")); + assertEquals("IPTC Status: Copyright Notice", metadata.get("CopyrightNotice")); + assertEquals("IPTC Content: Description Writer", metadata.get("Writer-Editor")); // for (String key : metadata.keySet()){ // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); // } @@ -178,39 +181,32 @@ public void testGroupTags() throws Exception { @Test public void testTag() { - assertEquals("string value", "John Doe", - Tag.AUTHOR.parseValue("John Doe")); + assertEquals("string value", "John Doe", Tag.AUTHOR.parseValue("John Doe")); assertEquals("integer value", 200, Tag.ISO.parseValue("200")); - assertEquals("double value, from fraction", .25, - Tag.SHUTTER_SPEED.parseValue("1/4")); - assertEquals("double value, from decimal", .25, - Tag.SHUTTER_SPEED.parseValue(".25")); + assertEquals("double value, from fraction", .25, Tag.SHUTTER_SPEED.parseValue("1/4")); + assertEquals("double value, from decimal", .25, Tag.SHUTTER_SPEED.parseValue(".25")); } @Test public void testVersionNumber() { - assertTrue(new VersionNumber("1.2") - .isBeforeOrEqualTo(new VersionNumber("1.2.3"))); - assertTrue(new VersionNumber(1, 2).isBeforeOrEqualTo(new VersionNumber( - "1.2"))); - assertTrue(new VersionNumber(1, 2, 3) - .isBeforeOrEqualTo(new VersionNumber("1.3"))); - assertTrue(new VersionNumber(1, 2, 3) - .isBeforeOrEqualTo(new VersionNumber(2, 1))); + assertTrue(new VersionNumber("1.2").isBeforeOrEqualTo(new VersionNumber("1.2.3"))); + assertTrue(new VersionNumber(1, 2).isBeforeOrEqualTo(new VersionNumber("1.2"))); + assertTrue(new VersionNumber(1, 2, 3).isBeforeOrEqualTo(new VersionNumber("1.3"))); + assertTrue(new VersionNumber(1, 2, 3).isBeforeOrEqualTo(new VersionNumber(2, 1))); } @Test public void testWriteTagStringNonDaemon() throws Exception { try (ExifToolService tool = create()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); MetadataTag[] tags = { Tag.DATE_TIME_ORIGINAL }; // Check the value is correct at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(Tag.DATE_TIME_ORIGINAL)); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); // Now change it String newDate = "2014:01:23 10:07:05"; @@ -220,34 +216,34 @@ public void testWriteTagStringNonDaemon() throws Exception { MetadataTag[] tags1 = { Tag.DATE_TIME_ORIGINAL }; // Finally check that it's updated - metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(Tag.DATE_TIME_ORIGINAL)); + metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is // not // affected by the change -// URL backup_url = getClass().getResource( -// "/nexus-s-electric-cars.jpg_original"); -// Path backupFile = Paths.get(backup_url.toURI()); -// -// Files.move(backupFile, imageFile, -// StandardCopyOption.REPLACE_EXISTING); + // URL backup_url = getClass().getResource( + // "/nexus-s-electric-cars.jpg_original"); + // Path backupFile = Paths.get(backup_url.toURI()); + // + // Files.move(backupFile, imageFile, + // StandardCopyOption.REPLACE_EXISTING); } } @Test public void testWriteTagString() throws Exception { - ExifToolService tool = create(Feature.STAY_OPEN); + try (ExifToolService tool = create(Feature.STAY_OPEN)) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); MetadataTag[] tags = { Tag.DATE_TIME_ORIGINAL }; // Check the value is correct at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(Tag.DATE_TIME_ORIGINAL)); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); // Now change it String newDate = "2014:01:23 10:07:05"; @@ -257,33 +253,34 @@ public void testWriteTagString() throws Exception { MetadataTag[] tags1 = { Tag.DATE_TIME_ORIGINAL }; // Finally check that it's updated - metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(Tag.DATE_TIME_ORIGINAL)); + metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is // not // affected by the change -// URL backup_url = getClass().getResource( -// "/nexus-s-electric-cars.jpg_original"); -// Path backupFile = Paths.get(backup_url.toURI()); -// Files.move(backupFile, imageFile, -// StandardCopyOption.REPLACE_EXISTING); -// + // URL backup_url = getClass().getResource( + // "/nexus-s-electric-cars.jpg_original"); + // Path backupFile = Paths.get(backup_url.toURI()); + // Files.move(backupFile, imageFile, + // StandardCopyOption.REPLACE_EXISTING); + // + } } @Test public void testWriteTagStringInvalidformat() throws Exception { try (ExifToolService tool = create(Feature.STAY_OPEN)) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); MetadataTag[] tags = { Tag.DATE_TIME_ORIGINAL }; // Check the value is correct at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(Tag.DATE_TIME_ORIGINAL)); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); String newDate = "2egek opkpgrpok"; Map newValues = new HashMap(); @@ -294,21 +291,21 @@ public void testWriteTagStringInvalidformat() throws Exception { MetadataTag[] tags1 = { Tag.DATE_TIME_ORIGINAL }; // Finally check that it's not updated - metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("DateTimeOriginal tag is wrong", - "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); + metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); // Finally copy the source file back over so the next test run is // not // affected by the change -// URL backup_url = getClass().getResource( -// "/nexus-s-electric-cars.jpg_original"); -// // might not exist -// if (backup_url != null) { -// Path backupFile = Paths.get(backup_url.toURI()); -// Files.move(backupFile, imageFile, -// StandardCopyOption.REPLACE_EXISTING); -// } + // URL backup_url = getClass().getResource( + // "/nexus-s-electric-cars.jpg_original"); + // // might not exist + // if (backup_url != null) { + // Path backupFile = Paths.get(backup_url.toURI()); + // Files.move(backupFile, imageFile, + // StandardCopyOption.REPLACE_EXISTING); + // } } } @@ -316,14 +313,15 @@ public void testWriteTagStringInvalidformat() throws Exception { public void testWriteTagNumberNonDaemon() throws Exception { try (ExifToolService tool = create()) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); MetadataTag[] tags = { Tag.ORIENTATION }; // Test what orientation value is at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", + metadata.get(Tag.ORIENTATION)); // Now change it Map newValues = new HashMap(); @@ -333,19 +331,19 @@ public void testWriteTagNumberNonDaemon() throws Exception { MetadataTag[] tags1 = { Tag.ORIENTATION }; // Finally check the updated value - metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("Orientation tag updated value is wrong", - "Rotate 180", metadata.get(Tag.ORIENTATION)); + metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); // Finally copy the source file back over so the next test run is // not // affected by the change -// URL backup_url = getClass().getResource( -// "/nexus-s-electric-cars.jpg_original"); -// Path backupFile = Paths.get(backup_url.toURI()); -// -// Files.move(backupFile, imageFile, -// StandardCopyOption.REPLACE_EXISTING); + // URL backup_url = getClass().getResource( + // "/nexus-s-electric-cars.jpg_original"); + // Path backupFile = Paths.get(backup_url.toURI()); + // + // Files.move(backupFile, imageFile, + // StandardCopyOption.REPLACE_EXISTING); } } @@ -353,14 +351,15 @@ public void testWriteTagNumberNonDaemon() throws Exception { public void testWriteTagNumber() throws Exception { try (ExifToolService tool = create(Feature.STAY_OPEN)) { URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); MetadataTag[] tags = { Tag.ORIENTATION }; // Test what orientation value is at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", + metadata.get(Tag.ORIENTATION)); // Now change it Map newValues = new HashMap(); @@ -370,166 +369,159 @@ public void testWriteTagNumber() throws Exception { MetadataTag[] tags1 = { Tag.ORIENTATION }; // Finally check the updated value - metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("Orientation tag updated value is wrong", - "Rotate 180", metadata.get(Tag.ORIENTATION)); + metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); // Finally copy the source file back over so the next test run is // not // affected by the change -// URL backup_url = getClass().getResource( -// "/nexus-s-electric-cars.jpg_original"); -// Path backupFile = Paths.get(backup_url.toURI()); -// -// Files.move(backupFile, imageFile, -// StandardCopyOption.REPLACE_EXISTING); + // URL backup_url = getClass().getResource( + // "/nexus-s-electric-cars.jpg_original"); + // Path backupFile = Paths.get(backup_url.toURI()); + // + // Files.move(backupFile, imageFile, + // StandardCopyOption.REPLACE_EXISTING); } } @Test public void testWriteMulipleTag() throws Exception { try (ExifToolService tool = create(Feature.STAY_OPEN)) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); - MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; - - // Finally check the updated value - metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not - // affected by the change -// URL backup_url = getClass().getResource( -// "/nexus-s-electric-cars.jpg_original"); -// Path backupFile = Paths.get(backup_url.toURI()); -// -// Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", + metadata.get(Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; + + // Finally check the updated value + metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + // URL backup_url = getClass().getResource( + // "/nexus-s-electric-cars.jpg_original"); + // Path backupFile = Paths.get(backup_url.toURI()); + // + // Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); } } @Test public void testWriteMulipleTagNonDaemon() throws Exception { try (ExifToolService tool = create()) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); - MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; - - // Finally check the updated value - metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not - // affected by the change -// URL backup_url = getClass().getResource( -// "/nexus-s-electric-cars.jpg_original"); -// Path backupFile = Paths.get(backup_url.toURI()); -// -// Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", + metadata.get(Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; + + // Finally check the updated value + metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + // URL backup_url = getClass().getResource( + // "/nexus-s-electric-cars.jpg_original"); + // Path backupFile = Paths.get(backup_url.toURI()); + // + // Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); } } @Test public void testWriteMultipleTagNonDaemon2() throws Exception { try (ExifToolService tool = create()) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()),imageFile, StandardCopyOption.REPLACE_EXISTING); - MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Orientation tag starting value is wrong", - "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", - metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(Tag.ORIENTATION, 3); - - // tool.writeMetadata(imageFile.toFile(), newValues); - tool.addImageMetadata(imageFile.toFile(), newValues); - MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; - - // Finally check the updated value - metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", - metadata.get(Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, - metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not - // affected by the change -// URL backup_url = getClass().getResource( -// "/nexus-s-electric-cars.jpg_original"); -// Path backupFile = Paths.get(backup_url.toURI()); -// -// Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", + metadata.get(Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); + + // tool.writeMetadata(imageFile.toFile(), newValues); + tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; + + // Finally check the updated value + metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Finally copy the source file back over so the next test run is not + // affected by the change + // URL backup_url = getClass().getResource( + // "/nexus-s-electric-cars.jpg_original"); + // Path backupFile = Paths.get(backup_url.toURI()); + // + // Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); } } @Test public void testWritingWithImplicitTypes() throws Exception { - try (ExifToolService tool = create(new ReadOptions() - .withNumericOutput(true).withConvertTypes(true), - Feature.MWG_MODULE)){ - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imagePath = Paths.get("target","nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()),imagePath, StandardCopyOption.REPLACE_EXISTING); - File imageFile = imagePath.toFile(); -// try { + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), + Feature.MWG_MODULE)) { + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imagePath = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imagePath, StandardCopyOption.REPLACE_EXISTING); + File imageFile = imagePath.toFile(); + // try { // Test what orientation value is at the start - SimpleDateFormat formatter = new SimpleDateFormat( - "yyyy:MM:dd hh:mm:ss"); + SimpleDateFormat formatter = new SimpleDateFormat("yyyy:MM:dd hh:mm:ss"); - Map metadata = tool.getImageMeta2(imageFile, - options, Tag.ORIENTATION, MwgTag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", 1, - metadata.get(Tag.ORIENTATION)); - assertEquals("Wrong starting value", - formatter.parse("2010:12:10 17:07:05"), + Map metadata = tool.getImageMeta2(imageFile, options, Tag.ORIENTATION, + MwgTag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", 1, metadata.get(Tag.ORIENTATION)); + assertEquals("Wrong starting value", formatter.parse("2010:12:10 17:07:05"), metadata.get(MwgTag.DATE_TIME_ORIGINAL)); // Now change them @@ -540,83 +532,84 @@ public void testWritingWithImplicitTypes() throws Exception { Date createDate = formatter.parse("2013:02:21 10:07:05"); data.put(MwgTag.CREATE_DATE, createDate.getTime()); data.put(MwgTag.KEYWORDS, new String[] { "a", "b", "c" }); - tool.writeMetadata(new WriteOptions().withDeleteBackupFile(false), - imageFile, data); + tool.writeMetadata(new WriteOptions().withDeleteBackupFile(false), imageFile, data); // Finally check the updated value - metadata = tool.getImageMeta6(imageFile, options, Tag.ORIENTATION, - imageFile, MwgTag.DATE_TIME_ORIGINAL, + metadata = tool.getImageMeta6(imageFile, options, Tag.ORIENTATION, imageFile, MwgTag.DATE_TIME_ORIGINAL, MwgTag.CREATE_DATE, MwgTag.KEYWORDS); - assertEquals("Orientation tag updated value is wrong", 3, - metadata.get(Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, - metadata.get(MwgTag.DATE_TIME_ORIGINAL)); - assertEquals("CreateDate tag is wrong", createDate, - metadata.get(MwgTag.CREATE_DATE)); - assertEquals("Keywords tag is wrong", "a", - ((String[]) metadata.get(MwgTag.KEYWORDS))[0]); + assertEquals("Orientation tag updated value is wrong", 3, metadata.get(Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, metadata.get(MwgTag.DATE_TIME_ORIGINAL)); + assertEquals("CreateDate tag is wrong", createDate, metadata.get(MwgTag.CREATE_DATE)); + assertEquals("Keywords tag is wrong", "a", ((String[]) metadata.get(MwgTag.KEYWORDS))[0]); // Finally copy the source file back over so the next test run is // not affected by the change -// } finally { -// URL backup_url = getClass().getResource( -// "/nexus-s-electric-cars.jpg_original"); -// if (backup_url != null) { -// Path backupFile = Paths.get(backup_url.toURI()); -// Files.move(backupFile, imageFile.toPath(), -// StandardCopyOption.REPLACE_EXISTING); -// } - + // } finally { + // URL backup_url = getClass().getResource( + // "/nexus-s-electric-cars.jpg_original"); + // if (backup_url != null) { + // Path backupFile = Paths.get(backup_url.toURI()); + // Files.move(backupFile, imageFile.toPath(), + // StandardCopyOption.REPLACE_EXISTING); + // } + } } - @Test(expected=ExifError.class) + @Test(expected = ExifError.class) public void testReadingUtf8NamesWithStayOpen() throws Exception { - try (ExifToolService tool = create( - new ReadOptions().withNumericOutput(true) - .withConvertTypes(true), Feature.STAY_OPEN)) { - URL url = getClass().getResource( - "/20140502_152336_Östliche Zubringerstraße.png"); + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), + Feature.STAY_OPEN)) { + URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); File imageFile = new File(url.toURI()); System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); + Map metadata2 = tool.getImageMeta3(imageFile, options); + assertEquals(19, metadata2.size()); + } + } + + @Test(expected = ExifError.class) + public void testReadingUtf8NamesWithStayOpenWithoutSpaces() throws Exception { + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), + Feature.STAY_OPEN)) { + URL url = getClass().getResource("/20140502_152336_Östliche_Zubringerstraße.png"); + File imageFile = new File(url.toURI()); + System.out.println(imageFile.getAbsolutePath()); + Map metadata = tool.getImageMeta3(imageFile, options); + assertEquals(19, metadata.size()); } } @Test public void testReadingUtf8NamesWithoutStayOpen() throws Exception { - try (ExifToolService tool = create( - new ReadOptions().withNumericOutput(true) - .withConvertTypes(true))) { - URL url = getClass().getResource( - "/20140502_152336_Östliche Zubringerstraße.png"); + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true))) { + URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); File imageFile = new File(url.toURI()); System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata.size()); } } + @Test public void testReadingUtf8NamesWithStayOpenAndWindows() throws Exception { - try (ExifToolService tool = create( - new ReadOptions().withNumericOutput(true) - .withConvertTypes(true), Feature.STAY_OPEN,Feature.WINDOWS)) { - URL url = getClass().getResource( - "/20140502_152336_Östliche Zubringerstraße.png"); + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), + Feature.STAY_OPEN, Feature.WINDOWS)) { + URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); File imageFile = new File(url.toURI()); System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata.size()); } } + @Test public void testReadingUtf8NamesOnWindows() throws Exception { - try (ExifToolService tool = create( - new ReadOptions().withNumericOutput(true) - .withConvertTypes(true), Feature.STAY_OPEN,Feature.WINDOWS)) { - URL url = getClass().getResource( - "/20131231_230955_Strada Frumoasă.png"); + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), + Feature.STAY_OPEN, Feature.WINDOWS)) { + URL url = getClass().getResource("/20131231_230955_Strada Frumoasă.png"); File imageFile = new File(url.toURI()); System.out.println(imageFile.getAbsolutePath()); Map metadata1 = tool.getImageMeta(imageFile, options); diff --git "a/src/test/resources/20140502_152336_\303\226stliche_Zubringerstra\303\237e.png" "b/src/test/resources/20140502_152336_\303\226stliche_Zubringerstra\303\237e.png" new file mode 100644 index 0000000000000000000000000000000000000000..e8485dbc989f3922c1306de3b4971e9bdbaff857 GIT binary patch literal 320660 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�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 z

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

ROc8Ud@-h_sgDllKE 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 LhUz8c Date: Tue, 23 Dec 2014 12:12:17 +0200 Subject: [PATCH 099/148] - fix logging --- .../exiftool/CleanupTimerTask.java | 3 +- .../thebuzzmedia/exiftool/ExifProcess.java | 77 +++++++++++-------- .../thebuzzmedia/exiftool/ExifToolNew2.java | 5 +- .../exiftool/KeepAliveExifProxy.java | 15 ++-- .../exiftool/LineReaderThread.java | 5 +- .../java/com/thebuzzmedia/exiftool/Tag.java | 5 +- .../exiftool/adapters/ExifToolService.java | 2 +- .../thebuzzmedia/exiftool/TestExifTool.java | 14 ++-- 8 files changed, 72 insertions(+), 54 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java b/src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java index 6a0bfd41..951d73ae 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java +++ b/src/main/java/com/thebuzzmedia/exiftool/CleanupTimerTask.java @@ -13,6 +13,7 @@ * @since 1.1 */ class CleanupTimerTask extends TimerTask { + private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(CleanupTimerTask.class); private ExifToolNew2 owner; public CleanupTimerTask(ExifToolNew2 owner) throws IllegalArgumentException { @@ -25,7 +26,7 @@ public CleanupTimerTask(ExifToolNew2 owner) throws IllegalArgumentException { @Override public void run() { - ExifToolNew3.log.info("\tAuto cleanup task running..."); + LOG.info("\tAuto cleanup task running..."); owner.close(); } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index e16196d7..780835e8 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -54,10 +54,10 @@ public String toString() { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { if (!all.isEmpty()) { - ExifToolNew3.log.warn("Close all leaked processes:" + all.keySet()); + LOG.warn("Close all leaked processes:" + all.keySet()); for (Entry> item : new HashSet>>( all.entrySet())) { - ExifToolNew3.log.warn("Close leaked process " + item, new RuntimeException()); + LOG.warn("Close leaked process " + item, new RuntimeException()); item.getValue()._2.close(); } } @@ -122,7 +122,7 @@ public static ExifProcess startup(String exifCmd, Charset charset) { public ExifProcess(boolean keepAlive, List args, Charset charset) { this.keepAlive = keepAlive; - ExifToolNew3.log.debug(String.format("Attempting to start ExifToolNew3 process using args: %s", args)); + LOG.debug(String.format("Attempting to start ExifToolNew3 process using args: %s", args)); try { this.process = new ProcessBuilder(args).start(); all.put(process.toString(), new Pair(toString(new RuntimeException("start of " @@ -132,13 +132,13 @@ public ExifProcess(boolean keepAlive, List args, Charset charset) { this.errReader = new LineReaderThread("exif-process-err-reader", new BufferedReader(new InputStreamReader( process.getErrorStream()))); errReader.start(); - ExifToolNew3.log.debug("\tSuccessful " + process + " started."); + LOG.debug("\tSuccessful " + process + " started."); } catch (Exception e) { String message = "Unable to start external ExifToolNew3 process using the execution arguments: " + args + ". Ensure ExifToolNew3 is installed correctly and runs using the command path '" + args.get(0) + "' as specified by the 'exiftool.path' system property."; - ExifToolNew3.log.debug(message); + LOG.debug(message); throw new RuntimeException(message, e); } } @@ -183,17 +183,16 @@ public synchronized String readLine() throws IOException { public synchronized List readResponse(List args) throws IOException { if (closed) throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); - ExifToolNew3.log.debug("Reading response back from ExifToolNew3..."); + LOG.debug("Reading response back from ExifToolNew3..."); String line; List all = new ArrayList(); while ((line = reader.readLine()) != null) { if (closed) { - ExifToolNew3.log.info("stream closed message"); + LOG.info("stream closed message"); throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); } - ExifToolNew3.log.debug("stream line read [" + line + "]"); - all.add(line); + LOG.debug("stream line read [" + line + "]"); /* * When using a persistent ExifToolNew3 process, it terminates its output to us with a "{ready}" clause on a * new line, we need to look for it and break from this loop when we see it otherwise this process will hang @@ -202,7 +201,29 @@ public synchronized List readResponse(List args) throws IOExcept if (keepAlive && line.equals("{ready}")) { break; } + all.add(line); + } + if (all.isEmpty()) { + String error = null; + try { + while ((error = readError()) == null) { + Thread.currentThread().sleep(100); + } + } catch (InterruptedException e) { + throw new RuntimeException("Didn't get anything back from exiftool with args [" + args + "].", e); + } + String message = error + ". " + all.size() + " lines where read [" + all + "] for exiftool with args [" + + args + "]."; + // if(result.contains("No matching files")){ + throw new ExifError(message); + // }else{ + // LOG.info(message); + // } } + return all; + } + + private String readError() throws ExifError { if (errReader.hasLines()) { StringBuffer sb = new StringBuffer(); for (String error : errReader.takeLines()) { @@ -212,18 +233,10 @@ public synchronized List readResponse(List args) throws IOExcept sb.append(error); } String result = sb.toString(); - String message = result + ". " + all.size() + " lines where read [" + all + "] for exiftool with args [" - + args + "]."; - // if(result.contains("No matching files")){ - throw new ExifError(message); - // }else{ - // ExifToolNew3.log.info(message); - // } + return result; + } else { + return null; } - if (all.isEmpty()) { - throw new RuntimeException("Didn't get anything back from exiftool with args [" + args + "]."); - } - return all; } public boolean isClosed() { @@ -237,15 +250,15 @@ public void close() { if (!closed) { closed = true; try { - ExifToolNew3.log.debug("Closing Read stream..."); + LOG.debug("Closing Read stream..."); reader.close(); - ExifToolNew3.log.debug("\tSuccessful"); + LOG.debug("\tSuccessful"); } catch (Exception e) { // no-op, just try to close it. } try { - ExifToolNew3.log + LOG .debug("Attempting to close ExifToolNew3 daemon process, issuing '-stay_open\\nFalse\\n' command..."); writer.write("-stay_open\nFalse\n"); writer.flush(); @@ -254,31 +267,31 @@ public void close() { } try { - ExifToolNew3.log.debug("Closing Write stream..."); + LOG.debug("Closing Write stream..."); writer.close(); - ExifToolNew3.log.debug("\tSuccessful"); + LOG.debug("\tSuccessful"); } catch (Exception e) { // no-op, just try to close it. } try { - ExifToolNew3.log.debug("Closing Error stream..."); + LOG.debug("Closing Error stream..."); errReader.close(); - ExifToolNew3.log.debug("\tSuccessful"); + LOG.debug("\tSuccessful"); } catch (Exception e) { // no-op, just try to close it. } - ExifToolNew3.log.debug("Read/Write streams successfully closed."); + LOG.debug("Read/Write streams successfully closed."); try { - ExifToolNew3.log.debug("\tDestroy process " + process + "..."); + LOG.debug("\tDestroy process " + process + "..."); process.destroy(); all.remove(process.toString()); - ExifToolNew3.log.debug("\tDestroy process " + process + " done => " + all.keySet()); + LOG.debug("\tDestroy process " + process + " done => " + all.keySet()); } catch (Exception e) { // - ExifToolNew3.log.debug("", e); + LOG.debug("", e); } // process = null; @@ -291,7 +304,7 @@ public void close() { @Override protected void finalize() throws Throwable { - ExifToolNew3.log.debug("\tFinalize process " + process + "."); + LOG.debug("\tFinalize process " + process + "."); close(); super.finalize(); } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java index 58177b49..36a3cab4 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java @@ -158,6 +158,7 @@ * @since 1.1 */ public class ExifToolNew2 implements RawExifTool { + private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ExifToolNew2.class); /** * Flag used to indicate if debugging output has been enabled by setting the "exiftool.debug" system * property to true. This value will be false if the " exiftool.debug" system @@ -339,7 +340,7 @@ public boolean isFeatureSupported(Feature feature) throws IllegalArgumentExcepti */ protected static void log(String message, Object... params) { if (DEBUG) - ExifToolNew3.log.debug(LOG_PREFIX + message + '\n', params); + LOG.debug(LOG_PREFIX + message + '\n', params); } /** @@ -962,7 +963,7 @@ public void writeMetadata(WriteOptions options, File image, Map v @Override protected void finalize() throws Throwable { - ExifToolNew3.log.info("ExifToolNew3 not used anymore shutdown the exiftool process..."); + LOG.info("ExifToolNew3 not used anymore shutdown the exiftool process..."); shutdown(); super.finalize(); } diff --git a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java index a2ea99cd..f3df31c5 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java +++ b/src/main/java/com/thebuzzmedia/exiftool/KeepAliveExifProxy.java @@ -17,9 +17,12 @@ public class KeepAliveExifProxy implements ExifProxy { private volatile long lastRunStart = 0; private volatile ExifProcess process; private final Charset charset; + public KeepAliveExifProxy(String exifCmd, List baseArgs, long inactivityTimeoutParam) { - this(exifCmd,baseArgs,inactivityTimeoutParam,ExifToolNew3.computeDefaultCharset(EnumSet.noneOf(Feature.class))); + this(exifCmd, baseArgs, inactivityTimeoutParam, ExifToolNew3.computeDefaultCharset(EnumSet + .noneOf(Feature.class))); } + public KeepAliveExifProxy(String exifCmd, List baseArgs, Charset charset) { this(exifCmd, baseArgs, Long.getLong(ExifToolNew.ENV_EXIF_TOOL_PROCESSCLEANUPDELAY, ExifToolNew.DEFAULT_PROCESS_CLEANUP_DELAY), charset); @@ -78,8 +81,7 @@ public List execute(final long runTimeoutMills, List args) { if (process == null || process.isClosed()) { synchronized (this) { if (process == null || process.isClosed()) { - ExifToolNew3.log - .debug("Starting daemon ExifToolNew3 process and creating read/write streams (this only happens once)..."); + LOG.debug("Starting daemon ExifToolNew3 process and creating read/write streams (this only happens once)..."); process = new ExifProcess(true, startupArgs, charset); } } @@ -91,21 +93,20 @@ public List execute(final long runTimeoutMills, List args) { @Override public void run() { if (process != null && !process.isClosed()) { - ExifToolNew3.log - .warn("Process ran too long closing, max " + runTimeoutMills + " mills"); + LOG.warn("Process ran too long closing, max " + runTimeoutMills + " mills"); process.close(); } } }; cleanupTimer.schedule(attemptTimer, runTimeoutMills); } - ExifToolNew3.log.debug("Streaming arguments to ExifToolNew3 process..."); + LOG.debug("Streaming arguments to ExifToolNew3 process..."); return process.sendToRunning(args); } catch (IOException ex) { if (ExifToolNew3.STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) && !shuttingDown.get()) { // only catch "Stream Closed" error (happens when // process has died) - ExifToolNew3.log.warn(String.format("Caught IOException(\"%s\"), will restart daemon", + LOG.warn(String.format("Caught IOException(\"%s\"), will restart daemon", ExifToolNew3.STREAM_CLOSED_MESSAGE)); process.close(); } else { diff --git a/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java b/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java index 215a2348..de9e1ebf 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java +++ b/src/main/java/com/thebuzzmedia/exiftool/LineReaderThread.java @@ -20,6 +20,7 @@ * @since 7/25/14 */ public class LineReaderThread extends Thread { + private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(LineReaderThread.class); private BufferedReader reader; private BlockingQueue lineBuffer = new ArrayBlockingQueue( 50, true); @@ -46,9 +47,9 @@ public void run() { } } } catch (IOException ex) { - ExifToolNew3.log.warn("Error in LineReaderThread.",ex); + LOG.warn("Error in LineReaderThread.",ex); } catch (InterruptedException ignored) { - ExifToolNew3.log.debug("er:",ignored); + LOG.debug("er:",ignored); } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/Tag.java b/src/main/java/com/thebuzzmedia/exiftool/Tag.java index 2808aba7..cfbb4482 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/Tag.java +++ b/src/main/java/com/thebuzzmedia/exiftool/Tag.java @@ -145,6 +145,7 @@ public enum Tag implements MetadataTag { THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class), ; + private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(Tag.class); private static final Map TAG_LOOKUP_MAP; /** @@ -356,10 +357,10 @@ public static Object deserialize(String tagName, String value, Class expectedTyp return value; } } catch (ParseException ex) { - ExifToolNew3.log.warn("Invalid format, Tag:" + tagName); + LOG.warn("Invalid format, Tag:" + tagName); return null; } catch (NumberFormatException ex) { - ExifToolNew3.log.warn("Invalid format, Tag:" + tagName); + LOG.warn("Invalid format, Tag:" + tagName); return null; } diff --git a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java index 1be1c5cb..b19018e5 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java +++ b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java @@ -357,7 +357,7 @@ public static Map toMap(List all) { resultMap.put(pair[0], pair[1]); LOG.debug(String.format("\tRead Tag [name=%s, value=%s]", pair[0], pair[1])); } else { - LOG.debug(String.format("\tIgnore line [%s]", line)); + LOG.info(String.format("\tIgnore line [%s]", line)); } } return resultMap; diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 9533ad9d..7364f017 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -109,7 +109,7 @@ public void run() { for (int j = 0; j < 5; j++) { runTests(tool, label); } - log.info("DONE: " + label + " success!"); + log.debug("DONE: " + label + " success!"); } catch (IOException ex) { fail(label); } catch (URISyntaxException e) { @@ -563,8 +563,8 @@ public void testReadingUtf8NamesWithStayOpen() throws Exception { Feature.STAY_OPEN)) { URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); File imageFile = new File(url.toURI()); - System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); + //should fail on the line before. this is just for breakpoint and retry Map metadata2 = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata2.size()); } @@ -576,7 +576,7 @@ public void testReadingUtf8NamesWithStayOpenWithoutSpaces() throws Exception { Feature.STAY_OPEN)) { URL url = getClass().getResource("/20140502_152336_Östliche_Zubringerstraße.png"); File imageFile = new File(url.toURI()); - System.out.println(imageFile.getAbsolutePath()); + //System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata.size()); } @@ -587,7 +587,7 @@ public void testReadingUtf8NamesWithoutStayOpen() throws Exception { try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true))) { URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); File imageFile = new File(url.toURI()); - System.out.println(imageFile.getAbsolutePath()); + //System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata.size()); } @@ -599,7 +599,7 @@ public void testReadingUtf8NamesWithStayOpenAndWindows() throws Exception { Feature.STAY_OPEN, Feature.WINDOWS)) { URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); File imageFile = new File(url.toURI()); - System.out.println(imageFile.getAbsolutePath()); + //System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata.size()); } @@ -611,10 +611,10 @@ public void testReadingUtf8NamesOnWindows() throws Exception { Feature.STAY_OPEN, Feature.WINDOWS)) { URL url = getClass().getResource("/20131231_230955_Strada Frumoasă.png"); File imageFile = new File(url.toURI()); - System.out.println(imageFile.getAbsolutePath()); + //System.out.println(imageFile.getAbsolutePath()); Map metadata1 = tool.getImageMeta(imageFile, options); assertEquals(19, metadata1.size()); - System.out.println(metadata1); + //System.out.println(metadata1); Map metadata = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata.size()); } From 6ca642f9026a1115590188b2919bb8c4136c1553 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 23 Dec 2014 12:12:47 +0200 Subject: [PATCH 100/148] - fix logging --- .../thebuzzmedia/exiftool/ExifToolNew3.java | 45 +++++++++---------- 1 file changed, 22 insertions(+), 23 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java index 8cccd17c..9eda7674 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java @@ -183,6 +183,7 @@ * @since 1.1 */ public class ExifToolNew3 implements RawExifTool { + private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ExifToolNew3.class); private static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; private static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; @@ -204,8 +205,6 @@ public class ExifToolNew3 implements RawExifTool { static final Pattern TAG_VALUE_PATTERN = Pattern.compile("\\s*:\\s*"); static final String STREAM_CLOSED_MESSAGE = "Stream closed"; - static Logger log = LoggerFactory.getLogger(ExifToolNew3.class); - /** * The absolute path to the ExifToolNew3 executable on the host system running this class as defined by the " * exiftool.path" system property. @@ -356,7 +355,7 @@ public boolean isFeatureSupported(Feature feature) throws RuntimeException { * ExifToolNew3 install, so we need to do that. */ if (supported == null) { - log.debug("Support for feature %s has not been checked yet, checking..."); + LOG.debug("Support for feature %s has not been checked yet, checking..."); supported = feature.isSupported(exifVersion); featureSupportedMap.put(feature, supported); } @@ -380,7 +379,7 @@ private void ensureProcessRunning() { if (process == null || process.isClosed()) { synchronized (this) { if (process == null || process.isClosed()) { - log.debug("Starting daemon ExifToolNew3 process and creating read/write streams (this only happens once)..."); + LOG.debug("Starting daemon ExifToolNew3 process and creating read/write streams (this only happens once)..."); process = ExifProcess.startup(exifCmd, charset); } } @@ -394,7 +393,7 @@ private void ensureProcessRunning() { currentCleanupTask = new TimerTask() { @Override public void run() { - log.info("Auto cleanup task running..."); + LOG.info("Auto cleanup task running..."); process.close(); } }; @@ -516,8 +515,8 @@ public Map getImageMeta(File file, ReadOptions readOptions, Stri // start process long startTime = System.currentTimeMillis(); - log.debug(String.format("Querying %d tags from image: %s", tags.length, file.getAbsolutePath())); - log.info("call stayOpen="+stayOpen +" exiftool "+ Joiner.on(" ").join(args)); + LOG.debug(String.format("Querying %d tags from image: %s", tags.length, file.getAbsolutePath())); + LOG.info("call stayOpen="+stayOpen +" exiftool "+ Joiner.on(" ").join(args)); /* * Using ExifToolNew3 in daemon mode (-stay_open True) executes different code paths below. So establish the * flag for this once and it is reused a multitude of times later in this method to figure out where to branch @@ -525,16 +524,16 @@ public Map getImageMeta(File file, ReadOptions readOptions, Stri */ Map resultMap; if (stayOpen) { - log.debug("Using ExifToolNew3 in daemon mode (-stay_open True)..."); + LOG.debug("Using ExifToolNew3 in daemon mode (-stay_open True)..."); resultMap = processStayOpen(args); } else { - log.debug("Using ExifToolNew3 in non-daemon mode (-stay_open False)..."); + LOG.debug("Using ExifToolNew3 in non-daemon mode (-stay_open False)..."); resultMap = ExifToolService.toMap(execute(args)); } // Print out how long the call to external ExifToolNew3 process took. - if (log.isDebugEnabled()) { - log.debug(String.format("Image Meta Processed in %d ms [queried %d tags and found %d values]", + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Image Meta Processed in %d ms [queried %d tags and found %d values]", (System.currentTimeMillis() - startTime), tags.length, resultMap.size())); } @@ -602,7 +601,7 @@ public void addImageMetadata(File image, Map values) throws IOExc + "], ensure that the image exists at the given path and that the executing Java process has permissions to write to it."); } - log.info("Adding Tags {} to {}", values, image.getAbsolutePath()); + LOG.info("Adding Tags {} to {}", values, image.getAbsolutePath()); // start process long startTime = System.currentTimeMillis(); @@ -610,8 +609,8 @@ public void addImageMetadata(File image, Map values) throws IOExc execute(null, image, values); // Print out how long the call to external ExifToolNew3 process took. - if (log.isDebugEnabled()) { - log.debug(String.format("Image Meta Processed in %d ms [added %d tags]", + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Image Meta Processed in %d ms [added %d tags]", (System.currentTimeMillis() - startTime), values.size())); } } @@ -619,10 +618,10 @@ public void addImageMetadata(File image, Map values) throws IOExc private void execute(WriteOptions options, File image, Map values) throws IOException { final boolean stayOpen = featureSet.contains(Feature.STAY_OPEN); if (stayOpen) { - log.debug("Using ExifToolNew3 in daemon mode (-stay_open True)..."); + LOG.debug("Using ExifToolNew3 in daemon mode (-stay_open True)..."); processStayOpen(createCommandList(image.getAbsolutePath(), values, stayOpen)); } else { - log.debug("Using ExifToolNew3 in non-daemon mode (-stay_open False)..."); + LOG.debug("Using ExifToolNew3 in non-daemon mode (-stay_open False)..."); ExifProcess .executeToResults(exifCmd, createCommandList(image.getAbsolutePath(), values, stayOpen), charset); } @@ -675,19 +674,19 @@ private Map processStayOpen(List args) throws IOExceptio attemptTimer = new TimerTask() { @Override public void run() { - log.warn("Process ran too long closing, max " + timeoutWhenKeepAlive + " mills"); + LOG.warn("Process ran too long closing, max " + timeoutWhenKeepAlive + " mills"); process.close(); } }; cleanupTimer.schedule(attemptTimer, timeoutWhenKeepAlive); } - log.debug("Streaming arguments to ExifToolNew3 process..."); + LOG.debug("Streaming arguments to ExifToolNew3 process..."); return ExifToolService.toMap(process.sendArgs(args)); } catch (IOException ex) { if (STREAM_CLOSED_MESSAGE.equals(ex.getMessage()) && !shuttingDown.get()) { // only catch "Stream Closed" error (happens when process // has died) - log.warn(String.format("Caught IOException(\"%s\"), will restart daemon", STREAM_CLOSED_MESSAGE)); + LOG.warn(String.format("Caught IOException(\"%s\"), will restart daemon", STREAM_CLOSED_MESSAGE)); process.close(); } else { throw ex; @@ -705,7 +704,7 @@ public void run() { /** * Helper method used to ensure a message is loggable before it is logged and then pre-pend a universal prefix to - * all log messages generated by this library to make the log entries easy to parse visually or programmatically. + * all LOG messages generated by this library to make the LOG entries easy to parse visually or programmatically. *

* If a message cannot be logged (logging is disabled) then this method returns immediately. *

@@ -715,7 +714,7 @@ public void run() { * calculations. * * @param message - * The log message in format string * syntax that will be logged. * @param params @@ -725,7 +724,7 @@ public void run() { * @see #LOG_PREFIX */ protected static void log(String message, Object... params) { - log.debug(message, params); + LOG.debug(message, params); } @Override @@ -745,7 +744,7 @@ public void writeMetadata(WriteOptions options, File image, Map v @Override protected void finalize() throws Throwable { - log.debug("Shutdown on finalize ..."); + LOG.debug("Shutdown on finalize ..."); shutdown(); super.finalize(); } From bd723c350dc57ddc05a442132559c3f9d55fb1b7 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 23 Dec 2014 12:50:14 +0200 Subject: [PATCH 101/148] - extracting MwgTags - parsing Date fields --- .../com/thebuzzmedia/exiftool/MwgTag.java | 5 + .../java/com/thebuzzmedia/exiftool/Tag.java | 103 +++++++-------- .../exiftool/adapters/ExifToolService.java | 125 ++++++++++-------- .../thebuzzmedia/exiftool/TestExifTool.java | 6 +- 4 files changed, 124 insertions(+), 115 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java b/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java index 67f4a002..91378871 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java +++ b/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java @@ -1,6 +1,7 @@ package com.thebuzzmedia.exiftool; import java.util.Date; +import java.util.Map; // ================================================================================ public enum MwgTag implements MetadataTag { @@ -51,4 +52,8 @@ public boolean isMapped() { public String toString() { return name; } + @SuppressWarnings("unchecked") + public V2 getValue(Map metadata) { + return (V2) Tag.parseValue(this, metadata.get(this)); + } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Tag.java b/src/main/java/com/thebuzzmedia/exiftool/Tag.java index cfbb4482..da506ec1 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/Tag.java +++ b/src/main/java/com/thebuzzmedia/exiftool/Tag.java @@ -175,9 +175,11 @@ public enum Tag implements MetadataTag { public static Tag forName(String name) { return TAG_LOOKUP_MAP.get(name); } + public static Map toTagMap(Map values) { return mapByTag(values); } + private static Map mapByTag(Map stringMap) { Map tagMap = new HashMap(Tag.values().length); for (Tag tag : Tag.values()) { @@ -221,31 +223,9 @@ private static Map mapByTag(Map stringMap) * not match, a ClassCastException will be * generated by the VM. */ - @SuppressWarnings("unchecked") + @SuppressWarnings("unchecked") public T parseValue(String value) throws IllegalArgumentException { - - if (value != null) { - if (Boolean.class.isAssignableFrom(this.getType())) { - return (T) Boolean.valueOf(value); - } else if (Byte.class.isAssignableFrom(this.getType())) { - return (T) Byte.valueOf(Byte.parseByte(value)); - } else if (Integer.class.isAssignableFrom(this.getType())) { - return (T) Integer.valueOf(Integer.parseInt(value)); - } else if (Short.class.isAssignableFrom(this.getType())) { - return (T) Short.valueOf(Short.parseShort(value)); - } else if (Long.class.isAssignableFrom(this.getType())) { - return (T) Long.valueOf(Long.parseLong(value)); - } else if (Float.class.isAssignableFrom(this.getType())) { - return (T) Float.valueOf(Float.parseFloat(value)); - } else if (Double.class.isAssignableFrom(this.getType())) { - return (T) parseDouble(value); - } else if (Character.class.isAssignableFrom(this.getType())) { - return (T) Character.valueOf(value.charAt(0)); - } else if (String.class.isAssignableFrom(this.getType())) { - return (T) value; - } - } - return null; + return parseValue((Class)getType(),value); } public String getRawValue(Map metadata) { @@ -253,50 +233,61 @@ public String getRawValue(Map metadata) { } @SuppressWarnings("unchecked") - public T getValue(Map metadata) { - return (T) parseValue(this, metadata.get(this)); + public V2 getValue(Map metadata) { + return (V2) parseValue(this, metadata.get(this)); } + @SuppressWarnings("unchecked") - public static T parseValue(Tag tag, Object value) - throws IllegalArgumentException, NumberFormatException { + public static T parseValue(MetadataTag tag, Object value) throws IllegalArgumentException, + NumberFormatException { if (tag == null) throw new IllegalArgumentException("tag cannot be null"); + Class type = tag.getType(); + return parseValue(type, value); + } + @SuppressWarnings("unchecked") + public static T parseValue(Class type, Object value) throws IllegalArgumentException, NumberFormatException { T result = null; - - // Check that there is work to do first. - if (value != null) { - Class type = tag.type; - if (type == value.getClass()) { - result = (T) value; - } else if (Boolean.class.isAssignableFrom(type)) - result = (T) Boolean.valueOf(value.toString()); - else if (Byte.class.isAssignableFrom(type)) - result = (T) Byte.valueOf(Byte.parseByte(value.toString())); - else if (Integer.class.isAssignableFrom(type)) - result = (T) Integer.valueOf(Integer.parseInt(value.toString())); - else if (Short.class.isAssignableFrom(type)) - result = (T) Short.valueOf(Short.parseShort(value.toString())); - else if (Long.class.isAssignableFrom(type)) - result = (T) Long.valueOf(Long.parseLong(value.toString())); - else if (Float.class.isAssignableFrom(type)) - result = (T) new Float(parseDouble(value.toString()).floatValue()); - else if (Double.class.isAssignableFrom(type)) - result = (T) parseDouble(value.toString()); - else if (Character.class.isAssignableFrom(type)) - result = (T) Character.valueOf(value.toString().charAt(0)); - else if (String.class.isAssignableFrom(type)) - result = (T) value.toString(); - } - + if (value == null) { + //nothing to do + } else if (type == value.getClass()) { + result = (T) value; + } else if (Boolean.class.isAssignableFrom(type)) + result = (T) Boolean.valueOf(value.toString()); + else if (Byte.class.isAssignableFrom(type)) + result = (T) Byte.valueOf(Byte.parseByte(value.toString())); + else if (Integer.class.isAssignableFrom(type)) + result = (T) Integer.valueOf(Integer.parseInt(value.toString())); + else if (Short.class.isAssignableFrom(type)) + result = (T) Short.valueOf(Short.parseShort(value.toString())); + else if (Long.class.isAssignableFrom(type)) + result = (T) Long.valueOf(Long.parseLong(value.toString())); + else if (Float.class.isAssignableFrom(type)) + result = (T) new Float(parseDouble(value.toString()).floatValue()); + else if (Double.class.isAssignableFrom(type)) + result = (T) parseDouble(value.toString()); + else if (Character.class.isAssignableFrom(type)) + result = (T) Character.valueOf(value.toString().charAt(0)); + else if (String.class.isAssignableFrom(type)) + result = (T) value.toString(); + else if (Date.class.equals(type)) { + SimpleDateFormat formatter = new SimpleDateFormat(ExifToolNew.EXIF_DATE_FORMAT); + try { + result = (T) formatter.parse((String) value); + } catch (ParseException e) { + throw new RuntimeException("Can't parse value " + value + " with format [" + + ExifToolNew.EXIF_DATE_FORMAT + "].", e); + } + } else + result = (T) value; return result; } private static Double parseDouble(String in) { if (in.contains("/")) { String[] enumeratorAndDivisor = in.split("/"); - return Double.parseDouble(enumeratorAndDivisor[0]) - / Double.parseDouble(enumeratorAndDivisor[1]); + return Double.parseDouble(enumeratorAndDivisor[0]) / Double.parseDouble(enumeratorAndDivisor[1]); } else { return Double.parseDouble(in); } diff --git a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java index b19018e5..68d5690a 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java +++ b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java @@ -27,18 +27,19 @@ public ExifToolService(RawExifTool exifTool) { public Map getImageMeta2(File image, ReadOptions options, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { Map all = getImageMeta(image, options, toKeys(tags)); - return (Map) toMetadataTagKeys(all); + return (Map) toMetadataTagKeys(all, tags); } -// -// public Map getImageMeta2c(File file, ReadOptions options, MetadataTag... tags) -// throws IllegalArgumentException, SecurityException, IOException { -// return getImageMeta6(file, options, tags); -// } -// -// public Map getImageMeta2b(File image, ReadOptions options, MetadataTag... tags) -// throws IllegalArgumentException, SecurityException, IOException { -// return (Map) getImageMeta3(image, options, tags); -// } + + // + // public Map getImageMeta2c(File file, ReadOptions options, MetadataTag... tags) + // throws IllegalArgumentException, SecurityException, IOException { + // return getImageMeta6(file, options, tags); + // } + // + // public Map getImageMeta2b(File image, ReadOptions options, MetadataTag... tags) + // throws IllegalArgumentException, SecurityException, IOException { + // return (Map) getImageMeta3(image, options, tags); + // } public Map getImageMeta3(File image, ReadOptions options, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { @@ -47,34 +48,37 @@ public Map getImageMeta3(File image, ReadOptions options, M public Map getImageMeta4d(File image, ReadOptions options, MetadataTag... tags) throws IllegalArgumentException, SecurityException, IOException { - return toMetadataTagKeys(getImageMeta(image, options, toKeys(tags))); + return toMetadataTagKeys(getImageMeta(image, options, toKeys(tags)), tags); } -// -// public Map getImageMeta4c(File file, ReadOptions options, Format format, MetadataTag... tags) -// throws IllegalArgumentException, SecurityException, IOException { -// Map result = getImageMeta6(file, options, tags); -// // since meta tags are passed we will have a proper Map result -// return (Map) result; -// } -// -// public Map getImageMeta4b(File image, ReadOptions options, Format format, MetadataTag... tags) -// throws IllegalArgumentException, SecurityException, IOException { -// if (tags == null) { -// tags = new MetadataTag[0]; -// } -// String[] stringTags = new String[tags.length]; -// int i = 0; -// for (MetadataTag tag : tags) { -// stringTags[i++] = tag.getKey(); -// } -// Map result = exifTool.getImageMeta(image, new ReadOptions().withNumericOutput(format) -// .withShowDuplicates(!true), stringTags); -// ReadOptions readOptions = new ReadOptions().withConvertTypes(true).withNumericOutput( -// format.equals(Format.NUMERIC)); -// return (Map) convertToMetadataTags(readOptions, result, tags); -// // map only known values? -// // return Tag.toTagMap(result); -// } + + // + // public Map getImageMeta4c(File file, ReadOptions options, Format format, MetadataTag... + // tags) + // throws IllegalArgumentException, SecurityException, IOException { + // Map result = getImageMeta6(file, options, tags); + // // since meta tags are passed we will have a proper Map result + // return (Map) result; + // } + // + // public Map getImageMeta4b(File image, ReadOptions options, Format format, MetadataTag... + // tags) + // throws IllegalArgumentException, SecurityException, IOException { + // if (tags == null) { + // tags = new MetadataTag[0]; + // } + // String[] stringTags = new String[tags.length]; + // int i = 0; + // for (MetadataTag tag : tags) { + // stringTags[i++] = tag.getKey(); + // } + // Map result = exifTool.getImageMeta(image, new ReadOptions().withNumericOutput(format) + // .withShowDuplicates(!true), stringTags); + // ReadOptions readOptions = new ReadOptions().withConvertTypes(true).withNumericOutput( + // format.equals(Format.NUMERIC)); + // return (Map) convertToMetadataTags(readOptions, result, tags); + // // map only known values? + // // return Tag.toTagMap(result); + // } public Map getImageMeta5(File image, ReadOptions options, Format format, TagGroup... tags) throws IllegalArgumentException, SecurityException, IOException { @@ -120,18 +124,18 @@ public Map getImageMeta5(File image, ReadOptions options, Format // } // @Override -// public Map getImageMeta5b(File image, ReadOptions options, Format format, TagGroup... tags) -// throws IllegalArgumentException, SecurityException, IOException { -// if (tags == null) { -// tags = new TagGroup[0]; -// } -// String[] stringTags = new String[tags.length]; -// int i = 0; -// for (TagGroup tag : tags) { -// stringTags[i++] = tag.getKey(); -// } -// return exifTool.getImageMeta(image, options.withNumericOutput(format).withShowDuplicates(false), stringTags); -// } + // public Map getImageMeta5b(File image, ReadOptions options, Format format, TagGroup... tags) + // throws IllegalArgumentException, SecurityException, IOException { + // if (tags == null) { + // tags = new TagGroup[0]; + // } + // String[] stringTags = new String[tags.length]; + // int i = 0; + // for (TagGroup tag : tags) { + // stringTags[i++] = tag.getKey(); + // } + // return exifTool.getImageMeta(image, options.withNumericOutput(format).withShowDuplicates(false), stringTags); + // } public Map getImageMeta6(File file, ReadOptions options, Object... tags) throws IOException { return getImageMeta7(file, options, tags); @@ -302,13 +306,22 @@ static MetadataTag toTag(String name) { return new CustomTag(name, String.class); } - private Map toMetadataTagKeys(Map all) { + private Map toMetadataTagKeys(Map all, MetadataTag... tags) { Map result = new HashMap(); - for (Entry entry : all.entrySet()) { - MetadataTag tag = toTag(entry.getKey()); - //if (tag != null) { - result.put(tag, entry.getValue()); - //} + if (tags == null | tags.length == 0) { + for (Entry entry : all.entrySet()) { + MetadataTag tag = toTag(entry.getKey()); + // if (tag != null) { + result.put(tag, entry.getValue()); + // } + } + } else { + for (MetadataTag tag : tags) { + String value = all.get(tag.getKey()); + if (value != null) { + result.put(tag, value); + } + } } return result; } diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 7364f017..700060ee 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -518,11 +518,11 @@ public void testWritingWithImplicitTypes() throws Exception { // Test what orientation value is at the start SimpleDateFormat formatter = new SimpleDateFormat("yyyy:MM:dd hh:mm:ss"); - Map metadata = tool.getImageMeta2(imageFile, options, Tag.ORIENTATION, + Map metadata = tool.getImageMeta2(imageFile, options.withNumericOutput(true), Tag.ORIENTATION, MwgTag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", 1, metadata.get(Tag.ORIENTATION)); + assertEquals("Orientation tag starting value is wrong", 1, Tag.ORIENTATION.getValue(metadata)); assertEquals("Wrong starting value", formatter.parse("2010:12:10 17:07:05"), - metadata.get(MwgTag.DATE_TIME_ORIGINAL)); + MwgTag.DATE_TIME_ORIGINAL.getValue(metadata)); // Now change them Map data = new HashMap(); From 2abda22bf667a9d2747c810415cd360ff1d89119 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Wed, 24 Dec 2014 10:16:25 +0200 Subject: [PATCH 102/148] - fix all 21 tests - log the way exiftool is called - properly encode tags that contains list of strings - encode MwgTags, TagGroup as well. - simplify tests --- .../com/thebuzzmedia/exiftool/CustomTag.java | 5 + .../com/thebuzzmedia/exiftool/ExifError.java | 7 +- .../thebuzzmedia/exiftool/ExifProcess.java | 3 +- .../thebuzzmedia/exiftool/ExifToolNew3.java | 76 ++++---- .../thebuzzmedia/exiftool/MetadataTag.java | 2 + .../com/thebuzzmedia/exiftool/MwgTag.java | 5 + .../java/com/thebuzzmedia/exiftool/Tag.java | 159 +++++++++------- .../com/thebuzzmedia/exiftool/TagGroup.java | 4 + .../thebuzzmedia/exiftool/TestExifTool.java | 177 +++++------------- 9 files changed, 201 insertions(+), 237 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/CustomTag.java b/src/main/java/com/thebuzzmedia/exiftool/CustomTag.java index 076cb40b..d927dd6f 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/CustomTag.java +++ b/src/main/java/com/thebuzzmedia/exiftool/CustomTag.java @@ -37,4 +37,9 @@ public boolean isMapped() { public String toString() { return getKey(); } + + @Override + public String toExif(T value) { + return Tag.toExif(this, value); + } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifError.java b/src/main/java/com/thebuzzmedia/exiftool/ExifError.java index baa55006..8f59325a 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifError.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifError.java @@ -1,6 +1,5 @@ package com.thebuzzmedia.exiftool; -import java.io.IOException; /** * Represents an error from the ExifToolNew3 @@ -10,8 +9,12 @@ * @version $Revision$ $LastChangedDate$ * @since 7/25/14 */ -public class ExifError extends IOException { +public class ExifError extends RuntimeException { public ExifError(String message) { super(message); } + + public ExifError(String message, Throwable cause) { + super(message, cause); + } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index 780835e8..b4f9d5d8 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -124,6 +124,7 @@ public ExifProcess(boolean keepAlive, List args, Charset charset) { this.keepAlive = keepAlive; LOG.debug(String.format("Attempting to start ExifToolNew3 process using args: %s", args)); try { + LOG.info("start background process: "+Joiner.on(" ").join(args)); this.process = new ProcessBuilder(args).start(); all.put(process.toString(), new Pair(toString(new RuntimeException("start of " + process)), this)); @@ -162,7 +163,7 @@ public synchronized List sendArgs(List args) throws IOException builder.append(arg).append("\n"); } builder.append("-execute\n"); - LOG.debug("sendArgs(\n" + builder.toString() + "\n)"); + LOG.info("exiftool " + Joiner.on(" ").join(args)); writeFlush(builder.toString()); return readResponse(args); } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java index 9eda7674..a1a5098d 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java @@ -20,19 +20,7 @@ import java.io.FileWriter; import java.io.IOException; import java.nio.charset.Charset; -import java.util.ArrayList; -import java.util.Arrays; -import java.util.Collection; -import java.util.Collections; -import java.util.EnumSet; -import java.util.HashMap; -import java.util.HashSet; -import java.util.List; -import java.util.Map; -import java.util.Set; -import java.util.StringTokenizer; -import java.util.Timer; -import java.util.TimerTask; +import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; @@ -43,6 +31,7 @@ import com.google.common.base.CharMatcher; import com.google.common.base.Joiner; +import com.google.common.collect.Lists; import com.thebuzzmedia.exiftool.adapters.ExifToolService; /** @@ -516,7 +505,7 @@ public Map getImageMeta(File file, ReadOptions readOptions, Stri // start process long startTime = System.currentTimeMillis(); LOG.debug(String.format("Querying %d tags from image: %s", tags.length, file.getAbsolutePath())); - LOG.info("call stayOpen="+stayOpen +" exiftool "+ Joiner.on(" ").join(args)); + LOG.info("call stayOpen=" + stayOpen + " exiftool " + Joiner.on(" ").join(args)); /* * Using ExifToolNew3 in daemon mode (-stay_open True) executes different code paths below. So establish the * flag for this once and it is reused a multitude of times later in this method to figure out where to branch @@ -628,36 +617,50 @@ private void execute(WriteOptions options, File image, Map values } private List createCommandList(String filename, Map values, boolean stayOpen) { - List args = new ArrayList(64); - for (Map.Entry entry : values.entrySet()) { - // works only for Tags - Tag tag = (Tag) entry.getKey(); + MetadataTag tag = (MetadataTag) entry.getKey(); Object value = entry.getValue(); - - StringBuilder arg = new StringBuilder(); - arg.append("-").append(tag.getKey()); - if (value instanceof Number) { - arg.append("#"); - } - arg.append("="); - if (value != null) { - // if (value instanceof String && !stayOpen) { - // arg.append("\"").append(value.toString()).append("\""); - // } else { - arg.append(value.toString()); - // } - } - args.add(arg.toString()); - + args.addAll(toRawData(tag, value)); } - args.add(filename); return args; } + private List toRawData(MetadataTag tag, Object value) { + if (tag.getType().equals(String[].class)) { + List result = new LinkedList(); + String[] array = (String[])value; + for (String value2 : array) { + String raw = getRawExif(tag, value2); + result.add(raw); + } + return result; + } else { + String raw = getRawExif(tag, value); + return Lists.newArrayList(raw); + } + } + + private String getRawExif(MetadataTag tag, Object value) { + StringBuilder arg = new StringBuilder(); + arg.append("-").append(tag.getKey()); + if (value instanceof Number) { + arg.append("#"); + } + arg.append("="); + if (value != null) { + // if (value instanceof String && !stayOpen) { + // arg.append("\"").append(value.toString()).append("\""); + // } else { + arg.append(tag.toExif(value)); + // } + } + String raw = arg.toString(); + return raw; + } + /** * Will attempt 3 times to use the running exif process, and if unable to complete successfully will throw * IOException @@ -739,7 +742,8 @@ public void rebuildMetadata(WriteOptions options, File file) throws IOException @Override public void writeMetadata(WriteOptions options, File image, Map values) throws IOException { - throw new RuntimeException("Not implemented."); + addImageMetadata(image, values); + // throw new RuntimeException("Not implemented."); } @Override diff --git a/src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java b/src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java index 8915f8a4..8a3a83ba 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java +++ b/src/main/java/com/thebuzzmedia/exiftool/MetadataTag.java @@ -19,4 +19,6 @@ public interface MetadataTag { public Class getType(); public boolean isMapped(); + + public String toExif(T value); } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java b/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java index 91378871..6972caa9 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java +++ b/src/main/java/com/thebuzzmedia/exiftool/MwgTag.java @@ -56,4 +56,9 @@ public String toString() { public V2 getValue(Map metadata) { return (V2) Tag.parseValue(this, metadata.get(this)); } + + @Override + public String toExif(T value) { + return Tag.toExif(this, value); + } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/Tag.java b/src/main/java/com/thebuzzmedia/exiftool/Tag.java index da506ec1..38db36ab 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/Tag.java +++ b/src/main/java/com/thebuzzmedia/exiftool/Tag.java @@ -6,48 +6,39 @@ import java.util.HashMap; import java.util.Map; +import com.google.common.base.Joiner; +import com.google.common.base.Splitter; + // ================================================================================ /** - * Enum used to pre-define a convenient list of tags that can be easily - * extracted from images using this class with an external install of - * ExifToolNew3. + * Enum used to pre-define a convenient list of tags that can be easily extracted from images using this class with an + * external install of ExifToolNew3. *

- * Each tag defined also includes a type hint for the parsed value - * associated with it when the default {@link Format#NUMERIC} value format - * is used. + * Each tag defined also includes a type hint for the parsed value associated with it when the default + * {@link Format#NUMERIC} value format is used. *

- * All replies from ExifToolNew3 are parsed as {@link String}s and using the - * type hint from each {@link Tag} can easily be converted to the correct - * data format by using the provided {@link Tag#parseValue(String)} method. + * All replies from ExifToolNew3 are parsed as {@link String}s and using the type hint from each {@link Tag} can easily + * be converted to the correct data format by using the provided {@link Tag#parseValue(String)} method. *

- * This class does not make an attempt at converting the value automatically - * in case the caller decides they would prefer tag values returned in - * {@link Format#HUMAN_READABLE} format and to avoid any compatibility - * issues with future versions of ExifToolNew3 if a tag's return value is - * changed. This approach to leaving returned tag values as strings until - * the caller decides they want to parse them is a safer and more robust - * approach. + * This class does not make an attempt at converting the value automatically in case the caller decides they would + * prefer tag values returned in {@link Format#HUMAN_READABLE} format and to avoid any compatibility issues with future + * versions of ExifToolNew3 if a tag's return value is changed. This approach to leaving returned tag values as strings + * until the caller decides they want to parse them is a safer and more robust approach. *

* The types provided by each tag are merely a hint based on the ExifToolNew3 Tag Guide by Phil Harvey; the caller is free to parse or - * process the returned {@link String} values any way they wish. + * href="http://www.sno.phy.queensu.ca/~phil/exiftool/TagNames/index.html" >ExifToolNew3 Tag Guide by Phil Harvey; + * the caller is free to parse or process the returned {@link String} values any way they wish. *

Tag Support

- * ExifToolNew3 is capable of parsing almost every tag known to man (1000+), but - * this class makes an attempt at pre-defining a convenient list of the most - * common tags for use. + * ExifToolNew3 is capable of parsing almost every tag known to man (1000+), but this class makes an attempt at + * pre-defining a convenient list of the most common tags for use. *

- * This list was determined by looking at the common metadata tag values - * written to images by popular mobile devices (iPhone, Android) as well as - * cameras like simple point and shoots as well as DSLRs. As an additional - * source of input the list of supported/common EXIF formats that Flickr - * supports was also reviewed to ensure the most common/useful tags were - * being covered here. + * This list was determined by looking at the common metadata tag values written to images by popular mobile devices + * (iPhone, Android) as well as cameras like simple point and shoots as well as DSLRs. As an additional source of input + * the list of supported/common EXIF formats that Flickr supports was also reviewed to ensure the most common/useful + * tags were being covered here. *

- * Please email me or file an issue - * if you think this list is missing a commonly used tag that should be - * added to it. + * Please email me or file an issue if you think this list + * is missing a commonly used tag that should be added to it. * * @author Riyad Kalla (software@thebuzzmedia.com) * @since 1.1 @@ -142,15 +133,13 @@ public enum Tag implements MetadataTag { // actually binary data, but what are we doing to do here??? Just use to // save to file... THUMBNAIL_IMAGE("ThumbnailImage", String.class), - THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class), - ; + THUMBNAIL_PHOTOSHOP("PhotoshopThumbnail", String.class), ; private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(Tag.class); private static final Map TAG_LOOKUP_MAP; /** - * Initializer used to init the static final tag/name lookup - * map used by all instances of this class. + * Initializer used to init the static final tag/name lookup map used by all instances of this class. */ static { Tag[] values = Tag.values(); @@ -163,14 +152,13 @@ public enum Tag implements MetadataTag { } /** - * Used to get the {@link Tag} identified by the given, case-sensitive, tag - * name. + * Used to get the {@link Tag} identified by the given, case-sensitive, tag name. * * @param name * The case-sensitive name of the tag that will be searched for. * - * @return the {@link Tag} identified by the given, case-sensitive, tag name - * or null if one couldn't be found. + * @return the {@link Tag} identified by the given, case-sensitive, tag name or null if one couldn't be + * found. */ public static Tag forName(String name) { return TAG_LOOKUP_MAP.get(name); @@ -191,41 +179,33 @@ private static Map mapByTag(Map stringMap) } /** - * Convenience method used to convert the given string Tag value - * (returned from the external ExifToolNew3 process) into the type described - * by the associated {@link Tag}. + * Convenience method used to convert the given string Tag value (returned from the external ExifToolNew3 process) + * into the type described by the associated {@link Tag}. * * @param * The type of the returned value. * @param value - * The {@link String} representation of the tag's value as - * parsed from the image. + * The {@link String} representation of the tag's value as parsed from the image. * - * @return the given string value converted to a native Java type (e.g. - * Integer, Double, etc.). + * @return the given string value converted to a native Java type (e.g. Integer, Double, etc.). * * @throws IllegalArgumentException * if tag is null. * @throws NumberFormatException - * if any exception occurs while trying to parse the given - * value to any of the supported numeric types - * in Java via calls to the respective parseXXX - * methods defined on all the numeric wrapper classes (e.g. - * {@link Integer#parseInt(String)} , - * {@link Double#parseDouble(String)} and so on). + * if any exception occurs while trying to parse the given value to any of the supported + * numeric types in Java via calls to the respective parseXXX methods defined on all the + * numeric wrapper classes (e.g. {@link Integer#parseInt(String)} , {@link Double#parseDouble(String)} + * and so on). * @throws ClassCastException - * if the type defined by T is incompatible - * with the type defined by {@link Tag#getType()} returned - * by the tag argument passed in. This class - * performs an implicit/unchecked cast to the type - * T before returning the parsed result of the - * type indicated by {@link Tag#getType()}. If the types do - * not match, a ClassCastException will be - * generated by the VM. + * if the type defined by T is incompatible with the type defined by {@link Tag#getType()} + * returned by the tag argument passed in. This class performs an implicit/unchecked cast + * to the type T before returning the parsed result of the type indicated by + * {@link Tag#getType()}. If the types do not match, a ClassCastException will be generated + * by the VM. */ @SuppressWarnings("unchecked") public T parseValue(String value) throws IllegalArgumentException { - return parseValue((Class)getType(),value); + return parseValue((Class) getType(), value); } public String getRawValue(Map metadata) { @@ -246,11 +226,42 @@ public static T parseValue(MetadataTag tag, Object value) throws IllegalArgu return parseValue(type, value); } + @SuppressWarnings("unchecked") + public static String toExif(MetadataTag tag, Object value) throws IllegalArgumentException, + NumberFormatException { + String result = null; + if (value == null) { + // nothing to do + } else { + Class type = tag.getType(); + if (Date.class.equals(type)) { + if (!Date.class.equals(value.getClass())) { + value = parseValue(tag, value); + } + SimpleDateFormat formatter = new SimpleDateFormat(ExifToolNew.EXIF_DATE_FORMAT); + try { + result = formatter.format(value); + } catch (IllegalArgumentException e) { + throw new ExifError("Cannot convert [" + value + "] of type " + value.getClass() + + " to date using formatter [" + ExifToolNew.EXIF_DATE_FORMAT + "]", e); + } + } else if (String[].class.equals(type)) { + // @see http://www.sno.phy.queensu.ca/~phil/exiftool/faq.html - 17. + // "List-type tags do not behave as expected" + // result = Joiner.on(", ").join((String[])value); + result = value.toString(); + } else { + result = value.toString(); + } + } + return result; + } + @SuppressWarnings("unchecked") public static T parseValue(Class type, Object value) throws IllegalArgumentException, NumberFormatException { T result = null; if (value == null) { - //nothing to do + // nothing to do } else if (type == value.getClass()) { result = (T) value; } else if (Boolean.class.isAssignableFrom(type)) @@ -271,13 +282,22 @@ else if (Character.class.isAssignableFrom(type)) result = (T) Character.valueOf(value.toString().charAt(0)); else if (String.class.isAssignableFrom(type)) result = (T) value.toString(); - else if (Date.class.equals(type)) { + else if (String[].class.equals(type)) { + // @see http://www.sno.phy.queensu.ca/~phil/exiftool/faq.html - 17. + // "List-type tags do not behave as expected" + result = (T) Splitter.on(", ").splitToList(value.toString()).toArray(new String[0]); + } else if (Date.class.equals(type)) { SimpleDateFormat formatter = new SimpleDateFormat(ExifToolNew.EXIF_DATE_FORMAT); try { - result = (T) formatter.parse((String) value); + result = (T) formatter.parse(value.toString()); } catch (ParseException e) { - throw new RuntimeException("Can't parse value " + value + " with format [" - + ExifToolNew.EXIF_DATE_FORMAT + "].", e); + try { + long value2 = Long.parseLong(value.toString()); + result = (T)new Date(value2); + } catch (NumberFormatException e2) { + throw new ExifError("Can't parse value " + value + " with format [" + + ExifToolNew.EXIF_DATE_FORMAT + "] and neither as a number of miliseconds from ["+new Date(0)+"].", e); + } } } else result = (T) value; @@ -395,4 +415,9 @@ private Tag(String key, Class type) { this.key = key; this.type = type; } + + @Override + public String toExif(T value) { + return toExif(this, value); + } } \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java b/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java index c90a9cd7..190065ec 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java +++ b/src/main/java/com/thebuzzmedia/exiftool/TagGroup.java @@ -40,4 +40,8 @@ public boolean isMapped() { return false; } + @Override + public String toExif(T value) { + return Tag.toExif(this, value); + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 700060ee..4d0ad493 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -14,6 +14,7 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; +import com.google.common.base.Joiner; import com.thebuzzmedia.exiftool.adapters.ExifToolService; /** @@ -219,16 +220,6 @@ public void testWriteTagStringNonDaemon() throws Exception { metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is - // not - // affected by the change - // URL backup_url = getClass().getResource( - // "/nexus-s-electric-cars.jpg_original"); - // Path backupFile = Paths.get(backup_url.toURI()); - // - // Files.move(backupFile, imageFile, - // StandardCopyOption.REPLACE_EXISTING); } } @@ -256,56 +247,37 @@ public void testWriteTagString() throws Exception { metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is - // not - // affected by the change - // URL backup_url = getClass().getResource( - // "/nexus-s-electric-cars.jpg_original"); - // Path backupFile = Paths.get(backup_url.toURI()); - // Files.move(backupFile, imageFile, - // StandardCopyOption.REPLACE_EXISTING); - // } } - @Test + @Test(expected=ExifError.class) public void testWriteTagStringInvalidformat() throws Exception { try (ExifToolService tool = create(Feature.STAY_OPEN)) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); - MetadataTag[] tags = { Tag.DATE_TIME_ORIGINAL }; + Files.copy(Paths.get(getClass().getResource("/nexus-s-electric-cars.jpg").toURI()), imageFile, + StandardCopyOption.REPLACE_EXISTING); // Check the value is correct at the start Map metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.DATE_TIME_ORIGINAL); + String initial = "2010:12:10 17:07:05"; + assertEquals("Wrong starting value", initial, Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); String newDate = "2egek opkpgrpok"; Map newValues = new HashMap(); newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - - // Now change it to an invalid value which should fail - tool.addImageMetadata(imageFile.toFile(), newValues); - MetadataTag[] tags1 = { Tag.DATE_TIME_ORIGINAL }; - + ExifError error = null; + try { + // Now change it to an invalid value which should fail + tool.addImageMetadata(imageFile.toFile(), newValues); + } catch (ExifError e) { + error = e; + } // Finally check that it's not updated metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("DateTimeOriginal tag is wrong", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is - // not - // affected by the change - // URL backup_url = getClass().getResource( - // "/nexus-s-electric-cars.jpg_original"); - // // might not exist - // if (backup_url != null) { - // Path backupFile = Paths.get(backup_url.toURI()); - // Files.move(backupFile, imageFile, - // StandardCopyOption.REPLACE_EXISTING); - // } + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", initial, Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); + throw error; } } @@ -334,16 +306,6 @@ public void testWriteTagNumberNonDaemon() throws Exception { metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is - // not - // affected by the change - // URL backup_url = getClass().getResource( - // "/nexus-s-electric-cars.jpg_original"); - // Path backupFile = Paths.get(backup_url.toURI()); - // - // Files.move(backupFile, imageFile, - // StandardCopyOption.REPLACE_EXISTING); } } @@ -372,33 +334,22 @@ public void testWriteTagNumber() throws Exception { metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); - - // Finally copy the source file back over so the next test run is - // not - // affected by the change - // URL backup_url = getClass().getResource( - // "/nexus-s-electric-cars.jpg_original"); - // Path backupFile = Paths.get(backup_url.toURI()); - // - // Files.move(backupFile, imageFile, - // StandardCopyOption.REPLACE_EXISTING); } } @Test public void testWriteMulipleTag() throws Exception { try (ExifToolService tool = create(Feature.STAY_OPEN)) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); - MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; - + Files.copy(Paths.get(getClass().getResource("/nexus-s-electric-cars.jpg").toURI()), imageFile, + StandardCopyOption.REPLACE_EXISTING); // Test what orientation value is at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + Map metadata = tool + .getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), + Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", - metadata.get(Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); + Tag.ORIENTATION.getRawValue(metadata)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); // Now change them String newDate = "2014:01:23 10:07:05"; @@ -407,21 +358,13 @@ public void testWriteMulipleTag() throws Exception { newValues.put(Tag.ORIENTATION, 3); tool.addImageMetadata(imageFile.toFile(), newValues); - MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; // Finally check the updated value - metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not - // affected by the change - // URL backup_url = getClass().getResource( - // "/nexus-s-electric-cars.jpg_original"); - // Path backupFile = Paths.get(backup_url.toURI()); - // - // Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); + metadata = tool + .getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), + Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", Tag.ORIENTATION.getRawValue(metadata)); + assertEquals("DateTimeOriginal tag is wrong", newDate, Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); } } @@ -454,14 +397,6 @@ public void testWriteMulipleTagNonDaemon() throws Exception { new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not - // affected by the change - // URL backup_url = getClass().getResource( - // "/nexus-s-electric-cars.jpg_original"); - // Path backupFile = Paths.get(backup_url.toURI()); - // - // Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); } } @@ -495,14 +430,6 @@ public void testWriteMultipleTagNonDaemon2() throws Exception { new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Finally copy the source file back over so the next test run is not - // affected by the change - // URL backup_url = getClass().getResource( - // "/nexus-s-electric-cars.jpg_original"); - // Path backupFile = Paths.get(backup_url.toURI()); - // - // Files.move(backupFile, imageFile, StandardCopyOption.REPLACE_EXISTING); } } @@ -510,16 +437,14 @@ public void testWriteMultipleTagNonDaemon2() throws Exception { public void testWritingWithImplicitTypes() throws Exception { try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), Feature.MWG_MODULE)) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); Path imagePath = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()), imagePath, StandardCopyOption.REPLACE_EXISTING); + Files.copy(Paths.get(getClass().getResource("/nexus-s-electric-cars.jpg").toURI()), imagePath, StandardCopyOption.REPLACE_EXISTING); File imageFile = imagePath.toFile(); - // try { // Test what orientation value is at the start SimpleDateFormat formatter = new SimpleDateFormat("yyyy:MM:dd hh:mm:ss"); - Map metadata = tool.getImageMeta2(imageFile, options.withNumericOutput(true), Tag.ORIENTATION, - MwgTag.DATE_TIME_ORIGINAL); + Map metadata = tool.getImageMeta2(imageFile, options.withNumericOutput(true), + Tag.ORIENTATION, MwgTag.DATE_TIME_ORIGINAL); assertEquals("Orientation tag starting value is wrong", 1, Tag.ORIENTATION.getValue(metadata)); assertEquals("Wrong starting value", formatter.parse("2010:12:10 17:07:05"), MwgTag.DATE_TIME_ORIGINAL.getValue(metadata)); @@ -535,25 +460,15 @@ public void testWritingWithImplicitTypes() throws Exception { tool.writeMetadata(new WriteOptions().withDeleteBackupFile(false), imageFile, data); // Finally check the updated value - metadata = tool.getImageMeta6(imageFile, options, Tag.ORIENTATION, imageFile, MwgTag.DATE_TIME_ORIGINAL, + metadata = tool.getImageMeta6(imageFile, options.withNumericOutput(true), Tag.ORIENTATION, imageFile, MwgTag.DATE_TIME_ORIGINAL, MwgTag.CREATE_DATE, MwgTag.KEYWORDS); - assertEquals("Orientation tag updated value is wrong", 3, metadata.get(Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, metadata.get(MwgTag.DATE_TIME_ORIGINAL)); - assertEquals("CreateDate tag is wrong", createDate, metadata.get(MwgTag.CREATE_DATE)); - assertEquals("Keywords tag is wrong", "a", ((String[]) metadata.get(MwgTag.KEYWORDS))[0]); - - // Finally copy the source file back over so the next test run is - // not affected by the change - - // } finally { - // URL backup_url = getClass().getResource( - // "/nexus-s-electric-cars.jpg_original"); - // if (backup_url != null) { - // Path backupFile = Paths.get(backup_url.toURI()); - // Files.move(backupFile, imageFile.toPath(), - // StandardCopyOption.REPLACE_EXISTING); - // } - + assertEquals("Orientation tag updated value is wrong", 3, Tag.ORIENTATION.getValue(metadata)); + assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, MwgTag.DATE_TIME_ORIGINAL.getValue(metadata)); + assertEquals("CreateDate tag is wrong", createDate, MwgTag.CREATE_DATE.getValue(metadata)); + assertEquals("Keywords tag is wrong", "a", ((String[]) MwgTag.KEYWORDS.getValue(metadata))[0]); + List keys = Arrays.asList(((String[]) MwgTag.KEYWORDS.getValue(metadata))); + assertEquals("Keywords tag is wrong", 3, keys.size()); + assertEquals("Keywords tag is wrong", "a:b:c", Joiner.on(":").join(keys)); } } @@ -564,7 +479,7 @@ public void testReadingUtf8NamesWithStayOpen() throws Exception { URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); File imageFile = new File(url.toURI()); Map metadata = tool.getImageMeta3(imageFile, options); - //should fail on the line before. this is just for breakpoint and retry + // should fail on the line before. this is just for breakpoint and retry Map metadata2 = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata2.size()); } @@ -576,7 +491,7 @@ public void testReadingUtf8NamesWithStayOpenWithoutSpaces() throws Exception { Feature.STAY_OPEN)) { URL url = getClass().getResource("/20140502_152336_Östliche_Zubringerstraße.png"); File imageFile = new File(url.toURI()); - //System.out.println(imageFile.getAbsolutePath()); + // System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata.size()); } @@ -587,7 +502,7 @@ public void testReadingUtf8NamesWithoutStayOpen() throws Exception { try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true))) { URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); File imageFile = new File(url.toURI()); - //System.out.println(imageFile.getAbsolutePath()); + // System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata.size()); } @@ -599,7 +514,7 @@ public void testReadingUtf8NamesWithStayOpenAndWindows() throws Exception { Feature.STAY_OPEN, Feature.WINDOWS)) { URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); File imageFile = new File(url.toURI()); - //System.out.println(imageFile.getAbsolutePath()); + // System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata.size()); } @@ -611,10 +526,10 @@ public void testReadingUtf8NamesOnWindows() throws Exception { Feature.STAY_OPEN, Feature.WINDOWS)) { URL url = getClass().getResource("/20131231_230955_Strada Frumoasă.png"); File imageFile = new File(url.toURI()); - //System.out.println(imageFile.getAbsolutePath()); + // System.out.println(imageFile.getAbsolutePath()); Map metadata1 = tool.getImageMeta(imageFile, options); assertEquals(19, metadata1.size()); - //System.out.println(metadata1); + // System.out.println(metadata1); Map metadata = tool.getImageMeta3(imageFile, options); assertEquals(19, metadata.size()); } From 46903c2dcb5fadc5afc44ac43ac1b21641b688f1 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:13:56 +0200 Subject: [PATCH 103/148] - prepare to add joda --- pom.xml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/pom.xml b/pom.xml index 8c6efbf3..c73b2f99 100644 --- a/pom.xml +++ b/pom.xml @@ -87,6 +87,11 @@ 1.7.5 test + + joda-time + joda-time + 2.2 + From b97e732faa34eee409edd539581e01dbf8b60e15 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:14:52 +0200 Subject: [PATCH 104/148] [maven-release-plugin] prepare release exiftool-lib-2.3.5 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index c73b2f99..2dc90a7a 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.5-SNAPSHOT + 2.3.5 https://github.com/raisercostin/exiftool @@ -21,7 +21,7 @@ scm:git:https://github.com/raisercostin/exiftool.git scm:git:https://github.com/raisercostin/exiftool.git https://github.com/raisercostin/exiftool.git - HEAD + exiftool-lib-2.3.5 From 2877a1f46af5a4f23205c1de90628e4564c56ac6 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:14:59 +0200 Subject: [PATCH 105/148] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 2dc90a7a..3052864d 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.5 + 2.3.6-SNAPSHOT https://github.com/raisercostin/exiftool @@ -21,7 +21,7 @@ scm:git:https://github.com/raisercostin/exiftool.git scm:git:https://github.com/raisercostin/exiftool.git https://github.com/raisercostin/exiftool.git - exiftool-lib-2.3.5 + HEAD From c98fdfc3f3be5a74f4601a556002c99e205dbee7 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:17:41 +0200 Subject: [PATCH 106/148] [maven-release-plugin] rollback the release of exiftool-lib-2.3.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 3052864d..c73b2f99 100644 --- a/pom.xml +++ b/pom.xml @@ -4,7 +4,7 @@ com.thebuzzmedia.exiftool exiftool-lib jar - 2.3.6-SNAPSHOT + 2.3.5-SNAPSHOT https://github.com/raisercostin/exiftool From 0376e764a4476017d9c946d0307b9dd0e2cbb06b Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:26:21 +0200 Subject: [PATCH 107/148] - add wagon extensions --- pom.xml | 68 ++++++++++++++++++++++++++++++++++++++++----------------- 1 file changed, 48 insertions(+), 20 deletions(-) diff --git a/pom.xml b/pom.xml index c73b2f99..52b14479 100644 --- a/pom.xml +++ b/pom.xml @@ -1,10 +1,23 @@ 4.0.0 + + org.raisercostin + raisercostin-maven-defaults + 3.3 + com.thebuzzmedia.exiftool exiftool-lib - jar 2.3.5-SNAPSHOT + jar + exiftool-lib + + + The Apache Software License, Version 2.0 + repo + http://www.apache.org/licenses/LICENSE-2.0.txt + + https://github.com/raisercostin/exiftool @@ -17,11 +30,11 @@ - scm:git:https://github.com/raisercostin/exiftool.git scm:git:https://github.com/raisercostin/exiftool.git https://github.com/raisercostin/exiftool.git HEAD + @@ -39,24 +52,12 @@ --> - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.0 - - 1.7 - 1.7 - - - - org.apache.maven.plugins - maven-release-plugin - 2.5 - - - + + UTF-8 + 1.5 + 1.5 + 1.7 + commons-io @@ -93,6 +94,26 @@ 2.2 + + + + + release @@ -124,6 +145,13 @@ + + + com.google.code.maven-svn-wagon + maven-svn-wagon + 1.4 + + From 1d9cff02689e61e285d34c34bc86db3c257c8a7c Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:27:38 +0200 Subject: [PATCH 108/148] - fix --- pom.xml | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/pom.xml b/pom.xml index 52b14479..f729a996 100644 --- a/pom.xml +++ b/pom.xml @@ -113,6 +113,13 @@ --> + + + com.google.code.maven-svn-wagon + maven-svn-wagon + 1.4 + + @@ -145,13 +152,6 @@ - - - com.google.code.maven-svn-wagon - maven-svn-wagon - 1.4 - - From 0ba0208c2f1072a4a315ff516c438d656b21e45d Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:28:22 +0200 Subject: [PATCH 109/148] [maven-release-plugin] prepare release exiftool-lib-2.3.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f729a996..ad9d63ea 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.5-SNAPSHOT + 2.3.5 jar exiftool-lib From 7c16cd3c7a4b46f9e0b7be2b0e06e73fd486c638 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:30:35 +0200 Subject: [PATCH 110/148] [maven-release-plugin] rollback the release of exiftool-lib-2.3.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ad9d63ea..f729a996 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.5 + 2.3.5-SNAPSHOT jar exiftool-lib From 8fbf98855b8bb349b8957495c0298d92a350b2fb Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:30:57 +0200 Subject: [PATCH 111/148] [maven-release-plugin] prepare release exiftool-lib-2.3.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f729a996..ad9d63ea 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.5-SNAPSHOT + 2.3.5 jar exiftool-lib From 1199e2b16ee16a2274bdb78db74ce59e0b921504 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:31:19 +0200 Subject: [PATCH 112/148] [maven-release-plugin] rollback the release of exiftool-lib-2.3.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ad9d63ea..f729a996 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.5 + 2.3.5-SNAPSHOT jar exiftool-lib From 904d133befd2322e5ba11993b77c5e9b2de554d6 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:32:41 +0200 Subject: [PATCH 113/148] [maven-release-plugin] prepare release exiftool-lib-2.3.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f729a996..ad9d63ea 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.5-SNAPSHOT + 2.3.5 jar exiftool-lib From b14f20cad17c230f7a8df7870a844ac50bcac065 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:32:55 +0200 Subject: [PATCH 114/148] [maven-release-plugin] rollback the release of exiftool-lib-2.3.5 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index ad9d63ea..f729a996 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.5 + 2.3.5-SNAPSHOT jar exiftool-lib From 918381897f2f0e16074b56efa45042e09d8dff84 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:33:17 +0200 Subject: [PATCH 115/148] - 2.3.6 release --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index f729a996..1316f299 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.5-SNAPSHOT + 2.3.6-SNAPSHOT jar exiftool-lib From 5dda054ea6b0d99319b0d836e3fdf040d81eb57e Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:33:43 +0200 Subject: [PATCH 116/148] [maven-release-plugin] prepare release exiftool-lib-2.3.6 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1316f299..03ee98ec 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.6-SNAPSHOT + 2.3.6 jar exiftool-lib From c65ba26789646665e034dcc207f1716318aacca0 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Fri, 26 Dec 2014 11:33:50 +0200 Subject: [PATCH 117/148] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 03ee98ec..1bffe9d4 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.6 + 2.3.7-SNAPSHOT jar exiftool-lib From fe355ddcaad19d7e61ddb00a7dd5b7497864b7d7 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 24 Jan 2015 20:41:57 +0200 Subject: [PATCH 118/148] - add autoclose on finalization --- .../thebuzzmedia/exiftool/ExifProcess.java | 4 +- .../thebuzzmedia/exiftool/ExifToolNew3.java | 37 ++++++++++++++++++- .../exiftool/adapters/ExifToolService.java | 4 ++ 3 files changed, 42 insertions(+), 3 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index b4f9d5d8..55a7cb7b 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -54,10 +54,10 @@ public String toString() { Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { if (!all.isEmpty()) { - LOG.warn("Close all leaked processes:" + all.keySet()); + LOG.debug("Close all not closed processes:" + all.keySet()); for (Entry> item : new HashSet>>( all.entrySet())) { - LOG.warn("Close leaked process " + item, new RuntimeException()); + LOG.debug("Close not closed process " + item, new RuntimeException()); item.getValue()._2.close(); } } diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java index a1a5098d..65026ace 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java @@ -33,7 +33,42 @@ import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.thebuzzmedia.exiftool.adapters.ExifToolService; - +/* + private def extractExifWithExifToolOld2(prefix: String, file: File): Try[Tags] = + Try { + + def split(text: String): Pair[String, String] = { + val all = text.splitAt(text.indexOf(":")) + Pair(all._1.trim.replaceAll("[/ ]", ""), all._2.drop(1).trim) + } + //println("Coulnd't get exif info from " + file) + import scala.sys.process._ + import scala.sys.process.ProcessIO + val pb = Process(s"""exiftool "${file.getAbsolutePath}"""") + var map = Map[String, String]() + val pio = new ProcessIO(_ => (), + stdout => scala.io.Source.fromInputStream(stdout) + .getLines.foreach { x => + //println(s"found $x") + map += split(x) + }, + _ => ()) + val a = pb.run(pio) + val blockTillExits = a.exitValue + if (blockTillExits == 0) { + //println(map) + //"exiftool".! + //println(map mkString "\n") + val result = map.toMap.map { x => + //println(x) + (prefix + x._1, formatted(x._2)_) + } + Tags(result) + } else { + throw new RuntimeException(s"Coulnd't get exif info from " + file + ". Got $blockTillExits from exiftool.") + } + } + */ /** * Provide a Java-like interface to Phil Harvey's excellent, Perl-based ExifToolNew3. diff --git a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java index 68d5690a..f79351d5 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java +++ b/src/main/java/com/thebuzzmedia/exiftool/adapters/ExifToolService.java @@ -352,6 +352,10 @@ public String apply(MetadataTag input) { public void close() { super.close(); } + @Override + protected void finalize() throws Throwable { + close(); + } /** * Compiled {@link Pattern} of ": " used to split compact output from ExifToolNew3 evenly into name/value pairs. From 736156cc0655a91921180be0befc3a9755bde351 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 24 Jan 2015 20:43:58 +0200 Subject: [PATCH 119/148] [maven-release-plugin] prepare release exiftool-lib-2.3.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 1bffe9d4..b360626b 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.7-SNAPSHOT + 2.3.7 jar exiftool-lib From db89deb7ed78bcef797b9414a0d9ef891aa53375 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Sat, 24 Jan 2015 20:44:06 +0200 Subject: [PATCH 120/148] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b360626b..24d1f5a0 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.7 + 2.3.8-SNAPSHOT jar exiftool-lib From 0d7b424985f83d9fe00ab2ae956f34205c5eacd5 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 3 Feb 2015 08:59:32 +0200 Subject: [PATCH 121/148] - fix bug on ExifProcess: errReader should be daemon - this.errReader.setDaemon(true); --- .../thebuzzmedia/exiftool/ExifProcess.java | 11 ++- .../com/thebuzzmedia/exiftool/ExifTool.java | 8 +- .../thebuzzmedia/exiftool/ExifToolNew.java | 14 +-- .../thebuzzmedia/exiftool/ExifToolNew2.java | 8 +- .../thebuzzmedia/exiftool/ExifToolNew3.java | 88 ++++++++++--------- .../thebuzzmedia/exiftool/RawExifTool.java | 2 +- .../exiftool/adapters/BaseRawExifTool.java | 10 +-- .../exiftool/adapters/RawExifToolAdapter.java | 8 +- 8 files changed, 79 insertions(+), 70 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index 55a7cb7b..858a23b9 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -51,6 +51,7 @@ public String toString() { private static final Map> all = Collections .synchronizedMap(new TreeMap>()); static { + LOG.debug("addShutdownHook"); Runtime.getRuntime().addShutdownHook(new Thread() { public void run() { if (!all.isEmpty()) { @@ -76,7 +77,7 @@ public static VersionNumber readVersion(String exifCmd) { } } - public static ExifProcess _execute(boolean keepAlive, List args, Charset charset) { + private static ExifProcess _execute(boolean keepAlive, List args, Charset charset) { return new ExifProcess(keepAlive, args, charset); } @@ -132,6 +133,7 @@ public ExifProcess(boolean keepAlive, List args, Charset charset) { this.writer = new OutputStreamWriter(process.getOutputStream(), charset); this.errReader = new LineReaderThread("exif-process-err-reader", new BufferedReader(new InputStreamReader( process.getErrorStream()))); + this.errReader.setDaemon(true); errReader.start(); LOG.debug("\tSuccessful " + process + " started."); } catch (Exception e) { @@ -256,6 +258,7 @@ public void close() { LOG.debug("\tSuccessful"); } catch (Exception e) { // no-op, just try to close it. + LOG.debug("", e); } try { @@ -263,8 +266,9 @@ public void close() { .debug("Attempting to close ExifToolNew3 daemon process, issuing '-stay_open\\nFalse\\n' command..."); writer.write("-stay_open\nFalse\n"); writer.flush(); - } catch (IOException ex) { + } catch (IOException e) { // log.error(ex,ex); + LOG.debug("", e); } try { @@ -273,6 +277,7 @@ public void close() { LOG.debug("\tSuccessful"); } catch (Exception e) { // no-op, just try to close it. + LOG.debug("", e); } try { @@ -281,8 +286,8 @@ public void close() { LOG.debug("\tSuccessful"); } catch (Exception e) { // no-op, just try to close it. + LOG.debug("", e); } - LOG.debug("Read/Write streams successfully closed."); try { diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java index d45d4643..f6c95e8e 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifTool.java @@ -426,10 +426,10 @@ public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException * streams used to communicate with it when {@link Feature#STAY_OPEN} is * enabled. This method has no effect if the stay open feature is not enabled. */ - @Override -public void startup(){ - exifProxy.startup(); - } +// @Override +//public void startup(){ +// exifProxy.startup(); +// } /** * This is same as {@link #close()}, added for consistency with {@link #startup()} diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java index 90a2e3e4..9a26062f 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew.java @@ -376,13 +376,13 @@ public boolean isFeatureEnabled(Feature feature) throws IllegalArgumentException return featureEnabledSet.contains(feature); } - /** - * Used to startup the external ExifToolNew3 process and open the read/write streams used to communicate with it - * when {@link Feature#STAY_OPEN} is enabled. This method has no effect if the stay open feature is not enabled. - */ - public void startup() { - exifProxy.startup(); - } +// /** +// * Used to startup the external ExifToolNew3 process and open the read/write streams used to communicate with it +// * when {@link Feature#STAY_OPEN} is enabled. This method has no effect if the stay open feature is not enabled. +// */ +// public void startup() { +// exifProxy.startup(); +// } /** * This is same as {@link #close()}, added for consistency with {@link #startup()} diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java index 36a3cab4..ea585d78 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew2.java @@ -935,10 +935,10 @@ void resetCleanupTask() { log("\t\tSuccessful"); } - @Override - public void startup() { - resetCleanupTask(); - } +// @Override +// public void startup() { +// resetCleanupTask(); +// } @Override public void shutdown() { diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java index 65026ace..23b4abf2 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java @@ -33,41 +33,42 @@ import com.google.common.base.Joiner; import com.google.common.collect.Lists; import com.thebuzzmedia.exiftool.adapters.ExifToolService; + /* - private def extractExifWithExifToolOld2(prefix: String, file: File): Try[Tags] = - Try { - - def split(text: String): Pair[String, String] = { - val all = text.splitAt(text.indexOf(":")) - Pair(all._1.trim.replaceAll("[/ ]", ""), all._2.drop(1).trim) - } - //println("Coulnd't get exif info from " + file) - import scala.sys.process._ - import scala.sys.process.ProcessIO - val pb = Process(s"""exiftool "${file.getAbsolutePath}"""") - var map = Map[String, String]() - val pio = new ProcessIO(_ => (), - stdout => scala.io.Source.fromInputStream(stdout) - .getLines.foreach { x => - //println(s"found $x") - map += split(x) - }, - _ => ()) - val a = pb.run(pio) - val blockTillExits = a.exitValue - if (blockTillExits == 0) { - //println(map) - //"exiftool".! - //println(map mkString "\n") - val result = map.toMap.map { x => - //println(x) - (prefix + x._1, formatted(x._2)_) - } - Tags(result) - } else { - throw new RuntimeException(s"Coulnd't get exif info from " + file + ". Got $blockTillExits from exiftool.") - } - } + private def extractExifWithExifToolOld2(prefix: String, file: File): Try[Tags] = + Try { + + def split(text: String): Pair[String, String] = { + val all = text.splitAt(text.indexOf(":")) + Pair(all._1.trim.replaceAll("[/ ]", ""), all._2.drop(1).trim) + } + //println("Coulnd't get exif info from " + file) + import scala.sys.process._ + import scala.sys.process.ProcessIO + val pb = Process(s"""exiftool "${file.getAbsolutePath}"""") + var map = Map[String, String]() + val pio = new ProcessIO(_ => (), + stdout => scala.io.Source.fromInputStream(stdout) + .getLines.foreach { x => + //println(s"found $x") + map += split(x) + }, + _ => ()) + val a = pb.run(pio) + val blockTillExits = a.exitValue + if (blockTillExits == 0) { + //println(map) + //"exiftool".! + //println(map mkString "\n") + val result = map.toMap.map { x => + //println(x) + (prefix + x._1, formatted(x._2)_) + } + Tags(result) + } else { + throw new RuntimeException(s"Coulnd't get exif info from " + file + ". Got $blockTillExits from exiftool.") + } + } */ /** * Provide a Java-like interface to Phil Harvey's excellent, Perl-based List createCommandList(String filename, Map value private List toRawData(MetadataTag tag, Object value) { if (tag.getType().equals(String[].class)) { List result = new LinkedList(); - String[] array = (String[])value; + String[] array = (String[]) value; for (String value2 : array) { String raw = getRawExif(tag, value2); result.add(raw); diff --git a/src/main/java/com/thebuzzmedia/exiftool/RawExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/RawExifTool.java index 1cb3c56d..098b2f2b 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/RawExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/RawExifTool.java @@ -64,7 +64,7 @@ public static ExifToolService create(ReadOptions readOptions, Feature... feature * Used to startup the external ExifToolNew3 process and open the read/write streams used to communicate with it * when {@link Feature#STAY_OPEN} is enabled. This method has no effect if the stay open feature is not enabled. */ - void startup(); +// void startup(); /** * This is same as {@link #close()}, added for consistency with {@link #startup()} diff --git a/src/main/java/com/thebuzzmedia/exiftool/adapters/BaseRawExifTool.java b/src/main/java/com/thebuzzmedia/exiftool/adapters/BaseRawExifTool.java index a3ec6b09..9b14c951 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/adapters/BaseRawExifTool.java +++ b/src/main/java/com/thebuzzmedia/exiftool/adapters/BaseRawExifTool.java @@ -15,11 +15,11 @@ public boolean isFeatureSupported(Feature feature) throws RuntimeException { return false; } - @Override - public void startup() { - // TODO Auto-generated method stub - - } +// @Override +// public void startup() { +// // TODO Auto-generated method stub +// +// } @Override public void shutdown() { diff --git a/src/main/java/com/thebuzzmedia/exiftool/adapters/RawExifToolAdapter.java b/src/main/java/com/thebuzzmedia/exiftool/adapters/RawExifToolAdapter.java index 4db66585..e5ad629f 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/adapters/RawExifToolAdapter.java +++ b/src/main/java/com/thebuzzmedia/exiftool/adapters/RawExifToolAdapter.java @@ -19,10 +19,10 @@ public boolean isFeatureSupported(Feature feature) throws RuntimeException { return exifTool.isFeatureSupported(feature); } - @Override - public void startup() { - exifTool.startup(); - } +// @Override +// public void startup() { +// exifTool.startup(); +// } @Override public void shutdown() { From 297c285f6ea5d17da0fd2abbdfae1fd3c5c542ea Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 3 Feb 2015 15:42:25 +0200 Subject: [PATCH 122/148] - better way to handle strange filenames: rename to a temp file and delete the temp file at the end --- .../thebuzzmedia/exiftool/ExifToolNew3.java | 150 +++++++++++++----- src/test/resources/simplelogger.properties | 2 +- 2 files changed, 114 insertions(+), 38 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java index 23b4abf2..39ebbe5c 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java @@ -15,19 +15,17 @@ */ package com.thebuzzmedia.exiftool; -import java.io.Closeable; import java.io.File; -import java.io.FileWriter; import java.io.IOException; import java.nio.charset.Charset; +import java.nio.file.Files; import java.util.*; import java.util.concurrent.atomic.AtomicBoolean; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; -import org.apache.commons.io.FilenameUtils; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; +import org.apache.commons.io.FileUtils; +import org.apache.commons.io.IOUtils; import com.google.common.base.CharMatcher; import com.google.common.base.Joiner; @@ -539,40 +537,85 @@ public Map getImageMeta(File file, ReadOptions readOptions, Stri + file.getAbsolutePath() + "], ensure that the image exists at the given path and that the executing Java process has permissions to read it."); } - args.add(getAbsoluteFileName(file)); - - // start process - long startTime = System.currentTimeMillis(); - LOG.debug(String.format("Querying %d tags from image: %s", tags.length, file.getAbsolutePath())); - LOG.info("call stayOpen=" + stayOpen + " exiftool " + Joiner.on(" ").join(args)); - /* - * Using ExifToolNew3 in daemon mode (-stay_open True) executes different code paths below. So establish the - * flag for this once and it is reused a multitude of times later in this method to figure out where to branch - * to. - */ - Map resultMap; - if (stayOpen) { - LOG.debug("Using ExifToolNew3 in daemon mode (-stay_open True)..."); - resultMap = processStayOpen(args); - } else { - LOG.debug("Using ExifToolNew3 in non-daemon mode (-stay_open False)..."); - resultMap = ExifToolService.toMap(execute(args)); + String absoluteName = getAbsoluteFileName(file); + String fileName = absoluteName; + File tempFileName = null; + if (absoluteName == null) { + tempFileName = getTemporaryCopiedFileName(file); + fileName = tempFileName.getAbsolutePath(); + LOG.info("Exiftool will work with temporary file " + fileName + " for original file [" + absoluteName + + "]."); } + Map resultMap; + try { + args.add(fileName); + + // start process + long startTime = System.currentTimeMillis(); + LOG.debug(String.format("Querying %d tags from image: %s", tags.length, file.getAbsolutePath())); + LOG.info("call stayOpen=" + stayOpen + " exiftool " + Joiner.on(" ").join(args)); + /* + * Using ExifToolNew3 in daemon mode (-stay_open True) executes different code paths below. So establish the + * flag for this once and it is reused a multitude of times later in this method to figure out where to + * branch to. + */ + if (stayOpen) { + LOG.debug("Using ExifToolNew3 in daemon mode (-stay_open True)..."); + resultMap = processStayOpen(args); + } else { + LOG.debug("Using ExifToolNew3 in non-daemon mode (-stay_open False)..."); + resultMap = ExifToolService.toMap(execute(args)); + } - // Print out how long the call to external ExifToolNew3 process took. - if (LOG.isDebugEnabled()) { - LOG.debug(String.format("Image Meta Processed in %d ms [queried %d tags and found %d values]", - (System.currentTimeMillis() - startTime), tags.length, resultMap.size())); + // Print out how long the call to external ExifToolNew3 process took. + if (LOG.isDebugEnabled()) { + LOG.debug(String.format("Image Meta Processed in %d ms [queried %d tags and found %d values]", + (System.currentTimeMillis() - startTime), tags.length, resultMap.size())); + } + } finally { + if (tempFileName != null) { + FileUtils.forceDelete(tempFileName); + } } - return resultMap; } + private File getTemporaryCopiedFileName(File file) { + File dest = new File(file.getParentFile(), "temp"); + copyFromAsHardLink(file, dest, false); + return dest; + } + + void copyFromAsHardLink(File src, File dest, Boolean overwriteIfAlreadyExists) { + try { + if (overwriteIfAlreadyExists) { + if (dest.exists()) { + FileUtils.forceDelete(dest); + } + FileUtils.forceMkdir(dest.getParentFile()); + Files.createLink(dest.toPath(), src.toPath()); + } else { + if (dest.exists()) { + throw new RuntimeException("Destination file " + this + " already exists."); + } else { + FileUtils.forceMkdir(dest.getParentFile()); + Files.createLink(dest.toPath(), src.toPath()); + } + } + } catch (IOException e) { + throw new RuntimeException(e); + } + } + public String getAbsoluteFileName(File file) { - if (!CharMatcher.ASCII.matchesAllOf(file.getAbsolutePath()) && featureSet.contains(Feature.WINDOWS)) - return getMSDOSName(file); - else + // if (!CharMatcher.ASCII.matchesAllOf(file.getAbsolutePath()) && featureSet.contains(Feature.WINDOWS)) + // return getMSDOSName(file); + // else + // return file.getAbsolutePath(); + if (CharMatcher.ASCII.matchesAllOf(file.getAbsolutePath())) { return file.getAbsolutePath(); + } + return null; } /** @@ -585,14 +628,47 @@ public String getAbsoluteFileName(File file) { public static String getMSDOSName(File file) { try { String path = getAbsolutePath(file); - Process process = Runtime.getRuntime().exec( - "cmd /c for %I in (\"" + file.getAbsolutePath() + "\") do @echo %~fsI"); + String path2 = file.getAbsolutePath(); + System.out.println(path2); + // String toExecute = "cmd.exe /c for %I in (\"" + path2 + "\") do @echo %~fsI"; + // ProcessBuilder pb = new ProcessBuilder("cmd","/c","for","%I","in","(" + path2 + ")","do","@echo","%~sI"); + path2 = new File( + "d:\\aaaaaaaaaaaaaaaaaaaaaaaaaaaa\\bbbbbbbbbbbbbbbbbb\\2013-12-22--12-10-42------Bulevardul-Petrochimiștilor.jpg") + .getAbsolutePath(); + path2 = new File( + "d:\\personal\\photos-tofix\\2013-proposed1-bad\\2013-12-22--12-10-42------Bulevardul-Petrochimiștilor.jpg") + .getAbsolutePath(); + + System.out.println(path2); + ProcessBuilder pb = new ProcessBuilder("cmd", "/c", "for", "%I", "in", "(\"" + path2 + "\")", "do", + "@echo", "%~fsI"); + // ProcessBuilder pb = new ProcessBuilder("cmd","/c","chcp 65001 & dir",path2); + // ProcessBuilder pb = new ProcessBuilder("cmd","/c","ls",path2); + Process process = pb.start(); + // Process process = Runtime.getRuntime().exec(execLine); + // Process process = Runtime.getRuntime().exec(new String[]{"cmd","/c","for","%I","in","(\"" + path2 + + // "\")","do","@echo","%~fsI"}); process.waitFor(); byte[] data = new byte[65536]; - int size = process.getInputStream().read(data); - if (size > 0) - path = new String(data, 0, size).replaceAll("\\r\\n", ""); - return path; + // InputStreamReader isr = new InputStreamReader(process.getInputStream(), "UTF-8"); + // String charset = Charset.defaultCharset().name(); + String charset = "UTF-8"; + String lines = IOUtils.toString(process.getInputStream(), charset); + // int size = process.getInputStream().read(data); + // String path3 = path; + // if (size > 0) + // path3 = new String(data, 0, size).replaceAll("\\r\\n", ""); + String path3 = lines; + System.out.println(pb.command()); + System.out.println(path3); + byte[] data2 = new byte[65536]; + int size2 = process.getErrorStream().read(data2); + if (size2 > 0) { + String error = new String(data2, 0, size2); + System.out.println(error); + throw new RuntimeException("Error was thrown " + error); + } + return path3; } catch (IOException e) { throw new RuntimeException(e); } catch (InterruptedException e) { diff --git a/src/test/resources/simplelogger.properties b/src/test/resources/simplelogger.properties index 7e866878..109bd981 100644 --- a/src/test/resources/simplelogger.properties +++ b/src/test/resources/simplelogger.properties @@ -1 +1 @@ - org.slf4j.simpleLogger.defaultLogLevel=info \ No newline at end of file + org.slf4j.simpleLogger.defaultLogLevel=warn \ No newline at end of file From d643b4993ab7e4059932f89e26a169d34c639506 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Thu, 5 Feb 2015 13:34:34 +0200 Subject: [PATCH 123/148] - the property defining executable should be public --- src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java index 39ebbe5c..a493d9ae 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java @@ -208,7 +208,7 @@ def split(text: String): Pair[String, String] = { public class ExifToolNew3 implements RawExifTool { private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ExifToolNew3.class); - private static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; + public static final String ENV_EXIF_TOOL_PATH = "exiftool.path"; private static final String ENV_EXIF_TOOL_PROCESSCLEANUPDELAY = "exiftool.processCleanupDelay"; private static final long DEFAULT_PROCESS_CLEANUP_DELAY = 0; From 74ae16a7e84a9dd551851014fa056ea85be3f6b6 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Thu, 5 Feb 2015 13:37:49 +0200 Subject: [PATCH 124/148] [maven-release-plugin] prepare release exiftool-lib-2.3.8 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 24d1f5a0..499d498f 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.8-SNAPSHOT + 2.3.8 jar exiftool-lib From b50de433cb7458a5dd507c1590419e66c1910cb2 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Thu, 5 Feb 2015 13:37:57 +0200 Subject: [PATCH 125/148] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 499d498f..8dabc908 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.8 + 2.3.9-SNAPSHOT jar exiftool-lib From 19bc669e4a02fdd9979b2bf28e24d358b4bc638f Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 23 Feb 2015 18:08:24 +0200 Subject: [PATCH 126/148] - fix first unique folder on some renames --- .../thebuzzmedia/exiftool/ExifToolNew3.java | 28 ++++++++++++++++--- .../com/thebuzzmedia/exiftool/Benchmark.java | 4 +-- 2 files changed, 25 insertions(+), 7 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java index a493d9ae..576e9d9d 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java @@ -24,8 +24,7 @@ import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; -import org.apache.commons.io.FileUtils; -import org.apache.commons.io.IOUtils; +import org.apache.commons.io.*; import com.google.common.base.CharMatcher; import com.google.common.base.Joiner; @@ -582,8 +581,9 @@ public Map getImageMeta(File file, ReadOptions readOptions, Stri private File getTemporaryCopiedFileName(File file) { File dest = new File(file.getParentFile(), "temp"); - copyFromAsHardLink(file, dest, false); - return dest; + File temp = findFirstUniqueFile(dest); + copyFromAsHardLink(file,temp, false); + return temp; } void copyFromAsHardLink(File src, File dest, Boolean overwriteIfAlreadyExists) { @@ -607,6 +607,26 @@ void copyFromAsHardLink(File src, File dest, Boolean overwriteIfAlreadyExists) { } } + private File findFirstUniqueFile(File dest) { + if(!dest.exists()){ + return dest; + } + File parent = dest.getParentFile(); + String full = dest.getAbsolutePath(); + String extension = FilenameUtils.getExtension(full); + String current = FilenameUtils.getBaseName(full); + int counter = 1; + int MAX_COUNTER = 100000; + do { + File file = new File(parent, current + "-" + counter + "." + extension); + if (!file.exists()) { + return file; + } + counter++; + } while (counter < MAX_COUNTER); + throw new RuntimeException("Couldn't find a unique name similar with ["+full+"] till "+MAX_COUNTER); + } + public String getAbsoluteFileName(File file) { // if (!CharMatcher.ASCII.matchesAllOf(file.getAbsolutePath()) && featureSet.contains(Feature.WINDOWS)) // return getMSDOSName(file); diff --git a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java index fd7c89be..9362d265 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java +++ b/src/test/java/com/thebuzzmedia/exiftool/Benchmark.java @@ -1,7 +1,6 @@ package com.thebuzzmedia.exiftool; -import java.io.File; -import java.io.IOException; +import java.io.*; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -9,7 +8,6 @@ import com.thebuzzmedia.exiftool.adapters.ExifToolService; public class Benchmark { - public static final int ITERATIONS = 25; private static Logger log = LoggerFactory.getLogger(Benchmark.class); From f6f50cadcbd23ced68bc5d31d1e90b79f06909f0 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 23 Feb 2015 18:09:27 +0200 Subject: [PATCH 127/148] [maven-release-plugin] prepare release exiftool-lib-2.3.9 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 8dabc908..b9cb2649 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.9-SNAPSHOT + 2.3.9 jar exiftool-lib From 155f2580a6b05063b9bb3c5438a6ad50411c83c9 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 23 Feb 2015 18:09:35 +0200 Subject: [PATCH 128/148] [maven-release-plugin] prepare for next development iteration --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index b9cb2649..e4ea0f25 100644 --- a/pom.xml +++ b/pom.xml @@ -8,7 +8,7 @@ com.thebuzzmedia.exiftool exiftool-lib - 2.3.9 + 2.3.10-SNAPSHOT jar exiftool-lib From b60bee5459d7c617c71a86b7ad0689dc1650a429 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 13:34:35 +0300 Subject: [PATCH 129/148] release to bintray --- pom.xml | 174 ++++++++++++------ .../thebuzzmedia/exiftool/TestExifTool.java | 48 +++-- 2 files changed, 142 insertions(+), 80 deletions(-) diff --git a/pom.xml b/pom.xml index e4ea0f25..76234f0a 100644 --- a/pom.xml +++ b/pom.xml @@ -1,63 +1,99 @@ - - 4.0.0 - - org.raisercostin - raisercostin-maven-defaults - 3.3 - + + + 4.0.0 + + org.raisercostin.utils + maven-defaults + 6 + com.thebuzzmedia.exiftool - exiftool-lib - 2.3.10-SNAPSHOT + exiftool + 2.3.10-raiserfork-SNAPSHOT jar - exiftool-lib - - - The Apache Software License, Version 2.0 - repo - http://www.apache.org/licenses/LICENSE-2.0.txt - - - https://github.com/raisercostin/exiftool + exiftool + Enhanced Java Integration for Phil Harvey's ExifTool. + ${git.url} + + Github + https://github.com/raisercostin/${project.artifactId}/issues + Riyad Kalla software@thebuzzmedia.com - - raisercostin - raisercostin@gmail.com - + + Costin Grigore + raisercostin@gmail.com + raisercostin + http://raisercostin.org + - scm:git:https://github.com/raisercostin/exiftool.git - scm:git:https://github.com/raisercostin/exiftool.git - https://github.com/raisercostin/exiftool.git - HEAD - + scm:git:${git.url}.git + scm:git:${git.url}.git + ${git.url} + ${project.artifactId}-${project.version} - - exiftool.releases - svn:https://raisercostin.googlecode.com/svn/maven2/ - - + + bintray + https://api.bintray.com/maven/${bintray.user}/${bintray.repo}/${bintray.package}/;publish=1 + + - - UTF-8 - 1.5 - 1.5 - 1.7 - + + raisercostin + ${project.artifactId} + github.com + https://${git.host}/${git.userOrGroup}/${git.repo} + raisercostin + raisercostin + maven + ${project.artifactId} + yyyyMMdd'T'HHmmss + https://api.bintray.com/maven/${bintray.user}/${bintray.repo}/${bintray.package} + ${dist.url}/releases/ + ${dist.url}/snapshots/ + ${dist.url}/sites/${project.groupId}-${project.artifactId}-${project.version} + false + false + + com.revomatico + 1.2.0.Final + 1.18.4 + 5.4.2 + 1.4.2 + 1.7.25 + 1.2.3 + 3.2.5.RELEASE + 5.1.4.RELEASE + + jdt_apt + 2.1.1.RELEASE + UTF-8 + UTF-8 + 1.5 + ${java.version} + 1.7 + ${java.version} + 1.2.71 + true + enable + 1.3 + 1.3 + ${java.version} + + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + commons-io @@ -67,7 +103,7 @@ org.slf4j slf4j-api - 1.7.5 + ${slf4j.version} compile @@ -85,7 +121,7 @@ org.slf4j slf4j-simple - 1.7.5 + ${slf4j.version} test @@ -96,14 +132,16 @@ - - 1.7 - 1.7 + ${source.java.version} + ${target.java.version} + true + true @@ -111,15 +149,7 @@ maven-release-plugin 2.5 - --> - - - com.google.code.maven-svn-wagon - maven-svn-wagon - 1.4 - - @@ -155,4 +185,26 @@ + + + jcenter-bintray + https://jcenter.bintray.com/ + + true + + + false + + + + raisercostin-bintray + https://dl.bintray.com/raisercostin/maven + + true + + + false + + + diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 4d0ad493..bd9b20a3 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -1,14 +1,24 @@ package com.thebuzzmedia.exiftool; -import static org.junit.Assert.*; +import static org.junit.Assert.assertEquals; +import static org.junit.Assert.assertTrue; +import static org.junit.Assert.fail; import java.io.File; import java.io.IOException; import java.net.URISyntaxException; import java.net.URL; -import java.nio.file.*; +import java.nio.file.Files; +import java.nio.file.Path; +import java.nio.file.Paths; +import java.nio.file.StandardCopyOption; import java.text.SimpleDateFormat; -import java.util.*; +import java.util.ArrayList; +import java.util.Arrays; +import java.util.Date; +import java.util.HashMap; +import java.util.List; +import java.util.Map; import org.junit.Test; import org.slf4j.Logger; @@ -154,10 +164,10 @@ private void testFile(ExifToolService tool, String resource, int size, int width Map metadata = tool.getImageMeta4d(imageFile, new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.values()); assertEquals(size, metadata.size()); - assertEquals(width, Tag.IMAGE_WIDTH.getValue(metadata)); - assertEquals(height, Tag.IMAGE_HEIGHT.getValue(metadata)); + assertEquals((Integer)width, Tag.IMAGE_WIDTH.getValue(metadata)); + assertEquals((Integer)height, Tag.IMAGE_HEIGHT.getValue(metadata)); assertEquals(model, Tag.MODEL.getValue(metadata)); - assertEquals(iso, Tag.ISO.getValue(metadata)); + assertEquals((Integer)iso, Tag.ISO.getValue(metadata)); assertEquals(shutterRaw, Tag.SHUTTER_SPEED.getRawValue(metadata)); assertEquals(shutter, (Double) Tag.SHUTTER_SPEED.getValue(metadata), 1e-5); } @@ -183,9 +193,9 @@ public void testGroupTags() throws Exception { @Test public void testTag() { assertEquals("string value", "John Doe", Tag.AUTHOR.parseValue("John Doe")); - assertEquals("integer value", 200, Tag.ISO.parseValue("200")); - assertEquals("double value, from fraction", .25, Tag.SHUTTER_SPEED.parseValue("1/4")); - assertEquals("double value, from decimal", .25, Tag.SHUTTER_SPEED.parseValue(".25")); + assertEquals("integer value", (Integer)200, Tag.ISO.parseValue("200")); + assertEquals("double value, from fraction", (Double).25, Tag.SHUTTER_SPEED.parseValue("1/4")); + assertEquals("double value, from decimal", (Double).25, Tag.SHUTTER_SPEED.parseValue(".25")); } @Test @@ -445,7 +455,7 @@ public void testWritingWithImplicitTypes() throws Exception { Map metadata = tool.getImageMeta2(imageFile, options.withNumericOutput(true), Tag.ORIENTATION, MwgTag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", 1, Tag.ORIENTATION.getValue(metadata)); + assertEquals("Orientation tag starting value is wrong", (Integer)1, Tag.ORIENTATION.getValue(metadata)); assertEquals("Wrong starting value", formatter.parse("2010:12:10 17:07:05"), MwgTag.DATE_TIME_ORIGINAL.getValue(metadata)); @@ -462,7 +472,7 @@ public void testWritingWithImplicitTypes() throws Exception { // Finally check the updated value metadata = tool.getImageMeta6(imageFile, options.withNumericOutput(true), Tag.ORIENTATION, imageFile, MwgTag.DATE_TIME_ORIGINAL, MwgTag.CREATE_DATE, MwgTag.KEYWORDS); - assertEquals("Orientation tag updated value is wrong", 3, Tag.ORIENTATION.getValue(metadata)); + assertEquals("Orientation tag updated value is wrong", (Integer)3, Tag.ORIENTATION.getValue(metadata)); assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, MwgTag.DATE_TIME_ORIGINAL.getValue(metadata)); assertEquals("CreateDate tag is wrong", createDate, MwgTag.CREATE_DATE.getValue(metadata)); assertEquals("Keywords tag is wrong", "a", ((String[]) MwgTag.KEYWORDS.getValue(metadata))[0]); @@ -472,7 +482,7 @@ public void testWritingWithImplicitTypes() throws Exception { } } - @Test(expected = ExifError.class) + @Test//(expected = ExifError.class) public void testReadingUtf8NamesWithStayOpen() throws Exception { try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), Feature.STAY_OPEN)) { @@ -481,11 +491,11 @@ public void testReadingUtf8NamesWithStayOpen() throws Exception { Map metadata = tool.getImageMeta3(imageFile, options); // should fail on the line before. this is just for breakpoint and retry Map metadata2 = tool.getImageMeta3(imageFile, options); - assertEquals(19, metadata2.size()); + assertEquals(21, metadata2.size()); } } - @Test(expected = ExifError.class) + @Test//(expected = ExifError.class) public void testReadingUtf8NamesWithStayOpenWithoutSpaces() throws Exception { try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), Feature.STAY_OPEN)) { @@ -493,7 +503,7 @@ public void testReadingUtf8NamesWithStayOpenWithoutSpaces() throws Exception { File imageFile = new File(url.toURI()); // System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); - assertEquals(19, metadata.size()); + assertEquals(21, metadata.size()); } } @@ -504,7 +514,7 @@ public void testReadingUtf8NamesWithoutStayOpen() throws Exception { File imageFile = new File(url.toURI()); // System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); - assertEquals(19, metadata.size()); + assertEquals(21, metadata.size()); } } @@ -516,7 +526,7 @@ public void testReadingUtf8NamesWithStayOpenAndWindows() throws Exception { File imageFile = new File(url.toURI()); // System.out.println(imageFile.getAbsolutePath()); Map metadata = tool.getImageMeta3(imageFile, options); - assertEquals(19, metadata.size()); + assertEquals(21, metadata.size()); } } @@ -528,10 +538,10 @@ public void testReadingUtf8NamesOnWindows() throws Exception { File imageFile = new File(url.toURI()); // System.out.println(imageFile.getAbsolutePath()); Map metadata1 = tool.getImageMeta(imageFile, options); - assertEquals(19, metadata1.size()); + assertEquals(21, metadata1.size()); // System.out.println(metadata1); Map metadata = tool.getImageMeta3(imageFile, options); - assertEquals(19, metadata.size()); + assertEquals(21, metadata.size()); } } } From 8ca90352f3fb6c4f3f18d1b89e6450a863b8d81b Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 13:45:17 +0300 Subject: [PATCH 130/148] upgrade release plugin --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index 76234f0a..c194db4e 100644 --- a/pom.xml +++ b/pom.xml @@ -147,7 +147,7 @@ org.apache.maven.plugins maven-release-plugin - 2.5 + 2.5.3/version> From 8c2cbf822049acbe96b4d5e889b251f4a5f610f0 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 13:46:01 +0300 Subject: [PATCH 131/148] fix --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index c194db4e..e7ef2c35 100644 --- a/pom.xml +++ b/pom.xml @@ -147,7 +147,7 @@ org.apache.maven.plugins maven-release-plugin - 2.5.3/version> + 2.5.3 From 4d9d7e0330dfe5b7f25266207c79f9b27f6ce111 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 13:48:20 +0300 Subject: [PATCH 132/148] fix to java 1.7 --- pom.xml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/pom.xml b/pom.xml index e7ef2c35..885d66e7 100644 --- a/pom.xml +++ b/pom.xml @@ -77,7 +77,7 @@ 2.1.1.RELEASE UTF-8 UTF-8 - 1.5 + 1.7 ${java.version} 1.7 ${java.version} From 9fa4eaacd3eaec436492b94f1f38ad730d5bb78f Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 13:49:08 +0300 Subject: [PATCH 133/148] [maven-release-plugin] prepare release exiftool-2.3.10-raiserfork --- pom.xml | 420 ++++++++++++++++++++++++++++---------------------------- 1 file changed, 210 insertions(+), 210 deletions(-) diff --git a/pom.xml b/pom.xml index 885d66e7..98fbafc5 100644 --- a/pom.xml +++ b/pom.xml @@ -1,210 +1,210 @@ - - - 4.0.0 - - org.raisercostin.utils - maven-defaults - 6 - - - com.thebuzzmedia.exiftool - exiftool - 2.3.10-raiserfork-SNAPSHOT - jar - exiftool - Enhanced Java Integration for Phil Harvey's ExifTool. - ${git.url} - - Github - https://github.com/raisercostin/${project.artifactId}/issues - - - - Riyad Kalla - software@thebuzzmedia.com - - - Costin Grigore - raisercostin@gmail.com - raisercostin - http://raisercostin.org - - - - scm:git:${git.url}.git - scm:git:${git.url}.git - ${git.url} - ${project.artifactId}-${project.version} - - - - bintray - https://api.bintray.com/maven/${bintray.user}/${bintray.repo}/${bintray.package}/;publish=1 - - - - - raisercostin - ${project.artifactId} - github.com - https://${git.host}/${git.userOrGroup}/${git.repo} - raisercostin - raisercostin - maven - ${project.artifactId} - yyyyMMdd'T'HHmmss - https://api.bintray.com/maven/${bintray.user}/${bintray.repo}/${bintray.package} - ${dist.url}/releases/ - ${dist.url}/snapshots/ - ${dist.url}/sites/${project.groupId}-${project.artifactId}-${project.version} - false - false - - com.revomatico - 1.2.0.Final - 1.18.4 - 5.4.2 - 1.4.2 - 1.7.25 - 1.2.3 - 3.2.5.RELEASE - 5.1.4.RELEASE - - jdt_apt - 2.1.1.RELEASE - UTF-8 - UTF-8 - 1.7 - ${java.version} - 1.7 - ${java.version} - 1.2.71 - true - enable - 1.3 - 1.3 - ${java.version} - - - - The Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - - - - - commons-io - commons-io - 2.2 - - - org.slf4j - slf4j-api - ${slf4j.version} - compile - - - com.google.guava - guava - 17.0 - - - junit - junit - 4.11 - test - - - - org.slf4j - slf4j-simple - ${slf4j.version} - test - - - joda-time - joda-time - 2.2 - - - - - - org.apache.maven.plugins - maven-compiler-plugin - 3.8.0 - - - ${source.java.version} - ${target.java.version} - true - true - - - - org.apache.maven.plugins - maven-release-plugin - 2.5.3 - - - - - - release - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.7 - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar - - - - - - - - - - - jcenter-bintray - https://jcenter.bintray.com/ - - true - - - false - - - - raisercostin-bintray - https://dl.bintray.com/raisercostin/maven - - true - - - false - - - - + + + 4.0.0 + + org.raisercostin.utils + maven-defaults + 6 + + + com.thebuzzmedia.exiftool + exiftool + 2.3.10-raiserfork + jar + exiftool + Enhanced Java Integration for Phil Harvey's ExifTool. + ${git.url} + + Github + https://github.com/raisercostin/${project.artifactId}/issues + + + + Riyad Kalla + software@thebuzzmedia.com + + + Costin Grigore + raisercostin@gmail.com + raisercostin + http://raisercostin.org + + + + scm:git:${git.url}.git + scm:git:${git.url}.git + ${git.url} + exiftool-2.3.10-raiserfork + + + + bintray + https://api.bintray.com/maven/${bintray.user}/${bintray.repo}/${bintray.package}/;publish=1 + + + + + raisercostin + ${project.artifactId} + github.com + https://${git.host}/${git.userOrGroup}/${git.repo} + raisercostin + raisercostin + maven + ${project.artifactId} + yyyyMMdd'T'HHmmss + https://api.bintray.com/maven/${bintray.user}/${bintray.repo}/${bintray.package} + ${dist.url}/releases/ + ${dist.url}/snapshots/ + ${dist.url}/sites/${project.groupId}-${project.artifactId}-${project.version} + false + false + + com.revomatico + 1.2.0.Final + 1.18.4 + 5.4.2 + 1.4.2 + 1.7.25 + 1.2.3 + 3.2.5.RELEASE + 5.1.4.RELEASE + + jdt_apt + 2.1.1.RELEASE + UTF-8 + UTF-8 + 1.7 + ${java.version} + 1.7 + ${java.version} + 1.2.71 + true + enable + 1.3 + 1.3 + ${java.version} + + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + commons-io + commons-io + 2.2 + + + org.slf4j + slf4j-api + ${slf4j.version} + compile + + + com.google.guava + guava + 17.0 + + + junit + junit + 4.11 + test + + + + org.slf4j + slf4j-simple + ${slf4j.version} + test + + + joda-time + joda-time + 2.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin + 3.8.0 + + + ${source.java.version} + ${target.java.version} + true + true + + + + org.apache.maven.plugins + maven-release-plugin + 2.5.3 + + + + + + release + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.7 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + + + + + jcenter-bintray + https://jcenter.bintray.com/ + + true + + + false + + + + raisercostin-bintray + https://dl.bintray.com/raisercostin/maven + + true + + + false + + + + From 6fce713302855a4bd0e48fc0bb9a986a91bf010c Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 13:49:20 +0300 Subject: [PATCH 134/148] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 98fbafc5..d5ec3c24 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ com.thebuzzmedia.exiftool exiftool - 2.3.10-raiserfork + 2.3.11-raiserfork-SNAPSHOT jar exiftool Enhanced Java Integration for Phil Harvey's ExifTool. @@ -34,7 +34,7 @@ scm:git:${git.url}.git scm:git:${git.url}.git ${git.url} - exiftool-2.3.10-raiserfork + ${project.artifactId}-${project.version} From 3b922a4a90bf3b762920dea9767ca7d86b5fcc7a Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 13:53:37 +0300 Subject: [PATCH 135/148] change groupId to release to bintray --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index d5ec3c24..33ff2313 100644 --- a/pom.xml +++ b/pom.xml @@ -7,9 +7,9 @@ 6 - com.thebuzzmedia.exiftool + org.raisercostin exiftool - 2.3.11-raiserfork-SNAPSHOT + 2.3.11-SNAPSHOT jar exiftool Enhanced Java Integration for Phil Harvey's ExifTool. From a49f8662fa57f70bd4865cefd2818f3fcade107a Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 13:54:11 +0300 Subject: [PATCH 136/148] [maven-release-plugin] prepare release exiftool-2.3.11 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 33ff2313..7bb24d69 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.raisercostin exiftool - 2.3.11-SNAPSHOT + 2.3.11 jar exiftool Enhanced Java Integration for Phil Harvey's ExifTool. @@ -34,7 +34,7 @@ scm:git:${git.url}.git scm:git:${git.url}.git ${git.url} - ${project.artifactId}-${project.version} + exiftool-2.3.11 From f4353e631ea38819776eb14c359b1d003ee3fb09 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 13:54:22 +0300 Subject: [PATCH 137/148] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 7bb24d69..72dd032a 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.raisercostin exiftool - 2.3.11 + 2.3.12-SNAPSHOT jar exiftool Enhanced Java Integration for Phil Harvey's ExifTool. @@ -34,7 +34,7 @@ scm:git:${git.url}.git scm:git:${git.url}.git ${git.url} - exiftool-2.3.11 + ${project.artifactId}-${project.version} From 9a7fbc1619d5df42d52d38cf88fea94c8e3efd31 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 17:48:57 +0300 Subject: [PATCH 138/148] upgrade guava and commons-io --- pom.xml | 231 +++++++++--------- .../thebuzzmedia/exiftool/ExifToolNew3.java | 2 +- 2 files changed, 116 insertions(+), 117 deletions(-) diff --git a/pom.xml b/pom.xml index 72dd032a..e8d45fde 100644 --- a/pom.xml +++ b/pom.xml @@ -1,50 +1,50 @@ - + 4.0.0 org.raisercostin.utils maven-defaults 6 - - org.raisercostin - exiftool - 2.3.12-SNAPSHOT - jar - exiftool - Enhanced Java Integration for Phil Harvey's ExifTool. + + org.raisercostin + exiftool + 2.3.12-SNAPSHOT + jar + exiftool + Enhanced Java Integration for Phil Harvey's ExifTool. ${git.url} Github https://github.com/raisercostin/${project.artifactId}/issues - - - Riyad Kalla - software@thebuzzmedia.com - + + + Riyad Kalla + software@thebuzzmedia.com + Costin Grigore raisercostin@gmail.com raisercostin http://raisercostin.org - - + + scm:git:${git.url}.git scm:git:${git.url}.git ${git.url} ${project.artifactId}-${project.version} - - + + bintray https://api.bintray.com/maven/${bintray.user}/${bintray.repo}/${bintray.package}/;publish=1 - - + + raisercostin ${project.artifactId} @@ -71,8 +71,7 @@ 1.2.3 3.2.5.RELEASE 5.1.4.RELEASE - + jdt_apt 2.1.1.RELEASE UTF-8 @@ -88,104 +87,104 @@ 1.3 ${java.version} - - - The Apache License, Version 2.0 - http://www.apache.org/licenses/LICENSE-2.0.txt - - - - - commons-io - commons-io - 2.2 - - - org.slf4j - slf4j-api - ${slf4j.version} - compile - - - com.google.guava - guava - 17.0 - - - junit - junit - 4.11 - test - - - - org.slf4j - slf4j-simple - ${slf4j.version} - test - - - joda-time - joda-time - 2.2 - - - - - - org.apache.maven.plugins - maven-compiler-plugin + + + The Apache License, Version 2.0 + http://www.apache.org/licenses/LICENSE-2.0.txt + + + + + commons-io + commons-io + 2.6 + + + org.slf4j + slf4j-api + ${slf4j.version} + compile + + + com.google.guava + guava + 27.1-jre + + + junit + junit + 4.11 + test + + + + org.slf4j + slf4j-simple + ${slf4j.version} + test + + + joda-time + joda-time + 2.10.2 + + + + + + org.apache.maven.plugins + maven-compiler-plugin 3.8.0 - - + + ${source.java.version} ${target.java.version} true true - - - - org.apache.maven.plugins - maven-release-plugin - 2.5.3 - - - - - - release - - - - org.apache.maven.plugins - maven-javadoc-plugin - 2.7 - - - attach-javadocs - - jar - - - - - - org.apache.maven.plugins - maven-source-plugin - - - attach-sources - - jar - - - - - - - - - + + + + org.apache.maven.plugins + maven-release-plugin + 2.5.3 + + + + + + release + + + + org.apache.maven.plugins + maven-javadoc-plugin + 2.7 + + + attach-javadocs + + jar + + + + + + org.apache.maven.plugins + maven-source-plugin + + + attach-sources + + jar + + + + + + + + + jcenter-bintray https://jcenter.bintray.com/ diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java index 576e9d9d..5d3cdc95 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifToolNew3.java @@ -632,7 +632,7 @@ public String getAbsoluteFileName(File file) { // return getMSDOSName(file); // else // return file.getAbsolutePath(); - if (CharMatcher.ASCII.matchesAllOf(file.getAbsolutePath())) { + if (CharMatcher.ascii().matchesAllOf(file.getAbsolutePath())) { return file.getAbsolutePath(); } return null; From 3fab44e2ebe90684fb606ead8393e0f3dc2155ca Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 17:49:55 +0300 Subject: [PATCH 139/148] [maven-release-plugin] prepare release exiftool-2.3.12 --- pom.xml | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/pom.xml b/pom.xml index e8d45fde..0f3fe4ff 100644 --- a/pom.xml +++ b/pom.xml @@ -1,6 +1,5 @@ - + 4.0.0 org.raisercostin.utils @@ -10,7 +9,7 @@ org.raisercostin exiftool - 2.3.12-SNAPSHOT + 2.3.12 jar exiftool Enhanced Java Integration for Phil Harvey's ExifTool. @@ -35,7 +34,7 @@ scm:git:${git.url}.git scm:git:${git.url}.git ${git.url} - ${project.artifactId}-${project.version} + exiftool-2.3.12 From bfd20e2640d47b1ded34319dde6492b2af83812d Mon Sep 17 00:00:00 2001 From: raisercostin Date: Mon, 10 Jun 2019 17:50:12 +0300 Subject: [PATCH 140/148] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 0f3fe4ff..97e14ef1 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.raisercostin exiftool - 2.3.12 + 2.3.13-SNAPSHOT jar exiftool Enhanced Java Integration for Phil Harvey's ExifTool. @@ -34,7 +34,7 @@ scm:git:${git.url}.git scm:git:${git.url}.git ${git.url} - exiftool-2.3.12 + ${project.artifactId}-${project.version} From dc1ea3343f61cb1de2175ebc80e6e6dbfc19990d Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 11 Jun 2019 12:45:31 +0300 Subject: [PATCH 141/148] proper end of line on windows --- design.png | Bin 0 -> 993057 bytes design.ucls | 564 +++++++++ .../thebuzzmedia/exiftool/ExifProcess.java | 5 +- .../thebuzzmedia/exiftool/TestExifTool.java | 1021 +++++++++-------- 4 files changed, 1080 insertions(+), 510 deletions(-) create mode 100644 design.png create mode 100644 design.ucls diff --git a/design.png b/design.png new file mode 100644 index 0000000000000000000000000000000000000000..be081f6ba589822d0c6448c5882b99e5330d9550 GIT binary patch literal 993057 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Ν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

eF3}jsTVF&=jN6)tAfGn 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 Kd@(}Ix5B3d0WLV=O4{+Jz)FBGKbQKu1 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
  • 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 + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + \ No newline at end of file diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index 858a23b9..aaa9bffb 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -160,11 +160,12 @@ public synchronized List sendArgs(List args) throws IOException if (!keepAlive) { throw new IOException("Not KeepAlive Process"); } + String eol = System.lineSeparator(); StringBuilder builder = new StringBuilder(); for (String arg : args) { - builder.append(arg).append("\n"); + builder.append(arg).append(eol); } - builder.append("-execute\n"); + builder.append("-execute").append(eol); LOG.info("exiftool " + Joiner.on(" ").join(args)); writeFlush(builder.toString()); return readResponse(args); diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index bd9b20a3..799ff5c8 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -36,512 +36,517 @@ */ public class TestExifTool { - private static final String TEST_FILES_PATH = "src/test/resources"; - private static Logger log = LoggerFactory.getLogger(TestExifTool.class); - - private static ExifToolService create(Feature... features) { - return RawExifTool.Factory.create(features); - // return new ExifToolNew2(features); - // return new ExifToolNew(features); - } - - private static ExifToolService create(int timeoutWhenKeepAliveInMillis, Feature... features) { - return RawExifTool.Factory.create(timeoutWhenKeepAliveInMillis, features); - // return new ExifToolNew(timeoutWhenKeepAliveInMillis, features); - // return new ExifToolNew2(timeoutWhenKeepAliveInMillis, features); - } - - private ExifToolService create(ReadOptions readOptions, Feature... features) { - return RawExifTool.Factory.create(readOptions, features); - } - - private ReadOptions options = new ReadOptions(); - - @Test - public void testSingleTool() throws Exception { - try (ExifToolService tool = create(Feature.STAY_OPEN)) { - assertTrue(runTests(tool, "")); - } - - try (ExifToolService tool = create(/* Feature.STAY_OPEN */)) { - assertTrue(runTests(tool, "")); - } - - // try (ExifToolService tool = create(Feature.STAY_OPEN)) { - // tool.startup(); - // assertTrue(runTests(tool, "")); - // } - } - - @Test - public void testConcurrent() throws Exception { - - int toolCount = 5; - - List threads = new ArrayList(toolCount); - for (int i = 1; i <= toolCount; i++) { - String toolName = "tool" + i; - Thread t = new Thread(toolName) { - @Override - public void run() { - log.debug(getName() + ": starting"); - try (ExifToolService tool = create(Feature.STAY_OPEN)) { - runTests(tool, getName()); - } catch (IOException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } catch (URISyntaxException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } finally { - log.debug(getName() + ": finished"); - } - } - }; - t.start(); - threads.add(t); - } - - for (Thread t : threads) { - t.run(); - } - } - - @Test - public void testManyThreadsOneTool() throws Exception { - try (ExifToolService tool = create(Feature.STAY_OPEN)) { - Thread[] threads = new Thread[20]; - for (int i = 0; i < threads.length; i++) { - final String label = "run " + i; - threads[i] = new Thread(new Runnable() { - @Override - public void run() { - try { - for (int j = 0; j < 5; j++) { - runTests(tool, label); - } - log.debug("DONE: " + label + " success!"); - } catch (IOException ex) { - fail(label); - } catch (URISyntaxException e) { - log.error(e.getMessage(), e); - fail(e.getMessage()); - } - } - }, label); - } - for (Thread thread : threads) { - thread.start(); - } - for (Thread thread : threads) { - thread.join(); - } - } - } - - @Test(expected = IOException.class) - public void testProcessTimeout() throws Exception { - try (ExifToolService tool = create(1, Feature.STAY_OPEN)) { - long start = System.currentTimeMillis(); - runTests(tool, "will fail"); - long end = System.currentTimeMillis(); - fail("should have failed. passed " + (end - start) + " miliseconds."); - } - } - - public boolean runTests(ExifToolService tool, String runId) throws IOException, URISyntaxException { - testFile(tool, "/kureckjones_jett_075_02-cropped.tif", 32, 728, 825, "P 45+", 100, "1/6", 0.16666); - testFile(tool, "/nexus-s-electric-cars.jpg", 27, 2560, 1920, "Nexus S", 50, "1/64", 0.015625); - // Map rawMetadata = tool.getImageMeta(imageFile, new - // ReadOptions().withNumericOutput(Format.HUMAN_READABLE)); - // assertEquals(231, rawMetadata.size()); - return true; - } - - private void testFile(ExifToolService tool, String resource, int size, int width, int height, String model, - int iso, String shutterRaw, double shutter) throws URISyntaxException, IOException { - File imageFile = new File(getClass().getResource(resource).toURI()); - Map metadata = tool.getImageMeta4d(imageFile, - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.values()); - assertEquals(size, metadata.size()); - assertEquals((Integer)width, Tag.IMAGE_WIDTH.getValue(metadata)); - assertEquals((Integer)height, Tag.IMAGE_HEIGHT.getValue(metadata)); - assertEquals(model, Tag.MODEL.getValue(metadata)); - assertEquals((Integer)iso, Tag.ISO.getValue(metadata)); - assertEquals(shutterRaw, Tag.SHUTTER_SPEED.getRawValue(metadata)); - assertEquals(shutter, (Double) Tag.SHUTTER_SPEED.getValue(metadata), 1e-5); - } - - @Test - public void testGroupTags() throws Exception { - try (ExifToolService tool = create(Feature.STAY_OPEN)) { - Map metadata; - - URL url = getClass().getResource("/iptc_test-photoshop.jpg"); - File f = new File(url.toURI()); - metadata = tool.getImageMeta5(f, options, Format.HUMAN_READABLE, TagGroup.IPTC); - assertEquals(17, metadata.size()); - assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); - assertEquals("IPTC Status: Copyright Notice", metadata.get("CopyrightNotice")); - assertEquals("IPTC Content: Description Writer", metadata.get("Writer-Editor")); - // for (String key : metadata.keySet()){ - // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); - // } - } - } - - @Test - public void testTag() { - assertEquals("string value", "John Doe", Tag.AUTHOR.parseValue("John Doe")); - assertEquals("integer value", (Integer)200, Tag.ISO.parseValue("200")); - assertEquals("double value, from fraction", (Double).25, Tag.SHUTTER_SPEED.parseValue("1/4")); - assertEquals("double value, from decimal", (Double).25, Tag.SHUTTER_SPEED.parseValue(".25")); - } - - @Test - public void testVersionNumber() { - assertTrue(new VersionNumber("1.2").isBeforeOrEqualTo(new VersionNumber("1.2.3"))); - assertTrue(new VersionNumber(1, 2).isBeforeOrEqualTo(new VersionNumber("1.2"))); - assertTrue(new VersionNumber(1, 2, 3).isBeforeOrEqualTo(new VersionNumber("1.3"))); - assertTrue(new VersionNumber(1, 2, 3).isBeforeOrEqualTo(new VersionNumber(2, 1))); - } - - @Test - public void testWriteTagStringNonDaemon() throws Exception { - try (ExifToolService tool = create()) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); - MetadataTag[] tags = { Tag.DATE_TIME_ORIGINAL }; - - // Check the value is correct at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - MetadataTag[] tags1 = { Tag.DATE_TIME_ORIGINAL }; - - // Finally check that it's updated - metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); - } - } - - @Test - public void testWriteTagString() throws Exception { - try (ExifToolService tool = create(Feature.STAY_OPEN)) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); - MetadataTag[] tags = { Tag.DATE_TIME_ORIGINAL }; - - // Check the value is correct at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Now change it - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - tool.addImageMetadata(imageFile.toFile(), newValues); - MetadataTag[] tags1 = { Tag.DATE_TIME_ORIGINAL }; - - // Finally check that it's updated - metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); - } - } - - @Test(expected=ExifError.class) - public void testWriteTagStringInvalidformat() throws Exception { - try (ExifToolService tool = create(Feature.STAY_OPEN)) { - Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(getClass().getResource("/nexus-s-electric-cars.jpg").toURI()), imageFile, - StandardCopyOption.REPLACE_EXISTING); - - // Check the value is correct at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.DATE_TIME_ORIGINAL); - String initial = "2010:12:10 17:07:05"; - assertEquals("Wrong starting value", initial, Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); - - String newDate = "2egek opkpgrpok"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - ExifError error = null; - try { - // Now change it to an invalid value which should fail - tool.addImageMetadata(imageFile.toFile(), newValues); - } catch (ExifError e) { - error = e; - } - // Finally check that it's not updated - metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.DATE_TIME_ORIGINAL); - assertEquals("DateTimeOriginal tag is wrong", initial, Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); - throw error; - } - } - - @Test - public void testWriteTagNumberNonDaemon() throws Exception { - try (ExifToolService tool = create()) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); - MetadataTag[] tags = { Tag.ORIENTATION }; - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", - metadata.get(Tag.ORIENTATION)); - - // Now change it - Map newValues = new HashMap(); - newValues.put(Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - MetadataTag[] tags1 = { Tag.ORIENTATION }; - - // Finally check the updated value - metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); - } - } - - @Test - public void testWriteTagNumber() throws Exception { - try (ExifToolService tool = create(Feature.STAY_OPEN)) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); - MetadataTag[] tags = { Tag.ORIENTATION }; - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", - metadata.get(Tag.ORIENTATION)); - - // Now change it - Map newValues = new HashMap(); - newValues.put(Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - MetadataTag[] tags1 = { Tag.ORIENTATION }; - - // Finally check the updated value - metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); - } - } - - @Test - public void testWriteMulipleTag() throws Exception { - try (ExifToolService tool = create(Feature.STAY_OPEN)) { - Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(getClass().getResource("/nexus-s-electric-cars.jpg").toURI()), imageFile, - StandardCopyOption.REPLACE_EXISTING); - // Test what orientation value is at the start - Map metadata = tool - .getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), - Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", - Tag.ORIENTATION.getRawValue(metadata)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - - // Finally check the updated value - metadata = tool - .getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), - Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", Tag.ORIENTATION.getRawValue(metadata)); - assertEquals("DateTimeOriginal tag is wrong", newDate, Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); - } - } - - @Test - public void testWriteMulipleTagNonDaemon() throws Exception { - try (ExifToolService tool = create()) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); - MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", - metadata.get(Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(Tag.ORIENTATION, 3); - - tool.addImageMetadata(imageFile.toFile(), newValues); - MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; - - // Finally check the updated value - metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); - } - } - - @Test - public void testWriteMultipleTagNonDaemon2() throws Exception { - try (ExifToolService tool = create()) { - URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); - Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); - MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; - - // Test what orientation value is at the start - Map metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); - assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", - metadata.get(Tag.ORIENTATION)); - assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); - - // Now change them - String newDate = "2014:01:23 10:07:05"; - Map newValues = new HashMap(); - newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); - newValues.put(Tag.ORIENTATION, 3); - - // tool.writeMetadata(imageFile.toFile(), newValues); - tool.addImageMetadata(imageFile.toFile(), newValues); - MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; - - // Finally check the updated value - metadata = tool.getImageMeta4d(imageFile.toFile(), - new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); - assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); - assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); - } - } - - @Test - public void testWritingWithImplicitTypes() throws Exception { - try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), - Feature.MWG_MODULE)) { - Path imagePath = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); - Files.copy(Paths.get(getClass().getResource("/nexus-s-electric-cars.jpg").toURI()), imagePath, StandardCopyOption.REPLACE_EXISTING); - File imageFile = imagePath.toFile(); - // Test what orientation value is at the start - SimpleDateFormat formatter = new SimpleDateFormat("yyyy:MM:dd hh:mm:ss"); - - Map metadata = tool.getImageMeta2(imageFile, options.withNumericOutput(true), - Tag.ORIENTATION, MwgTag.DATE_TIME_ORIGINAL); - assertEquals("Orientation tag starting value is wrong", (Integer)1, Tag.ORIENTATION.getValue(metadata)); - assertEquals("Wrong starting value", formatter.parse("2010:12:10 17:07:05"), - MwgTag.DATE_TIME_ORIGINAL.getValue(metadata)); - - // Now change them - Map data = new HashMap(); - Date dateTimeOrig = formatter.parse("2014:01:23 10:07:05"); - data.put(MwgTag.DATE_TIME_ORIGINAL, dateTimeOrig); - data.put(Tag.ORIENTATION, 3); - Date createDate = formatter.parse("2013:02:21 10:07:05"); - data.put(MwgTag.CREATE_DATE, createDate.getTime()); - data.put(MwgTag.KEYWORDS, new String[] { "a", "b", "c" }); - tool.writeMetadata(new WriteOptions().withDeleteBackupFile(false), imageFile, data); - - // Finally check the updated value - metadata = tool.getImageMeta6(imageFile, options.withNumericOutput(true), Tag.ORIENTATION, imageFile, MwgTag.DATE_TIME_ORIGINAL, - MwgTag.CREATE_DATE, MwgTag.KEYWORDS); - assertEquals("Orientation tag updated value is wrong", (Integer)3, Tag.ORIENTATION.getValue(metadata)); - assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, MwgTag.DATE_TIME_ORIGINAL.getValue(metadata)); - assertEquals("CreateDate tag is wrong", createDate, MwgTag.CREATE_DATE.getValue(metadata)); - assertEquals("Keywords tag is wrong", "a", ((String[]) MwgTag.KEYWORDS.getValue(metadata))[0]); - List keys = Arrays.asList(((String[]) MwgTag.KEYWORDS.getValue(metadata))); - assertEquals("Keywords tag is wrong", 3, keys.size()); - assertEquals("Keywords tag is wrong", "a:b:c", Joiner.on(":").join(keys)); - } - } - - @Test//(expected = ExifError.class) - public void testReadingUtf8NamesWithStayOpen() throws Exception { - try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), - Feature.STAY_OPEN)) { - URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); - File imageFile = new File(url.toURI()); - Map metadata = tool.getImageMeta3(imageFile, options); - // should fail on the line before. this is just for breakpoint and retry - Map metadata2 = tool.getImageMeta3(imageFile, options); - assertEquals(21, metadata2.size()); - } - } - - @Test//(expected = ExifError.class) - public void testReadingUtf8NamesWithStayOpenWithoutSpaces() throws Exception { - try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), - Feature.STAY_OPEN)) { - URL url = getClass().getResource("/20140502_152336_Östliche_Zubringerstraße.png"); - File imageFile = new File(url.toURI()); - // System.out.println(imageFile.getAbsolutePath()); - Map metadata = tool.getImageMeta3(imageFile, options); - assertEquals(21, metadata.size()); - } - } - - @Test - public void testReadingUtf8NamesWithoutStayOpen() throws Exception { - try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true))) { - URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); - File imageFile = new File(url.toURI()); - // System.out.println(imageFile.getAbsolutePath()); - Map metadata = tool.getImageMeta3(imageFile, options); - assertEquals(21, metadata.size()); - } - } - - @Test - public void testReadingUtf8NamesWithStayOpenAndWindows() throws Exception { - try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), - Feature.STAY_OPEN, Feature.WINDOWS)) { - URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); - File imageFile = new File(url.toURI()); - // System.out.println(imageFile.getAbsolutePath()); - Map metadata = tool.getImageMeta3(imageFile, options); - assertEquals(21, metadata.size()); - } - } - - @Test - public void testReadingUtf8NamesOnWindows() throws Exception { - try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), - Feature.STAY_OPEN, Feature.WINDOWS)) { - URL url = getClass().getResource("/20131231_230955_Strada Frumoasă.png"); - File imageFile = new File(url.toURI()); - // System.out.println(imageFile.getAbsolutePath()); - Map metadata1 = tool.getImageMeta(imageFile, options); - assertEquals(21, metadata1.size()); - // System.out.println(metadata1); - Map metadata = tool.getImageMeta3(imageFile, options); - assertEquals(21, metadata.size()); - } - } + private static final String TEST_FILES_PATH = "src/test/resources"; + private static Logger log = LoggerFactory.getLogger(TestExifTool.class); + + private static ExifToolService create(Feature... features) { + return RawExifTool.Factory.create(features); + // return new ExifToolNew2(features); + // return new ExifToolNew(features); + } + + private static ExifToolService create(int timeoutWhenKeepAliveInMillis, Feature... features) { + return RawExifTool.Factory.create(timeoutWhenKeepAliveInMillis, features); + // return new ExifToolNew(timeoutWhenKeepAliveInMillis, features); + // return new ExifToolNew2(timeoutWhenKeepAliveInMillis, features); + } + + private ExifToolService create(ReadOptions readOptions, Feature... features) { + return RawExifTool.Factory.create(readOptions, features); + } + + private ReadOptions options = new ReadOptions(); + + @Test + public void testSingleTool() throws Exception { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { + assertTrue(runTests(tool, "")); + } + + try (ExifToolService tool = create(/* Feature.STAY_OPEN */)) { + assertTrue(runTests(tool, "")); + } + + // try (ExifToolService tool = create(Feature.STAY_OPEN)) { + // tool.startup(); + // assertTrue(runTests(tool, "")); + // } + } + + @Test + public void testConcurrent() throws Exception { + + int toolCount = 5; + + List threads = new ArrayList(toolCount); + for (int i = 1; i <= toolCount; i++) { + String toolName = "tool" + i; + Thread t = new Thread(toolName) { + @Override + public void run() { + log.debug(getName() + ": starting"); + try (ExifToolService tool = create(Feature.STAY_OPEN)) { + runTests(tool, getName()); + } catch (IOException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } catch (URISyntaxException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } finally { + log.debug(getName() + ": finished"); + } + } + }; + t.start(); + threads.add(t); + } + + for (Thread t : threads) { + t.run(); + } + } + + @Test + public void testManyThreadsOneTool() throws Exception { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { + Thread[] threads = new Thread[20]; + for (int i = 0; i < threads.length; i++) { + final String label = "run " + i; + threads[i] = new Thread(new Runnable() { + @Override + public void run() { + try { + for (int j = 0; j < 5; j++) { + runTests(tool, label); + } + log.debug("DONE: " + label + " success!"); + } catch (IOException ex) { + fail(label); + } catch (URISyntaxException e) { + log.error(e.getMessage(), e); + fail(e.getMessage()); + } + } + }, label); + } + for (Thread thread : threads) { + thread.start(); + } + for (Thread thread : threads) { + thread.join(); + } + } + } + + @Test(expected = IOException.class) + public void testProcessTimeout() throws Exception { + try (ExifToolService tool = create(1, Feature.STAY_OPEN)) { + long start = System.currentTimeMillis(); + runTests(tool, "will fail"); + long end = System.currentTimeMillis(); + fail("should have failed. passed " + (end - start) + " miliseconds."); + } + } + + public boolean runTests(ExifToolService tool, String runId) throws IOException, URISyntaxException { + testFile(tool, "/kureckjones_jett_075_02-cropped.tif", 32, 728, 825, "P 45+", 100, "1/6", 0.16666); + testFile(tool, "/nexus-s-electric-cars.jpg", 27, 2560, 1920, "Nexus S", 50, "1/64", 0.015625); + // Map rawMetadata = tool.getImageMeta(imageFile, new + // ReadOptions().withNumericOutput(Format.HUMAN_READABLE)); + // assertEquals(231, rawMetadata.size()); + return true; + } + + private void testFile(ExifToolService tool, String resource, int size, int width, int height, String model, int iso, String shutterRaw, + double shutter) throws URISyntaxException, IOException { + File imageFile = new File(getClass().getResource(resource).toURI()); + Map metadata = tool.getImageMeta4d(imageFile, new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), + Tag.values()); + assertEquals(size, metadata.size()); + assertEquals((Integer) width, Tag.IMAGE_WIDTH.getValue(metadata)); + assertEquals((Integer) height, Tag.IMAGE_HEIGHT.getValue(metadata)); + assertEquals(model, Tag.MODEL.getValue(metadata)); + assertEquals((Integer) iso, Tag.ISO.getValue(metadata)); + assertEquals(shutterRaw, Tag.SHUTTER_SPEED.getRawValue(metadata)); + assertEquals(shutter, (Double) Tag.SHUTTER_SPEED.getValue(metadata), 1e-5); + } + + @Test + public void testGroupTags() throws Exception { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { + Map metadata; + + URL url = getClass().getResource("/iptc_test-photoshop.jpg"); + File f = new File(url.toURI()); + metadata = tool.getImageMeta5(f, options, Format.HUMAN_READABLE, TagGroup.IPTC); + assertEquals(17, metadata.size()); + assertEquals("IPTC Content: Keywords", metadata.get("Keywords")); + assertEquals("IPTC Status: Copyright Notice", metadata.get("CopyrightNotice")); + assertEquals("IPTC Content: Description Writer", metadata.get("Writer-Editor")); + // for (String key : metadata.keySet()){ + // log.info(String.format("\t\t%s: %s", key, metadata.get(key))); + // } + } + } + + @Test + public void testTag() { + assertEquals("string value", "John Doe", Tag.AUTHOR.parseValue("John Doe")); + assertEquals("integer value", (Integer) 200, Tag.ISO.parseValue("200")); + assertEquals("double value, from fraction", (Double) .25, Tag.SHUTTER_SPEED.parseValue("1/4")); + assertEquals("double value, from decimal", (Double) .25, Tag.SHUTTER_SPEED.parseValue(".25")); + } + + @Test + public void testVersionNumber() { + assertTrue(new VersionNumber("1.2").isBeforeOrEqualTo(new VersionNumber("1.2.3"))); + assertTrue(new VersionNumber(1, 2).isBeforeOrEqualTo(new VersionNumber("1.2"))); + assertTrue(new VersionNumber(1, 2, 3).isBeforeOrEqualTo(new VersionNumber("1.3"))); + assertTrue(new VersionNumber(1, 2, 3).isBeforeOrEqualTo(new VersionNumber(2, 1))); + } + + @Test + public void testWriteTagStringNonDaemon() throws Exception { + try (ExifToolService tool = create()) { + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.DATE_TIME_ORIGINAL }; + + // Check the value is correct at the start + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.DATE_TIME_ORIGINAL }; + + // Finally check that it's updated + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); + } + } + + @Test + public void testWriteTagString() throws Exception { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.DATE_TIME_ORIGINAL }; + + // Check the value is correct at the start + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change it + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.DATE_TIME_ORIGINAL }; + + // Finally check that it's updated + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); + } + } + + @Test(expected = ExifError.class) + public void testWriteTagStringInvalidformat() throws Exception { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(getClass().getResource("/nexus-s-electric-cars.jpg").toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); + + // Check the value is correct at the start + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.DATE_TIME_ORIGINAL); + String initial = "2010:12:10 17:07:05"; + assertEquals("Wrong starting value", initial, Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); + + String newDate = "2egek opkpgrpok"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + ExifError error = null; + try { + // Now change it to an invalid value which should fail + tool.addImageMetadata(imageFile.toFile(), newValues); + } catch (ExifError e) { + error = e; + } + // Finally check that it's not updated + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), + Tag.DATE_TIME_ORIGINAL); + assertEquals("DateTimeOriginal tag is wrong", initial, Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); + throw error; + } + } + + @Test + public void testWriteTagNumberNonDaemon() throws Exception { + try (ExifToolService tool = create()) { + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION }; + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + + // Now change it + Map newValues = new HashMap(); + newValues.put(Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION }; + + // Finally check the updated value + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); + } + } + + @Test + public void testWriteTagNumber() throws Exception { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION }; + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + + // Now change it + Map newValues = new HashMap(); + newValues.put(Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION }; + + // Finally check the updated value + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); + } + } + + @Test + public void testWriteMulipleTag() throws Exception { + try (ExifToolService tool = create(Feature.STAY_OPEN)) { + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(getClass().getResource("/nexus-s-electric-cars.jpg").toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); + // Test what orientation value is at the start + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", Tag.ORIENTATION.getRawValue(metadata)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + + // Finally check the updated value + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), Tag.ORIENTATION, + Tag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", Tag.ORIENTATION.getRawValue(metadata)); + assertEquals("DateTimeOriginal tag is wrong", newDate, Tag.DATE_TIME_ORIGINAL.getRawValue(metadata)); + } + } + + @Test + public void testWriteMulipleTagNonDaemon() throws Exception { + try (ExifToolService tool = create()) { + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); + + tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; + + // Finally check the updated value + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); + } + } + + @Test + public void testWriteMultipleTagNonDaemon2() throws Exception { + try (ExifToolService tool = create()) { + URL url = getClass().getResource("/nexus-s-electric-cars.jpg"); + Path imageFile = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(url.toURI()), imageFile, StandardCopyOption.REPLACE_EXISTING); + MetadataTag[] tags = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; + + // Test what orientation value is at the start + Map metadata = tool.getImageMeta4d(imageFile.toFile(), + new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags); + assertEquals("Orientation tag starting value is wrong", "Horizontal (normal)", metadata.get(Tag.ORIENTATION)); + assertEquals("Wrong starting value", "2010:12:10 17:07:05", metadata.get(Tag.DATE_TIME_ORIGINAL)); + + // Now change them + String newDate = "2014:01:23 10:07:05"; + Map newValues = new HashMap(); + newValues.put(Tag.DATE_TIME_ORIGINAL, newDate); + newValues.put(Tag.ORIENTATION, 3); + + // tool.writeMetadata(imageFile.toFile(), newValues); + tool.addImageMetadata(imageFile.toFile(), newValues); + MetadataTag[] tags1 = { Tag.ORIENTATION, Tag.DATE_TIME_ORIGINAL }; + + // Finally check the updated value + metadata = tool.getImageMeta4d(imageFile.toFile(), new ReadOptions().withNumericOutput(Format.HUMAN_READABLE), tags1); + assertEquals("Orientation tag updated value is wrong", "Rotate 180", metadata.get(Tag.ORIENTATION)); + assertEquals("DateTimeOriginal tag is wrong", newDate, metadata.get(Tag.DATE_TIME_ORIGINAL)); + } + } + + @Test + public void testWritingWithImplicitTypes() throws Exception { + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), Feature.MWG_MODULE)) { + Path imagePath = Paths.get("target", "nexus-s-electric-cars-tochange.jpg"); + Files.copy(Paths.get(getClass().getResource("/nexus-s-electric-cars.jpg").toURI()), imagePath, StandardCopyOption.REPLACE_EXISTING); + File imageFile = imagePath.toFile(); + // Test what orientation value is at the start + SimpleDateFormat formatter = new SimpleDateFormat("yyyy:MM:dd hh:mm:ss"); + + Map metadata = tool.getImageMeta2(imageFile, options.withNumericOutput(true), Tag.ORIENTATION, + MwgTag.DATE_TIME_ORIGINAL); + assertEquals("Orientation tag starting value is wrong", (Integer) 1, Tag.ORIENTATION.getValue(metadata)); + assertEquals("Wrong starting value", formatter.parse("2010:12:10 17:07:05"), MwgTag.DATE_TIME_ORIGINAL.getValue(metadata)); + + // Now change them + Map data = new HashMap(); + Date dateTimeOrig = formatter.parse("2014:01:23 10:07:05"); + data.put(MwgTag.DATE_TIME_ORIGINAL, dateTimeOrig); + data.put(Tag.ORIENTATION, 3); + Date createDate = formatter.parse("2013:02:21 10:07:05"); + data.put(MwgTag.CREATE_DATE, createDate.getTime()); + data.put(MwgTag.KEYWORDS, new String[] { "a", "b", "c" }); + tool.writeMetadata(new WriteOptions().withDeleteBackupFile(false), imageFile, data); + + // Finally check the updated value + metadata = tool.getImageMeta6(imageFile, options.withNumericOutput(true), Tag.ORIENTATION, imageFile, MwgTag.DATE_TIME_ORIGINAL, + MwgTag.CREATE_DATE, MwgTag.KEYWORDS); + assertEquals("Orientation tag updated value is wrong", (Integer) 3, Tag.ORIENTATION.getValue(metadata)); + assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, MwgTag.DATE_TIME_ORIGINAL.getValue(metadata)); + assertEquals("CreateDate tag is wrong", createDate, MwgTag.CREATE_DATE.getValue(metadata)); + assertEquals("Keywords tag is wrong", "a", ((String[]) MwgTag.KEYWORDS.getValue(metadata))[0]); + List keys = Arrays.asList(((String[]) MwgTag.KEYWORDS.getValue(metadata))); + assertEquals("Keywords tag is wrong", 3, keys.size()); + assertEquals("Keywords tag is wrong", "a:b:c", Joiner.on(":").join(keys)); + } + } + + @Test // (expected = ExifError.class) + public void testReadingUtf8NamesWithStayOpen() throws Exception { + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), Feature.STAY_OPEN)) { + URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); + File imageFile = new File(url.toURI()); + Map metadata = tool.getImageMeta3(imageFile, options); + // should fail on the line before. this is just for breakpoint and retry + Map metadata2 = tool.getImageMeta3(imageFile, options); + assertEquals(21, metadata2.size()); + } + } + + @Test // (expected = ExifError.class) + public void testReadingUtf8NamesWithStayOpenWithoutSpaces() throws Exception { + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), Feature.STAY_OPEN)) { + URL url = getClass().getResource("/20140502_152336_Östliche_Zubringerstraße.png"); + File imageFile = new File(url.toURI()); + // System.out.println(imageFile.getAbsolutePath()); + Map metadata = tool.getImageMeta3(imageFile, options); + assertEquals(21, metadata.size()); + } + } + + @Test + public void testReadingUtf8NamesWithoutStayOpen() throws Exception { + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true))) { + URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); + File imageFile = new File(url.toURI()); + // System.out.println(imageFile.getAbsolutePath()); + Map metadata = tool.getImageMeta3(imageFile, options); + assertEquals(21, metadata.size()); + } + } + + @Test + public void testReadingUtf8NamesWithStayOpenAndWindows() throws Exception { + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), Feature.STAY_OPEN, + Feature.WINDOWS)) { + URL url = getClass().getResource("/20140502_152336_Östliche Zubringerstraße.png"); + File imageFile = new File(url.toURI()); + // System.out.println(imageFile.getAbsolutePath()); + Map metadata = tool.getImageMeta3(imageFile, options); + assertEquals(21, metadata.size()); + } + } + + @Test + public void testReadingUtf8NamesOnWindows() throws Exception { + try (ExifToolService tool = create(new ReadOptions().withNumericOutput(true).withConvertTypes(true), Feature.STAY_OPEN, + Feature.WINDOWS)) { + URL url = getClass().getResource("/20131231_230955_Strada Frumoasă.png"); + File imageFile = new File(url.toURI()); + // System.out.println(imageFile.getAbsolutePath()); + Map metadata1 = tool.getImageMeta(imageFile, options); + assertEquals(21, metadata1.size()); + // System.out.println(metadata1); + Map metadata = tool.getImageMeta3(imageFile, options); + assertEquals(21, metadata.size()); + } + } + + @Test + public void testReadingOnWindowsEndOfLine() throws Exception { + ExifToolNew3 exifTool = new ExifToolNew3(Feature.WINDOWS, Feature.STAY_OPEN); + Map map = exifTool.getImageMeta( + new File("e:\\work\\electrica\\00-ICT\\FOCSANI\\__Echipamente AMR Telecomunicatii\\20 SDEE Focsani 27,1843148 45,69987857.jpg"), + new ReadOptions() + , + "GPSAltitude", + "GPSLatitude", + "GPSLatitudeRef", + "GPSLongitude", + "GPSLongitudeRef", + "GPSAltitude", + "GPSAltitudeRef", + "GPSSpeed", + "GPSSpeedRef", + "GPSProcessingMethod", + "GPSDestBearing", + "GPSDestBearingRef", + "GPSTimeStamp" + ); + System.out.println(map); + } } From 2d4fe2bc5811413147bf87df70391e2c1f772d40 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 11 Jun 2019 12:46:05 +0300 Subject: [PATCH 142/148] [maven-release-plugin] prepare release exiftool-2.3.13 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 97e14ef1..8e8a39a0 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.raisercostin exiftool - 2.3.13-SNAPSHOT + 2.3.13 jar exiftool Enhanced Java Integration for Phil Harvey's ExifTool. @@ -34,7 +34,7 @@ scm:git:${git.url}.git scm:git:${git.url}.git ${git.url} - ${project.artifactId}-${project.version} + exiftool-2.3.13 From c8dbb9c2ed6fe588d5f1393c60e9bdcf651b673b Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 11 Jun 2019 12:46:18 +0300 Subject: [PATCH 143/148] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 8e8a39a0..3a5845a7 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.raisercostin exiftool - 2.3.13 + 2.3.14-SNAPSHOT jar exiftool Enhanced Java Integration for Phil Harvey's ExifTool. @@ -34,7 +34,7 @@ scm:git:${git.url}.git scm:git:${git.url}.git ${git.url} - exiftool-2.3.13 + ${project.artifactId}-${project.version} From 44400f522bcafe450d928c421585e6a3dcc4e7d1 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 11 Jun 2019 13:10:47 +0300 Subject: [PATCH 144/148] Fix in case an empty response came. --- .../thebuzzmedia/exiftool/ExifProcess.java | 513 +++++++++--------- .../thebuzzmedia/exiftool/TestExifTool.java | 5 +- 2 files changed, 260 insertions(+), 258 deletions(-) diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index aaa9bffb..d6c6ed68 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -21,6 +21,7 @@ import java.util.regex.Pattern; import com.google.common.base.Joiner; +import com.google.common.base.Preconditions; import com.google.common.base.Strings; import com.google.common.collect.Collections2; import com.google.common.collect.Lists; @@ -31,288 +32,288 @@ * streams for reading and writing data. */ public final class ExifProcess { - private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ExifProcess.class); + private static final org.slf4j.Logger LOG = org.slf4j.LoggerFactory.getLogger(ExifProcess.class); - private static class Pair { - final P1 _1; - final P2 _2; + private static class Pair { + final P1 _1; + final P2 _2; - public Pair(P1 _1, P2 _2) { - this._1 = _1; - this._2 = _2; - } + public Pair(P1 _1, P2 _2) { + this._1 = _1; + this._2 = _2; + } - @Override - public String toString() { - return "Pair(" + _1 + "," + _2 + ")"; - } - } + @Override + public String toString() { + return "Pair(" + _1 + "," + _2 + ")"; + } + } - private static final Map> all = Collections - .synchronizedMap(new TreeMap>()); - static { - LOG.debug("addShutdownHook"); - Runtime.getRuntime().addShutdownHook(new Thread() { - public void run() { - if (!all.isEmpty()) { - LOG.debug("Close all not closed processes:" + all.keySet()); - for (Entry> item : new HashSet>>( - all.entrySet())) { - LOG.debug("Close not closed process " + item, new RuntimeException()); - item.getValue()._2.close(); - } - } - } - }); - } + private static final Map> all = Collections + .synchronizedMap(new TreeMap>()); + static { + LOG.debug("addShutdownHook"); + Runtime.getRuntime().addShutdownHook(new Thread() { + public void run() { + if (!all.isEmpty()) { + LOG.debug("Close all not closed processes:" + all.keySet()); + for (Entry> item : new HashSet>>(all.entrySet())) { + LOG.debug("Close not closed process " + item, new RuntimeException()); + item.getValue()._2.close(); + } + } + } + }); + } - public static VersionNumber readVersion(String exifCmd) { - ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, "-ver"), Charset.defaultCharset()); - try { - return new VersionNumber(process.readLine()); - } catch (IOException ex) { - throw new RuntimeException(String.format("Unable to check version number of ExifToolNew3: %s", exifCmd)); - } finally { - process.close(); - } - } + public static VersionNumber readVersion(String exifCmd) { + ExifProcess process = new ExifProcess(false, Arrays.asList(exifCmd, "-ver"), Charset.defaultCharset()); + try { + return new VersionNumber(process.readLine()); + } catch (IOException ex) { + throw new RuntimeException(String.format("Unable to check version number of ExifToolNew3: %s", exifCmd)); + } finally { + process.close(); + } + } - private static ExifProcess _execute(boolean keepAlive, List args, Charset charset) { - return new ExifProcess(keepAlive, args, charset); - } + private static ExifProcess _execute(boolean keepAlive, List args, Charset charset) { + return new ExifProcess(keepAlive, args, charset); + } - public static List executeToResults(String exifCmd, List args, Charset charset) throws IOException { - List newArgs = new ArrayList(args.size() + 1); - newArgs.add(exifCmd); - newArgs.addAll(args); - ExifProcess process = _execute(false, newArgs, charset); - try { - return process.readResponse(args); - } catch (Throwable e) { - throw new RuntimeException(String.format("When executing %s we got %s", toCmd(newArgs), e.getMessage()), e); - } finally { - process.close(); - } - } + public static List executeToResults(String exifCmd, List args, Charset charset) throws IOException { + List newArgs = new ArrayList(args.size() + 1); + newArgs.add(exifCmd); + newArgs.addAll(args); + ExifProcess process = _execute(false, newArgs, charset); + try { + return process.readResponse(args); + } catch (Throwable e) { + throw new RuntimeException(String.format("When executing %s we got %s", toCmd(newArgs), e.getMessage()), e); + } finally { + process.close(); + } + } - private static String toCmd(List args) { - StringBuilder sb = new StringBuilder(); - for (String arg : args) { - sb.append(arg).append(" "); - } - return sb.toString(); - } + private static String toCmd(List args) { + StringBuilder sb = new StringBuilder(); + for (String arg : args) { + sb.append(arg).append(" "); + } + return sb.toString(); + } - // - // public static String executeToString(String exifCmd, List args, Charset charset) throws IOException { - // return ExifProxy.$.toResponse(executeToResults(exifCmd,args,charset)); - // } - // - public static ExifProcess startup(String exifCmd, Charset charset) { - List args = Arrays.asList(exifCmd, "-stay_open", "True", "-@", "-"); - return _execute(true, args, charset); - } + // + // public static String executeToString(String exifCmd, List args, Charset charset) throws IOException { + // return ExifProxy.$.toResponse(executeToResults(exifCmd,args,charset)); + // } + // + public static ExifProcess startup(String exifCmd, Charset charset) { + List args = Arrays.asList(exifCmd, "-stay_open", "True", "-@", "-"); + return _execute(true, args, charset); + } - private final ReentrantLock closeLock = new ReentrantLock(false); - private final boolean keepAlive; - private final Process process; - private final BufferedReader reader; - private final OutputStreamWriter writer; - private final LineReaderThread errReader; - private volatile boolean closed = false; + private final ReentrantLock closeLock = new ReentrantLock(false); + private final boolean keepAlive; + private final Process process; + private final BufferedReader reader; + private final OutputStreamWriter writer; + private final LineReaderThread errReader; + private volatile boolean closed = false; - public ExifProcess(boolean keepAlive, List args, Charset charset) { - this.keepAlive = keepAlive; - LOG.debug(String.format("Attempting to start ExifToolNew3 process using args: %s", args)); - try { - LOG.info("start background process: "+Joiner.on(" ").join(args)); - this.process = new ProcessBuilder(args).start(); - all.put(process.toString(), new Pair(toString(new RuntimeException("start of " - + process)), this)); - this.reader = new BufferedReader(new InputStreamReader(process.getInputStream())); - this.writer = new OutputStreamWriter(process.getOutputStream(), charset); - this.errReader = new LineReaderThread("exif-process-err-reader", new BufferedReader(new InputStreamReader( - process.getErrorStream()))); - this.errReader.setDaemon(true); - errReader.start(); - LOG.debug("\tSuccessful " + process + " started."); - } catch (Exception e) { - String message = "Unable to start external ExifToolNew3 process using the execution arguments: " + args - + ". Ensure ExifToolNew3 is installed correctly and runs using the command path '" + args.get(0) - + "' as specified by the 'exiftool.path' system property."; + public ExifProcess(boolean keepAlive, List args, Charset charset) { + this.keepAlive = keepAlive; + LOG.debug(String.format("Attempting to start ExifToolNew3 process using args: %s", args)); + try { + LOG.info("start background process: " + Joiner.on(" ").join(args)); + this.process = new ProcessBuilder(args).start(); + all.put(process.toString(), new Pair(toString(new RuntimeException("start of " + process)), this)); + this.reader = new BufferedReader(new InputStreamReader(process.getInputStream())); + this.writer = new OutputStreamWriter(process.getOutputStream(), charset); + this.errReader = new LineReaderThread("exif-process-err-reader", new BufferedReader(new InputStreamReader(process.getErrorStream()))); + this.errReader.setDaemon(true); + errReader.start(); + LOG.debug("\tSuccessful " + process + " started."); + } catch (Exception e) { + String message = "Unable to start external ExifToolNew3 process using the execution arguments: " + args + + ". Ensure ExifToolNew3 is installed correctly and runs using the command path '" + args.get(0) + + "' as specified by the 'exiftool.path' system property."; - LOG.debug(message); - throw new RuntimeException(message, e); - } - } + LOG.debug(message); + throw new RuntimeException(message, e); + } + } - private String toString(Throwable throwable) { - StringWriter sw = new StringWriter(); - throwable.printStackTrace(new PrintWriter(sw)); - return sw.getBuffer().toString(); - } + private String toString(Throwable throwable) { + StringWriter sw = new StringWriter(); + throwable.printStackTrace(new PrintWriter(sw)); + return sw.getBuffer().toString(); + } - public synchronized List sendToRunning(List args) throws IOException { - return sendArgs(args); - } + public synchronized List sendToRunning(List args) throws IOException { + return sendArgs(args); + } - public synchronized List sendArgs(List args) throws IOException { - if (!keepAlive) { - throw new IOException("Not KeepAlive Process"); - } - String eol = System.lineSeparator(); - StringBuilder builder = new StringBuilder(); - for (String arg : args) { - builder.append(arg).append(eol); - } - builder.append("-execute").append(eol); - LOG.info("exiftool " + Joiner.on(" ").join(args)); - writeFlush(builder.toString()); - return readResponse(args); - } + public synchronized List sendArgs(List args) throws IOException { + if (!keepAlive) { + throw new IOException("Not KeepAlive Process"); + } + StringBuilder builder = new StringBuilder(); + for (String arg : args) { + builder.append(arg).append("\n"); + } + builder.append("-execute\n"); + LOG.info("exiftool " + Joiner.on(" ").join(args)); + writeFlush(builder.toString()); + return readResponse(args); + } - public synchronized void writeFlush(String message) throws IOException { - if (closed) - throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); - writer.write(message); - writer.flush(); - } + public synchronized void writeFlush(String message) throws IOException { + if (closed) + throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); + writer.write(message); + writer.flush(); + } - public synchronized String readLine() throws IOException { - if (closed) - throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); - return reader.readLine(); - } + public synchronized String readLine() throws IOException { + if (closed) + throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); + return reader.readLine(); + } - public synchronized List readResponse(List args) throws IOException { - if (closed) - throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); - LOG.debug("Reading response back from ExifToolNew3..."); - String line; - List all = new ArrayList(); + public synchronized List readResponse(List args) throws IOException { + if (closed) + throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); + LOG.debug("Reading response back from ExifToolNew3..."); + String line; + List all = new ArrayList(); - while ((line = reader.readLine()) != null) { - if (closed) { - LOG.info("stream closed message"); - throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); - } - LOG.debug("stream line read [" + line + "]"); - /* - * When using a persistent ExifToolNew3 process, it terminates its output to us with a "{ready}" clause on a - * new line, we need to look for it and break from this loop when we see it otherwise this process will hang - * indefinitely blocking on the input stream with no data to read. - */ - if (keepAlive && line.equals("{ready}")) { - break; - } - all.add(line); - } - if (all.isEmpty()) { - String error = null; - try { - while ((error = readError()) == null) { - Thread.currentThread().sleep(100); - } - } catch (InterruptedException e) { - throw new RuntimeException("Didn't get anything back from exiftool with args [" + args + "].", e); - } - String message = error + ". " + all.size() + " lines where read [" + all + "] for exiftool with args [" - + args + "]."; - // if(result.contains("No matching files")){ - throw new ExifError(message); - // }else{ - // LOG.info(message); - // } - } - return all; - } + while ((line = reader.readLine()) != null) { + if (closed) { + LOG.info("stream closed message"); + throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); + } + LOG.debug("stream line read [" + line + "]"); + /* + * When using a persistent ExifToolNew3 process, it terminates its output to us with a "{ready}" clause on a new + * line, we need to look for it and break from this loop when we see it otherwise this process will hang + * indefinitely blocking on the input stream with no data to read. + */ + if (keepAlive && line.equals("{ready}")) { + break; + } + all.add(line); + } + Preconditions.checkNotNull(line, "Should wait to get {ready}"); + String error = readError(); + if (error != null) { + // + // } + // if (all.isEmpty()) { + // //since no result came it is a chance we have an error + // String error = null; + // try { + // while ((error = readError()) == null) { + // Thread.currentThread().sleep(100); + // } + // } catch (InterruptedException e) { + // throw new RuntimeException("Didn't get anything back from exiftool with args [" + args + "].", e); + // } + String message = error + ". " + all.size() + " lines where read [" + all + "] for exiftool with args [" + args + "]."; + // if(result.contains("No matching files")){ + throw new ExifError(message); + // }else{ + // LOG.info(message); + // } + } + return all; + } - private String readError() throws ExifError { - if (errReader.hasLines()) { - StringBuffer sb = new StringBuffer(); - for (String error : errReader.takeLines()) { - if (error.toLowerCase().startsWith("error")) { - throw new ExifError(error); - } - sb.append(error); - } - String result = sb.toString(); - return result; - } else { - return null; - } - } + private String readError() throws ExifError { + if (errReader.hasLines()) { + StringBuffer sb = new StringBuffer(); + for (String error : errReader.takeLines()) { + if (error.toLowerCase().startsWith("error")) { + throw new ExifError(error); + } + sb.append(error); + } + String result = sb.toString(); + return result; + } else { + return null; + } + } - public boolean isClosed() { - return closed; - } + public boolean isClosed() { + return closed; + } - public void close() { - if (!closed) { - closeLock.lock(); - try { - if (!closed) { - closed = true; - try { - LOG.debug("Closing Read stream..."); - reader.close(); - LOG.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - LOG.debug("", e); - } + public void close() { + if (!closed) { + closeLock.lock(); + try { + if (!closed) { + closed = true; + try { + LOG.debug("Closing Read stream..."); + reader.close(); + LOG.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + LOG.debug("", e); + } - try { - LOG - .debug("Attempting to close ExifToolNew3 daemon process, issuing '-stay_open\\nFalse\\n' command..."); - writer.write("-stay_open\nFalse\n"); - writer.flush(); - } catch (IOException e) { - // log.error(ex,ex); - LOG.debug("", e); - } + try { + LOG.debug("Attempting to close ExifToolNew3 daemon process, issuing '-stay_open\\nFalse\\n' command..."); + writer.write("-stay_open\nFalse\n"); + writer.flush(); + } catch (IOException e) { + // log.error(ex,ex); + LOG.debug("", e); + } - try { - LOG.debug("Closing Write stream..."); - writer.close(); - LOG.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - LOG.debug("", e); - } + try { + LOG.debug("Closing Write stream..."); + writer.close(); + LOG.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + LOG.debug("", e); + } - try { - LOG.debug("Closing Error stream..."); - errReader.close(); - LOG.debug("\tSuccessful"); - } catch (Exception e) { - // no-op, just try to close it. - LOG.debug("", e); - } - LOG.debug("Read/Write streams successfully closed."); + try { + LOG.debug("Closing Error stream..."); + errReader.close(); + LOG.debug("\tSuccessful"); + } catch (Exception e) { + // no-op, just try to close it. + LOG.debug("", e); + } + LOG.debug("Read/Write streams successfully closed."); - try { - LOG.debug("\tDestroy process " + process + "..."); - process.destroy(); - all.remove(process.toString()); - LOG.debug("\tDestroy process " + process + " done => " + all.keySet()); - } catch (Exception e) { - // - LOG.debug("", e); - } - // process = null; + try { + LOG.debug("\tDestroy process " + process + "..."); + process.destroy(); + all.remove(process.toString()); + LOG.debug("\tDestroy process " + process + " done => " + all.keySet()); + } catch (Exception e) { + // + LOG.debug("", e); + } + // process = null; - } - } finally { - closeLock.unlock(); - } - } - } + } + } finally { + closeLock.unlock(); + } + } + } - @Override - protected void finalize() throws Throwable { - LOG.debug("\tFinalize process " + process + "."); - close(); - super.finalize(); - } + @Override + protected void finalize() throws Throwable { + LOG.debug("\tFinalize process " + process + "."); + close(); + super.finalize(); + } } \ No newline at end of file diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index 799ff5c8..aa3c7c93 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -529,8 +529,9 @@ public void testReadingUtf8NamesOnWindows() throws Exception { @Test public void testReadingOnWindowsEndOfLine() throws Exception { ExifToolNew3 exifTool = new ExifToolNew3(Feature.WINDOWS, Feature.STAY_OPEN); - Map map = exifTool.getImageMeta( - new File("e:\\work\\electrica\\00-ICT\\FOCSANI\\__Echipamente AMR Telecomunicatii\\20 SDEE Focsani 27,1843148 45,69987857.jpg"), + URL url = getClass().getResource("/20131231_230955_Strada Frumoasă.png"); + File imageFile = new File(url.toURI()); + Map map = exifTool.getImageMeta(imageFile, new ReadOptions() , "GPSAltitude", From 75d20b7aa779ba890317bee8d7d0529d3718e84a Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 11 Jun 2019 13:31:12 +0300 Subject: [PATCH 145/148] logging & improve bugs related to ExifProcess --- pom.xml | 18 ++++++++++++------ .../com/thebuzzmedia/exiftool/ExifProcess.java | 18 ++++++++++++++---- 2 files changed, 26 insertions(+), 10 deletions(-) diff --git a/pom.xml b/pom.xml index 3a5845a7..13a02c88 100644 --- a/pom.xml +++ b/pom.xml @@ -109,6 +109,11 @@ guava 27.1-jre + + joda-time + joda-time + 2.10.2 + junit junit @@ -117,15 +122,16 @@ - org.slf4j - slf4j-simple - ${slf4j.version} + ch.qos.logback + logback-core + ${logback.version} test - joda-time - joda-time - 2.10.2 + ch.qos.logback + logback-classic + ${logback.version} + test diff --git a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java index d6c6ed68..51679060 100644 --- a/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java +++ b/src/main/java/com/thebuzzmedia/exiftool/ExifProcess.java @@ -17,6 +17,7 @@ import java.util.Map; import java.util.Map.Entry; import java.util.TreeMap; +import java.util.concurrent.TimeUnit; import java.util.concurrent.locks.ReentrantLock; import java.util.regex.Pattern; @@ -185,15 +186,23 @@ public synchronized List readResponse(List args) throws IOExcept if (closed) throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); LOG.debug("Reading response back from ExifToolNew3..."); - String line; + //String line; List all = new ArrayList(); - - while ((line = reader.readLine()) != null) { +// if(!keepAlive) { +// boolean result = process.waitFor(10, TimeUnit.SECONDS); +// } + while(true){ + String line = reader.readLine(); if (closed) { LOG.info("stream closed message"); throw new IOException(ExifToolNew3.STREAM_CLOSED_MESSAGE); } LOG.debug("stream line read [" + line + "]"); + if(!keepAlive && line==null) { + Preconditions.checkState(!process.isAlive()); + //if no keep alive then the null should be returned + break; + } /* * When using a persistent ExifToolNew3 process, it terminates its output to us with a "{ready}" clause on a new * line, we need to look for it and break from this loop when we see it otherwise this process will hang @@ -204,7 +213,7 @@ public synchronized List readResponse(List args) throws IOExcept } all.add(line); } - Preconditions.checkNotNull(line, "Should wait to get {ready}"); + //Preconditions.checkNotNull(line, "Should wait to get {ready}"); String error = readError(); if (error != null) { // @@ -264,6 +273,7 @@ public void close() { LOG.debug("", e); } + if(keepAlive) try { LOG.debug("Attempting to close ExifToolNew3 daemon process, issuing '-stay_open\\nFalse\\n' command..."); writer.write("-stay_open\nFalse\n"); From d76b0c286999a6173942fc9c02ae6e7dae25e9f4 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 11 Jun 2019 13:33:41 +0300 Subject: [PATCH 146/148] fix all tests --- src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java index aa3c7c93..421a8ad2 100644 --- a/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java +++ b/src/test/java/com/thebuzzmedia/exiftool/TestExifTool.java @@ -453,7 +453,7 @@ public void testWritingWithImplicitTypes() throws Exception { tool.writeMetadata(new WriteOptions().withDeleteBackupFile(false), imageFile, data); // Finally check the updated value - metadata = tool.getImageMeta6(imageFile, options.withNumericOutput(true), Tag.ORIENTATION, imageFile, MwgTag.DATE_TIME_ORIGINAL, + metadata = tool.getImageMeta6(imageFile, options.withNumericOutput(true), Tag.ORIENTATION, MwgTag.DATE_TIME_ORIGINAL, MwgTag.CREATE_DATE, MwgTag.KEYWORDS); assertEquals("Orientation tag updated value is wrong", (Integer) 3, Tag.ORIENTATION.getValue(metadata)); assertEquals("DateTimeOriginal tag is wrong", dateTimeOrig, MwgTag.DATE_TIME_ORIGINAL.getValue(metadata)); From cf466ee67cd91e4103102de22354f5da346b5455 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 11 Jun 2019 13:35:13 +0300 Subject: [PATCH 147/148] [maven-release-plugin] prepare release exiftool-2.3.14 --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index 13a02c88..ce2c7808 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.raisercostin exiftool - 2.3.14-SNAPSHOT + 2.3.14 jar exiftool Enhanced Java Integration for Phil Harvey's ExifTool. @@ -34,7 +34,7 @@ scm:git:${git.url}.git scm:git:${git.url}.git ${git.url} - ${project.artifactId}-${project.version} + exiftool-2.3.14 From e6e651966c314caf3f0cf1be9d7a1c5daca140e1 Mon Sep 17 00:00:00 2001 From: raisercostin Date: Tue, 11 Jun 2019 13:35:24 +0300 Subject: [PATCH 148/148] [maven-release-plugin] prepare for next development iteration --- pom.xml | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/pom.xml b/pom.xml index ce2c7808..73d5707d 100644 --- a/pom.xml +++ b/pom.xml @@ -9,7 +9,7 @@ org.raisercostin exiftool - 2.3.14 + 2.3.15-SNAPSHOT jar exiftool Enhanced Java Integration for Phil Harvey's ExifTool. @@ -34,7 +34,7 @@ scm:git:${git.url}.git scm:git:${git.url}.git ${git.url} - exiftool-2.3.14 + ${project.artifactId}-${project.version}