libis-format 0.9.41 → 0.9.44

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.
Files changed (52) hide show
  1. checksums.yaml +4 -4
  2. data/README.md +365 -0
  3. data/bin/droid +1 -1
  4. data/bin/fido +1 -1
  5. data/bin/pdf_copy +1 -1
  6. data/lib/libis/format/config.rb +1 -0
  7. data/lib/libis/format/converter/audio_converter.rb +1 -1
  8. data/lib/libis/format/converter/base.rb +2 -1
  9. data/lib/libis/format/converter/office_converter.rb +2 -2
  10. data/lib/libis/format/converter/pdf_converter.rb +6 -6
  11. data/lib/libis/format/converter/video_converter.rb +96 -2
  12. data/lib/libis/format/identifier.rb +12 -12
  13. data/lib/libis/format/tool/droid.rb +108 -0
  14. data/lib/libis/format/tool/extension_identification.rb +58 -0
  15. data/lib/libis/format/tool/ffmpeg.rb +43 -0
  16. data/lib/libis/format/tool/fido.rb +91 -0
  17. data/lib/libis/format/tool/file_tool.rb +78 -0
  18. data/lib/libis/format/tool/identification_tool.rb +175 -0
  19. data/lib/libis/format/tool/office_to_pdf.rb +54 -0
  20. data/lib/libis/format/tool/pdf_copy.rb +42 -0
  21. data/lib/libis/format/tool/pdf_merge.rb +43 -0
  22. data/lib/libis/format/tool/pdf_optimizer.rb +38 -0
  23. data/lib/libis/format/tool/pdf_split.rb +41 -0
  24. data/lib/libis/format/tool/pdf_to_pdfa.rb +78 -0
  25. data/lib/libis/format/tool/pdfa_validator.rb +63 -0
  26. data/lib/libis/format/tool.rb +23 -0
  27. data/lib/libis/format/version.rb +1 -1
  28. data/lib/libis/format.rb +1 -15
  29. data/libis-format.gemspec +1 -2
  30. data/spec/converter_audio_spec.rb +66 -0
  31. data/spec/converter_image_spec.rb +166 -0
  32. data/spec/converter_office_spec.rb +84 -0
  33. data/spec/converter_pdf_spec.rb +30 -0
  34. data/spec/converter_repository_spec.rb +91 -0
  35. data/spec/converter_video_spec.rb +97 -0
  36. data/spec/data/video/copyright.png +0 -0
  37. data/spec/identifier_spec.rb +3 -15
  38. metadata +32 -33
  39. data/lib/libis/format/droid.rb +0 -106
  40. data/lib/libis/format/extension_identification.rb +0 -55
  41. data/lib/libis/format/ffmpeg.rb +0 -41
  42. data/lib/libis/format/fido.rb +0 -89
  43. data/lib/libis/format/file_tool.rb +0 -76
  44. data/lib/libis/format/identification_tool.rb +0 -174
  45. data/lib/libis/format/office_to_pdf.rb +0 -52
  46. data/lib/libis/format/pdf_copy.rb +0 -40
  47. data/lib/libis/format/pdf_merge.rb +0 -41
  48. data/lib/libis/format/pdf_optimizer.rb +0 -36
  49. data/lib/libis/format/pdf_split.rb +0 -39
  50. data/lib/libis/format/pdf_to_pdfa.rb +0 -74
  51. data/lib/libis/format/pdfa_validator.rb +0 -61
  52. data/spec/converter_spec.rb +0 -433
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 52324c2a0a320c5a4e9940998515baf300186927
4
- data.tar.gz: 8a19e17da36919d97d9310663136a9b9d9889a31
3
+ metadata.gz: 22fe2305d1461bf58825e88933f215cd64fffdba
4
+ data.tar.gz: 454e2fc45afeae5b338723df845923c7f4364d10
5
5
  SHA512:
6
- metadata.gz: 1dd5dea124dfc761dc0b39f6a5810ac61424b29ff88ffcd17eb32a1bdb423625146c6b67a649eced61908b048b83f02f3fd9f53d0c3762a1f78889e770432cce
7
- data.tar.gz: 40369f9ea7ccdfc2e4b84e239d78e36952c87e0b3351e700a1ce2bd104ab446f1f5ff64816ea57c7faf9c71928f73721ed73b6bb4acbc83237531bb8aa621a5e
6
+ metadata.gz: ecf6f26241e61b34c6162c31ee1f55896a8d9bb67b01e2484db1714d1c5dfc75ce5666fad215dc8bc99d6e12d6f50fac3e81f92c9f47a5d8f26bdb43c0766d7b
7
+ data.tar.gz: 8743beb8af9bc17f9953e9488d0fc78ccb8e709a5fcbc551470926fea972e39560b6ab092faa52789109ff796b7309f45bba9844e395c1e2cc0f3c10d94b27b8
data/README.md CHANGED
@@ -30,6 +30,371 @@ Or install it yourself as:
30
30
 
31
31
  The type database is the core of the format services. It stores information about all the known formats.
32
32
 
33
+ ### ::Libis::Format::Identifier
34
+
35
+ This class enables support for format identification. It will use 3 external tools to identify a file format:
36
+ droid, fido and the unix file tool. Based on several criteria, the results of these tools will be given a
37
+ score and the result with the highest confidence is returned. The output of all tools can also be returned.
38
+ The format identification result contains a MIME-type and a PRONOM PUID if they are known. Also the calculated
39
+ score, the tool that produced the outcome and recognition method are listed. Some tools also return more
40
+ information like the format name and format version. If these are present on the most confident output, their
41
+ values will also be part of the result info.
42
+
43
+ Unidentified files will be listed with MIME-type 'application/octet-stream' and PUID 'fmt/unknown'.
44
+
45
+ The main method #get that performs the format identification takes two parameters:
46
+ - file: can be a string representing a file or directory path, but also an array of file paths.
47
+ - options: optional hash with parameters that influence the behaviour of the format identification process
48
+
49
+ The options has accespts the following keys (Symbol types):
50
+ - :droid
51
+ Boolean if set to false will not use the Droid tool. Default: true
52
+ - :fido
53
+ Boolean if set to false will not use the Fido tool. Default: true
54
+ - :file
55
+ Boolean if set to false will not use the Unix file tool. Default: true
56
+ - :tool
57
+ Symbol either :droid, :fido or :file. A shortcut option for setting only the given value to true.
58
+ - :xml_validation
59
+ Boolean if set to false will not perform XML validation (see below)
60
+ - :recursive
61
+ Boolean if set to true and a directory is passed as first argument, Identifier will parse the
62
+ directory tree recursively and will process all files found. Default: false
63
+ - :base_dir
64
+ String. Normally file will be referenced by their absolute path in the results. If a value is
65
+ supplied for this option, the given path will be stripped from the start of the file references in the
66
+ result. Default: nil.
67
+ - :keep_output
68
+ Boolean if set will store the output of each identification tool in the result structure. Default: false
69
+
70
+ The result of the identification is a Hash with the following keys:
71
+ - :messages
72
+ a list (Array) of error and warning messages that the Identifier or one of the tools used has generated.
73
+ Each entry is another Array with the first argument the severity of the message and the second one the
74
+ message itself.
75
+ - :output
76
+ optional output of each tool as an Array with an entry per tool and grouped into a Hash by file reference.
77
+ - :formats
78
+ a Hash with file references as key and the outcome of the identification as value.
79
+
80
+ The identification outcome is a Hash of key-value pairs for each property returned. Keys are lower-case
81
+ symbols. If the tools gave results that deffer in a significant part, their outcome will be added to a list as
82
+ :alternatives (see example).
83
+
84
+ #### XML Validation
85
+
86
+ None of the tools used is able to identify an XML file by its content. In our context this is especially
87
+ annoying for EAD XML files as we want to identify them in order to process them different from the other XML
88
+ files. The Identifier solves this by performing an extra check on files identified as XML files. It will
89
+ validate each XML file against a list of XML schemas and return the matching MIME-type in the result. If the
90
+ Type Database contains an entry for this format, the result will be extended with the information from the
91
+ Type Database.
92
+
93
+ With the :xml_validation option this behaviour can be turned off, for instance in cases where no EAD files are
94
+ to be expected or no further identification of XML files is needed. Note that if no XML files are present, the
95
+ Identifier will not spend any time on XML validation anyway.
96
+
97
+ The list of validation schemas can be extended with the class method #add_xml_validation which takes two
98
+ parameters: a MIME-type and the path to an XML schema (XSD). If you want to also assign a fictuous PUID to the
99
+ XML type you should add an entry to your Type Database with the same MIME-type.
100
+
101
+ ### Example
102
+
103
+ ```
104
+ ```
105
+
106
+ ```
107
+ {
108
+ :messages => [
109
+ [0] [
110
+ [0] :debug,
111
+ [1] "XML file validated against XML Schema: [...]/data/ead.xsd"
112
+ ],
113
+ [1] [
114
+ [0] :debug,
115
+ [1] "XML file validated against XML Schema: [...]/data/ead.xsd"
116
+ ],
117
+ [2] [
118
+ [0] :debug,
119
+ [1] "XML file validated against XML Schema: [...]/data/ead.xsd"
120
+ ]
121
+ ],
122
+ :output => {
123
+ "[...]/data/Cevennes2.bmp" => [
124
+ [0] {
125
+ :matchtype => "signature",
126
+ :ext_mismatch => "false",
127
+ :puid => "fmt/116",
128
+ :mimetype => "image/bmp",
129
+ :format_name => "Windows Bitmap",
130
+ :format_version => "3.0",
131
+ :source => :droid,
132
+ :TYPE => :BMP,
133
+ :GROUP => :IMAGE,
134
+ :score => 7
135
+ },
136
+ [1] {
137
+ :puid => "fmt/116",
138
+ :format_name => "Windows Bitmap",
139
+ :format_version => "Windows Bitmap 3.0",
140
+ :mimetype => "image/bmp",
141
+ :matchtype => "signature",
142
+ :source => :fido,
143
+ :TYPE => :BMP,
144
+ :GROUP => :IMAGE,
145
+ :score => 7
146
+ },
147
+ [2] {
148
+ :mimetype => "image/bmp",
149
+ :matchtype => "magic",
150
+ :source => :file,
151
+ :TYPE => :BMP,
152
+ :GROUP => :IMAGE,
153
+ :score => 2
154
+ }
155
+ ],
156
+ "[...]/data/Cevennes2.jp2" => [
157
+ [0] {
158
+ :matchtype => "signature",
159
+ :ext_mismatch => "false",
160
+ :puid => "x-fmt/392",
161
+ :mimetype => "image/jp2",
162
+ :format_name => "JP2 (JPEG 2000 part 1)",
163
+ :format_version => "",
164
+ :source => :droid,
165
+ :TYPE => :JP2,
166
+ :GROUP => :IMAGE,
167
+ :score => 7
168
+ },
169
+ [1] {
170
+ :puid => "x-fmt/392",
171
+ :format_name => "JP2 (JPEG 2000 part 1)",
172
+ :format_version => "JPEG2000",
173
+ :mimetype => "image/jp2",
174
+ :matchtype => "signature",
175
+ :source => :fido,
176
+ :TYPE => :JP2,
177
+ :GROUP => :IMAGE,
178
+ :score => 7
179
+ },
180
+ [2] {
181
+ :mimetype => "image/jp2",
182
+ :matchtype => "magic",
183
+ :source => :file,
184
+ :TYPE => :JP2,
185
+ :GROUP => :IMAGE,
186
+ :score => 2
187
+ }
188
+ ],
189
+ [...]
190
+ },
191
+ :formats => {
192
+ "[...]/data/Cevennes2.bmp" => {
193
+ :matchtype => "signature",
194
+ :ext_mismatch => "false",
195
+ :puid => "fmt/116",
196
+ :mimetype => "image/bmp",
197
+ :format_name => "Windows Bitmap",
198
+ :format_version => "3.0",
199
+ :source => :droid,
200
+ :TYPE => :BMP,
201
+ :GROUP => :IMAGE,
202
+ :score => 7
203
+ },
204
+ "[...]/data/Cevennes2.jp2" => {
205
+ :matchtype => "signature",
206
+ :ext_mismatch => "false",
207
+ :puid => "x-fmt/392",
208
+ :mimetype => "image/jp2",
209
+ :format_name => "JP2 (JPEG 2000 part 1)",
210
+ :format_version => "JPEG2000",
211
+ :source => :droid,
212
+ :TYPE => :JP2,
213
+ :GROUP => :IMAGE,
214
+ :score => 7
215
+ },
216
+ "[...]/data/NikonRaw-CameraRaw.TIF" => {
217
+ :matchtype => "signature",
218
+ :ext_mismatch => "false",
219
+ :puid => "fmt/353",
220
+ :mimetype => "image/tiff",
221
+ :format_name => "Tagged Image File Format",
222
+ :format_version => "TIFF generic (little-endian)",
223
+ :source => :droid,
224
+ :TYPE => :TIFF,
225
+ :GROUP => :IMAGE,
226
+ :score => 7
227
+ },
228
+ "[...]/data/NikonRaw-CaptureOne.tif" => {
229
+ :matchtype => "signature",
230
+ :ext_mismatch => "false",
231
+ :puid => "x-fmt/387",
232
+ :mimetype => "image/tiff",
233
+ :format_name => "Exchangeable Image File Format (Uncompressed)",
234
+ :format_version => "2.2",
235
+ :source => :droid,
236
+ :TYPE => :TIFF,
237
+ :GROUP => :IMAGE,
238
+ :score => 7,
239
+ :alternatives => [
240
+ [0] {
241
+ :puid => "fmt/353",
242
+ :format_name => "Tagged Image File Format",
243
+ :format_version => "TIFF generic (little-endian)",
244
+ :mimetype => "image/tiff",
245
+ :matchtype => "signature",
246
+ :source => :fido,
247
+ :TYPE => :TIFF,
248
+ :GROUP => :IMAGE,
249
+ :score => 7
250
+ },
251
+ [1] {
252
+ :matchtype => "signature",
253
+ :ext_mismatch => "false",
254
+ :puid => "x-fmt/387",
255
+ :mimetype => "image/tiff",
256
+ :format_name => "Exchangeable Image File Format (Uncompressed)",
257
+ :format_version => "2.2",
258
+ :source => :droid,
259
+ :TYPE => :TIFF,
260
+ :GROUP => :IMAGE,
261
+ :score => 7
262
+ }
263
+ ]
264
+ },
265
+ "[...]/data/test-ead.xml" => {
266
+ :matchtype => "signature",
267
+ :ext_mismatch => "false",
268
+ :puid => "fmt/101",
269
+ :mimetype => "archive/ead",
270
+ :format_name => "Encoded Archival Description (EAD)",
271
+ :format_version => "",
272
+ :source => :xsd_validation,
273
+ :TYPE => :EAD,
274
+ :GROUP => :ARCHIVE,
275
+ :score => 7,
276
+ :tool => :droid,
277
+ :match_type => "xsd_validation"
278
+ },
279
+ "[...]/data/test.doc" => {
280
+ :matchtype => "container",
281
+ :ext_mismatch => "false",
282
+ :puid => "fmt/40",
283
+ :mimetype => "application/msword",
284
+ :format_name => "Microsoft Word Document",
285
+ :format_version => "97-2003",
286
+ :source => :droid,
287
+ :TYPE => :MSDOC,
288
+ :GROUP => :TEXT,
289
+ :score => 9,
290
+ :alternatives => [
291
+ [0] {
292
+ :matchtype => "container",
293
+ :ext_mismatch => "false",
294
+ :puid => "fmt/40",
295
+ :mimetype => "application/msword",
296
+ :format_name => "Microsoft Word Document",
297
+ :format_version => "97-2003",
298
+ :source => :droid,
299
+ :TYPE => :MSDOC,
300
+ :GROUP => :TEXT,
301
+ :score => 9
302
+ },
303
+ [1] {
304
+ :puid => "fmt/111",
305
+ :format_name => "OLE2 Compound Document Format",
306
+ :format_version => "OLE2 Compound Document Format",
307
+ :mimetype => nil,
308
+ :matchtype => "signature",
309
+ :source => :fido,
310
+ :score => 3
311
+ }
312
+ ]
313
+ },
314
+ "[...]/data/test.docx" => {
315
+ :matchtype => "container",
316
+ :ext_mismatch => "false",
317
+ :puid => "fmt/412",
318
+ :mimetype => "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
319
+ :format_name => "Microsoft Word for Windows",
320
+ :format_version => "2007 onwards",
321
+ :source => :droid,
322
+ :TYPE => :MSDOCX,
323
+ :GROUP => :TEXT,
324
+ :score => 9
325
+ },
326
+ "[...]/data/test.xlsx" => {
327
+ :matchtype => "container",
328
+ :ext_mismatch => "false",
329
+ :puid => "fmt/214",
330
+ :mimetype => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
331
+ :format_name => "Microsoft Excel for Windows",
332
+ :format_version => "2007 onwards",
333
+ :source => :droid,
334
+ :TYPE => :MSXLSX,
335
+ :GROUP => :TABULAR,
336
+ :score => 9,
337
+ :alternatives => [
338
+ [0] {
339
+ :matchtype => "container",
340
+ :ext_mismatch => "false",
341
+ :puid => "fmt/214",
342
+ :mimetype => "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
343
+ :format_name => "Microsoft Excel for Windows",
344
+ :format_version => "2007 onwards",
345
+ :source => :droid,
346
+ :TYPE => :MSXLSX,
347
+ :GROUP => :TABULAR,
348
+ :score => 9
349
+ },
350
+ [1] {
351
+ :mimetype => "application/octet-stream",
352
+ :matchtype => "magic",
353
+ :source => :file,
354
+ :score => -2
355
+ }
356
+ ]
357
+ },
358
+ "[...]/data/test_pdfa.pdf" => {
359
+ :matchtype => "signature",
360
+ :ext_mismatch => "false",
361
+ :puid => "fmt/354",
362
+ :mimetype => "application/pdf",
363
+ :format_name => "Acrobat PDF/A - Portable Document Format",
364
+ :format_version => "1b",
365
+ :source => :droid,
366
+ :TYPE => :PDFA,
367
+ :GROUP => :TEXT,
368
+ :score => 7,
369
+ :alternatives => [
370
+ [0] {
371
+ :puid => "fmt/19",
372
+ :format_name => "Acrobat PDF 1.5 - Portable Document Format",
373
+ :format_version => "PDF 1.5",
374
+ :mimetype => "application/pdf",
375
+ :matchtype => "signature",
376
+ :source => :fido,
377
+ :TYPE => :PDF,
378
+ :GROUP => :TEXT,
379
+ :score => 7
380
+ },
381
+ [1] {
382
+ :matchtype => "signature",
383
+ :ext_mismatch => "false",
384
+ :puid => "fmt/354",
385
+ :mimetype => "application/pdf",
386
+ :format_name => "Acrobat PDF/A - Portable Document Format",
387
+ :format_version => "1b",
388
+ :source => :droid,
389
+ :TYPE => :PDFA,
390
+ :GROUP => :TEXT,
391
+ :score => 7
392
+ }
393
+ ]
394
+ }
395
+ }
396
+ }
397
+ ```
33
398
  ## Contributing
34
399
 
35
400
  1. Fork it ( https://github.com/Kris-LIBIS/LIBIS_Format/fork )
data/bin/droid CHANGED
@@ -5,7 +5,7 @@ require 'libis-tools'
5
5
 
6
6
  ::Libis::Tools::Config.logger.level = :WARN
7
7
 
8
- result = ::Libis::Format::Droid.run ARGV[0]
8
+ result = ::Libis::Format::Tool::Droid.run ARGV[0]
9
9
 
10
10
  result.each do |r|
11
11
  r.each do |key, value|
data/bin/fido CHANGED
@@ -5,7 +5,7 @@ require 'libis-tools'
5
5
 
6
6
  ::Libis::Tools::Config.logger.level = :WARN
7
7
 
8
- result = ::Libis::Format::Fido.run ARGV[0]
8
+ result = ::Libis::Format::Tool::Fido.run ARGV[0]
9
9
 
10
10
  result.each do |key, value|
11
11
  puts "#{key}: #{value}"
data/bin/pdf_copy CHANGED
@@ -9,5 +9,5 @@ source = ARGV.shift
9
9
  target = ARGV.shift
10
10
  options = ARGV
11
11
 
12
- ::Libis::Format::PdfCopy.run source, target, options
12
+ ::Libis::Format::Tool::PdfCopy.run source, target, options
13
13
 
@@ -22,6 +22,7 @@ module Libis
22
22
  Config[:xml_validations] = [['archive/ead', File.join(data_dir, 'ead.xsd')]]
23
23
  Config[:type_database] = File.join(data_dir, 'types.yml')
24
24
  Config[:raw_audio_convert_cmd] = 'sox %s -e signed -b 16 -t wav %s rate %d channels %d'
25
+ Config[:watermark_font] = '/usr/share/fonts/truetype/liberation/LiberationSans-Regular.ttf'
25
26
 
26
27
  end
27
28
  end
@@ -168,7 +168,7 @@ module Libis
168
168
  opts[:output] << '-ar' << @options[:sampling_freq] if @options[:sampling_freq]
169
169
  opts[:output] << '-ac' << @options[:channels] if @options[:channels]
170
170
  opts[:output] << '-f' << @options[:format] if @options[:format]
171
- result = Libis::Format::FFMpeg.run(source, target, opts)
171
+ result = Libis::Format::Tool::FFMpeg.run(source, target, opts)
172
172
  info "FFMpeg output: #{result}"
173
173
  result
174
174
  target
@@ -3,6 +3,7 @@
3
3
  ### require 'tools/string'
4
4
  require 'tmpdir'
5
5
  require 'libis/tools/logger'
6
+ require 'libis/tools/temp_file'
6
7
  require 'libis/format/type_database'
7
8
 
8
9
  require_relative 'repository'
@@ -43,7 +44,7 @@ module Libis
43
44
  end
44
45
 
45
46
  def Base.using_temp(target)
46
- tempfile = File.join(Dir.tmpdir, Dir::Tmpname.make_tmpname(['convert', File.extname(target)], File.basename(target, '.*').gsub(/\s/, '_')))
47
+ tempfile = Tools::TempFile.name("convert-#{File.basename(target, '.*').gsub(/\s/, '_')}", File.extname(target))
47
48
  result = yield tempfile
48
49
  return nil unless result
49
50
  FileUtils.move result, target
@@ -2,7 +2,7 @@
2
2
 
3
3
  require_relative 'base'
4
4
 
5
- require 'libis/format/office_to_pdf'
5
+ require 'libis/format/tool/office_to_pdf'
6
6
  require 'libis/format/type_database'
7
7
 
8
8
  module Libis
@@ -38,7 +38,7 @@ module Libis
38
38
  def convert(source, target, format, opts = {})
39
39
  super
40
40
 
41
- return nil unless OfficeToPdf.run(source, target)
41
+ return nil unless Format::Tool::OfficeToPdf.run(source, target)
42
42
 
43
43
  target
44
44
 
@@ -3,9 +3,9 @@
3
3
  require_relative 'base'
4
4
 
5
5
  require 'libis/tools/extend/hash'
6
- require 'libis/format/pdf_copy'
7
- require 'libis/format/pdf_to_pdfa'
8
- require 'libis/format/pdf_optimizer'
6
+ require 'libis/format/tool/pdf_copy'
7
+ require 'libis/format/tool/pdf_to_pdfa'
8
+ require 'libis/format/tool/pdf_optimizer'
9
9
 
10
10
  module Libis
11
11
  module Format
@@ -126,7 +126,7 @@ module Libis
126
126
  def optimize_pdf(source, target, quality)
127
127
 
128
128
  using_temp(target) do |tmpname|
129
- result = Libis::Format::PdfOptimizer.run(source, tmpname, quality)
129
+ result = Libis::Format::Tool::PdfOptimizer.run(source, tmpname, quality)
130
130
  unless result[:status] == 0
131
131
  error("Pdf optimization encountered errors:\n%s", (result[:err] + result[:out]).join('\n'))
132
132
  next nil
@@ -138,7 +138,7 @@ module Libis
138
138
  def convert_pdf(source, target)
139
139
 
140
140
  using_temp(target) do |tmpname|
141
- result = Libis::Format::PdfCopy.run(
141
+ result = Libis::Format::Tool::PdfCopy.run(
142
142
  source, tmpname,
143
143
  @options.map { |k, v|
144
144
  if v.nil?
@@ -159,7 +159,7 @@ module Libis
159
159
  def pdf_to_pdfa(source, target)
160
160
 
161
161
  using_temp(target) do |tmpname|
162
- result = Libis::Format::PdfToPdfa.run source, tmpname
162
+ result = Libis::Format::Tool::PdfToPdfa.run source, tmpname
163
163
  unless result[:status] == 0
164
164
  error("Pdf/A conversion encountered errors:\n%s", result[:err].join('\n'))
165
165
  next nil
@@ -1,5 +1,5 @@
1
1
  require_relative 'base'
2
- require 'libis/format/ffmpeg'
2
+ require 'libis/format/tool/ffmpeg'
3
3
 
4
4
  require 'fileutils'
5
5
 
@@ -82,6 +82,49 @@ module Libis
82
82
  @options[:scale] = width_x_height
83
83
  end
84
84
 
85
+ # @param [String] file Image file path to use as watermark
86
+ def watermark_image(file)
87
+ @options[:watermark_image] = file
88
+ end
89
+
90
+ # @param [String] value text for watermark. No watermark if nil (default)
91
+ def watermark_text(value)
92
+ @options[:watermark_text] = value
93
+ end
94
+
95
+ # @param [Integer] value Font size for watermark text. Default: 10
96
+ # Note that the font is selected by the Config[:watermark_font] setting
97
+ def watermark_text_size(value)
98
+ @options[:watermark_text_size] = value.to_i
99
+ end
100
+
101
+ # @param [String] value Text color for the watermark text. Default: white
102
+ def watermark_text_color(value)
103
+ @options[:watermark_text_color] = value
104
+ end
105
+
106
+ # @param [String] value Text color for the watermark text shadow. Default: black
107
+ def watermark_text_shadow_color(value)
108
+ @options[:watermark_text_shadow_color] = value
109
+ end
110
+
111
+ # @param [Integer] value Offset of the watermark text shadow. Used for both x and y offset; default: 1
112
+ # If the offset is set to 0, no shadow will be printed
113
+ def watermark_text_shadow_offset(value)
114
+ @options[:watermark_text_offset] = value.to_i
115
+ end
116
+
117
+ # @param [String] value one of 'bottom_left' (default), 'top_left', 'bottom_right', 'top_right', 'center'
118
+ def watermark_position(value)
119
+ @options[:watermark_position] = value
120
+ end
121
+
122
+ # @param [Number] value watermark opacity (0-1) with 0 = invisible and 1 = 100% opaque. Default: 0.5
123
+ def watermark_opacity(value)
124
+ @options[:watermark_opacity] = value.to_f
125
+ end
126
+
127
+ # @param [Boolean] value If set to true automatically selects optimal format for web viewing. Default: false
85
128
  def web_stream(value)
86
129
  if value
87
130
  @options[:video_codec] = 'h264'
@@ -89,14 +132,17 @@ module Libis
89
132
  end
90
133
  end
91
134
 
135
+ # @param [String] name name of a preset. See FFMpeg documentation for more info
92
136
  def preset(name)
93
137
  @options[:preset] = name
94
138
  end
95
139
 
140
+ # @param [String] name name of an audio preset. See FFMpeg documentation for more info
96
141
  def audio_preset(name)
97
142
  @options[:audio_preset] = name
98
143
  end
99
144
 
145
+ # @param [String] name name of a video preset. See FFMpeg documentation for more info
100
146
  def video_preset(name)
101
147
  @options[:video_preset] = name
102
148
  end
@@ -163,6 +209,36 @@ module Libis
163
209
  opts = {global: [], input: [], filter: [], output: []}
164
210
  opts[:global] << '-hide_banner'
165
211
  opts[:global] << '-loglevel' << (@options[:quiet] ? 'fatal' : 'warning')
212
+
213
+ # Watermark info
214
+ @options[:watermark_opacity] ||= 0.5
215
+ if @options[:watermark_image]
216
+ opts[:filter] << '-i' << @options[:watermark_image] << '-filter_complex'
217
+ opts[:filter] << "[1:v]format=argb,colorchannelmixer=aa=%f[wm];[0:v][wm]overlay=%s" %
218
+ [@options[:watermark_opacity], watermark_position_text]
219
+ elsif @options[:watermark_text]
220
+ @options[:watermark_text_size] ||= 10
221
+ @options[:watermark_text_color] ||= 'white'
222
+ @options[:watermark_text_shadow_color] ||= 'black'
223
+ @options[:watermark_text_shadow_offset] ||= 1
224
+ filter_text = "drawtext=text='%s':%s:fontfile=%s:fontsize=%d:fontcolor=%s@%f" %
225
+ [
226
+ @options[:watermark_text],
227
+ watermark_position_text(true),
228
+ Config[:watermark_font],
229
+ @options[:watermark_text_size],
230
+ @options[:watermark_text_color],
231
+ @options[:watermark_opacity]
232
+ ]
233
+ filter_text += ':shadowcolor=%s@%f:shadowx=%d:shadowy=%d' %
234
+ [
235
+ @options[:watermark_text_shadow_color],
236
+ @options[:watermark_opacity],
237
+ @options[:watermark_text_shadow_offset],
238
+ @options[:watermark_text_shadow_offset]
239
+ ] if @options[:watermark_text_shadow_offset] > 0
240
+ opts[:filter] << '-vf' << filter_text
241
+ end
166
242
  opts[:output] << '-ac' << @options[:audio_channels] if @options[:audio_channels]
167
243
  opts[:output] << '-c:a' << @options[:audio_codec] if @options[:audio_codec]
168
244
  opts[:output] << '-c:v' << @options[:video_codec] if @options[:video_codec]
@@ -188,11 +264,29 @@ module Libis
188
264
  opts[:output] << '-pre' << @options[:preset] if @options[:preset]
189
265
  opts[:output] << '-apre' << @options[:audio_preset] if @options[:audio_preset]
190
266
  opts[:output] << '-vpre' << @options[:video_preset] if @options[:video_preset]
191
- result = Libis::Format::FFMpeg.run(source, target, opts)
267
+ info "FFMpeg options: #{opts}"
268
+ result = Libis::Format::Tool::FFMpeg.run(source, target, opts)
192
269
  info "FFMpeg output: #{result}"
193
270
  target
194
271
  end
195
272
 
273
+ def watermark_position_text(for_text = false, margin = 10)
274
+ w = for_text ? 'tw' : 'w'
275
+ h = for_text ? 'th' : 'h'
276
+ case @options[:watermark_position]
277
+ when 'bottom_left'
278
+ "x=#{margin}:y=H-#{h}-#{margin}"
279
+ when 'top_left'
280
+ "x=#{margin}:y=#{margin}"
281
+ when 'bottom_right'
282
+ "x=W-#{w}-#{margin}:y=H-#{h}-#{margin}"
283
+ when 'top_right'
284
+ "x=W-#{w}-#{margin}:y=#{margin}"
285
+ else
286
+ "x=#{margin}:y=H-#{h}-#{margin}"
287
+ end
288
+ end
289
+
196
290
  end
197
291
 
198
292
  end