libis-format 1.3.4 → 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 -52
  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 -250
  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 +58 -47
  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 -35
  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,160 +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 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
- # - rotation: rotation of the watermark text (in degrees; integer number)
94
- # - size: font size of the watermark text
95
- # - opacity: opacity of the watermark (fraction 0.0 - 1.0)
96
- # - gap: size of the gap between watermark instances. Integer value is absolute size in points (1/72 inch).
97
- # Fractions are percentage of widht/height.
98
- # If both options are given, the file will be used as-is if it exists and is a valid image file. Otherwise the
99
- # file will be created or overwritten with a newly created watermark image.
100
- #
101
- # The created watermark file will be a PNG image with transparent background containing the supplied text
102
- # slanted by 30 degrees counter-clockwise.
103
- #
104
- # @param [Hash] options Hash of options for watermark creation.
105
-
106
- def watermark(options = {})
107
- options.key_strings_to_symbols!
108
- if options[:file] || options[:image]
109
- watermark_image(options)
110
- elsif options[:text]
111
- watermark_text(options)
112
- elsif options[:banner]
113
- watermark_banner(options)
114
- end
115
- end
116
-
117
- # Use an image as watermark
118
- #
119
- # Next to the :file or :image option, this enables the following options:
120
- # - tiles: number of tiles of the watermark - default 4
121
- # 0: no tiling, so only 1 watermark will be placed with the original size
122
- # 1: 1 tile, so the watermark will be scaled up to fill the image
123
- # n > 1: minimum n tiles in both directions
124
- # n < 0: tile without scaling the watermark
125
- # - size: same as tiles - for backwards compatibility
126
- # - resize: fraction 0.0 - 1.0
127
- # - gap: size of the gap between watermark instances. Fractions as percentage of widht/height. - default 0.2
128
- # - opacity: opacity of the watermark (fraction 0.0 - 1.0) - default 0.1
129
- # - gravity: center point of the overlay - default 'center'
130
- # - composition: algorithm to use to compose both images - default modulate
131
- def watermark_image(options = {})
132
- options.key_strings_to_symbols!
133
- @options[:watermark] = {command: 'image'}
134
- @options[:watermark][:data] = options[:file] || options[:image]
135
- @options[:watermark][:tiles] = (options[:tiles] || options[:size] || 4).to_i
136
- @options[:watermark][:resize] = ((options[:resize]).to_f * 100).to_i if options[:resize]
137
- @options[:watermark][:gap] = ((options[:gap] || 0.2).to_f * 100).to_i
138
- @options[:watermark][:opacity] = ((options[:opacity] || 0.1).to_f * 100).to_i
139
- @options[:watermark][:gravity] = options[:gravity] || 'center'
140
- @options[:watermark][:composition] = options[:composition] || 'modulate'
141
- @options[:watermark][:rotation] = 360 - (options[:rotation] || 30).to_i
142
- end
143
-
144
- # Use text as watermark
145
- #
146
- # Next to the :text option, this enables the following options:
147
- # - tiles: number of tiles of the watermark - default 4
148
- # 0: no tiling, so only 1 watermark will be placed with the original size
149
- # 1: 1 tile, so the watermark will be scaled up to fill the image
150
- # n > 1: minimum n tiles in both directions
151
- # n < 0: tile without scaling the watermark
152
- # - size: same as tiles - for backwards compatibility
153
- # - resize: fraction 0.0 - 1.0
154
- # - gap: size of the gap between watermark instances. Fractions as percentage of widht/height. - default 0.2
155
- # - opacity: opacity of the watermark (fraction 0.0 - 1.0) - default 0.1
156
- # - gravity: center point of the overlay - default 'center'
157
- # - composition: algorithm to use to compose both images - default modulate
158
- # - rotation: rotation of the text
159
- def watermark_text(options = {})
160
- options.key_strings_to_symbols!
161
- @options[:watermark] = {command: 'text'}
162
- @options[:watermark][:data] = options[:text] || '© LIBIS'
163
- @options[:watermark][:tiles] = (options[:tiles] || options[:size] || 4).to_i
164
- @options[:watermark][:resize] = ((options[:resize]).to_f * 100).to_i if options[:resize]
165
- @options[:watermark][:gap] = ((options[:gap] || 0.2).to_f * 100).to_i
166
- @options[:watermark][:opacity] = ((options[:opacity] || 0.1).to_f * 100).to_i
167
- @options[:watermark][:gravity] = options[:gravity] || 'center'
168
- @options[:watermark][:composition] = options[:composition] || 'modulate'
169
- @options[:watermark][:rotation] = 360 - (options[:rotation] || 30).to_i
170
- end
171
-
172
- # Create a vertical banner to the right side of each page
173
- #
174
- # The banner options are:
175
- # - banner: text to put in the banner
176
- # - add_filename: append filename to the text (use any value to enable)
177
- # - fontsize: size of the font (in points) (default: autoscale)
178
- # - width: width of the banner (default: 3% of image height). Not including a border of 30% of the banner width
179
- # - background_color_(red|green|blue): color components of background (default: rgb(84,190,233))
180
- # - text_color_(red|green|blue): color components of background (default: rgb(255,255,255))
181
- def watermark_banner(options = {})
182
- options.key_strings_to_symbols!
183
- @options[:watermark] = {command: 'banner'}
184
- @options[:watermark][:data] = options[:banner] || '© LIBIS'
185
- @options[:watermark][:add_filename] = !!options[:add_filename]
186
- @options[:watermark][:size] = options[:fontsize] if options[:fontsize]
187
- @options[:watermark][:width] = options[:width] if options[:width]
188
- @options[:watermark][:background_red] = options[:background_color_red] || 84
189
- @options[:watermark][:background_green] = options[:background_color_green] || 190
190
- @options[:watermark][:background_blue] = options[:background_color_blue] || 233
191
- @options[:watermark][:text_red] = options[:text_color_red] || 255
192
- @options[:watermark][:text_green] = options[:text_color_green] || 255
193
- @options[:watermark][:text_blue] = options[:text_color_blue] || 255
98
+ self
194
99
  end
195
100
 
196
101
  def convert(source, target, format, opts = {})
@@ -198,147 +103,34 @@ module Libis
198
103
 
199
104
  FileUtils.mkpath(File.dirname(target))
200
105
 
201
- if source.is_a? Array
202
-
203
- assemble_and_convert(source, target, format)
204
-
205
- elsif File.directory?(source)
206
- source_list = Dir[File.join(source, '**', '*')].reject { |p| File.directory? p }
207
-
208
- assemble_and_convert(source_list, target, format)
106
+ convert_image(source, target, format)
209
107
 
210
- else
211
-
212
- image = MiniMagick::Image.open(source) { |b| b.quiet } # rubocop:disable Style/SymbolProc
213
-
214
- if image.pages.size > 1
215
- if @page
216
- convert_image(image.pages[@page].path, target, format)
217
- else
218
- # noinspection RubyBlockToMethodReference
219
- assemble_and_convert(image.pages.map(&:path), target, format)
220
- end
221
- else
222
- convert_image(source, target, format)
223
- end
224
- end
108
+ target
225
109
 
226
- {
227
- files: [target],
228
- converter: self.class.name
229
- }
230
- end
231
-
232
- def assemble_and_convert(sources, target, format)
233
- warn 'Received multiple images as input and single page format as target.' unless self.class.multipage?(format)
234
- converted_pages = sources.inject([]) do |list, path|
235
- # noinspection RubyArgCount
236
- converted = Tempfile.new(['page-', ".#{Libis::Format::TypeDatabase.type_extentions(format).first}"])
237
- convert_image(path, converted.path, format)
238
- list << converted
239
- end
240
- MiniMagick.convert do |b|
241
- b.append unless self.class.multipage?(format)
242
- converted_pages.each { |page| b << page.path }
243
- b << target
244
- end
245
- converted_pages.each do |temp_file|
246
- temp_file.close
247
- temp_file.unlink
248
- end
249
110
  end
250
111
 
251
112
  protected
252
113
 
253
114
  def convert_image(source, target, format)
254
- image_info = nil
255
-
256
- MiniMagick.convert do |convert|
257
- # Make converter silent
258
- convert.quiet if @quiet
259
115
 
260
- # Build watermark image in buffer
261
- wm = @options.delete(:watermark)
262
- if wm
263
- image_info = MiniMagick::Image::Info.new(source) { |b| b.quiet }
264
- case wm[:command]
265
- when 'text'
266
- convert.background 'transparent'
267
- convert.size('2000x2000')
268
- convert.gravity 'Center'
269
- convert.font('Helvetica').fill('black').pointsize(72) # .stroke('black').strokewidth(1)
270
- convert << "label:#{wm[:data]}"
271
- convert.rotate wm[:rotation]
272
- convert.trim.repage.+ # rubocop:disable Lint/Void
273
- convert.bordercolor('transparent').border("#{wm[:gap]}%") if wm[:gap].positive?
274
- convert.filter('Lagrange')
275
- convert.resize("#{image_info['width'] / wm[:tiles]}x#{image_info['height'] / wm[:tiles]}") if wm[:tiles].positive?
276
- convert.resize("#{wm[:resize]}%") if wm[:resize]
277
- when 'image'
278
- convert << wm[:data]
279
- convert.background 'transparent'
280
- convert.bordercolor('transparent').border("#{wm[:gap]}%") if wm[:gap].positive?
281
- convert.rotate wm[:rotation]
282
- convert.filter('Lagrange')
283
- convert.resize("#{image_info['width'] / wm[:tiles]}x#{image_info['height'] / wm[:tiles]}") if wm[:tiles].positive?
284
- convert.resize("#{wm[:resize]}%") if wm[:resize]
285
- when 'banner'
286
- banner_width = wm[:width] || [0.03 * image_info['height'], 20].max.round(0)
287
- banner_border = banner_width / 3
288
- convert.background "rgb(#{wm[:background_red]},#{wm[:background_green]},#{wm[:background_blue]})"
289
- convert.size("#{image_info['height']}x#{banner_width}")
290
- convert.bordercolor "rgb(#{wm[:background_red]},#{wm[:background_green]},#{wm[:background_blue]})"
291
- convert.border "0x#{banner_border}"
292
- convert.fill "rgb(#{wm[:text_red]},#{wm[:text_green]},#{wm[:text_blue]})"
293
- convert.font "Liberation-Sans"
294
- convert.pointsize wm[:size] if wm[:size]
295
- convert.gravity 'Center'
296
- convert << "label:#{wm[:data]}#{wm[:add_filename] ? File.basename(source, '.*') : ''}"
297
- end
298
-
299
- # Save watermark image to buffer
300
- convert.write('mpr:watermark').delete.+
301
- 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
302
120
 
303
- # load source image
121
+ MiniMagick::Tool::Convert.new do |convert|
122
+ convert.quiet if @quiet
304
123
  convert << source
305
-
306
- # force flatten image if necessary
307
124
  convert.flatten if @options[:flatten].nil? && format == :JPG
308
-
309
- # add watermark image
310
- if wm
311
- if wm[:command] == 'banner'
312
- convert.rotate '-90'
313
- convert << 'mpr:watermark'
314
- convert.rotate '180'
315
- convert.append
316
- convert.rotate '-90'
317
- else
318
- if (0..1).include? wm[:tiles]
319
- convert << 'mpr:watermark'
320
- else
321
- convert.stack do |stack|
322
- stack.size("#{image_info['width']}x#{image_info['height']}")
323
- stack << 'xc:transparent'
324
- stack.tile('mpr:watermark')
325
- stack.draw "rectangle 0,0,#{image_info['width']},#{image_info['height']}"
326
- end
327
- convert.compose(wm[:composition])
328
- convert.gravity(wm[:gravity])
329
- convert.define("compose:args=#{wm[:opacity]}%")
330
- convert.composite
331
- end
332
- 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'
333
128
  end
334
129
 
335
- @flags.each { |f, v| v.is_a?(TrueClass) ? convert.send(f).+ : convert.send(f) }
336
- convert << '+set' << 'modify-date' << '+set' << 'create-date' if @delete_date
337
-
338
130
  colorspace = @options.delete(:colorspace) || 'sRGB'
339
131
  unless @options.empty?
340
132
  convert.colorspace('RGB')
341
- @options.each { |o, v| convert.send(o, v) }
133
+ @options.each {|o, v| convert.send(o, v)}
342
134
  end
343
135
  convert.colorspace(colorspace)
344
136
  convert.profile @profile if @profile
@@ -350,8 +142,11 @@ module Libis
350
142
  end
351
143
 
352
144
  target
145
+
353
146
  end
147
+
354
148
  end
149
+
355
150
  end
356
151
  end
357
- 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