Copyright | (c) Martin Hoppenheit 2020 |
---|---|
License | MIT |
Maintainer | martin@hoppenheit.info |
Safe Haskell | None |
Language | Haskell2010 |
This module contains bindings to the ExifTool command-line application that enable reading, writing and deleting metadata in various file formats. Here's a short code example, the details are explained below.
{-# LANGUAGE OverloadedStrings #-} {-# LANGUAGE OverloadedLists #-} import ExifTool import Data.HashMap.Strict ((!?)) example :: IO () example = withExifTool $ \et -> do -- Read metadata, with exact (!?) and fuzzy (~~) tag lookup. m <- getMeta et "a.jpg" print $ m !? Tag "EXIF" "ExifIFD" "DateTimeOriginal" print $ m ~~ Tag "EXIF" "" "XResolution" print $ m ~~ Tag "XMP" "" "" -- Write and delete metadata. setMeta et [(Tag "XMP" "XMP-dc" "Description", String "...")] "a.jpg" deleteMeta et [Tag "XMP" "XMP-dc" "Description"] "a.jpg"
Note that this module expects the exiftool
binary to be in your PATH.
Synopsis
- data ExifTool
- startExifTool :: IO ExifTool
- stopExifTool :: ExifTool -> IO ()
- withExifTool :: (ExifTool -> IO a) -> IO a
- getMeta :: ExifTool -> Text -> IO Metadata
- setMeta :: ExifTool -> Metadata -> Text -> IO ()
- deleteMeta :: ExifTool -> [Tag] -> Text -> IO ()
- getMetaEither :: ExifTool -> Text -> IO (Either Text Metadata)
- setMetaEither :: ExifTool -> Metadata -> Text -> IO (Either Text ())
- deleteMetaEither :: ExifTool -> [Tag] -> Text -> IO (Either Text ())
- type Metadata = HashMap Tag Value
- data Tag = Tag {
- tagFamily0 :: !Text
- tagFamily1 :: !Text
- tagName :: !Text
- data Value
- = String !Text
- | Binary !ByteString
- | Number !Scientific
- | Bool !Bool
- | List ![Value]
- filterByTag :: (Tag -> Bool) -> Metadata -> Metadata
- (~~) :: Metadata -> Tag -> Metadata
Running an ExifTool instance
Most functions in this module interact with an ExifTool instance
i.e., a running ExifTool process represented by the ExifTool
data
type. The easiest way to obtain an instance is the withExifTool
function that takes care of starting and stopping the process.
An ExifTool instance, initialized with startExifTool
and terminated with
stopExifTool
.
startExifTool :: IO ExifTool Source #
Start an ExifTool instance. Use stopExifTool
when done, or withExifTool
to combine both steps.
stopExifTool :: ExifTool -> IO () Source #
Stop a running ExifTool instance.
withExifTool :: (ExifTool -> IO a) -> IO a Source #
Start an ExifTool instance, do something with it, then stop it.
Reading and writing metadata
The ExifTool instance can then be used to read, write or delete metadata in a file with the respective functions. These come in two variants, one that throws runtime errors when the ExifTool process returns error messages and one that instead produces Either values. Choose those that best fit your use case.
Read all metadata from a file, with ExifTool errors leading to runtime
errors. (Use getMetaEither
instead if you would rather intercept them.)
Write metadata to a file, with ExifTool errors leading to runtime errors.
(Use setMetaEither
instead if you would rather intercept them.) The file is
modified in place. Make sure you have the necessary backups!
Delete metadata from a file, with ExifTool errors leading to runtime
errors. (Use deleteMetaEither
instead if you would rather intercept them.)
The file is modified in place. Make sure you have the necessary backups!
Read all metadata from a file, with ExifTool errors returned as Left values.
Write metadata to a file, with ExifTool errors returned as Left values. The file is modified in place. Make sure you have the necessary backups!
Delete metadata from a file, with ExifTool errors returned as Left values. The file is modified in place. Make sure you have the necessary backups!
Data types and utility functions
Metadata is represented by a HashMap
of
Tag
/Value
pairs (with alias Metadata
), so it is advisable to
import some functions like lookup
or
!?
from the Data.HashMap.Strict module. The
ExifTool module defines additional utility functions that make working
with Metadata easier.
An ExifTool tag name, consisting of three components:
- The family 0 tag group (information type) e.g.,
EXIF
orXMP
. - The family 1 tag group (specific location) e.g.,
IFD0
orXMP-dc
. - The actual tag name e.g.,
XResolution
orDescription
.
Example: Tag "EXIF" "IFD0" "XResolution"
corresponds to the ExifTool
tag name EXIF:IFD0:XResolution
.
During development, there are several ways to find the exact name of a tag:
- See https://exiftool.org/#groups for a list of tag groups.
- Run something like
exiftool -s -a -G:0:1
. - Use the
~~
operator in ghci.
Tag | |
|
Instances
Eq Tag Source # | |
Show Tag Source # | |
Generic Tag Source # | |
Hashable Tag Source # | |
ToJSON Tag Source # | |
ToJSONKey Tag Source # | |
Defined in ExifTool | |
FromJSON Tag Source # | |
FromJSONKey Tag Source # | |
Defined in ExifTool | |
type Rep Tag Source # | |
Defined in ExifTool type Rep Tag = D1 ('MetaData "Tag" "ExifTool" "exiftool-0.1.0.0-inplace" 'False) (C1 ('MetaCons "Tag" 'PrefixI 'True) (S1 ('MetaSel ('Just "tagFamily0") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: (S1 ('MetaSel ('Just "tagFamily1") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text) :*: S1 ('MetaSel ('Just "tagName") 'NoSourceUnpackedness 'SourceStrict 'DecidedStrict) (Rec0 Text)))) |
An ExifTool tag value, enclosed in a type wrapper.
String !Text | |
Binary !ByteString | |
Number !Scientific | |
Bool !Bool | |
List ![Value] |
(~~) :: Metadata -> Tag -> Metadata infixl 8 Source #
Filter metadata by fuzzy tag name matching. Tag names are matched ignoring case, and empty components of the given tag name are considered wildcards. Examples:
m ~~ Tag "EXIF" "IFD0" "XResolution"
matches exactly the given tag name (ignoring case)m ~~ Tag "exif" "" "xresolution"
matches all EXIF tags with name xresolution (ignoring case), includingEXIF:IFD0:XResolution
andEXIF:IFD1:XResolution
m ~~ Tag "XMP" "" ""
matches all XMP tags
Note that ~~
has higher precedence than <>
, so m ~~ t <> m ~~ t' == (m
~~ t) <> (m ~~ t')
which makes combining filters easy.
Hint: This operator is useful to find exact tag names in ghci.