public class ExifTool extends Object
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
getImageMeta(File, Tag...)
or
getImageMeta(File, Format, Tag...)
with a list of ExifTool.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.
Results from calls to getImageMeta
are returned in a Map
with the ExifTool.Tag
values as the keys and String
values for every
tag that had a value in the image file as the values. ExifTool.Tag
s with no
value found in the image are omitted from the result map.
While each ExifTool.Tag
provides a hint at which format the resulting value
for that tag is returned as from ExifTool (see ExifTool.Tag.getType()
), that
only applies to values returned with an output format of
ExifTool.Format.NUMERIC
and it is ultimately up to the caller to decide how
best to parse or convert the returned values.
The ExifTool.Tag
Enum provides the Tag#parseValue(Tag, 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.
-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.
Support for using ExifTool in daemon mode is enabled by passing
ExifTool.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 EXIF_TOOL_PATH
before successfully instantiating the class and
will notify you via an ExifTool.UnsupportedFeatureException
if the native
ExifTool doesn't support the requested feature.
In the event of an ExifTool.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.
ExifTool.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 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
PROCESS_CLEANUP_DELAY
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 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).
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).
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 ExifTool.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 ExifTool.Feature.STAY_OPEN
to
the constructor of this class) and when done, instead of 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.
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
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
ProcessBuilder.command(List)
method is used to avoid the copying of
array elements when ProcessBuilder.command(String...)
is used and
avoiding the (hidden) use of StringTokenizer
when
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).
ThreadLocal
s to ensure Thread-safe, highly parallel use.
Modifier and Type | Class and Description |
---|---|
static class |
ExifTool.Feature
Enum used to define the different kinds of features in the native
ExifTool executable that this class can help you take advantage of.
|
static class |
ExifTool.Format
Enum used to define the 2 different output formats that
ExifTool.Tag
values can be returned in: numeric or human-readable text. |
static class |
ExifTool.Tag
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.
|
class |
ExifTool.UnsupportedFeatureException
Class used to define an exception that occurs when the caller attempts to
use a
ExifTool.Feature that the underlying native ExifTool install does
not support (i.e. |
Modifier and Type | Field and Description |
---|---|
protected static String |
CLEANUP_THREAD_NAME
Name used to identify the (optional) cleanup
Thread . |
static Boolean |
DEBUG
Flag used to indicate if debugging output has been enabled by setting the
"
exiftool.debug " system property to true . |
static String |
EXIF_TOOL_PATH
The absolute path to the ExifTool executable on the host system running
this class as defined by the "
exiftool.path " system
property. |
protected static Map<ExifTool.Feature,Boolean> |
FEATURE_SUPPORT_MAP
Map shared across all instances of this class that maintains the state of
ExifTool.Feature s and if they are supported or not (supported=true,
unsupported=false) by the underlying native ExifTool process being used
in conjunction with this class. |
static String |
LOG_PREFIX
Prefix to every log message this library logs.
|
static long |
PROCESS_CLEANUP_DELAY
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
ExifTool.Feature.STAY_OPEN feature is
used. |
protected static Pattern |
TAG_VALUE_PATTERN
Compiled
Pattern of ": " used to split compact output from
ExifTool evenly into name/value pairs. |
Constructor and Description |
---|
ExifTool() |
ExifTool(ExifTool.Feature... features) |
Modifier and Type | Method and Description |
---|---|
protected static void |
checkFeatureSupport(ExifTool.Feature... features)
Used to verify the version of ExifTool installed is a high enough version
to support the given features.
|
void |
close()
Used to shutdown the external ExifTool process and close the read/write
streams used to communicate with it when
ExifTool.Feature.STAY_OPEN is
enabled. |
Map<ExifTool.Tag,String> |
getImageMeta(File image,
ExifTool.Format format,
ExifTool.Tag... tags) |
Map<ExifTool.Tag,String> |
getImageMeta(File image,
ExifTool.Tag... tags) |
boolean |
isFeatureEnabled(ExifTool.Feature feature)
Used to determine if the given
ExifTool.Feature has been enabled for this
particular instance of ExifTool . |
static boolean |
isFeatureSupported(ExifTool.Feature feature)
Used to determine if the given
ExifTool.Feature is supported by the
underlying native install of ExifTool pointed at by
EXIF_TOOL_PATH . |
boolean |
isRunning()
For
ExifTool instances with ExifTool.Feature.STAY_OPEN support
enabled, this method is used to determine if there is currently a running
ExifTool process associated with this class. |
protected static void |
log(String message,
Object... params)
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.
|
protected static com.thebuzzmedia.exiftool.ExifTool.IOStream |
startExifToolProcess(List<String> args) |
public static final Boolean DEBUG
exiftool.debug
" system property to true
. This
value will be false
if the " exiftool.debug
"
system property is undefined or set to false
.
This system property can be set on startup with:
-Dexiftool.debug=true
or by calling System.setProperty(String, String)
before
this class is loaded.
Default value is false
.public static final String LOG_PREFIX
[exiftool]
" (including the space).public static final String EXIF_TOOL_PATH
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 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
".
new File(".").getAbsolutePath()
points at
during runtime.public static final long PROCESS_CLEANUP_DELAY
ExifTool.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 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 close()
.
Default value is 600,000
(10 minutes).protected static final String CLEANUP_THREAD_NAME
Thread
.
This is only provided to make debugging and profiling easier for
implementors 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
".protected static final Pattern TAG_VALUE_PATTERN
Pattern
of ": " used to split compact output from
ExifTool evenly into name/value pairs.protected static final Map<ExifTool.Feature,Boolean> FEATURE_SUPPORT_MAP
ExifTool.Feature
s and if they are supported or not (supported=true,
unsupported=false) by the underlying native ExifTool process being used
in conjunction with this class.
If a ExifTool.Feature
is missing from the map (has no true
or
false
flag associated with it, but null
instead) then that means that feature has not been checked for support
yet and this class will know to call
checkFeatureSupport(Feature...)
on it to determine its supported
state.
For efficiency reasons, individual ExifTool.Feature
s are checked for
support one time during each run of the VM and never again during the
session of that running VM.public ExifTool()
public ExifTool(ExifTool.Feature... features) throws ExifTool.UnsupportedFeatureException
public static boolean isFeatureSupported(ExifTool.Feature feature) throws IllegalArgumentException, RuntimeException
ExifTool.Feature
is supported by the
underlying native install of ExifTool pointed at by
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
Map
that all instances of this class share.feature
- The feature to check support for in the underlying ExifTool
install.true
if support for the given ExifTool.Feature
was
confirmed to work with the currently installed ExifTool or
false
if it is not supported.IllegalArgumentException
- if feature
is null
.RuntimeException
- if any exception occurs while attempting to start the
external ExifTool process to verify feature support.protected static void log(String message, Object... params)
params
array, care should
be taken not to call this method with primitive values unless
DEBUG
is true
; otherwise the VM will be spending
time performing unnecessary auto-boxing calculations.message
- The log message in format string syntax that will be logged.params
- The parameters that will be swapped into all the place holders
in the original messages before being logged.LOG_PREFIX
protected static void checkFeatureSupport(ExifTool.Feature... features) throws RuntimeException
exiftool -ver
" to get the
version of the installed ExifTool and then compares that version to the
least required version specified by the given features (see
ExifTool.Feature.getVersion()
).features
- The features whose required versions will be checked against
the installed ExifTool for support.RuntimeException
- if any exception occurs communicating with the external
ExifTool process spun up in order to check its version.protected static com.thebuzzmedia.exiftool.ExifTool.IOStream startExifToolProcess(List<String> args) throws RuntimeException
RuntimeException
public void close()
ExifTool.Feature.STAY_OPEN
is
enabled.
NOTE: Calling this method does not preclude this
instance of 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 PROCESS_CLEANUP_DELAY
.
Calling this method on an instance of this class without
ExifTool.Feature.STAY_OPEN
support enabled has no effect.public boolean isRunning()
ExifTool
instances with ExifTool.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
close()
and this class will automatically re-create them on the
next call to getImageMeta
if necessary.true
if there is an external ExifTool process in
daemon mode associated with this class utilizing the
ExifTool.Feature.STAY_OPEN
feature, otherwise returns
false
.public boolean isFeatureEnabled(ExifTool.Feature feature) throws IllegalArgumentException
ExifTool.Feature
has been enabled for this
particular instance of ExifTool
.
This method is different from 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.feature
- The feature to check if it has been enabled for us or not on
this instance.true
if the given ExifTool.Feature
is currently
enabled on this instance of ExifTool
, otherwise returns
false
.IllegalArgumentException
- if feature
is null
.public Map<ExifTool.Tag,String> getImageMeta(File image, ExifTool.Tag... tags) throws IllegalArgumentException, SecurityException, IOException
public Map<ExifTool.Tag,String> getImageMeta(File image, ExifTool.Format format, ExifTool.Tag... tags) throws IllegalArgumentException, SecurityException, IOException
Copyright © 2015. All Rights Reserved.