libis-format 1.3.3 → 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 +40 -153
  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 +83 -125
  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,10 +1,9 @@
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
 
@@ -13,26 +12,26 @@ MiniMagick.configure do |config|
13
12
  config.validate_on_create = false
14
13
  config.validate_on_write = false
15
14
  config.whiny = false
16
- config.tmpdir = Libis::Format::Config[:tempdir] || Dir.tmpdir
17
15
  end
18
16
 
19
17
  module Libis
20
18
  module Format
21
19
  module Converter
20
+
22
21
  # noinspection RubyTooManyInstanceVariablesInspection
23
22
  class ImageConverter < Libis::Format::Converter::Base
23
+
24
24
  def self.input_types
25
- %i[TIFF JPG PNG BMP GIF PDF JP2]
25
+ [:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2, :PBM, :PGM, :PPM]
26
26
  end
27
27
 
28
28
  def self.output_types(format = nil)
29
- return [] unless input_types.include?(format)
30
-
31
- %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]
32
31
  end
33
32
 
34
33
  def self.multipage?(format)
35
- %i[PDF TIFF GIF PBM PGM PPM].include?(format)
34
+ [:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM].include?(format)
36
35
  end
37
36
 
38
37
  def initialize
@@ -41,114 +40,62 @@ module Libis
41
40
  end
42
41
 
43
42
  def image_convert(_)
44
- # force usage of this converter
43
+ #force usage of this converter
45
44
  end
46
45
 
47
- def quiet(value)
48
- @quiet = !!value
46
+ def quiet(v)
47
+ @quiet = !!v
48
+ self
49
49
  end
50
50
 
51
- def page(number)
52
- @page = number
51
+ def page(nr)
52
+ @page = nr
53
+ self
53
54
  end
54
55
 
55
56
  def scale(percent)
56
57
  @options[:scale] = percent
58
+ self
57
59
  end
58
60
 
59
61
  def resize(geometry)
60
62
  @options[:resize] = geometry
63
+ self
61
64
  end
62
65
 
63
66
  def quality(value)
64
67
  @options[:quality] = value
68
+ self
65
69
  end
66
70
 
67
71
  def dpi(value)
68
72
  @options[:density] = value
73
+ self
69
74
  end
70
75
 
71
76
  def resample(value)
72
77
  @options[:resample] = value
78
+ self
73
79
  end
74
80
 
75
81
  def flatten(value = true)
76
- @options[:flatten] = !!value
82
+ @options[:flatten] = value
83
+ self
77
84
  end
78
85
 
79
86
  def colorspace(value)
80
87
  @options[:colorspace] = value
88
+ self
81
89
  end
82
90
 
83
91
  def delete_date(value = true)
84
- @delete_date = !!value
92
+ @delete_date = value
93
+ self
85
94
  end
86
95
 
87
96
  def profile(icc)
88
97
  @profile = icc
89
- end
90
-
91
- # Create or use a watermark image.
92
- #
93
- # The watermark options are:
94
- # - file: watermark image to use
95
- # - text: text to create a watermark from
96
- # - rotation: rotation of the watermark text (counter clockwise in degrees; integer number) - default 30
97
- # - tiles: number of tiles of the watermark - default 4
98
- # - 0: no tiling, so only 1 watermark will be placed with the original size
99
- # - 1: 1 tile, so the watermark will be scaled up to fill the image
100
- # - n > 1: minimum n tiles in both directions
101
- # - n < 0: tile without scaling the watermark
102
- # - size: same as tiles - for backwards compatibility
103
- # - resize: fraction 0.0 - 1.0
104
- # - gap: size of the gap between watermark instances. Fractions as percentage of widht/height. - default 0.2
105
- # - opacity: opacity of the watermark (fraction 0.0 - 1.0) - default 0.1
106
- # - gravity: center point of the overlay - default 'center'
107
- # If both options are given, the file will be used as-is if it exists and is a valid image file. Otherwise the
108
- # file will be created or overwritten with a newly created watermark image.
109
- #
110
- # The created watermark file will be a PNG image with transparent background containing the supplied text
111
- # slanted by 30 degrees counter-clockwise.
112
- #
113
- # @param [Hash] options Hash of options for watermark creation.
114
- def watermark(options = {})
115
- text = options[:text] || '© LIBIS'
116
- @wm_tiles = (options[:tiles] || '4').to_i
117
- @wm_tiles ||= (options[:size] || '4').to_i
118
- @wm_resize = ((options[:resize]).to_f * 100).to_i if options[:resize]
119
- @wm_opacity = ((options[:opacity] || 0.1).to_f * 100).to_i
120
- @wm_composition = options[:composition] || 'modulate'
121
- @wm_gravity = options[:gravity] || 'center'
122
- @wm_gap = ((options[:gap] || 0.2).to_f * 100).to_i
123
- rotation = 360 - (options[:rotation] || 30).to_i
124
- @wm_image = MiniMagick::Image.new(options[:file]) if options[:file]
125
- return if @wm_image&.valid?
126
-
127
- image = options[:file] || (Dir::Tmpname.create(%w[wm_image .png]) { |_| })
128
- # noinspection RubyResolve
129
- MiniMagick::Tool::Convert.new do |convert|
130
- # noinspection RubyLiteralArrayInspection
131
- convert.quiet
132
- convert.background 'transparent'
133
- convert.size('2000x2000')
134
- convert.gravity 'Center'
135
- convert.font('Helvetica').fill('black').pointsize(72) # .stroke('black').strokewidth(1)
136
- convert << "label:#{text}"
137
- convert.rotate rotation
138
- convert.trim.repage.+ # rubocop:disable Lint/Void
139
- convert << image
140
- end
141
- if options[:file]
142
- @wm_image = MiniMagick::Image.new(image)
143
- else
144
- @wm_image = MiniMagick::Image.open(image)
145
- File.delete(image)
146
- end
147
- # noinspection RubyResolve
148
- return if @wm_image.valid?
149
-
150
- error "Problem creating watermark image '#{image}'."
151
- @wm_image = nil
98
+ self
152
99
  end
153
100
 
154
101
  def convert(source, target, format, opts = {})
@@ -156,97 +103,34 @@ module Libis
156
103
 
157
104
  FileUtils.mkpath(File.dirname(target))
158
105
 
159
- if source.is_a? Array
160
-
161
- assemble_and_convert(source, target, format)
162
-
163
- elsif File.directory?(source)
164
- source_list = Dir[File.join(source, '**', '*')].reject { |p| File.directory? p }
165
-
166
- assemble_and_convert(source_list, target, format)
106
+ convert_image(source, target, format)
167
107
 
168
- else
169
-
170
- image = MiniMagick::Image.open(source) { |b| b.quiet } # rubocop:disable Style/SymbolProc
171
-
172
- if image.pages.size > 1
173
- if @page
174
- convert_image(image.pages[@page].path, target, format)
175
- else
176
- # noinspection RubyBlockToMethodReference
177
- assemble_and_convert(image.pages.map(&:path), target, format)
178
- end
179
- else
180
- convert_image(source, target, format)
181
- end
182
- end
183
-
184
- {
185
- files: [target],
186
- converter: self.class.name
187
- }
188
- end
108
+ target
189
109
 
190
- def assemble_and_convert(sources, target, format)
191
- warn 'Received multiple images as input and single page format as target.' unless self.class.multipage?(format)
192
- converted_pages = sources.inject([]) do |list, path|
193
- # noinspection RubyArgCount
194
- converted = Tempfile.new(['page-', ".#{Libis::Format::TypeDatabase.type_extentions(format).first}"])
195
- convert_image(path, converted.path, format)
196
- list << converted
197
- end
198
- MiniMagick::Tool::Convert.new do |b|
199
- b.append unless self.class.multipage?(format)
200
- converted_pages.each { |page| b << page.path }
201
- b << target
202
- end
203
- converted_pages.each do |temp_file|
204
- temp_file.close
205
- temp_file.unlink
206
- end
207
110
  end
208
111
 
209
112
  protected
210
113
 
211
114
  def convert_image(source, target, format)
212
- image_info = nil
213
- image_info = MiniMagick::Image::Info.new(source) { |b| b.quiet } if @wm_image # rubocop:disable Style/SymbolProc
214
115
 
215
- MiniMagick::Tool::Convert.new do |convert|
216
- convert.quiet if @quiet
217
- if @wm_image
218
- convert << @wm_image.path
219
- convert.bordercolor('transparent').border("#{@wm_gap}%") if @wm_gap.positive?
220
- convert.filter('Lagrange')
221
- convert.resize("#{image_info['width'] / @wm_tiles}x#{image_info['height'] / @wm_tiles}") if @wm_tiles.positive?
222
- convert.resize("#{@wm_resize}%") if @wm_resize
223
- convert.write('mpr:watermark').delete.+
224
- 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
225
120
 
121
+ MiniMagick::Tool::Convert.new do |convert|
226
122
  convert.quiet if @quiet
227
123
  convert << source
228
124
  convert.flatten if @options[:flatten].nil? && format == :JPG
229
- if @wm_image
230
- if (@wm_tiles >= 0) && (@wm_tiles <= 1)
231
- convert << 'mpr:watermark'
232
- else
233
- convert.stack do |stack|
234
- stack.size("#{image_info['width']}x#{image_info['height']}")
235
- stack << 'xc:transparent'
236
- stack.tile('mpr:watermark')
237
- stack.draw "rectangle 0,0,#{image_info['width']},#{image_info['height']}"
238
- end
239
- end
240
- convert.compose(@wm_composition).gravity(@wm_gravity).define("compose:args=#{@wm_opacity}%").composite
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'
241
128
  end
242
129
 
243
- @flags.each { |f, v| v.is_a?(TrueClass) ? convert.send(f).+ : convert.send(f) }
244
- convert << '+set' << 'modify-date' << '+set' << 'create-date' if @delete_date
245
-
246
130
  colorspace = @options.delete(:colorspace) || 'sRGB'
247
131
  unless @options.empty?
248
132
  convert.colorspace('RGB')
249
- @options.each { |o, v| convert.send(o, v) }
133
+ @options.each {|o, v| convert.send(o, v)}
250
134
  end
251
135
  convert.colorspace(colorspace)
252
136
  convert.profile @profile if @profile
@@ -258,8 +142,11 @@ module Libis
258
142
  end
259
143
 
260
144
  target
145
+
261
146
  end
147
+
262
148
  end
149
+
263
150
  end
264
151
  end
265
- 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
@@ -0,0 +1,261 @@
1
+ # encoding: utf-8
2
+
3
+ require_relative 'base'
4
+ require 'libis/format/identifier'
5
+
6
+ require 'mini_magick'
7
+ # noinspection RubyResolve
8
+ require 'fileutils'
9
+
10
+ MiniMagick.logger.level = ::Logger::UNKNOWN
11
+
12
+ MiniMagick.configure do |config|
13
+ # config.cli = :graphicsmagick
14
+ config.validate_on_create = false
15
+ config.validate_on_write = false
16
+ config.whiny = false
17
+ end
18
+
19
+ module Libis
20
+ module Format
21
+ module Converter
22
+
23
+ # noinspection RubyTooManyInstanceVariablesInspection
24
+ class ImageWatermarker < Libis::Format::Converter::Base
25
+
26
+ def self.input_types
27
+ [:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2]
28
+ end
29
+
30
+ def self.output_types(format = nil)
31
+ return [] unless input_types.include?(format) if format
32
+ [format]
33
+ end
34
+
35
+ def self.multipage?(format)
36
+ [:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM].include?(format)
37
+ end
38
+
39
+ def initialize
40
+ super
41
+ @quiet = true
42
+ @wm_image = nil
43
+ @wm_file = nil
44
+ @wm_text = '© LIBIS'
45
+ @wm_tiles = 4
46
+ @wm_resize = nil
47
+ @wm_gap = 20
48
+ @wm_gravity = 'Center'
49
+ @wm_rotation = 30
50
+ @wm_composition ='modulate'
51
+ @wm_composition_args = '10'
52
+ end
53
+
54
+ def image_watermark(_)
55
+ #force usage of this converter
56
+ self
57
+ end
58
+
59
+ def quiet(v)
60
+ @quiet = !!v
61
+ self
62
+ end
63
+
64
+ def page(v)
65
+ @page = v.to_i
66
+ self
67
+ end
68
+
69
+ # watermark image to use
70
+ def file(v)
71
+ @wm_file = v.blank? ? nil : v
72
+ self
73
+ end
74
+
75
+ # text to create a watermark from
76
+ def text(v)
77
+ @wm_text = v.blank? ? nil : v
78
+ self
79
+ end
80
+
81
+ # rotation of the watermark text (counter clockwise in degrees; integer number)
82
+ # default 30
83
+ def rotation(v)
84
+ @wm_rotation = v.to_i
85
+ self
86
+ end
87
+
88
+ # number of tiles of the watermark
89
+ # default 4
90
+ # 0: no tiling, so only 1 watermark will be placed with the original size
91
+ # 1: 1 tile, so the watermark will be scaled up to fill the image
92
+ # n > 1: minimum n tiles in both directions
93
+ # n < 0: tile without scaling the watermark
94
+ def tiles(v)
95
+ @wm_tiles = v.to_i
96
+ self
97
+ end
98
+
99
+ # fraction 0.0 - 1.0
100
+ def resize(v)
101
+ @wm_resize = (v.to_f * 100).to_i
102
+ self
103
+ end
104
+
105
+ # size of the gap between watermark instances. Fractions as percentage of widht/height
106
+ # default 0.2
107
+ def gap(v)
108
+ @wm_gap = (v.to_f * 100).to_i
109
+ self
110
+ end
111
+
112
+ # center point for the watermark overlay
113
+ # default 'center'
114
+ def gravity(v)
115
+ @wm_gravity = v.blank? ? nil : v
116
+ self
117
+ end
118
+
119
+ # the image composition method for merging the watermark image
120
+ # default 'modulate'
121
+ # See https://imagemagick.org/script/compose.php for more information
122
+ def composition(v)
123
+ @wm_composition = v.blank? ? nil : v
124
+ self
125
+ end
126
+
127
+ # arguments for the composition method
128
+ # default '10'
129
+ # See https://imagemagick.org/script/compose.php for more information
130
+ def composition_args(v)
131
+ @wm_composition_args = v.blank? ? nil : v
132
+ self
133
+ end
134
+
135
+
136
+ def convert(source, target, format, opts = {})
137
+ super
138
+
139
+ FileUtils.mkpath(File.dirname(target))
140
+
141
+ if source.is_a?(Array) || File.directory?(source)
142
+ error 'Only a single image file is allowed for input'
143
+ else
144
+ image = MiniMagick::Image.open(source) { |b| b.quiet }
145
+
146
+ if image.pages.size > 1
147
+ if @page
148
+ convert_image(image.pages[@page].path, target, format)
149
+ else
150
+ error 'multipage input file detecte; you need to supply a page number'
151
+ end
152
+ else
153
+ convert_image(source, target, format)
154
+ end
155
+ end
156
+
157
+ target
158
+
159
+ end
160
+
161
+ protected
162
+
163
+ # noinspection DuplicatedCode
164
+ def convert_image(source, target, format)
165
+
166
+ wm_image = watermark_image
167
+ return nil unless wm_image
168
+ image_info = MiniMagick::Image::Info.new(source) {|b| b.quiet}
169
+
170
+ MiniMagick::Tool::Convert.new do |convert|
171
+ convert.quiet if @quiet
172
+
173
+ # adapt watermark image to tile size and apply gap and resize if necessary
174
+ convert << @wm_image.path
175
+ # noinspection RubyResolve
176
+ convert.bordercolor('transparent').border("#{@wm_gap}%") if @wm_gap > 0
177
+ convert.filter('Lagrange')
178
+ convert.resize("#{image_info['width'] / @wm_tiles}x#{image_info['height'] / @wm_tiles}") if @wm_tiles > 0
179
+ convert.resize("#{@wm_resize}%") if @wm_resize
180
+ convert.write('mpr:watermark').delete.+
181
+
182
+ # convert the source image
183
+ convert << source
184
+ if @wm_tiles >= 0 and @wm_tiles <= 1
185
+ # only 1 watermark required (tiles = 0/1 => scaled no/yes)
186
+ convert << 'mpr:watermark'
187
+ else
188
+ # fill the image size with a pattern of the watermark image
189
+ convert.stack do |stack|
190
+ stack.size("#{image_info['width']}x#{image_info['height']}")
191
+ stack << 'xc:transparent'
192
+ # noinspection RubyResolve
193
+ stack.tile('mpr:watermark')
194
+ # noinspection RubyResolve
195
+ stack.draw "rectangle 0,0,#{image_info['width']},#{image_info['height']}"
196
+ end
197
+ end
198
+ # perform the blending operation
199
+ convert.compose(@wm_composition).gravity(@wm_gravity).define("compose:args=#{@wm_composition_args}").composite
200
+
201
+ convert.format(format)
202
+ convert << target
203
+
204
+ debug "ImageMagick command: '#{convert.command.join(' ')}'"
205
+ end
206
+
207
+ target
208
+
209
+ end
210
+
211
+ private
212
+
213
+ # Create or use a watermark image.
214
+ #
215
+ # If both text and image are set, the file will be used as-is if it exists and is a valid image file. Otherwise the
216
+ # file will be created or overwritten with a newly created watermark image.
217
+ #
218
+ # The created watermark file will be a 2000x2000 pixels PNG image with transparent background
219
+ #
220
+ # The text will be slanted by given rotation degrees counter-clockwise
221
+ def watermark_image
222
+ rotation = 360 - @wm_rotation
223
+ @wm_image = MiniMagick::Image.new(@wm_file) if @wm_file
224
+ # only create image if file is not an image
225
+ unless @wm_image&.valid?
226
+ # noinspection RubyResolve
227
+ # Create image file (as given or temp file)
228
+ image = @wm_file || (Dir::Tmpname.create(%w(wm_image .png)) {|_|})
229
+ # noinspection RubyResolve
230
+ MiniMagick::Tool::Convert.new do |convert|
231
+ convert.quiet # allways quiet
232
+ convert.background 'transparent'
233
+ convert.size('2000x2000')
234
+ convert.gravity 'Center'
235
+ convert.font('Helvetica').fill('black').pointsize(72) #.stroke('black').strokewidth(1)
236
+ convert << "label:#{@wm_text}"
237
+ convert.rotate rotation
238
+ convert.trim.repage.+
239
+ convert << image
240
+ end
241
+ if @wm_file
242
+ @wm_image = MiniMagick::Image.new(image)
243
+ else # delete temp file
244
+ @wm_image = MiniMagick::Image.open(image)
245
+ File.delete(image)
246
+ end
247
+ # noinspection RubyResolve
248
+ unless @wm_image.valid?
249
+ error "Problem creating watermark image '#{image}'."
250
+ @wm_image = nil
251
+ end
252
+ @wm_image
253
+ end
254
+ end
255
+
256
+
257
+ end
258
+
259
+ end
260
+ end
261
+ end