libis-format 1.0.1 → 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.
- checksums.yaml +5 -5
- data/.gitignore +3 -1
- data/.travis.yml +43 -25
- data/README.md +2 -2
- data/base/Dockerfile +35 -0
- data/base/Dockerfile.alpine +20 -0
- data/base/Dockerfile.rvm +56 -0
- data/base/rework_path +20 -0
- data/bin/libis_format +8 -0
- data/docker_cfg.yml +1 -0
- data/lib/libis/format.rb +5 -1
- data/lib/libis/format/cli/convert.rb +310 -0
- data/lib/libis/format/cli/format.rb +77 -0
- data/lib/libis/format/cli/prompt_helper.rb +87 -0
- data/lib/libis/format/cli/sub_command.rb +22 -0
- data/lib/libis/format/command_line.rb +25 -0
- data/lib/libis/format/config.rb +14 -10
- data/lib/libis/format/converter/audio_converter.rb +3 -37
- data/lib/libis/format/converter/base.rb +21 -8
- data/lib/libis/format/converter/chain.rb +3 -3
- data/lib/libis/format/converter/image_assembler.rb +82 -0
- data/lib/libis/format/converter/image_converter.rb +36 -134
- data/lib/libis/format/converter/image_splitter.rb +80 -0
- data/lib/libis/format/converter/image_watermarker.rb +261 -0
- data/lib/libis/format/converter/jp2_converter.rb +2 -2
- data/lib/libis/format/converter/office_converter.rb +2 -2
- data/lib/libis/format/converter/pdf_assembler.rb +66 -0
- data/lib/libis/format/converter/pdf_converter.rb +33 -89
- data/lib/libis/format/converter/pdf_optimizer.rb +70 -0
- data/lib/libis/format/converter/pdf_splitter.rb +65 -0
- data/lib/libis/format/converter/pdf_watermarker.rb +110 -0
- data/lib/libis/format/converter/spreadsheet_converter.rb +2 -2
- data/lib/libis/format/converter/video_converter.rb +1 -1
- data/lib/libis/format/identifier.rb +7 -7
- data/lib/libis/format/info.rb +27 -0
- data/lib/libis/format/library.rb +147 -0
- data/lib/libis/format/tool/droid.rb +2 -2
- data/lib/libis/format/tool/extension_identification.rb +4 -4
- data/lib/libis/format/tool/ffmpeg.rb +1 -1
- data/lib/libis/format/tool/fido.rb +1 -1
- data/lib/libis/format/tool/fop_pdf.rb +1 -1
- data/lib/libis/format/tool/identification_tool.rb +6 -6
- data/lib/libis/format/tool/office_to_pdf.rb +1 -1
- data/lib/libis/format/tool/pdf_copy.rb +1 -1
- data/lib/libis/format/tool/pdf_merge.rb +1 -1
- data/lib/libis/format/tool/pdf_split.rb +1 -1
- data/lib/libis/format/tool/pdf_to_pdfa.rb +1 -2
- data/lib/libis/format/tool/pdfa_validator.rb +3 -4
- data/lib/libis/format/tool/spreadsheet_to_ods.rb +2 -1
- data/lib/libis/format/version.rb +1 -1
- data/lib/libis/format/yaml_loader.rb +71 -0
- data/libis-format.gemspec +4 -4
- data/tools/fop/build/fop.jar +0 -0
- data/tools/fop/conf/fop.xconf +466 -0
- data/tools/fop/fop +258 -0
- data/tools/fop/fop.bat +75 -0
- data/tools/fop/fop.cmd +31 -0
- data/tools/fop/fop.js +341 -0
- data/tools/fop/lib/README.txt +243 -0
- data/tools/fop/lib/avalon-framework-api-4.3.1.jar +0 -0
- data/tools/fop/lib/avalon-framework-impl-4.3.1.jar +0 -0
- data/tools/fop/lib/avalon-framework.LICENSE.txt +175 -0
- data/tools/fop/lib/avalon-framework.NOTICE.TXT +11 -0
- data/tools/fop/lib/batik-all-1.10.jar +0 -0
- data/tools/fop/lib/batik.LICENSE.txt +201 -0
- data/tools/fop/lib/batik.NOTICE.txt +18 -0
- data/tools/fop/lib/commons-io-1.3.1.jar +0 -0
- data/tools/fop/lib/commons-io.LICENSE.txt +203 -0
- data/tools/fop/lib/commons-io.NOTICE.txt +6 -0
- data/tools/fop/lib/commons-logging-1.0.4.jar +0 -0
- data/tools/fop/lib/commons-logging.LICENSE.txt +202 -0
- data/tools/fop/lib/commons-logging.NOTICE.txt +3 -0
- data/tools/fop/lib/fontbox-2.0.7.jar +0 -0
- data/tools/fop/lib/serializer-2.7.2.jar +0 -0
- data/tools/fop/lib/serializer.LICENSE.txt +201 -0
- data/tools/fop/lib/serializer.NOTICE.txt +15 -0
- data/tools/fop/lib/xalan-2.7.2.jar +0 -0
- data/tools/fop/lib/xalan.BCEL.LICENSE.txt +52 -0
- data/tools/fop/lib/xalan.LICENSE.txt +202 -0
- data/tools/fop/lib/xalan.NOTICE.txt +44 -0
- data/tools/fop/lib/xalan.regexp.LICENSE.txt +52 -0
- data/tools/fop/lib/xalan.runtime.LICENSE.txt +20 -0
- data/tools/fop/lib/xerces.LICENSE.txt +56 -0
- data/tools/fop/lib/xercesImpl-2.9.1.jar +0 -0
- data/tools/fop/lib/xercesImpl.LICENSE.txt +201 -0
- data/tools/fop/lib/xercesImpl.NOTICE.txt +14 -0
- data/tools/fop/lib/xml-apis-1.3.04.jar +0 -0
- data/tools/fop/lib/xml-apis-ext-1.3.04.jar +0 -0
- data/tools/fop/lib/xml-apis-ext.LICENSE.dom-documentation.txt +73 -0
- data/tools/fop/lib/xml-apis-ext.LICENSE.dom-software.txt +61 -0
- data/tools/fop/lib/xml-apis-ext.LICENSE.sac.html +75 -0
- data/tools/fop/lib/xml-apis-ext.LICENSE.txt +202 -0
- data/tools/fop/lib/xml-apis-ext.NOTICE.txt +16 -0
- data/tools/fop/lib/xml-apis-ext.README.dom.txt +56 -0
- data/tools/fop/lib/xml-apis.LICENSE-SAX.html +17 -0
- data/tools/fop/lib/xml-apis.LICENSE.DOM-documentation.html +74 -0
- data/tools/fop/lib/xml-apis.LICENSE.DOM-software.html +66 -0
- data/tools/fop/lib/xml-apis.LICENSE.txt +201 -0
- data/tools/fop/lib/xml-apis.NOTICE.txt +13 -0
- data/tools/fop/lib/xmlgraphics-commons-2.3.jar +0 -0
- data/tools/fop/lib/xmlgraphics-commons.LICENSE.txt +202 -0
- data/tools/fop/lib/xmlgraphics-commons.NOTICE.txt +5 -0
- data/tools/pdfbox/pdfbox-app-2.0.13.jar +0 -0
- data/tools/pdfbox/{pdfbox-app-1.8.10.jar → preflight-app-2.0.13.jar} +0 -0
- metadata +78 -252
- data/lib/libis/format/type_database.rb +0 -201
- data/spec/converter_audio_spec.rb +0 -66
- data/spec/converter_fop_spec.rb +0 -37
- data/spec/converter_image_spec.rb +0 -166
- data/spec/converter_office_spec.rb +0 -84
- data/spec/converter_pdf_spec.rb +0 -30
- data/spec/converter_repository_spec.rb +0 -97
- data/spec/converter_spreadsheet_spec.rb +0 -39
- data/spec/converter_video_spec.rb +0 -97
- data/spec/converter_xsl_spec.rb +0 -56
- data/spec/data/Cevennes2.bmp +0 -0
- data/spec/data/Cevennes2.jp2 +0 -0
- data/spec/data/Cevennes2.ppm +0 -22492
- data/spec/data/NikonRaw-CameraRaw.TIF +0 -0
- data/spec/data/NikonRaw-CaptureOne.tif +0 -0
- data/spec/data/audio/carlin_disappointed.aac +0 -0
- data/spec/data/audio/carlin_disappointed.ac3 +0 -0
- data/spec/data/audio/carlin_disappointed.aiff +0 -0
- data/spec/data/audio/carlin_disappointed.au +0 -0
- data/spec/data/audio/carlin_disappointed.flac +0 -0
- data/spec/data/audio/carlin_disappointed.m4a +0 -0
- data/spec/data/audio/carlin_disappointed.mka +0 -0
- data/spec/data/audio/carlin_disappointed.mp3 +0 -0
- data/spec/data/audio/carlin_disappointed.ogg +0 -0
- data/spec/data/audio/carlin_disappointed.ra +0 -0
- data/spec/data/audio/carlin_disappointed.voc +0 -0
- data/spec/data/audio/carlin_disappointed.wav +0 -0
- data/spec/data/audio/carlin_disappointed.wma +0 -0
- data/spec/data/audio/greensleeves.aac +0 -0
- data/spec/data/audio/greensleeves.ac3 +0 -0
- data/spec/data/audio/greensleeves.aiff +0 -0
- data/spec/data/audio/greensleeves.au +0 -0
- data/spec/data/audio/greensleeves.flac +0 -0
- data/spec/data/audio/greensleeves.m4a +0 -0
- data/spec/data/audio/greensleeves.mka +0 -0
- data/spec/data/audio/greensleeves.mp3 +0 -0
- data/spec/data/audio/greensleeves.ogg +0 -0
- data/spec/data/audio/greensleeves.ra +0 -0
- data/spec/data/audio/greensleeves.voc +0 -0
- data/spec/data/audio/greensleeves.wav +0 -0
- data/spec/data/audio/greensleeves.wma +0 -0
- data/spec/data/audio/king_nonviolence.aac +0 -0
- data/spec/data/audio/king_nonviolence.ac3 +0 -0
- data/spec/data/audio/king_nonviolence.aiff +0 -0
- data/spec/data/audio/king_nonviolence.au +0 -0
- data/spec/data/audio/king_nonviolence.flac +0 -0
- data/spec/data/audio/king_nonviolence.m4a +0 -0
- data/spec/data/audio/king_nonviolence.mka +0 -0
- data/spec/data/audio/king_nonviolence.mp3 +0 -0
- data/spec/data/audio/king_nonviolence.ogg +0 -0
- data/spec/data/audio/king_nonviolence.ra +0 -0
- data/spec/data/audio/king_nonviolence.voc +0 -0
- data/spec/data/audio/king_nonviolence.wav +0 -0
- data/spec/data/audio/king_nonviolence.wma +0 -0
- data/spec/data/audio/top_gun_secret.aac +0 -0
- data/spec/data/audio/top_gun_secret.ac3 +0 -0
- data/spec/data/audio/top_gun_secret.aiff +0 -0
- data/spec/data/audio/top_gun_secret.au +0 -0
- data/spec/data/audio/top_gun_secret.flac +0 -0
- data/spec/data/audio/top_gun_secret.m4a +0 -0
- data/spec/data/audio/top_gun_secret.mka +0 -0
- data/spec/data/audio/top_gun_secret.mp3 +0 -0
- data/spec/data/audio/top_gun_secret.ogg +0 -0
- data/spec/data/audio/top_gun_secret.ra +0 -0
- data/spec/data/audio/top_gun_secret.voc +0 -0
- data/spec/data/audio/top_gun_secret.wav +0 -0
- data/spec/data/audio/top_gun_secret.wma +0 -0
- data/spec/data/multipage.tif +0 -0
- data/spec/data/multipage.tif.jp2 +0 -0
- data/spec/data/test-ead.xml +0 -392
- data/spec/data/test-jpg.tif +0 -0
- data/spec/data/test-lzw.tif +0 -0
- data/spec/data/test-options.jpg +0 -0
- data/spec/data/test-options.png +0 -0
- data/spec/data/test.bmp +0 -0
- data/spec/data/test.doc +0 -0
- data/spec/data/test.docx +0 -0
- data/spec/data/test.gif +0 -0
- data/spec/data/test.jpg +0 -0
- data/spec/data/test.ods +0 -0
- data/spec/data/test.odt +0 -0
- data/spec/data/test.pdf +0 -0
- data/spec/data/test.pdf.tif +0 -0
- data/spec/data/test.png +0 -0
- data/spec/data/test.ps +0 -8631
- data/spec/data/test.psd +0 -0
- data/spec/data/test.rtf +0 -1455
- data/spec/data/test.tif +0 -0
- data/spec/data/test.txt +0 -12
- data/spec/data/test.xcf +0 -0
- data/spec/data/test.xls +0 -0
- data/spec/data/test.xlsx +0 -0
- data/spec/data/test.xml +0 -4
- data/spec/data/test_pdfa.pdf +0 -0
- data/spec/data/video/SampleVideo_1080x720_2mb.flv +0 -0
- data/spec/data/video/SampleVideo_1080x720_2mb.mkv +0 -0
- data/spec/data/video/SampleVideo_1080x720_2mb.mp4 +0 -0
- data/spec/data/video/SampleVideo_176x144_2mb.3gp +0 -0
- data/spec/data/video/SampleVideo_320x240_2mb.3gp +0 -0
- data/spec/data/video/SampleVideo_360x240_2mb.flv +0 -0
- data/spec/data/video/SampleVideo_360x240_2mb.mkv +0 -0
- data/spec/data/video/SampleVideo_360x240_2mb.mp4 +0 -0
- data/spec/data/video/copyright.png +0 -0
- data/spec/data/xml/134476_ead.XML +0 -1
- data/spec/data/xml/134476_ead.pdf +0 -0
- data/spec/data/xml/134476_fo.XML +0 -383
- data/spec/data/xml/134476_raw.XML +0 -141
- data/spec/data/xml/ead2fo_pdf.xsl +0 -1453
- data/spec/data/xml/header_nolink_pdf.xsl +0 -120
- data/spec/data/xml/lookupLists.xsl +0 -488
- data/spec/data/xml/scope_eadToHTML.xsl +0 -2376
- data/spec/data/xml/scope_xmlToEAD_dom.xsl +0 -952
- data/spec/identifier_spec.rb +0 -161
- data/spec/spec_helper.rb +0 -58
- data/spec/test_types.yml +0 -12
- data/spec/type_database_spec.rb +0 -140
- data/tools/pdfbox/preflight-app-1.8.10.jar +0 -0
|
@@ -4,31 +4,36 @@ require_relative 'base'
|
|
|
4
4
|
require 'libis/format/identifier'
|
|
5
5
|
|
|
6
6
|
require 'mini_magick'
|
|
7
|
-
require 'fileutils'
|
|
8
7
|
|
|
9
|
-
MiniMagick.logger.level = ::Logger::
|
|
8
|
+
MiniMagick.logger.level = ::Logger::UNKNOWN
|
|
10
9
|
|
|
11
10
|
MiniMagick.configure do |config|
|
|
12
11
|
# config.cli = :graphicsmagick
|
|
13
12
|
config.validate_on_create = false
|
|
14
13
|
config.validate_on_write = false
|
|
14
|
+
config.whiny = false
|
|
15
15
|
end
|
|
16
16
|
|
|
17
17
|
module Libis
|
|
18
18
|
module Format
|
|
19
19
|
module Converter
|
|
20
20
|
|
|
21
|
+
# noinspection RubyTooManyInstanceVariablesInspection
|
|
21
22
|
class ImageConverter < Libis::Format::Converter::Base
|
|
22
23
|
|
|
23
24
|
def self.input_types
|
|
24
|
-
[:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2]
|
|
25
|
+
[:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2, :PBM, :PGM, :PPM]
|
|
25
26
|
end
|
|
26
27
|
|
|
27
28
|
def self.output_types(format = nil)
|
|
28
|
-
return [] unless input_types.include?(format)
|
|
29
|
+
return [] unless input_types.include?(format) if format
|
|
29
30
|
[:TIFF, :JPG, :PNG, :BMP, :GIF, :PDF, :JP2]
|
|
30
31
|
end
|
|
31
32
|
|
|
33
|
+
def self.multipage?(format)
|
|
34
|
+
[:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM].include?(format)
|
|
35
|
+
end
|
|
36
|
+
|
|
32
37
|
def initialize
|
|
33
38
|
@wm_image = nil
|
|
34
39
|
super
|
|
@@ -39,101 +44,58 @@ module Libis
|
|
|
39
44
|
end
|
|
40
45
|
|
|
41
46
|
def quiet(v)
|
|
42
|
-
@
|
|
47
|
+
@quiet = !!v
|
|
48
|
+
self
|
|
43
49
|
end
|
|
44
50
|
|
|
45
51
|
def page(nr)
|
|
46
52
|
@page = nr
|
|
53
|
+
self
|
|
47
54
|
end
|
|
48
55
|
|
|
49
56
|
def scale(percent)
|
|
50
57
|
@options[:scale] = percent
|
|
58
|
+
self
|
|
51
59
|
end
|
|
52
60
|
|
|
53
61
|
def resize(geometry)
|
|
54
62
|
@options[:resize] = geometry
|
|
63
|
+
self
|
|
55
64
|
end
|
|
56
65
|
|
|
57
66
|
def quality(value)
|
|
58
67
|
@options[:quality] = value
|
|
68
|
+
self
|
|
59
69
|
end
|
|
60
70
|
|
|
61
71
|
def dpi(value)
|
|
62
72
|
@options[:density] = value
|
|
73
|
+
self
|
|
63
74
|
end
|
|
64
75
|
|
|
65
76
|
def resample(value)
|
|
66
77
|
@options[:resample] = value
|
|
78
|
+
self
|
|
67
79
|
end
|
|
68
80
|
|
|
69
|
-
def flatten
|
|
70
|
-
@
|
|
81
|
+
def flatten(value = true)
|
|
82
|
+
@options[:flatten] = value
|
|
83
|
+
self
|
|
71
84
|
end
|
|
72
85
|
|
|
73
86
|
def colorspace(value)
|
|
74
87
|
@options[:colorspace] = value
|
|
88
|
+
self
|
|
75
89
|
end
|
|
76
90
|
|
|
77
|
-
def delete_date
|
|
78
|
-
@delete_date =
|
|
91
|
+
def delete_date(value = true)
|
|
92
|
+
@delete_date = value
|
|
93
|
+
self
|
|
79
94
|
end
|
|
80
95
|
|
|
81
96
|
def profile(icc)
|
|
82
97
|
@profile = icc
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
# Create or use a watermark image.
|
|
86
|
-
#
|
|
87
|
-
# The watermark options are:
|
|
88
|
-
# - file: watermark image to use
|
|
89
|
-
# - text: text to create a watermark from
|
|
90
|
-
# - rotation: rotation of the watermark text (counter clockwise in degrees; integer number) - default 30
|
|
91
|
-
# - size: size of the watermark (integer > 0, 1/n of image size) - default 4
|
|
92
|
-
# - opacity: opacity of the watermark (fraction 0.0 - 1.0) - default 0.3
|
|
93
|
-
# - gap: size of the gap between watermark instances. Fractions as percentage of widht/height. - default 0.2
|
|
94
|
-
# If both options are given, the file will be used as-is if it exists and is a valid image file. Otherwise the
|
|
95
|
-
# file will be created or overwritten with a newly created watermark image.
|
|
96
|
-
#
|
|
97
|
-
# The created watermark file will be a PNG image with transparent background containing the supplied text
|
|
98
|
-
# slanted by 30 degrees counter-clockwise.
|
|
99
|
-
#
|
|
100
|
-
# @param [Hash] options Hash of options for watermark creation.
|
|
101
|
-
def watermark(options = {})
|
|
102
|
-
text = options[:text] || '© LIBIS'
|
|
103
|
-
@wm_size = (options[:size] || '4').to_i
|
|
104
|
-
@wm_opacity = ((options[:opacity] || 0.1).to_f * 100).to_i
|
|
105
|
-
@wm_composition = options[:composition] || 'modulate'
|
|
106
|
-
gap = ((options[:gap] || 0.2).to_f * 100).to_i
|
|
107
|
-
rotation = 360 - (options[:rotation] || 30).to_i
|
|
108
|
-
@wm_image = MiniMagick::Image.new(options[:file]) if options[:file]
|
|
109
|
-
unless @wm_image && @wm_image.valid?
|
|
110
|
-
image = options[:file] || (Dir::Tmpname.create(%w(wm_image .png)) { |_|})
|
|
111
|
-
# noinspection RubyResolve
|
|
112
|
-
MiniMagick::Tool::Convert.new do |convert|
|
|
113
|
-
# noinspection RubyLiteralArrayInspection
|
|
114
|
-
convert.quiet
|
|
115
|
-
convert.background 'transparent'
|
|
116
|
-
convert.size('2000x2000')
|
|
117
|
-
convert.gravity 'Center'
|
|
118
|
-
convert.font('Helvetica').fill('black').pointsize(72) #.stroke('black').strokewidth(1)
|
|
119
|
-
convert << "label:#{text}"
|
|
120
|
-
convert.rotate rotation
|
|
121
|
-
convert.trim.repage.+
|
|
122
|
-
convert.bordercolor('transparent').border("#{gap}%")
|
|
123
|
-
convert << image
|
|
124
|
-
end
|
|
125
|
-
if options[:file]
|
|
126
|
-
@wm_image = MiniMagick::Image.new(image)
|
|
127
|
-
else
|
|
128
|
-
@wm_image = MiniMagick::Image.open(image)
|
|
129
|
-
File.delete(image)
|
|
130
|
-
end
|
|
131
|
-
# noinspection RubyResolve
|
|
132
|
-
unless @wm_image.valid?
|
|
133
|
-
error "Problem creating watermark image '#{image}'."
|
|
134
|
-
@wm_image = nil
|
|
135
|
-
end
|
|
136
|
-
end
|
|
98
|
+
self
|
|
137
99
|
end
|
|
138
100
|
|
|
139
101
|
def convert(source, target, format, opts = {})
|
|
@@ -141,88 +103,26 @@ module Libis
|
|
|
141
103
|
|
|
142
104
|
FileUtils.mkpath(File.dirname(target))
|
|
143
105
|
|
|
144
|
-
|
|
145
|
-
sources = source
|
|
146
|
-
|
|
147
|
-
unless [:PDF, :TIFF, :GIF, :PBM, :PGM, :PPM].include? format
|
|
148
|
-
error 'Can ony assemble multiple images into multi-page/layer format'
|
|
149
|
-
return nil
|
|
150
|
-
end
|
|
151
|
-
|
|
152
|
-
assemble_and_convert(sources, target, format)
|
|
153
|
-
|
|
154
|
-
elsif File.directory?(source)
|
|
155
|
-
sources = Dir[File.join(source, '**', '*')].reject { |p| File.directory? p }
|
|
156
|
-
|
|
157
|
-
unless [:TIFF, :PDF].include? format
|
|
158
|
-
error 'Can ony assemble multiple images into multi-page/layer format'
|
|
159
|
-
return nil
|
|
160
|
-
end
|
|
161
|
-
|
|
162
|
-
assemble_and_convert(sources, target, format)
|
|
163
|
-
|
|
164
|
-
else
|
|
165
|
-
|
|
166
|
-
image = MiniMagick::Image.new(source)
|
|
167
|
-
|
|
168
|
-
if image.pages.size > 1
|
|
169
|
-
if @page
|
|
170
|
-
convert_image(image.pages[@page].path, target, format)
|
|
171
|
-
else
|
|
172
|
-
assemble_and_convert(image.pages.map { |page| page.path }, target, format)
|
|
173
|
-
end
|
|
174
|
-
else
|
|
175
|
-
convert_image(source, target, format)
|
|
176
|
-
end
|
|
177
|
-
end
|
|
106
|
+
convert_image(source, target, format)
|
|
178
107
|
|
|
179
108
|
target
|
|
180
109
|
|
|
181
110
|
end
|
|
182
111
|
|
|
183
|
-
def assemble_and_convert(sources, target, format)
|
|
184
|
-
converted_pages = sources.inject([]) do |list, path|
|
|
185
|
-
converted = Tempfile.new(['page-', ".#{Libis::Format::TypeDatabase.type_extentions(format).first}"])
|
|
186
|
-
convert_image(path, converted.path, format)
|
|
187
|
-
list << converted
|
|
188
|
-
end
|
|
189
|
-
MiniMagick::Tool::Convert.new do |b|
|
|
190
|
-
converted_pages.each { |page| b << page.path }
|
|
191
|
-
b << target
|
|
192
|
-
end
|
|
193
|
-
converted_pages.each do |temp_file|
|
|
194
|
-
temp_file.close
|
|
195
|
-
temp_file.unlink
|
|
196
|
-
end
|
|
197
|
-
end
|
|
198
|
-
|
|
199
112
|
protected
|
|
200
113
|
|
|
201
114
|
def convert_image(source, target, format)
|
|
202
115
|
|
|
203
|
-
|
|
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
|
|
204
120
|
|
|
205
121
|
MiniMagick::Tool::Convert.new do |convert|
|
|
206
|
-
if @
|
|
207
|
-
convert << @wm_image.path
|
|
208
|
-
convert.filter('Lagrange')
|
|
209
|
-
convert.resize("#{image_info['width'] / @wm_size}x#{image_info['height'] / @wm_size}").write('mpr:watermark').delete.+
|
|
210
|
-
end
|
|
211
|
-
|
|
122
|
+
convert.quiet if @quiet
|
|
212
123
|
convert << source
|
|
213
|
-
convert.flatten if format == :JPG
|
|
214
|
-
|
|
215
|
-
# noinspection RubyResolve
|
|
216
|
-
convert.stack do |stack|
|
|
217
|
-
stack.size("#{image_info['width']}x#{image_info['height']}")
|
|
218
|
-
stack << 'xc:transparent'
|
|
219
|
-
stack.tile('mpr:watermark')
|
|
220
|
-
stack.draw "rectangle 0,0,#{image_info['width']},#{image_info['height']}"
|
|
221
|
-
end
|
|
222
|
-
convert.compose(@wm_composition).define("compose:args=#{@wm_opacity}").composite
|
|
223
|
-
end
|
|
224
|
-
|
|
225
|
-
@flags.each { |f, v| v.is_a?(FalseClass) ? convert.send(f).+ : convert.send(f) }
|
|
124
|
+
convert.flatten if @options[:flatten].nil? && format == :JPG
|
|
125
|
+
@flags.each {|f, v| v.is_a?(TrueClass) ? convert.send(f).+ : convert.send(f)}
|
|
226
126
|
if @delete_date
|
|
227
127
|
convert << '+set' << 'modify-date' << '+set' << 'create-date'
|
|
228
128
|
end
|
|
@@ -230,13 +130,15 @@ module Libis
|
|
|
230
130
|
colorspace = @options.delete(:colorspace) || 'sRGB'
|
|
231
131
|
unless @options.empty?
|
|
232
132
|
convert.colorspace('RGB')
|
|
233
|
-
@options.each {
|
|
133
|
+
@options.each {|o, v| convert.send(o, v)}
|
|
234
134
|
end
|
|
235
135
|
convert.colorspace(colorspace)
|
|
236
136
|
convert.profile @profile if @profile
|
|
237
137
|
|
|
238
138
|
convert.format(format)
|
|
239
139
|
convert << target
|
|
140
|
+
|
|
141
|
+
debug "ImageMagick command: '#{convert.command.join(' ')}'"
|
|
240
142
|
end
|
|
241
143
|
|
|
242
144
|
target
|
|
@@ -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
|