libis-format 1.3.7.2 → 2.0.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.
Files changed (78) hide show
  1. checksums.yaml +4 -4
  2. data/.coveralls.yml +2 -0
  3. data/.gitignore +20 -0
  4. data/.travis.yml +70 -0
  5. data/Gemfile +0 -12
  6. data/README.md +2 -2
  7. data/Rakefile +8 -0
  8. data/base/Dockerfile +35 -0
  9. data/base/Dockerfile.alpine +20 -0
  10. data/base/Dockerfile.rvm +56 -0
  11. data/base/rework_path +20 -0
  12. data/bin/{pdf_tool → pdf_copy} +2 -3
  13. data/data/PDFA_def.ps +3 -3
  14. data/data/eciRGB_v2.icc +0 -0
  15. data/data/types.yml +4 -17
  16. data/docker_cfg.yml +1 -0
  17. data/lib/libis/format/cli/convert.rb +4 -4
  18. data/lib/libis/format/cli/prompt_helper.rb +24 -32
  19. data/lib/libis/format/command_line.rb +3 -2
  20. data/lib/libis/format/config.rb +23 -19
  21. data/lib/libis/format/converter/audio_converter.rb +31 -56
  22. data/lib/libis/format/converter/base.rb +36 -16
  23. data/lib/libis/format/converter/chain.rb +32 -62
  24. data/lib/libis/format/converter/fop_pdf_converter.rb +8 -4
  25. data/lib/libis/format/converter/image_assembler.rb +82 -0
  26. data/lib/libis/format/converter/image_converter.rb +45 -248
  27. data/lib/libis/format/converter/image_splitter.rb +80 -0
  28. data/lib/libis/format/converter/image_watermarker.rb +261 -0
  29. data/lib/libis/format/converter/jp2_converter.rb +38 -36
  30. data/lib/libis/format/converter/office_converter.rb +28 -22
  31. data/lib/libis/format/converter/pdf_assembler.rb +66 -0
  32. data/lib/libis/format/converter/pdf_converter.rb +52 -200
  33. data/lib/libis/format/converter/pdf_optimizer.rb +70 -0
  34. data/lib/libis/format/converter/pdf_splitter.rb +65 -0
  35. data/lib/libis/format/converter/pdf_watermarker.rb +110 -0
  36. data/lib/libis/format/converter/repository.rb +13 -7
  37. data/lib/libis/format/converter/spreadsheet_converter.rb +16 -10
  38. data/lib/libis/format/converter/video_converter.rb +73 -109
  39. data/lib/libis/format/converter/xslt_converter.rb +11 -13
  40. data/lib/libis/format/converter.rb +1 -1
  41. data/lib/libis/format/identifier.rb +46 -44
  42. data/lib/libis/format/info.rb +27 -0
  43. data/lib/libis/format/library.rb +147 -0
  44. data/lib/libis/format/tool/droid.rb +30 -29
  45. data/lib/libis/format/tool/extension_identification.rb +26 -24
  46. data/lib/libis/format/tool/{ff_mpeg.rb → ffmpeg.rb} +10 -17
  47. data/lib/libis/format/tool/fido.rb +27 -22
  48. data/lib/libis/format/tool/file_tool.rb +24 -11
  49. data/lib/libis/format/tool/fop_pdf.rb +14 -25
  50. data/lib/libis/format/tool/identification_tool.rb +40 -38
  51. data/lib/libis/format/tool/office_to_pdf.rb +18 -30
  52. data/lib/libis/format/tool/pdf_copy.rb +47 -0
  53. data/lib/libis/format/tool/pdf_merge.rb +19 -25
  54. data/lib/libis/format/tool/pdf_optimizer.rb +19 -22
  55. data/lib/libis/format/tool/pdf_split.rb +33 -6
  56. data/lib/libis/format/tool/pdf_to_pdfa.rb +31 -45
  57. data/lib/libis/format/tool/pdfa_validator.rb +30 -24
  58. data/lib/libis/format/tool/spreadsheet_to_ods.rb +18 -29
  59. data/lib/libis/format/tool.rb +3 -4
  60. data/lib/libis/format/version.rb +1 -3
  61. data/lib/libis/format/yaml_loader.rb +71 -0
  62. data/lib/libis/format.rb +7 -5
  63. data/lib/libis-format.rb +0 -2
  64. data/libis-format.gemspec +18 -24
  65. data/tools/PdfTool.jar +0 -0
  66. data/tools/pdfbox/pdfbox-app-2.0.13.jar +0 -0
  67. data/tools/pdfbox/{preflight-app-3.0.3.jar → preflight-app-2.0.13.jar} +0 -0
  68. metadata +86 -128
  69. data/data/AdobeRGB1998.icc +0 -0
  70. data/lib/libis/format/converter/email_converter.rb +0 -36
  71. data/lib/libis/format/tool/msg_to_pdf.rb +0 -270
  72. data/lib/libis/format/tool/pdf_tool.rb +0 -52
  73. data/lib/libis/format/type_database.rb +0 -156
  74. data/lib/libis/format/type_database_impl.rb +0 -153
  75. data/tools/pdf2pdfa +0 -395
  76. data/tools/pdfbox/pdfbox-app-3.0.3.jar +0 -0
  77. /data/bin/{droid_tool → droid} +0 -0
  78. /data/bin/{fido_tool → fido} +0 -0
@@ -1,34 +1,37 @@
1
- # frozen_string_literal: true
1
+ # encoding: utf-8
2
2
 
3
3
  require_relative 'base'
4
4
  require 'libis/format/identifier'
5
5
 
6
6
  require 'mini_magick'
7
- require 'fileutils'
8
7
 
9
8
  MiniMagick.logger.level = ::Logger::UNKNOWN
10
9
 
11
10
  MiniMagick.configure do |config|
12
- config.tmpdir = Libis::Format::Config[:tempdir] || Dir.tmpdir
11
+ # config.cli = :graphicsmagick
12
+ config.validate_on_create = false
13
+ config.validate_on_write = false
14
+ config.whiny = false
13
15
  end
14
16
 
15
17
  module Libis
16
18
  module Format
17
19
  module Converter
20
+
18
21
  # noinspection RubyTooManyInstanceVariablesInspection
19
22
  class ImageConverter < Libis::Format::Converter::Base
23
+
20
24
  def self.input_types
21
- %i[TIFF JPG PNG BMP GIF PDF JP2]
25
+ [:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2, :PBM, :PGM, :PPM]
22
26
  end
23
27
 
24
28
  def self.output_types(format = nil)
25
- return [] unless input_types.include?(format)
26
-
27
- %i[TIFF JPG PNG BMP GIF PDF JP2]
29
+ return [] unless input_types.include?(format) if format
30
+ [:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2]
28
31
  end
29
32
 
30
33
  def self.multipage?(format)
31
- %i[PDF TIFF GIF PBM PGM PPM].include?(format)
34
+ [:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM].include?(format)
32
35
  end
33
36
 
34
37
  def initialize
@@ -37,153 +40,62 @@ module Libis
37
40
  end
38
41
 
39
42
  def image_convert(_)
40
- # force usage of this converter
43
+ #force usage of this converter
41
44
  end
42
45
 
43
- def quiet(value)
44
- @quiet = !!value
46
+ def quiet(v)
47
+ @quiet = !!v
48
+ self
45
49
  end
46
50
 
47
- def page(number)
48
- @page = number
51
+ def page(nr)
52
+ @page = nr
53
+ self
49
54
  end
50
55
 
51
56
  def scale(percent)
52
57
  @options[:scale] = percent
58
+ self
53
59
  end
54
60
 
55
61
  def resize(geometry)
56
62
  @options[:resize] = geometry
63
+ self
57
64
  end
58
65
 
59
66
  def quality(value)
60
67
  @options[:quality] = value
68
+ self
61
69
  end
62
70
 
63
71
  def dpi(value)
64
72
  @options[:density] = value
73
+ self
65
74
  end
66
75
 
67
76
  def resample(value)
68
77
  @options[:resample] = value
78
+ self
69
79
  end
70
80
 
71
81
  def flatten(value = true)
72
- @options[:flatten] = !!value
82
+ @options[:flatten] = value
83
+ self
73
84
  end
74
85
 
75
86
  def colorspace(value)
76
87
  @options[:colorspace] = value
88
+ self
77
89
  end
78
90
 
79
91
  def delete_date(value = true)
80
- @delete_date = !!value
92
+ @delete_date = value
93
+ self
81
94
  end
82
95
 
83
96
  def profile(icc)
84
97
  @profile = icc
85
- end
86
-
87
- # Create or use a watermark image.
88
- #
89
- # The main watermark options are (use symbols):
90
- # - text: text to create a watermark from
91
- # - file: watermark image to use
92
- # - image: same as above
93
- # - banner: use side banner
94
- #
95
- # For each of these options above a dedicated option handler will be called
96
- #
97
- # @param [Hash] options Hash of options for watermark creation.
98
-
99
- def watermark(options = {})
100
- options.key_strings_to_symbols!
101
- if options[:file] || options[:image]
102
- watermark_image(options)
103
- elsif options[:text]
104
- watermark_text(options)
105
- elsif options[:banner]
106
- watermark_banner(options)
107
- end
108
- end
109
-
110
- # Use an image as watermark
111
- #
112
- # Next to the :file or :image option, this enables the following options:
113
- # - tiles: number of tiles of the watermark - default 4
114
- # 0: no tiling, so only 1 watermark will be placed with the original size
115
- # 1: 1 tile, so the watermark will be scaled up to fill the image
116
- # n > 1: minimum n tiles in both directions
117
- # n < 0: tile without scaling the watermark
118
- # - size: same as tiles - for backwards compatibility
119
- # - resize: fraction 0.0 - 1.0
120
- # - gap: size of the gap between watermark instances. Fractions as percentage of widht/height. - default 0.2
121
- # - opacity: opacity of the watermark (fraction 0.0 - 1.0) - default 0.1
122
- # - gravity: center point of the overlay - default 'center'
123
- # - composition: algorithm to use to compose both images - default modulate
124
- def watermark_image(options = {})
125
- options.key_strings_to_symbols!
126
- @options[:watermark] = {command: 'image'}
127
- @options[:watermark][:data] = options[:file] || options[:image]
128
- @options[:watermark][:tiles] = (options[:tiles] || options[:size] || 4).to_i
129
- @options[:watermark][:resize] = ((options[:resize]).to_f * 100).to_i if options[:resize]
130
- @options[:watermark][:gap] = ((options[:gap] || 0.2).to_f * 100).to_i
131
- @options[:watermark][:opacity] = ((options[:opacity] || 0.1).to_f * 100).to_i
132
- @options[:watermark][:gravity] = options[:gravity] || 'center'
133
- @options[:watermark][:composition] = options[:composition] || 'modulate'
134
- @options[:watermark][:rotation] = 360 - (options[:rotation] || 30).to_i
135
- end
136
-
137
- # Use text as watermark
138
- #
139
- # Next to the :text option, this enables the following options:
140
- # - tiles: number of tiles of the watermark - default 4
141
- # 0: no tiling, so only 1 watermark will be placed with the original size
142
- # 1: 1 tile, so the watermark will be scaled up to fill the image
143
- # n > 1: minimum n tiles in both directions
144
- # n < 0: tile without scaling the watermark
145
- # - size: same as tiles - for backwards compatibility
146
- # - resize: fraction 0.0 - 1.0
147
- # - gap: size of the gap between watermark instances. Fractions as percentage of widht/height. - default 0.2
148
- # - opacity: opacity of the watermark (fraction 0.0 - 1.0) - default 0.1
149
- # - gravity: center point of the overlay - default 'center'
150
- # - composition: algorithm to use to compose both images - default modulate
151
- # - rotation: rotation of the text
152
- def watermark_text(options = {})
153
- options.key_strings_to_symbols!
154
- @options[:watermark] = {command: 'text'}
155
- @options[:watermark][:data] = options[:text] || '© LIBIS'
156
- @options[:watermark][:tiles] = (options[:tiles] || options[:size] || 4).to_i
157
- @options[:watermark][:resize] = ((options[:resize]).to_f * 100).to_i if options[:resize]
158
- @options[:watermark][:gap] = ((options[:gap] || 0.2).to_f * 100).to_i
159
- @options[:watermark][:opacity] = ((options[:opacity] || 0.1).to_f * 100).to_i
160
- @options[:watermark][:gravity] = options[:gravity] || 'center'
161
- @options[:watermark][:composition] = options[:composition] || 'modulate'
162
- @options[:watermark][:rotation] = 360 - (options[:rotation] || 30).to_i
163
- end
164
-
165
- # Create a vertical banner to the right side of the image
166
- #
167
- # The banner options are:
168
- # - banner: text to put in the banner
169
- # - add_filename: append filename to the text (use any value to enable)
170
- # - fontsize: size of the font (in points) (default: autoscale)
171
- # - width: width of the banner (default: 3% of image height). Not including a border of 1/3 of the banner width
172
- # - background_color_(red|green|blue): color components of background (default: rgb(84,190,233))
173
- # - text_color_(red|green|blue): color components of background (default: rgb(255,255,255))
174
- def watermark_banner(options = {})
175
- options.key_strings_to_symbols!
176
- @options[:watermark] = {command: 'banner'}
177
- @options[:watermark][:data] = options[:banner] || '© LIBIS'
178
- @options[:watermark][:add_filename] = !!options[:add_filename]
179
- @options[:watermark][:size] = options[:fontsize] if options[:fontsize]
180
- @options[:watermark][:width] = options[:width] if options[:width]
181
- @options[:watermark][:background_red] = options[:background_color_red] || 84
182
- @options[:watermark][:background_green] = options[:background_color_green] || 190
183
- @options[:watermark][:background_blue] = options[:background_color_blue] || 233
184
- @options[:watermark][:text_red] = options[:text_color_red] || 255
185
- @options[:watermark][:text_green] = options[:text_color_green] || 255
186
- @options[:watermark][:text_blue] = options[:text_color_blue] || 255
98
+ self
187
99
  end
188
100
 
189
101
  def convert(source, target, format, opts = {})
@@ -191,152 +103,34 @@ module Libis
191
103
 
192
104
  FileUtils.mkpath(File.dirname(target))
193
105
 
194
- if source.is_a? Array
195
-
196
- assemble_and_convert(source, target, format)
197
-
198
- elsif File.directory?(source)
199
- source_list = Dir[File.join(source, '**', '*')].reject { |p| File.directory? p }
200
-
201
- assemble_and_convert(source_list, target, format)
106
+ convert_image(source, target, format)
202
107
 
203
- else
204
-
205
- image = MiniMagick::Image.open(source) { |b| b.quiet } # rubocop:disable Style/SymbolProc
206
-
207
- if image.pages.size > 1
208
- if @page
209
- convert_image(image.pages[@page].path, target, format)
210
- else
211
- # noinspection RubyBlockToMethodReference
212
- assemble_and_convert(image.pages.map(&:path), target, format)
213
- end
214
- else
215
- convert_image(source, target, format)
216
- end
217
- end
108
+ target
218
109
 
219
- {
220
- files: [target],
221
- converter: self.class.name
222
- }
223
- end
224
-
225
- def assemble_and_convert(sources, target, format)
226
- warn 'Received multiple images as input and single page format as target.' unless self.class.multipage?(format)
227
- converted_pages = sources.inject([]) do |list, path|
228
- # noinspection RubyArgCount
229
- converted = Tempfile.new(['page-', ".#{Libis::Format::TypeDatabase.type_extentions(format).first}"])
230
- convert_image(path, converted.path, format)
231
- list << converted
232
- end
233
- MiniMagick.convert do |b|
234
- b.append unless self.class.multipage?(format)
235
- converted_pages.each { |page| b << page.path }
236
- b << target
237
- end
238
- converted_pages.each do |temp_file|
239
- temp_file.close
240
- temp_file.unlink
241
- end
242
110
  end
243
111
 
244
112
  protected
245
113
 
246
114
  def convert_image(source, target, format)
247
- image_info = nil
248
-
249
- MiniMagick.convert do |convert|
250
- # Make converter silent
251
- convert.quiet if @quiet
252
115
 
253
- # Build watermark image in buffer
254
- wm = @options.delete(:watermark)
255
- if wm
256
- image_info = MiniMagick::Image::Info.new(source) { |b| b.quiet }
257
- im_height = image_info['height']
258
- im_width = image_info['width']
259
- case wm[:command]
260
- when 'text'
261
- convert.background 'transparent'
262
- convert.size('2000x2000')
263
- convert.gravity 'Center'
264
- convert.font('Helvetica').fill('black').pointsize(72) # .stroke('black').strokewidth(1)
265
- convert << "label:#{wm[:data]}"
266
- convert.rotate wm[:rotation]
267
- convert.trim.repage.+ # rubocop:disable Lint/Void
268
- convert.bordercolor('transparent').border("#{wm[:gap]}%") if wm[:gap].positive?
269
- convert.filter('Lagrange')
270
- convert.resize("#{im_width / wm[:tiles]}x#{im_height / wm[:tiles]}") if wm[:tiles].positive?
271
- convert.resize("#{wm[:resize]}%") if wm[:resize]
272
- when 'image'
273
- convert << wm[:data]
274
- convert.background 'transparent'
275
- convert.bordercolor('transparent').border("#{wm[:gap]}%") if wm[:gap].positive?
276
- convert.rotate wm[:rotation]
277
- convert.filter('Lagrange')
278
- convert.resize("#{im_width / wm[:tiles]}x#{im_height / wm[:tiles]}") if wm[:tiles].positive?
279
- convert.resize("#{wm[:resize]}%") if wm[:resize]
280
- when 'banner'
281
- banner_width = wm[:width] || [0.03 * im_height, 20].max.round(0)
282
- banner_border = banner_width / 3
283
- convert.background "rgb(#{wm[:background_red]},#{wm[:background_green]},#{wm[:background_blue]})"
284
- convert.size("#{im_height}x#{banner_width}")
285
- convert.bordercolor "rgb(#{wm[:background_red]},#{wm[:background_green]},#{wm[:background_blue]})"
286
- convert.border "0x#{banner_border}"
287
- convert.fill "rgb(#{wm[:text_red]},#{wm[:text_green]},#{wm[:text_blue]})"
288
- convert.font "Liberation-Sans"
289
- convert.pointsize wm[:size] if wm[:size]
290
- convert.gravity 'Center'
291
- convert << "label:#{wm[:data]}#{wm[:add_filename] ? File.basename(source, '.*') : ''}"
292
- end
293
-
294
- # Save watermark image to buffer
295
- convert.write('mpr:watermark').delete.+
296
-
297
- # Restore canvas to source image size (workaround for IM bug when loading JP2K files)
298
- convert.size("#{im_width}x#{im_height}")
299
- end
116
+ if @page
117
+ image = MiniMagick::Image.open(source) { |b| b.quiet }
118
+ source = image.pages[@page].path if image.pages.size > 1
119
+ end
300
120
 
301
- # load source image
121
+ MiniMagick::Tool::Convert.new do |convert|
122
+ convert.quiet if @quiet
302
123
  convert << source
303
-
304
- # force flatten image if necessary
305
124
  convert.flatten if @options[:flatten].nil? && format == :JPG
306
-
307
- # add watermark image
308
- if wm
309
- if wm[:command] == 'banner'
310
- convert.rotate '-90'
311
- convert << 'mpr:watermark'
312
- convert.rotate '180'
313
- convert.append
314
- convert.rotate '-90'
315
- else
316
- if (0..1).include? wm[:tiles]
317
- convert << 'mpr:watermark'
318
- else
319
- convert.stack do |stack|
320
- stack.size("#{image_info['width']}x#{image_info['height']}")
321
- stack << 'xc:transparent'
322
- stack.tile('mpr:watermark')
323
- stack.draw "rectangle 0,0,#{image_info['width']},#{image_info['height']}"
324
- end
325
- convert.compose(wm[:composition])
326
- convert.gravity(wm[:gravity])
327
- convert.define("compose:args=#{wm[:opacity]}%")
328
- convert.composite
329
- end
330
- end
125
+ @flags.each {|f, v| v.is_a?(TrueClass) ? convert.send(f).+ : convert.send(f)}
126
+ if @delete_date
127
+ convert << '+set' << 'modify-date' << '+set' << 'create-date'
331
128
  end
332
129
 
333
- @flags.each { |f, v| v.is_a?(TrueClass) ? convert.send(f).+ : convert.send(f) }
334
- convert << '+set' << 'modify-date' << '+set' << 'create-date' if @delete_date
335
-
336
130
  colorspace = @options.delete(:colorspace) || 'sRGB'
337
131
  unless @options.empty?
338
132
  convert.colorspace('RGB')
339
- @options.each { |o, v| convert.send(o, v) }
133
+ @options.each {|o, v| convert.send(o, v)}
340
134
  end
341
135
  convert.colorspace(colorspace)
342
136
  convert.profile @profile if @profile
@@ -348,8 +142,11 @@ module Libis
348
142
  end
349
143
 
350
144
  target
145
+
351
146
  end
147
+
352
148
  end
149
+
353
150
  end
354
151
  end
355
- end
152
+ end
@@ -0,0 +1,80 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'base'
4
+ require 'libis/format/identifier'
5
+
6
+ require 'mini_magick'
7
+
8
+ MiniMagick.logger.level = ::Logger::UNKNOWN
9
+
10
+ MiniMagick.configure do |config|
11
+ # config.cli = :graphicsmagick
12
+ config.validate_on_create = false
13
+ config.validate_on_write = false
14
+ config.whiny = false
15
+ end
16
+
17
+ module Libis
18
+ module Format
19
+ module Converter
20
+
21
+ class ImageSplitter < Libis::Format::Converter::Base
22
+
23
+ def self.input_types
24
+ [:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM]
25
+ end
26
+
27
+ def self.output_types(format = nil)
28
+ return [] unless input_types.include?(format) if format
29
+ [:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2]
30
+ end
31
+
32
+ def self.multipage?(format)
33
+ [:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM].include?(format)
34
+ end
35
+
36
+ def image_split(_)
37
+ #force usage of this converter
38
+ end
39
+
40
+ def quiet(v)
41
+ @quiet = !!v
42
+ end
43
+
44
+ def convert(source, target, format, opts = {})
45
+ super
46
+
47
+ FileUtils.mkpath(File.dirname(target))
48
+
49
+ if self.class.multipage?(format)
50
+ target = File.join(File.dirname(target), "#{File.basename(target, '.*')}-%d#{File.extname(target)}")
51
+ end
52
+
53
+ result = split_image(source, target, format)
54
+ return nil unless result
55
+ target
56
+
57
+ end
58
+
59
+ private
60
+
61
+ def split_image(source, target, format)
62
+
63
+ MiniMagick::Tool::Convert.new do |convert|
64
+ convert.quiet if @quiet
65
+ convert << source
66
+ convert.format(format)
67
+ convert << target
68
+
69
+ debug "ImageMagick command: '#{convert.command.join(' ')}'"
70
+ end
71
+
72
+ target
73
+
74
+ end
75
+
76
+ end
77
+
78
+ end
79
+ end
80
+ end