multi_exiftool 0.12.0 → 0.16.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +4 -4
- data/.aspell.pws +2 -1
- data/Changelog +17 -0
- data/README.md +51 -3
- data/Rakefile +3 -3
- data/lib/multi_exiftool.rb +29 -15
- data/lib/multi_exiftool/batch.rb +42 -0
- data/lib/multi_exiftool/executable.rb +12 -5
- data/lib/multi_exiftool/reader.rb +11 -3
- data/lib/multi_exiftool/writer.rb +3 -3
- data/multi_exiftool.gemspec +7 -7
- data/regtest/read_all_tags.yml +1 -1
- data/test/data/example.config +363 -0
- data/test/test_batch.rb +42 -0
- data/test/test_functional_api.rb +101 -0
- data/test/test_reader.rb +14 -0
- data/test/test_values.rb +5 -5
- metadata +10 -7
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA256:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 43d4f9d91d7d4c6321b5e9698e3aaecc38fd1044e140110f5e4ff22fdf15ee96
|
4
|
+
data.tar.gz: a9ff99dd7943f29ce6219f75a3dad31ce06c3e4abf458e50aa6c9e8903660022
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 648a9ba62793a9c0215c06cc701935bd123612d7491be111e0e96398e9f2bcc42399f2bf42591ce70c2722579e04d113394832c337ca04674036c2b93f014f2b
|
7
|
+
data.tar.gz: 17d5d839ba13f1a07f2ec586c78b68bb950e54f2e6f67f2288fcdb01dda5f5ff341db462b8d103fa510eb5eb190080cf883c8d85de16fdcda89aee994414cd4a
|
data/.aspell.pws
CHANGED
data/Changelog
CHANGED
@@ -1,3 +1,20 @@
|
|
1
|
+
0.16.0
|
2
|
+
Add option to use config files.
|
3
|
+
|
4
|
+
0.15.0
|
5
|
+
Make multi_exiftool work with Ruby 1.9 again.
|
6
|
+
|
7
|
+
0.14.1
|
8
|
+
Fix two typos.
|
9
|
+
|
10
|
+
0.14.0
|
11
|
+
Improve api for batch processing.
|
12
|
+
|
13
|
+
0.13.0
|
14
|
+
Implement batch processing to allow to write different values to multiple file
|
15
|
+
with only one call of the ExifTool command-line application.
|
16
|
+
Update documentation.
|
17
|
+
|
1
18
|
0.12.0
|
2
19
|
Implement Values#respond_to_missing?.
|
3
20
|
Improve documentation and fix example code.
|
data/README.md
CHANGED
@@ -3,7 +3,7 @@
|
|
3
3
|
## Description
|
4
4
|
|
5
5
|
This library is a wrapper for the ExifTool command-line application
|
6
|
-
(
|
6
|
+
(https://exiftool.org) written by Phil Harvey.
|
7
7
|
It is designed for dealing with multiple files at once by creating
|
8
8
|
commands to call exiftool with various arguments, call it and parsing
|
9
9
|
the results.
|
@@ -60,6 +60,54 @@ else
|
|
60
60
|
end
|
61
61
|
```
|
62
62
|
|
63
|
+
If it is necessary to write different values to multiple files there is batch processing
|
64
|
+
|
65
|
+
```ruby
|
66
|
+
require 'multi_exiftool'
|
67
|
+
|
68
|
+
# Object oriented approach
|
69
|
+
|
70
|
+
batch = MultiExiftool::Batch.new
|
71
|
+
Dir['*.jpg'].each_with_index do |filename, i|
|
72
|
+
values = {creator: 'Jan Friedrich', copyright: 'Public Domain', comment: "This is file number #{i+1}."}
|
73
|
+
batch.write filename, values
|
74
|
+
end
|
75
|
+
if batch.execute
|
76
|
+
puts 'ok'
|
77
|
+
else
|
78
|
+
puts batch.errors
|
79
|
+
end
|
80
|
+
|
81
|
+
# Functional approach
|
82
|
+
|
83
|
+
errors = MultiExiftool.batch do
|
84
|
+
Dir['*.jpg'].each_with_index do |filename, i|
|
85
|
+
values = {creator: 'Jan Friedrich', copyright: 'Public Domain', comment: "This is file number #{i+1}."}
|
86
|
+
write filename, values
|
87
|
+
end
|
88
|
+
end
|
89
|
+
if errors.empty?
|
90
|
+
puts 'ok'
|
91
|
+
else
|
92
|
+
puts errors
|
93
|
+
end
|
94
|
+
|
95
|
+
# or alternative with block parameter as yielded Batch instance
|
96
|
+
|
97
|
+
errors = MultiExiftool.batch do |batch|
|
98
|
+
Dir['*.jpg'].each_with_index do |filename, i|
|
99
|
+
values = {creator: 'Jan Friedrich', copyright: 'Public Domain', comment: "This is file number #{i+1}."}
|
100
|
+
batch.write filename, values
|
101
|
+
end
|
102
|
+
end
|
103
|
+
if errors.empty?
|
104
|
+
puts 'ok'
|
105
|
+
else
|
106
|
+
puts errors
|
107
|
+
end
|
108
|
+
```
|
109
|
+
|
110
|
+
|
63
111
|
### Deleting
|
64
112
|
|
65
113
|
```ruby
|
@@ -153,7 +201,7 @@ The method Values#convert is called each time a value is fetched.
|
|
153
201
|
- Ruby 1.9.1 or higher
|
154
202
|
- An installation of the ExifTool command-line application (version 7.65 or
|
155
203
|
higher). Instructions for installation you can find under
|
156
|
-
|
204
|
+
https://exiftool.org/install.html .
|
157
205
|
- If you have problems with special characters (like German umlauts) in
|
158
206
|
filenames on windows system it is recommended to use exiftool version 9.79
|
159
207
|
or higher.
|
@@ -185,7 +233,7 @@ SemVerTag.
|
|
185
233
|
|
186
234
|
## Author
|
187
235
|
|
188
|
-
Jan Friedrich <
|
236
|
+
Jan Friedrich <janfri26@gmail.com>
|
189
237
|
|
190
238
|
## MIT License
|
191
239
|
|
data/Rakefile
CHANGED
@@ -11,8 +11,8 @@ Rim.setup do |p|
|
|
11
11
|
p.version = MultiExiftool::VERSION
|
12
12
|
p.authors = 'Jan Friedrich'
|
13
13
|
p.email = 'janfri26@gmail.com'
|
14
|
-
p.summary = 'This library is a wrapper for the ExifTool command-line application (
|
15
|
-
p.description = 'This library a
|
14
|
+
p.summary = 'This library is a wrapper for the ExifTool command-line application (https://exiftool.org).'
|
15
|
+
p.description = 'This library is a wrapper for the ExifTool command-line application (https://exiftool.org) written by Phil Harvey. It is designed for dealing with multiple files at once by creating commands to call exiftool with various arguments, call it and parsing the results.'
|
16
16
|
p.ruby_version = '>=1.9.1'
|
17
17
|
p.license = 'MIT'
|
18
18
|
p.homepage = 'https://github.com/janfri/multi_exiftool'
|
@@ -21,7 +21,7 @@ Rim.setup do |p|
|
|
21
21
|
| Please ensure you have installed exiftool version 7.65 or higher and |
|
22
22
|
| it's found in your PATH (Try "exiftool -ver" on your commandline). |
|
23
23
|
| For more details see |
|
24
|
-
|
|
24
|
+
| https://exiftool.org/install.html |
|
25
25
|
+-----------------------------------------------------------------------+
|
26
26
|
}
|
27
27
|
p.development_dependencies << %w(contest ~>0.1)
|
data/lib/multi_exiftool.rb
CHANGED
@@ -4,10 +4,11 @@
|
|
4
4
|
require_relative 'multi_exiftool/values'
|
5
5
|
require_relative 'multi_exiftool/reader'
|
6
6
|
require_relative 'multi_exiftool/writer'
|
7
|
+
require_relative 'multi_exiftool/batch'
|
7
8
|
|
8
9
|
module MultiExiftool
|
9
10
|
|
10
|
-
VERSION = '0.
|
11
|
+
VERSION = '0.16.0'
|
11
12
|
|
12
13
|
@exiftool_command = 'exiftool'
|
13
14
|
|
@@ -25,15 +26,7 @@ module MultiExiftool
|
|
25
26
|
# # error handling
|
26
27
|
# end
|
27
28
|
def read filenames, opts={}
|
28
|
-
reader = Reader.new
|
29
|
-
reader.filenames = filenames
|
30
|
-
if val = opts.delete(:tags)
|
31
|
-
reader.tags = val
|
32
|
-
end
|
33
|
-
if val = opts.delete(:group)
|
34
|
-
reader.group = val
|
35
|
-
end
|
36
|
-
reader.options = opts unless opts.empty?
|
29
|
+
reader = Reader.new(filenames, opts)
|
37
30
|
values = reader.read
|
38
31
|
[values, reader.errors]
|
39
32
|
end
|
@@ -47,10 +40,7 @@ module MultiExiftool
|
|
47
40
|
# # do error handling
|
48
41
|
# end
|
49
42
|
def write filenames, values, opts={}
|
50
|
-
writer = Writer.new
|
51
|
-
writer.filenames = filenames
|
52
|
-
writer.values = values
|
53
|
-
writer.options = opts unless opts.empty?
|
43
|
+
writer = Writer.new(filenames, values, opts)
|
54
44
|
writer.write
|
55
45
|
writer.errors
|
56
46
|
end
|
@@ -70,11 +60,35 @@ module MultiExiftool
|
|
70
60
|
# unless errors.empty?
|
71
61
|
# # do error handling
|
72
62
|
# end
|
73
|
-
def delete_values filenames,
|
63
|
+
def delete_values filenames, opts={}
|
64
|
+
tags = opts.fetch(:tags, :all)
|
74
65
|
values = Array(tags).inject(Hash.new) {|h,tag| h[tag] = nil; h}
|
75
66
|
write(filenames, values)
|
76
67
|
end
|
77
68
|
|
69
|
+
|
70
|
+
# Execute a batch of write commands
|
71
|
+
# Returns an array of the error messages
|
72
|
+
#
|
73
|
+
# Example:
|
74
|
+
# errors = MultiExiftool.batch do
|
75
|
+
# Dir['*.jpg'].each_with_index do |filename, i|
|
76
|
+
# write filename, {author: 'Jan Friedrich', comment: "This is file number #{i+1}."}
|
77
|
+
# end
|
78
|
+
# unless errors.empty?
|
79
|
+
# # do error handling
|
80
|
+
# end
|
81
|
+
def batch &block
|
82
|
+
batch = Batch.new
|
83
|
+
if block.arity == 0
|
84
|
+
batch.instance_exec &block
|
85
|
+
else
|
86
|
+
yield batch
|
87
|
+
end
|
88
|
+
batch.execute
|
89
|
+
batch.errors
|
90
|
+
end
|
91
|
+
|
78
92
|
attr_accessor :exiftool_command
|
79
93
|
attr_reader :exiftool_version
|
80
94
|
|
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative 'executable'
|
5
|
+
|
6
|
+
module MultiExiftool
|
7
|
+
|
8
|
+
# Allow to define a batch for different writing operations as one call of the
|
9
|
+
# ExifTool command-line application
|
10
|
+
class Batch
|
11
|
+
|
12
|
+
include Executable
|
13
|
+
|
14
|
+
# Define batch operation inside a block
|
15
|
+
def initialize &blk
|
16
|
+
@writers = []
|
17
|
+
instance_exec &blk if block_given?
|
18
|
+
end
|
19
|
+
|
20
|
+
# Define a write operation for the batch.
|
21
|
+
def write filenames, values, options={}
|
22
|
+
w = MultiExiftool::Writer.new(filenames, values, options)
|
23
|
+
@writers << w
|
24
|
+
end
|
25
|
+
|
26
|
+
# Getting the command-line arguments which would be executed
|
27
|
+
# when calling #write. It could be useful for logging, debugging or
|
28
|
+
# whatever.
|
29
|
+
def exiftool_args
|
30
|
+
@writers.map {|w| w.exiftool_args + ['-execute']}.flatten
|
31
|
+
end
|
32
|
+
|
33
|
+
private
|
34
|
+
|
35
|
+
def parse_results
|
36
|
+
@errors = @stderr.read.split(/\n/)
|
37
|
+
@errors.empty?
|
38
|
+
end
|
39
|
+
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -9,12 +9,15 @@ module MultiExiftool
|
|
9
9
|
module Executable
|
10
10
|
|
11
11
|
attr_reader :errors
|
12
|
-
attr_accessor :filenames, :numerical, :options
|
12
|
+
attr_accessor :config, :filenames, :numerical, :options
|
13
13
|
|
14
|
-
def initialize
|
15
|
-
@options =
|
16
|
-
@filenames =
|
14
|
+
def initialize filenames=[], options={}
|
15
|
+
@options = options
|
16
|
+
@filenames = filenames
|
17
17
|
@option_mapping = {numerical: :n}
|
18
|
+
if val = options.delete(:config)
|
19
|
+
@config = val
|
20
|
+
end
|
18
21
|
end
|
19
22
|
|
20
23
|
def options
|
@@ -57,7 +60,11 @@ module MultiExiftool
|
|
57
60
|
end
|
58
61
|
|
59
62
|
def execute_command
|
60
|
-
|
63
|
+
args = ['-@', '-']
|
64
|
+
if @config
|
65
|
+
args = ['-config', @config] + args
|
66
|
+
end
|
67
|
+
stdin, @stdout, @stderr = Open3.popen3(exiftool_command, *args)
|
61
68
|
exiftool_args.each do |part|
|
62
69
|
stdin << part
|
63
70
|
stdin << "\n"
|
@@ -15,9 +15,17 @@ module MultiExiftool
|
|
15
15
|
|
16
16
|
include Executable
|
17
17
|
|
18
|
-
def initialize
|
19
|
-
super
|
20
|
-
|
18
|
+
def initialize filenames=[], opts={}
|
19
|
+
super(filenames, opts)
|
20
|
+
if val = opts.delete(:tags)
|
21
|
+
@tags = val
|
22
|
+
else
|
23
|
+
@tags = []
|
24
|
+
end
|
25
|
+
if val = opts.delete(:group)
|
26
|
+
@group = val
|
27
|
+
end
|
28
|
+
@options = opts unless opts.empty?
|
21
29
|
end
|
22
30
|
|
23
31
|
def self.mandatory_args
|
data/multi_exiftool.gemspec
CHANGED
@@ -1,5 +1,5 @@
|
|
1
1
|
# -*- encoding: utf-8 -*-
|
2
|
-
# stub: multi_exiftool 0.
|
2
|
+
# stub: multi_exiftool 0.16.0 ruby lib
|
3
3
|
#
|
4
4
|
# This file is automatically generated by rim.
|
5
5
|
# PLEASE DO NOT EDIT IT DIRECTLY!
|
@@ -7,22 +7,22 @@
|
|
7
7
|
|
8
8
|
Gem::Specification.new do |s|
|
9
9
|
s.name = "multi_exiftool"
|
10
|
-
s.version = "0.
|
10
|
+
s.version = "0.16.0"
|
11
11
|
|
12
12
|
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
13
13
|
s.require_paths = ["lib"]
|
14
14
|
s.authors = ["Jan Friedrich"]
|
15
|
-
s.date = "2020-
|
16
|
-
s.description = "This library a
|
15
|
+
s.date = "2020-10-27"
|
16
|
+
s.description = "This library is a wrapper for the ExifTool command-line application (https://exiftool.org) written by Phil Harvey. It is designed for dealing with multiple files at once by creating commands to call exiftool with various arguments, call it and parsing the results."
|
17
17
|
s.email = "janfri26@gmail.com"
|
18
|
-
s.files = ["./.aspell.pws", "Changelog", "Gemfile", "LICENSE", "README.md", "Rakefile", "lib/multi_exiftool", "lib/multi_exiftool.rb", "lib/multi_exiftool/executable.rb", "lib/multi_exiftool/reader.rb", "lib/multi_exiftool/values.rb", "lib/multi_exiftool/writer.rb", "multi_exiftool.gemspec", "regtest/read_all_tags.rb", "regtest/read_all_tags.yml", "regtest/test.jpg", "test/data", "test/data/a.jpg", "test/data/b.jpg", "test/data/c.jpg", "test/helper.rb", "test/test_executable.rb", "test/test_exiftool_stuff.rb", "test/test_functional_api.rb", "test/test_reader.rb", "test/test_values.rb", "test/test_values_using_groups.rb", "test/test_writer.rb", "test/test_writer_groups.rb"]
|
18
|
+
s.files = ["./.aspell.pws", "Changelog", "Gemfile", "LICENSE", "README.md", "Rakefile", "lib/multi_exiftool", "lib/multi_exiftool.rb", "lib/multi_exiftool/batch.rb", "lib/multi_exiftool/executable.rb", "lib/multi_exiftool/reader.rb", "lib/multi_exiftool/values.rb", "lib/multi_exiftool/writer.rb", "multi_exiftool.gemspec", "regtest/read_all_tags.rb", "regtest/read_all_tags.yml", "regtest/test.jpg", "test/data", "test/data/a.jpg", "test/data/b.jpg", "test/data/c.jpg", "test/data/example.config", "test/helper.rb", "test/test_batch.rb", "test/test_executable.rb", "test/test_exiftool_stuff.rb", "test/test_functional_api.rb", "test/test_reader.rb", "test/test_values.rb", "test/test_values_using_groups.rb", "test/test_writer.rb", "test/test_writer_groups.rb"]
|
19
19
|
s.homepage = "https://github.com/janfri/multi_exiftool"
|
20
20
|
s.licenses = ["MIT"]
|
21
|
-
s.post_install_message = "\n+-----------------------------------------------------------------------+\n| Please ensure you have installed exiftool version 7.65 or higher and |\n| it's found in your PATH (Try \"exiftool -ver\" on your commandline). |\n| For more details see |\n|
|
21
|
+
s.post_install_message = "\n+-----------------------------------------------------------------------+\n| Please ensure you have installed exiftool version 7.65 or higher and |\n| it's found in your PATH (Try \"exiftool -ver\" on your commandline). |\n| For more details see |\n| https://exiftool.org/install.html |\n+-----------------------------------------------------------------------+\n "
|
22
22
|
s.required_ruby_version = Gem::Requirement.new(">= 1.9.1")
|
23
23
|
s.requirements = ["exiftool, version 7.65 or higher"]
|
24
24
|
s.rubygems_version = "3.1.2"
|
25
|
-
s.summary = "This library is a wrapper for the ExifTool command-line application (
|
25
|
+
s.summary = "This library is a wrapper for the ExifTool command-line application (https://exiftool.org)."
|
26
26
|
|
27
27
|
if s.respond_to? :specification_version then
|
28
28
|
s.specification_version = 4
|
data/regtest/read_all_tags.yml
CHANGED
@@ -0,0 +1,363 @@
|
|
1
|
+
# Copied from https://exiftool.org/config.html
|
2
|
+
|
3
|
+
#------------------------------------------------------------------------------
|
4
|
+
# File: example.config
|
5
|
+
#
|
6
|
+
# Description: Example user configuration file for Image::ExifTool
|
7
|
+
#
|
8
|
+
# Notes: This example file shows how to define your own shortcuts and
|
9
|
+
# add new EXIF, IPTC, XMP, PNG, MIE and Composite tags, as well
|
10
|
+
# as how to specify preferred lenses for the LensID tag, and
|
11
|
+
# define new file types and default ExifTool option values.
|
12
|
+
#
|
13
|
+
# Note that unknown tags may be extracted even if they aren't
|
14
|
+
# defined, but tags must be defined to be written. Also note
|
15
|
+
# that it is possible to override an existing tag definition
|
16
|
+
# with a user-defined tag.
|
17
|
+
#
|
18
|
+
# To activate this file, rename it to ".ExifTool_config" and
|
19
|
+
# place it in your home directory or the exiftool application
|
20
|
+
# directory. (On Mac and some Windows systems this must be done
|
21
|
+
# via the command line since the GUI's may not allow filenames to
|
22
|
+
# begin with a dot. Use the "rename" command in Windows or "mv"
|
23
|
+
# on the Mac.) This causes ExifTool to automatically load the
|
24
|
+
# file when run. Your home directory is determined by the first
|
25
|
+
# defined of the following environment variables:
|
26
|
+
#
|
27
|
+
# 1. EXIFTOOL_HOME
|
28
|
+
# 2. HOME
|
29
|
+
# 3. HOMEDRIVE + HOMEPATH
|
30
|
+
# 4. (the current directory)
|
31
|
+
#
|
32
|
+
# Alternatively, the -config option of the exiftool application
|
33
|
+
# may be used to load a specific configuration file (note that
|
34
|
+
# this must be the first option on the command line):
|
35
|
+
#
|
36
|
+
# exiftool -config example.config ...
|
37
|
+
#
|
38
|
+
# This example file defines the following 16 new tags as well as
|
39
|
+
# a number of Shortcut and Composite tags:
|
40
|
+
#
|
41
|
+
# 1. EXIF:NewEXIFTag
|
42
|
+
# 2. GPS:GPSPitch
|
43
|
+
# 3. GPS:GPSRoll
|
44
|
+
# 4. IPTC:NewIPTCTag
|
45
|
+
# 5. XMP-xmp:NewXMPxmpTag
|
46
|
+
# 6. XMP-exif:GPSPitch
|
47
|
+
# 7. XMP-exif:GPSRoll
|
48
|
+
# 8. XMP-xxx:NewXMPxxxTag1
|
49
|
+
# 9. XMP-xxx:NewXMPxxxTag2
|
50
|
+
# 10. XMP-xxx:NewXMPxxxTag3
|
51
|
+
# 11. XMP-xxx:NewXMPxxxStruct
|
52
|
+
# 12. PNG:NewPngTag1
|
53
|
+
# 13. PNG:NewPngTag2
|
54
|
+
# 14. PNG:NewPngTag3
|
55
|
+
# 15. MIE-Meta:NewMieTag1
|
56
|
+
# 16. MIE-Test:NewMieTag2
|
57
|
+
#
|
58
|
+
# For detailed information on the definition of tag tables and
|
59
|
+
# tag information hashes, see lib/Image/ExifTool/README.
|
60
|
+
#------------------------------------------------------------------------------
|
61
|
+
|
62
|
+
# Shortcut tags are used when extracting information to simplify
|
63
|
+
# commonly used commands. They can be used to represent groups
|
64
|
+
# of tags, or to provide an alias for a tag name.
|
65
|
+
%Image::ExifTool::UserDefined::Shortcuts = (
|
66
|
+
MyShortcut => ['exif:createdate','exposuretime','aperture'],
|
67
|
+
MyAlias => 'FocalLengthIn35mmFormat',
|
68
|
+
);
|
69
|
+
|
70
|
+
# NOTE: All tag names used in the following tables are case sensitive.
|
71
|
+
|
72
|
+
# The %Image::ExifTool::UserDefined hash defines new tags to be added
|
73
|
+
# to existing tables.
|
74
|
+
%Image::ExifTool::UserDefined = (
|
75
|
+
# All EXIF tags are added to the Main table, and WriteGroup is used to
|
76
|
+
# specify where the tag is written (default is ExifIFD if not specified):
|
77
|
+
'Image::ExifTool::Exif::Main' => {
|
78
|
+
# Example 1. EXIF:NewEXIFTag
|
79
|
+
0xd000 => {
|
80
|
+
Name => 'NewEXIFTag',
|
81
|
+
Writable => 'int16u',
|
82
|
+
WriteGroup => 'IFD0',
|
83
|
+
},
|
84
|
+
# add more user-defined EXIF tags here...
|
85
|
+
},
|
86
|
+
# the Geotag feature writes these additional GPS tags if available:
|
87
|
+
'Image::ExifTool::GPS::Main' => {
|
88
|
+
# Example 2. GPS:GPSPitch
|
89
|
+
0xd000 => {
|
90
|
+
Name => 'GPSPitch',
|
91
|
+
Writable => 'rational64s',
|
92
|
+
},
|
93
|
+
# Example 3. GPS:GPSRoll
|
94
|
+
0xd001 => {
|
95
|
+
Name => 'GPSRoll',
|
96
|
+
Writable => 'rational64s',
|
97
|
+
},
|
98
|
+
},
|
99
|
+
# IPTC tags are added to a specific record type (eg. application record):
|
100
|
+
# (Note: IPTC tag ID's are limited to the range 0-255)
|
101
|
+
'Image::ExifTool::IPTC::ApplicationRecord' => {
|
102
|
+
# Example 4. IPTC:NewIPTCTag
|
103
|
+
160 => {
|
104
|
+
Name => 'NewIPTCTag',
|
105
|
+
Format => 'string[0,16]',
|
106
|
+
},
|
107
|
+
# add more user-defined IPTC ApplicationRecord tags here...
|
108
|
+
},
|
109
|
+
# XMP tags may be added to existing namespaces:
|
110
|
+
'Image::ExifTool::XMP::xmp' => {
|
111
|
+
# Example 5. XMP-xmp:NewXMPxmpTag
|
112
|
+
NewXMPxmpTag => { Groups => { 2 => 'Author' } },
|
113
|
+
# add more user-defined XMP-xmp tags here...
|
114
|
+
},
|
115
|
+
# special Geotag tags for XMP-exif:
|
116
|
+
'Image::ExifTool::XMP::exif' => {
|
117
|
+
# Example 6. XMP-exif:GPSPitch
|
118
|
+
GPSPitch => { Writable => 'rational', Groups => { 2 => 'Location' } },
|
119
|
+
# Example 7. XMP-exif:GPSRoll
|
120
|
+
GPSRoll => { Writable => 'rational', Groups => { 2 => 'Location' } },
|
121
|
+
},
|
122
|
+
# new XMP namespaces (eg. xxx) must be added to the Main XMP table:
|
123
|
+
'Image::ExifTool::XMP::Main' => {
|
124
|
+
# namespace definition for examples 8 to 11
|
125
|
+
xxx => { # <-- must be the same as the NAMESPACE prefix
|
126
|
+
SubDirectory => {
|
127
|
+
TagTable => 'Image::ExifTool::UserDefined::xxx',
|
128
|
+
# (see the definition of this table below)
|
129
|
+
},
|
130
|
+
},
|
131
|
+
# add more user-defined XMP namespaces here...
|
132
|
+
},
|
133
|
+
# new PNG tags are added to the PNG::TextualData table:
|
134
|
+
'Image::ExifTool::PNG::TextualData' => {
|
135
|
+
# Example 12. PNG:NewPngTag1
|
136
|
+
NewPngTag1 => { },
|
137
|
+
# Example 13. PNG:NewPngTag2
|
138
|
+
NewPngTag2 => { },
|
139
|
+
# Example 14. PNG:NewPngTag3
|
140
|
+
NewPngTag3 => { },
|
141
|
+
},
|
142
|
+
# add a new MIE tag (NewMieTag1) and group (MIE-Test) to MIE-Meta
|
143
|
+
# (Note: MIE group names must NOT end with a number)
|
144
|
+
'Image::ExifTool::MIE::Meta' => {
|
145
|
+
# Example 15. MIE-Meta:NewMieTag1
|
146
|
+
NewMieTag1 => {
|
147
|
+
Writable => 'rational64u',
|
148
|
+
Units => [ 'cm', 'in' ],
|
149
|
+
},
|
150
|
+
# new MIE "Test" group for example 16
|
151
|
+
Test => {
|
152
|
+
SubDirectory => {
|
153
|
+
TagTable => 'Image::ExifTool::UserDefined::MIETest',
|
154
|
+
DirName => 'MIE-Test',
|
155
|
+
},
|
156
|
+
},
|
157
|
+
},
|
158
|
+
# Composite tags are added to the Composite table:
|
159
|
+
'Image::ExifTool::Composite' => {
|
160
|
+
# Composite tags have values that are derived from the values of
|
161
|
+
# other tags. The Require/Desire elements below specify constituent
|
162
|
+
# tags that must/may exist, and the keys of these hashes are used as
|
163
|
+
# indices in the @val array of the ValueConv expression to access the
|
164
|
+
# numerical (-n) values of these tags. Print-converted values are
|
165
|
+
# accessed via the @prt array. All Require'd tags must exist for
|
166
|
+
# the Composite tag to be evaluated. If no Require'd tags are
|
167
|
+
# specified, then at least one of the Desire'd tags must exist. See
|
168
|
+
# the Composite table in Image::ExifTool::Exif for more examples,
|
169
|
+
# and lib/Image/ExifTool/README for all of the details.
|
170
|
+
BaseName => {
|
171
|
+
Require => {
|
172
|
+
0 => 'FileName',
|
173
|
+
},
|
174
|
+
# remove the extension from FileName
|
175
|
+
ValueConv => '$val[0] =~ /(.*)\./ ? $1 : $val[0]',
|
176
|
+
},
|
177
|
+
# the next few examples demonstrate simplifications which may be
|
178
|
+
# used if only one tag is Require'd or Desire'd:
|
179
|
+
# 1) the Require lookup may be replaced with a simple tag name
|
180
|
+
# 2) "$val" may be used to represent "$val[0]" in the expression
|
181
|
+
FileExtension => {
|
182
|
+
Require => 'FileName',
|
183
|
+
ValueConv => '$val=~/\.([^.]*)$/; $1',
|
184
|
+
},
|
185
|
+
# override CircleOfConfusion tag to use D/1750 instead of D/1440
|
186
|
+
CircleOfConfusion => {
|
187
|
+
Require => 'ScaleFactor35efl',
|
188
|
+
Groups => { 2 => 'Camera' },
|
189
|
+
ValueConv => 'sqrt(24*24+36*36) / ($val * 1750)',
|
190
|
+
# an optional PrintConv may be used to format the value
|
191
|
+
PrintConv => 'sprintf("%.3f mm",$val)',
|
192
|
+
},
|
193
|
+
# generate a description for this file type
|
194
|
+
FileTypeDescription => {
|
195
|
+
Require => 'FileType',
|
196
|
+
ValueConv => 'GetFileType($val,1) || $val',
|
197
|
+
},
|
198
|
+
# calculate physical image size based on resolution
|
199
|
+
PhysicalImageSize => {
|
200
|
+
Require => {
|
201
|
+
0 => 'ImageWidth',
|
202
|
+
1 => 'ImageHeight',
|
203
|
+
2 => 'XResolution',
|
204
|
+
3 => 'YResolution',
|
205
|
+
4 => 'ResolutionUnit',
|
206
|
+
},
|
207
|
+
ValueConv => '$val[0]/$val[2] . " " . $val[1]/$val[3]',
|
208
|
+
# (the @prt array contains print-formatted values)
|
209
|
+
PrintConv => 'sprintf("%.1fx%.1f $prt[4]", split(" ",$val))',
|
210
|
+
},
|
211
|
+
# [advanced] select largest JPEG preview image
|
212
|
+
BigImage => {
|
213
|
+
Groups => { 2 => 'Preview' },
|
214
|
+
Desire => {
|
215
|
+
0 => 'JpgFromRaw',
|
216
|
+
1 => 'PreviewImage',
|
217
|
+
2 => 'OtherImage',
|
218
|
+
# (DNG and A100 ARW may be have 2 PreviewImage's)
|
219
|
+
3 => 'PreviewImage (1)',
|
220
|
+
# (if the MPF has 2 previews, MPImage3 could be the larger one)
|
221
|
+
4 => 'MPImage3',
|
222
|
+
},
|
223
|
+
# ValueConv may also be a code reference
|
224
|
+
# Inputs: 0) reference to list of values, 1) ExifTool object
|
225
|
+
ValueConv => sub {
|
226
|
+
my $val = shift;
|
227
|
+
my ($image, $bigImage, $len, $bigLen);
|
228
|
+
foreach $image (@$val) {
|
229
|
+
next unless ref $image eq 'SCALAR';
|
230
|
+
# check for JPEG image (or "Binary data" if -b not used)
|
231
|
+
next unless $$image =~ /^(\xff\xd8\xff|Binary data (\d+))/;
|
232
|
+
$len = $2 || length $$image; # get image length
|
233
|
+
# save largest image
|
234
|
+
next if defined $bigLen and $bigLen >= $len;
|
235
|
+
$bigLen = $len;
|
236
|
+
$bigImage = $image;
|
237
|
+
}
|
238
|
+
return $bigImage;
|
239
|
+
},
|
240
|
+
},
|
241
|
+
# **** ADD ADDITIONAL COMPOSITE TAG DEFINITIONS HERE ****
|
242
|
+
},
|
243
|
+
);
|
244
|
+
|
245
|
+
# This is a basic example of the definition for a new XMP namespace.
|
246
|
+
# This table is referenced through a SubDirectory tag definition
|
247
|
+
# in the %Image::ExifTool::UserDefined definition above.
|
248
|
+
# The namespace prefix for these tags is 'xxx', which corresponds to
|
249
|
+
# an ExifTool family 1 group name of 'XMP-xxx'.
|
250
|
+
%Image::ExifTool::UserDefined::xxx = (
|
251
|
+
GROUPS => { 0 => 'XMP', 1 => 'XMP-xxx', 2 => 'Image' },
|
252
|
+
NAMESPACE => { 'xxx' => 'http://ns.myname.com/xxx/1.0/' },
|
253
|
+
WRITABLE => 'string', # (default to string-type tags)
|
254
|
+
# Example 8. XMP-xxx:NewXMPxxxTag1 (an alternate-language tag)
|
255
|
+
# - replace "NewXMPxxxTag1" with your own tag name (eg. "MyTag")
|
256
|
+
NewXMPxxxTag1 => { Writable => 'lang-alt' },
|
257
|
+
# Example 9. XMP-xxx:NewXMPxxxTag2 (a string tag in the Author category)
|
258
|
+
NewXMPxxxTag2 => { Groups => { 2 => 'Author' } },
|
259
|
+
# Example 10. XMP-xxx:NewXMPxxxTag3 (an unordered List-type tag)
|
260
|
+
NewXMPxxxTag3 => { List => 'Bag' },
|
261
|
+
# Example 11. XMP-xxx:NewXMPxxxStruct (a structured tag)
|
262
|
+
# - example structured XMP tag
|
263
|
+
NewXMPxxxStruct => {
|
264
|
+
# the "Struct" entry defines the structure fields
|
265
|
+
Struct => {
|
266
|
+
# optional namespace prefix and URI for structure fields
|
267
|
+
# (required only if different than NAMESPACE above)
|
268
|
+
# --> multiple entries may exist in this namespace lookup,
|
269
|
+
# with the last one alphabetically being the default for
|
270
|
+
# the fields, but each field may have a "Namespace"
|
271
|
+
# element to specify which prefix to use
|
272
|
+
NAMESPACE => { 'test' => 'http://x.y.z/test/' },
|
273
|
+
# optional structure name (used for warning messages only)
|
274
|
+
STRUCT_NAME => 'MyStruct',
|
275
|
+
# optional rdf:type property for the structure
|
276
|
+
TYPE => 'http://x.y.z/test/xystruct',
|
277
|
+
# structure fields (very similar to tag definitions)
|
278
|
+
X => { Writable => 'integer' },
|
279
|
+
Y => { Writable => 'integer' },
|
280
|
+
# a nested structure...
|
281
|
+
Things => {
|
282
|
+
List => 'Bag',
|
283
|
+
Struct => {
|
284
|
+
NAMESPACE => { thing => 'http://x.y.z/thing/' },
|
285
|
+
What => { },
|
286
|
+
Where => { },
|
287
|
+
},
|
288
|
+
},
|
289
|
+
},
|
290
|
+
List => 'Seq', # structures may also be elements of a list
|
291
|
+
},
|
292
|
+
# Each field in the structure has a corresponding flattened tag that is
|
293
|
+
# generated automatically with an ID made from a concatenation of the
|
294
|
+
# original structure tag ID and the field name (after capitalizing the
|
295
|
+
# first letter of the field name if necessary). The Name and/or
|
296
|
+
# Description of these flattened tags may be changed if desired, but all
|
297
|
+
# other tag properties are taken from the structure field definition.
|
298
|
+
# The "Flat" flag must be used when setting the Name or Description of a
|
299
|
+
# flattened tag. For example:
|
300
|
+
NewXMPxxxStructX => { Name => 'SomeOtherName', Flat => 1 },
|
301
|
+
);
|
302
|
+
|
303
|
+
# Adding a new MIE group requires a few extra definitions
|
304
|
+
use Image::ExifTool::MIE;
|
305
|
+
%Image::ExifTool::UserDefined::MIETest = (
|
306
|
+
%Image::ExifTool::MIE::tableDefaults, # default MIE table entries
|
307
|
+
GROUPS => { 0 => 'MIE', 1 => 'MIE-Test', 2 => 'Document' },
|
308
|
+
WRITE_GROUP => 'MIE-Test',
|
309
|
+
# Example 16. MIE-Test:NewMieTag2
|
310
|
+
NewMieTag2 => { }, # new user-defined tag in MIE-Test group
|
311
|
+
);
|
312
|
+
|
313
|
+
# A special 'Lenses' list can be defined to give priority to specific lenses
|
314
|
+
# in the logic to determine a lens model for the Composite:LensID tag
|
315
|
+
@Image::ExifTool::UserDefined::Lenses = (
|
316
|
+
'Sigma AF 10-20mm F4-5.6 EX DC',
|
317
|
+
'Tokina AF193-2 19-35mm f/3.5-4.5',
|
318
|
+
);
|
319
|
+
|
320
|
+
# User-defined file types to recognize
|
321
|
+
%Image::ExifTool::UserDefined::FileTypes = (
|
322
|
+
XXX => { # <-- the extension of the new file type (case insensitive)
|
323
|
+
# BaseType specifies the format upon which this file is based (case
|
324
|
+
# sensitive). If BaseType is defined, then the file will be fully
|
325
|
+
# supported, and in this case the Magic pattern should not be defined
|
326
|
+
BaseType => 'TIFF',
|
327
|
+
MIMEType => 'image/x-xxx',
|
328
|
+
Description => 'My XXX file type',
|
329
|
+
# if the BaseType is writable by ExifTool, then the new file type
|
330
|
+
# will also be writable unless otherwise specified, like this:
|
331
|
+
Writable => 0,
|
332
|
+
},
|
333
|
+
YYY => {
|
334
|
+
# without BaseType, the file will be recognized but not supported
|
335
|
+
Magic => '0123abcd', # regular expression to match at start of file
|
336
|
+
MIMEType => 'application/test',
|
337
|
+
Description => 'My YYY file type',
|
338
|
+
},
|
339
|
+
ZZZ => {
|
340
|
+
# if neither BaseType nor Magic are defined, the file will be
|
341
|
+
# recognized by extension only. MIMEType will be application/unknown
|
342
|
+
# unless otherwise specified
|
343
|
+
Description => 'My ZZZ file type',
|
344
|
+
},
|
345
|
+
# if only BaseType is specified, then the following simplified syntax
|
346
|
+
# may be used. In this example, files with extension "TTT" will be
|
347
|
+
# processed as JPEG files
|
348
|
+
TTT => 'JPEG',
|
349
|
+
);
|
350
|
+
|
351
|
+
# Change default location for writing QuickTime tags so Keys is preferred
|
352
|
+
# (by default, the PREFERRED levels are: ItemList=2, UserData=1, Keys=0)
|
353
|
+
use Image::ExifTool::QuickTime;
|
354
|
+
$Image::ExifTool::QuickTime::Keys{PREFERRED} = 3;
|
355
|
+
|
356
|
+
# Specify default ExifTool option values
|
357
|
+
# (see the Options function documentation for available options)
|
358
|
+
%Image::ExifTool::UserDefined::Options = (
|
359
|
+
CoordFormat => '%.6f', # change default GPS coordinate format
|
360
|
+
Duplicates => 1, # make -a default for the exiftool app
|
361
|
+
GeoMaxHDOP => 4, # ignore GPS fixes with HDOP > 4
|
362
|
+
RequestAll => 3, # request additional tags not normally generated
|
363
|
+
);
|
data/test/test_batch.rb
ADDED
@@ -0,0 +1,42 @@
|
|
1
|
+
# encoding: utf-8
|
2
|
+
# frozen_string_literal: true
|
3
|
+
|
4
|
+
require_relative 'helper'
|
5
|
+
|
6
|
+
class TestBatch < Test::Unit::TestCase
|
7
|
+
|
8
|
+
MANDATORY_WRITER_ARGS = MultiExiftool::Writer.mandatory_args
|
9
|
+
|
10
|
+
context 'exiftool_args method' do
|
11
|
+
|
12
|
+
setup do
|
13
|
+
@filenames = %w(a.jpg b.jpg c.jpg)
|
14
|
+
@multiple_values = @filenames.map do |filename|
|
15
|
+
{author: 'janfri', comment: "Comment for file #{filename}"}
|
16
|
+
end
|
17
|
+
end
|
18
|
+
|
19
|
+
test 'only filenames and values' do
|
20
|
+
batch = MultiExiftool::Batch.new
|
21
|
+
@filenames.zip @multiple_values do |filename, values|
|
22
|
+
batch.write filename, values
|
23
|
+
end
|
24
|
+
exiftool_args = @filenames.zip(@multiple_values).map do |filename, values|
|
25
|
+
[MANDATORY_WRITER_ARGS, '-author=janfri', "-comment=Comment for file #{filename}", filename, '-execute']
|
26
|
+
end.flatten
|
27
|
+
assert_equal exiftool_args, batch.exiftool_args
|
28
|
+
end
|
29
|
+
|
30
|
+
test 'filenames, values and options' do
|
31
|
+
options = {overwrite_original: true}
|
32
|
+
batch = MultiExiftool::Batch.new
|
33
|
+
@filenames.zip @multiple_values do |filename, values|
|
34
|
+
batch.write filename, values, options
|
35
|
+
end
|
36
|
+
exiftool_args = @filenames.zip(@multiple_values).map do |filename, _values|
|
37
|
+
[MANDATORY_WRITER_ARGS, '-overwrite_original', '-author=janfri', "-comment=Comment for file #{filename}", filename, '-execute']
|
38
|
+
end.flatten
|
39
|
+
assert_equal exiftool_args, batch.exiftool_args
|
40
|
+
end
|
41
|
+
end
|
42
|
+
end
|
data/test/test_functional_api.rb
CHANGED
@@ -60,6 +60,18 @@ class TestFunctionalApi < Test::Unit::TestCase
|
|
60
60
|
end
|
61
61
|
end
|
62
62
|
|
63
|
+
test 'successful reading with user defined tags in config file' do
|
64
|
+
run_in_temp_dir do
|
65
|
+
values, errors = MultiExiftool.read(%w[a.jpg b.jpg c.jpg], tags: %w[basename fileextension])
|
66
|
+
assert_equal [nil, nil, nil], values.map(&:basename)
|
67
|
+
assert_equal [nil, nil, nil], values.map(&:file_extension)
|
68
|
+
assert_equal [], errors
|
69
|
+
values, errors = MultiExiftool.read(%w[a.jpg b.jpg c.jpg], config: 'example.config', tags: %w[basename fileextension])
|
70
|
+
assert_equal %w[a b c], values.map(&:basename)
|
71
|
+
assert_equal %w[jpg]*3, values.map(&:file_extension)
|
72
|
+
assert_equal [], errors
|
73
|
+
end
|
74
|
+
end
|
63
75
|
end
|
64
76
|
|
65
77
|
context 'writing' do
|
@@ -188,4 +200,93 @@ class TestFunctionalApi < Test::Unit::TestCase
|
|
188
200
|
|
189
201
|
end
|
190
202
|
|
203
|
+
context 'batch' do
|
204
|
+
|
205
|
+
setup do
|
206
|
+
@filenames = %w(a.jpg b.jpg c.jpg)
|
207
|
+
@multiple_values = @filenames.map do |fn|
|
208
|
+
{author: 'Jan Friedrich', comment: "Comment for file #{fn}"}
|
209
|
+
end
|
210
|
+
end
|
211
|
+
|
212
|
+
context 'instance_exec' do
|
213
|
+
|
214
|
+
test 'only filenames and values' do
|
215
|
+
run_in_temp_dir do
|
216
|
+
filenames = @filenames
|
217
|
+
multiple_values = @multiple_values
|
218
|
+
errors = MultiExiftool.batch do
|
219
|
+
filenames.zip multiple_values do |filename, values|
|
220
|
+
write filename, values
|
221
|
+
end
|
222
|
+
end
|
223
|
+
assert_equal [], errors
|
224
|
+
values, errors = MultiExiftool.read(@filenames)
|
225
|
+
assert_equal ['Jan Friedrich'] * 3, values.map {|e| e['Author']}
|
226
|
+
assert_equal ['Comment for file a.jpg', 'Comment for file b.jpg', 'Comment for file c.jpg'], values.map {|e| e['Comment']}
|
227
|
+
assert_equal [], errors
|
228
|
+
assert_equal 3, Dir['*_original'].size
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
test 'options with boolean argument' do
|
233
|
+
run_in_temp_dir do
|
234
|
+
filenames = @filenames
|
235
|
+
multiple_values = @multiple_values
|
236
|
+
options = {overwrite_original: true}
|
237
|
+
errors = MultiExiftool.batch do
|
238
|
+
filenames.zip multiple_values do |filename, values|
|
239
|
+
write filename, values, options
|
240
|
+
end
|
241
|
+
end
|
242
|
+
assert_equal [], errors
|
243
|
+
values, errors = MultiExiftool.read(@filenames)
|
244
|
+
assert_equal ['Jan Friedrich'] * 3, values.map {|e| e['Author']}
|
245
|
+
assert_equal ['Comment for file a.jpg', 'Comment for file b.jpg', 'Comment for file c.jpg'], values.map {|e| e['Comment']}
|
246
|
+
assert_equal [], errors
|
247
|
+
assert_equal [], Dir['*_original']
|
248
|
+
end
|
249
|
+
end
|
250
|
+
|
251
|
+
end
|
252
|
+
|
253
|
+
context 'yield' do
|
254
|
+
|
255
|
+
test 'only filenames and values' do
|
256
|
+
run_in_temp_dir do
|
257
|
+
errors = MultiExiftool.batch do |batch|
|
258
|
+
@filenames.zip @multiple_values do |filename, values|
|
259
|
+
batch.write filename, values
|
260
|
+
end
|
261
|
+
end
|
262
|
+
assert_equal [], errors
|
263
|
+
values, errors = MultiExiftool.read(@filenames)
|
264
|
+
assert_equal ['Jan Friedrich'] * 3, values.map {|e| e['Author']}
|
265
|
+
assert_equal ['Comment for file a.jpg', 'Comment for file b.jpg', 'Comment for file c.jpg'], values.map {|e| e['Comment']}
|
266
|
+
assert_equal [], errors
|
267
|
+
assert_equal 3, Dir['*_original'].size
|
268
|
+
end
|
269
|
+
end
|
270
|
+
|
271
|
+
test 'options with boolean argument' do
|
272
|
+
run_in_temp_dir do
|
273
|
+
options = {overwrite_original: true}
|
274
|
+
errors = MultiExiftool.batch do |batch|
|
275
|
+
@filenames.zip @multiple_values do |filename, values|
|
276
|
+
batch.write filename, values, options
|
277
|
+
end
|
278
|
+
end
|
279
|
+
assert_equal [], errors
|
280
|
+
values, errors = MultiExiftool.read(@filenames)
|
281
|
+
assert_equal ['Jan Friedrich'] * 3, values.map {|e| e['Author']}
|
282
|
+
assert_equal ['Comment for file a.jpg', 'Comment for file b.jpg', 'Comment for file c.jpg'], values.map {|e| e['Comment']}
|
283
|
+
assert_equal [], errors
|
284
|
+
assert_equal [], Dir['*_original']
|
285
|
+
end
|
286
|
+
end
|
287
|
+
|
288
|
+
end
|
289
|
+
|
290
|
+
end
|
291
|
+
|
191
292
|
end
|
data/test/test_reader.rb
CHANGED
@@ -157,6 +157,20 @@ class TestReader < Test::Unit::TestCase
|
|
157
157
|
end
|
158
158
|
end
|
159
159
|
|
160
|
+
test 'successful reading with user defined tags in config file' do
|
161
|
+
run_in_temp_dir do
|
162
|
+
@reader.filenames = %w(a.jpg b.jpg c.jpg)
|
163
|
+
@reader.tags = %w[basename]
|
164
|
+
res = @reader.read
|
165
|
+
assert_equal [nil, nil, nil], res.map(&:basename)
|
166
|
+
assert_equal [], @reader.errors
|
167
|
+
@reader.config = 'example.config'
|
168
|
+
res = @reader.read
|
169
|
+
assert_equal %w[a b c], res.map(&:basename)
|
170
|
+
assert_equal [], @reader.errors
|
171
|
+
end
|
172
|
+
end
|
173
|
+
|
160
174
|
end
|
161
175
|
|
162
176
|
end
|
data/test/test_values.rb
CHANGED
@@ -137,19 +137,19 @@ class TestValues < Test::Unit::TestCase
|
|
137
137
|
|
138
138
|
test 'different formats as string' do
|
139
139
|
@hash.keys.each do |k|
|
140
|
-
|
140
|
+
assert_equal true, @values.has_tag?(k)
|
141
141
|
end
|
142
142
|
end
|
143
143
|
|
144
144
|
test 'different formats as symbol' do
|
145
145
|
@hash.keys.each do |k|
|
146
|
-
|
146
|
+
assert_equal true, @values.has_tag?(k.to_sym)
|
147
147
|
end
|
148
148
|
end
|
149
149
|
|
150
150
|
test 'non existent key' do
|
151
151
|
['iso', 'ISO', :iso, :ISO].each do |t|
|
152
|
-
|
152
|
+
assert_equal false, @values.has_tag?(t)
|
153
153
|
end
|
154
154
|
end
|
155
155
|
end
|
@@ -182,13 +182,13 @@ class TestValues < Test::Unit::TestCase
|
|
182
182
|
|
183
183
|
test 'existing keys' do
|
184
184
|
[:fnumber, :f_number, :FNumber, 'fnumber', 'f_number', 'FNumber', :author, :Author, 'author', 'Author'].each do |t|
|
185
|
-
|
185
|
+
assert_equal true, @values.respond_to?(t)
|
186
186
|
end
|
187
187
|
end
|
188
188
|
|
189
189
|
test 'non existing key' do
|
190
190
|
['iso', 'ISO', :iso, :ISO].each do |t|
|
191
|
-
|
191
|
+
assert_equal false, @values.respond_to?(t)
|
192
192
|
end
|
193
193
|
end
|
194
194
|
|
metadata
CHANGED
@@ -1,14 +1,14 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: multi_exiftool
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 0.
|
4
|
+
version: 0.16.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Jan Friedrich
|
8
|
-
autorequire:
|
8
|
+
autorequire:
|
9
9
|
bindir: bin
|
10
10
|
cert_chain: []
|
11
|
-
date: 2020-
|
11
|
+
date: 2020-10-27 00:00:00.000000000 Z
|
12
12
|
dependencies:
|
13
13
|
- !ruby/object:Gem::Dependency
|
14
14
|
name: rake
|
@@ -80,7 +80,7 @@ dependencies:
|
|
80
80
|
- - "~>"
|
81
81
|
- !ruby/object:Gem::Version
|
82
82
|
version: '2'
|
83
|
-
description: This library a
|
83
|
+
description: This library is a wrapper for the ExifTool command-line application (https://exiftool.org)
|
84
84
|
written by Phil Harvey. It is designed for dealing with multiple files at once by
|
85
85
|
creating commands to call exiftool with various arguments, call it and parsing the
|
86
86
|
results.
|
@@ -96,6 +96,7 @@ files:
|
|
96
96
|
- README.md
|
97
97
|
- Rakefile
|
98
98
|
- lib/multi_exiftool.rb
|
99
|
+
- lib/multi_exiftool/batch.rb
|
99
100
|
- lib/multi_exiftool/executable.rb
|
100
101
|
- lib/multi_exiftool/reader.rb
|
101
102
|
- lib/multi_exiftool/values.rb
|
@@ -107,7 +108,9 @@ files:
|
|
107
108
|
- test/data/a.jpg
|
108
109
|
- test/data/b.jpg
|
109
110
|
- test/data/c.jpg
|
111
|
+
- test/data/example.config
|
110
112
|
- test/helper.rb
|
113
|
+
- test/test_batch.rb
|
111
114
|
- test/test_executable.rb
|
112
115
|
- test/test_exiftool_stuff.rb
|
113
116
|
- test/test_functional_api.rb
|
@@ -123,7 +126,7 @@ metadata: {}
|
|
123
126
|
post_install_message: "\n+-----------------------------------------------------------------------+\n|
|
124
127
|
Please ensure you have installed exiftool version 7.65 or higher and |\n| it's
|
125
128
|
found in your PATH (Try \"exiftool -ver\" on your commandline). |\n| For more
|
126
|
-
details see |\n|
|
129
|
+
details see |\n| https://exiftool.org/install.html
|
127
130
|
\ |\n+-----------------------------------------------------------------------+\n
|
128
131
|
\ "
|
129
132
|
rdoc_options: []
|
@@ -142,7 +145,7 @@ required_rubygems_version: !ruby/object:Gem::Requirement
|
|
142
145
|
requirements:
|
143
146
|
- exiftool, version 7.65 or higher
|
144
147
|
rubygems_version: 3.1.2
|
145
|
-
signing_key:
|
148
|
+
signing_key:
|
146
149
|
specification_version: 4
|
147
|
-
summary: This library is a wrapper for the ExifTool command-line application (
|
150
|
+
summary: This library is a wrapper for the ExifTool command-line application (https://exiftool.org).
|
148
151
|
test_files: []
|