mini_magick 3.8.1 → 4.9.4
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/lib/mini_gmagick.rb +1 -0
- data/lib/mini_magick/configuration.rb +198 -0
- data/lib/mini_magick/image/info.rb +192 -0
- data/lib/mini_magick/image.rb +456 -341
- data/lib/mini_magick/shell.rb +81 -0
- data/lib/mini_magick/tool/animate.rb +14 -0
- data/lib/mini_magick/tool/compare.rb +14 -0
- data/lib/mini_magick/tool/composite.rb +14 -0
- data/lib/mini_magick/tool/conjure.rb +14 -0
- data/lib/mini_magick/tool/convert.rb +14 -0
- data/lib/mini_magick/tool/display.rb +14 -0
- data/lib/mini_magick/tool/identify.rb +14 -0
- data/lib/mini_magick/tool/import.rb +14 -0
- data/lib/mini_magick/tool/magick.rb +14 -0
- data/lib/mini_magick/tool/mogrify.rb +14 -0
- data/lib/mini_magick/tool/mogrify_restricted.rb +15 -0
- data/lib/mini_magick/tool/montage.rb +14 -0
- data/lib/mini_magick/tool/stream.rb +14 -0
- data/lib/mini_magick/tool.rb +297 -0
- data/lib/mini_magick/utilities.rb +23 -50
- data/lib/mini_magick/version.rb +5 -5
- data/lib/mini_magick.rb +54 -65
- metadata +49 -51
- data/lib/mini_magick/command_builder.rb +0 -94
- data/lib/mini_magick/errors.rb +0 -4
- data/spec/files/actually_a_gif.jpg +0 -0
- data/spec/files/animation.gif +0 -0
- data/spec/files/composited.jpg +0 -0
- data/spec/files/erroneous.jpg +0 -0
- data/spec/files/layers.psd +0 -0
- data/spec/files/leaves (spaced).tiff +0 -0
- data/spec/files/not_an_image.php +0 -1
- data/spec/files/png.png +0 -0
- data/spec/files/simple-minus.gif +0 -0
- data/spec/files/simple.gif +0 -0
- data/spec/files/trogdor.jpg +0 -0
- data/spec/files/trogdor_capitalized.JPG +0 -0
- data/spec/lib/mini_magick/command_builder_spec.rb +0 -153
- data/spec/lib/mini_magick/image_spec.rb +0 -499
- data/spec/lib/mini_magick_spec.rb +0 -63
- data/spec/spec_helper.rb +0 -29
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
|
-
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
2
|
+
SHA256:
|
3
|
+
metadata.gz: 3ab4ce03957b9a0f941f9bd2c34a5dcab63faffac5143eb6e7c90d7d860b57c5
|
4
|
+
data.tar.gz: 7bd78f0c862f1ca72b34e3c6fc4d14297adfa9dd6bc36218a35ef68c235320b5
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: 16c4bfa3744a2bea117bff0118afcbf89fac2f3d9e92c5c8af2b095f6c1381c1d000bede5086ccffd72ecca8152845cde11a5ff762186bd90793ee5d83e03a77
|
7
|
+
data.tar.gz: fe593ad2a7bfd4b6f2d9892533fd5347046e7dfb6cfd8e3bc6049cb1ae7686f5af60c23f33254175bca4728a58bdeeab2b9bfb873ebd94c46f14e68e086f002f
|
data/lib/mini_gmagick.rb
CHANGED
@@ -0,0 +1,198 @@
|
|
1
|
+
require 'mini_magick/utilities'
|
2
|
+
require 'logger'
|
3
|
+
|
4
|
+
module MiniMagick
|
5
|
+
module Configuration
|
6
|
+
|
7
|
+
##
|
8
|
+
# Set whether you want to use [ImageMagick](http://www.imagemagick.org) or
|
9
|
+
# [GraphicsMagick](http://www.graphicsmagick.org).
|
10
|
+
#
|
11
|
+
# @return [Symbol] `:imagemagick`, `:imagemagick7`, or `:graphicsmagick`
|
12
|
+
#
|
13
|
+
attr_accessor :cli
|
14
|
+
|
15
|
+
##
|
16
|
+
# If you don't have the CLI tools in your PATH, you can set the path to the
|
17
|
+
# executables.
|
18
|
+
#
|
19
|
+
attr_writer :cli_path
|
20
|
+
# @private (for backwards compatibility)
|
21
|
+
attr_accessor :processor_path
|
22
|
+
|
23
|
+
##
|
24
|
+
# Adds a prefix to the CLI command.
|
25
|
+
# For example, you could use `firejail` to run all commands in a sandbox.
|
26
|
+
# Can be a string, or an array of strings.
|
27
|
+
# e.g. 'firejail', or ['firejail', '--force']
|
28
|
+
#
|
29
|
+
# @return [String]
|
30
|
+
# @return [Array<String>]
|
31
|
+
#
|
32
|
+
attr_accessor :cli_prefix
|
33
|
+
|
34
|
+
##
|
35
|
+
# If you don't want commands to take too long, you can set a timeout (in
|
36
|
+
# seconds).
|
37
|
+
#
|
38
|
+
# @return [Integer]
|
39
|
+
#
|
40
|
+
attr_accessor :timeout
|
41
|
+
##
|
42
|
+
# When get to `true`, it outputs each command to STDOUT in their shell
|
43
|
+
# version.
|
44
|
+
#
|
45
|
+
# @return [Boolean]
|
46
|
+
#
|
47
|
+
attr_reader :debug
|
48
|
+
##
|
49
|
+
# Logger for {#debug}, default is `MiniMagick::Logger.new(STDOUT)`, but
|
50
|
+
# you can override it, for example if you want the logs to be written to
|
51
|
+
# a file.
|
52
|
+
#
|
53
|
+
# @return [Logger]
|
54
|
+
#
|
55
|
+
attr_accessor :logger
|
56
|
+
|
57
|
+
##
|
58
|
+
# If set to `true`, it will `identify` every newly created image, and raise
|
59
|
+
# `MiniMagick::Invalid` if the image is not valid. Useful for validating
|
60
|
+
# user input, although it adds a bit of overhead. Defaults to `true`.
|
61
|
+
#
|
62
|
+
# @return [Boolean]
|
63
|
+
#
|
64
|
+
attr_accessor :validate_on_create
|
65
|
+
##
|
66
|
+
# If set to `true`, it will `identify` every image that gets written (with
|
67
|
+
# {MiniMagick::Image#write}), and raise `MiniMagick::Invalid` if the image
|
68
|
+
# is not valid. Useful for validating that processing was sucessful,
|
69
|
+
# although it adds a bit of overhead. Defaults to `true`.
|
70
|
+
#
|
71
|
+
# @return [Boolean]
|
72
|
+
#
|
73
|
+
attr_accessor :validate_on_write
|
74
|
+
|
75
|
+
##
|
76
|
+
# If set to `false`, it will not raise errors when ImageMagick returns
|
77
|
+
# status code different than 0. Defaults to `true`.
|
78
|
+
#
|
79
|
+
# @return [Boolean]
|
80
|
+
#
|
81
|
+
attr_accessor :whiny
|
82
|
+
|
83
|
+
##
|
84
|
+
# Instructs MiniMagick how to execute the shell commands. Available
|
85
|
+
# APIs are "open3" (default) and "posix-spawn" (requires the "posix-spawn"
|
86
|
+
# gem).
|
87
|
+
#
|
88
|
+
# @return [String]
|
89
|
+
#
|
90
|
+
attr_accessor :shell_api
|
91
|
+
|
92
|
+
def self.extended(base)
|
93
|
+
base.validate_on_create = true
|
94
|
+
base.validate_on_write = true
|
95
|
+
base.whiny = true
|
96
|
+
base.shell_api = "open3"
|
97
|
+
base.logger = Logger.new($stdout).tap { |l| l.level = Logger::INFO }
|
98
|
+
end
|
99
|
+
|
100
|
+
##
|
101
|
+
# @yield [self]
|
102
|
+
# @example
|
103
|
+
# MiniMagick.configure do |config|
|
104
|
+
# config.cli = :graphicsmagick
|
105
|
+
# config.timeout = 5
|
106
|
+
# end
|
107
|
+
#
|
108
|
+
def configure
|
109
|
+
yield self
|
110
|
+
end
|
111
|
+
|
112
|
+
CLI_DETECTION = {
|
113
|
+
imagemagick: "mogrify",
|
114
|
+
graphicsmagick: "gm",
|
115
|
+
imagemagick7: "magick",
|
116
|
+
}
|
117
|
+
|
118
|
+
# @private (for backwards compatibility)
|
119
|
+
def processor
|
120
|
+
@processor ||= CLI_DETECTION.values.detect do |processor|
|
121
|
+
MiniMagick::Utilities.which(processor)
|
122
|
+
end
|
123
|
+
end
|
124
|
+
|
125
|
+
# @private (for backwards compatibility)
|
126
|
+
def processor=(processor)
|
127
|
+
@processor = processor.to_s
|
128
|
+
|
129
|
+
unless CLI_DETECTION.value?(@processor)
|
130
|
+
raise ArgumentError,
|
131
|
+
"processor has to be set to either \"magick\", \"mogrify\" or \"gm\"" \
|
132
|
+
", was set to #{@processor.inspect}"
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
##
|
137
|
+
# Get [ImageMagick](http://www.imagemagick.org) or
|
138
|
+
# [GraphicsMagick](http://www.graphicsmagick.org).
|
139
|
+
#
|
140
|
+
# @return [Symbol] `:imagemagick` or `:graphicsmagick`
|
141
|
+
#
|
142
|
+
def cli
|
143
|
+
if instance_variable_defined?("@cli")
|
144
|
+
instance_variable_get("@cli")
|
145
|
+
else
|
146
|
+
cli = CLI_DETECTION.key(processor) or
|
147
|
+
fail MiniMagick::Error, "You must have ImageMagick or GraphicsMagick installed"
|
148
|
+
|
149
|
+
instance_variable_set("@cli", cli)
|
150
|
+
end
|
151
|
+
end
|
152
|
+
|
153
|
+
##
|
154
|
+
# Set whether you want to use [ImageMagick](http://www.imagemagick.org) or
|
155
|
+
# [GraphicsMagick](http://www.graphicsmagick.org).
|
156
|
+
#
|
157
|
+
def cli=(value)
|
158
|
+
@cli = value
|
159
|
+
|
160
|
+
if not CLI_DETECTION.key?(@cli)
|
161
|
+
raise ArgumentError,
|
162
|
+
"CLI has to be set to either :imagemagick, :imagemagick7 or :graphicsmagick" \
|
163
|
+
", was set to #{@cli.inspect}"
|
164
|
+
end
|
165
|
+
end
|
166
|
+
|
167
|
+
##
|
168
|
+
# If you set the path of CLI tools, you can get the path of the
|
169
|
+
# executables.
|
170
|
+
#
|
171
|
+
# @return [String]
|
172
|
+
#
|
173
|
+
def cli_path
|
174
|
+
if instance_variable_defined?("@cli_path")
|
175
|
+
instance_variable_get("@cli_path")
|
176
|
+
else
|
177
|
+
processor_path = instance_variable_get("@processor_path") if instance_variable_defined?("@processor_path")
|
178
|
+
|
179
|
+
instance_variable_set("@cli_path", processor_path)
|
180
|
+
end
|
181
|
+
end
|
182
|
+
|
183
|
+
##
|
184
|
+
# When set to `true`, it outputs each command to STDOUT in their shell
|
185
|
+
# version.
|
186
|
+
#
|
187
|
+
def debug=(value)
|
188
|
+
warn "MiniMagick.debug is deprecated and will be removed in MiniMagick 5. Use `MiniMagick.logger.level = Logger::DEBUG` instead."
|
189
|
+
logger.level = value ? Logger::DEBUG : Logger::INFO
|
190
|
+
end
|
191
|
+
|
192
|
+
# Backwards compatibility
|
193
|
+
def reload_tools
|
194
|
+
warn "MiniMagick.reload_tools is deprecated because it is no longer necessary"
|
195
|
+
end
|
196
|
+
|
197
|
+
end
|
198
|
+
end
|
@@ -0,0 +1,192 @@
|
|
1
|
+
require "json"
|
2
|
+
|
3
|
+
module MiniMagick
|
4
|
+
class Image
|
5
|
+
# @private
|
6
|
+
class Info
|
7
|
+
ASCII_ENCODED_EXIF_KEYS = %w[ExifVersion FlashPixVersion]
|
8
|
+
|
9
|
+
def initialize(path)
|
10
|
+
@path = path
|
11
|
+
@info = {}
|
12
|
+
end
|
13
|
+
|
14
|
+
def [](value, *args)
|
15
|
+
case value
|
16
|
+
when "format", "width", "height", "dimensions", "size", "human_size"
|
17
|
+
cheap_info(value)
|
18
|
+
when "colorspace"
|
19
|
+
colorspace
|
20
|
+
when "mime_type"
|
21
|
+
mime_type
|
22
|
+
when "resolution"
|
23
|
+
resolution(*args)
|
24
|
+
when "signature"
|
25
|
+
signature
|
26
|
+
when /^EXIF\:/i
|
27
|
+
raw_exif(value)
|
28
|
+
when "exif"
|
29
|
+
exif
|
30
|
+
when "details"
|
31
|
+
details
|
32
|
+
when "data"
|
33
|
+
data
|
34
|
+
else
|
35
|
+
raw(value)
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
def clear
|
40
|
+
@info.clear
|
41
|
+
end
|
42
|
+
|
43
|
+
def cheap_info(value)
|
44
|
+
@info.fetch(value) do
|
45
|
+
format, width, height, size = self["%m %w %h %b"].split(" ")
|
46
|
+
|
47
|
+
path = @path
|
48
|
+
path = path.match(/\[\d+\]$/).pre_match if path =~ /\[\d+\]$/
|
49
|
+
|
50
|
+
@info.update(
|
51
|
+
"format" => format,
|
52
|
+
"width" => Integer(width),
|
53
|
+
"height" => Integer(height),
|
54
|
+
"dimensions" => [Integer(width), Integer(height)],
|
55
|
+
"size" => File.size(path),
|
56
|
+
"human_size" => size,
|
57
|
+
)
|
58
|
+
|
59
|
+
@info.fetch(value)
|
60
|
+
end
|
61
|
+
rescue ArgumentError, TypeError
|
62
|
+
raise MiniMagick::Invalid, "image data can't be read"
|
63
|
+
end
|
64
|
+
|
65
|
+
def colorspace
|
66
|
+
@info["colorspace"] ||= self["%r"]
|
67
|
+
end
|
68
|
+
|
69
|
+
def mime_type
|
70
|
+
"image/#{self["format"].downcase}"
|
71
|
+
end
|
72
|
+
|
73
|
+
def resolution(unit = nil)
|
74
|
+
output = identify do |b|
|
75
|
+
b.units unit if unit
|
76
|
+
b.format "%x %y"
|
77
|
+
end
|
78
|
+
output.split(" ").map(&:to_i)
|
79
|
+
end
|
80
|
+
|
81
|
+
def raw_exif(value)
|
82
|
+
self["%[#{value}]"]
|
83
|
+
end
|
84
|
+
|
85
|
+
def exif
|
86
|
+
@info["exif"] ||= (
|
87
|
+
hash = {}
|
88
|
+
output = self["%[EXIF:*]"]
|
89
|
+
|
90
|
+
output.each_line do |line|
|
91
|
+
line = line.chomp("\n")
|
92
|
+
|
93
|
+
case MiniMagick.cli
|
94
|
+
when :imagemagick, :imagemagick7
|
95
|
+
if match = line.match(/^exif:/)
|
96
|
+
key, value = match.post_match.split("=", 2)
|
97
|
+
value = decode_comma_separated_ascii_characters(value) if ASCII_ENCODED_EXIF_KEYS.include?(key)
|
98
|
+
hash[key] = value
|
99
|
+
else
|
100
|
+
hash[hash.keys.last] << "\n#{line}"
|
101
|
+
end
|
102
|
+
when :graphicsmagick
|
103
|
+
next if line == "unknown"
|
104
|
+
key, value = line.split("=", 2)
|
105
|
+
value.gsub!("\\012", "\n") # convert "\012" characters to newlines
|
106
|
+
hash[key] = value
|
107
|
+
end
|
108
|
+
end
|
109
|
+
|
110
|
+
hash
|
111
|
+
)
|
112
|
+
end
|
113
|
+
|
114
|
+
def raw(value)
|
115
|
+
@info["raw:#{value}"] ||= identify { |b| b.format(value) }
|
116
|
+
end
|
117
|
+
|
118
|
+
def signature
|
119
|
+
@info["signature"] ||= self["%#"]
|
120
|
+
end
|
121
|
+
|
122
|
+
def details
|
123
|
+
warn "[MiniMagick] MiniMagick::Image#details has been deprecated, as it was causing too many parsing errors. You should use MiniMagick::Image#data instead, which differs in a way that the keys are in camelcase." if MiniMagick.imagemagick? || MiniMagick.imagemagick7?
|
124
|
+
|
125
|
+
@info["details"] ||= (
|
126
|
+
details_string = identify(&:verbose)
|
127
|
+
key_stack = []
|
128
|
+
details_string.lines.to_a[1..-1].each_with_object({}) do |line, details_hash|
|
129
|
+
next if !line.valid_encoding? || line.strip.length.zero?
|
130
|
+
|
131
|
+
level = line[/^\s*/].length / 2 - 1
|
132
|
+
if level >= 0
|
133
|
+
key_stack.pop until key_stack.size <= level
|
134
|
+
else
|
135
|
+
# Some metadata, such as SVG clipping paths, will be saved without
|
136
|
+
# indentation, resulting in a level of -1
|
137
|
+
last_key = details_hash.keys.last
|
138
|
+
details_hash[last_key] = '' if details_hash[last_key].empty?
|
139
|
+
details_hash[last_key] << line
|
140
|
+
next
|
141
|
+
end
|
142
|
+
|
143
|
+
key, _, value = line.partition(/:[\s]/).map(&:strip)
|
144
|
+
hash = key_stack.inject(details_hash) { |_hash, _key| _hash.fetch(_key) }
|
145
|
+
if value.empty?
|
146
|
+
hash[key] = {}
|
147
|
+
key_stack.push key
|
148
|
+
else
|
149
|
+
hash[key] = value
|
150
|
+
end
|
151
|
+
end
|
152
|
+
)
|
153
|
+
end
|
154
|
+
|
155
|
+
def data
|
156
|
+
raise Error, "MiniMagick::Image#data isn't supported on GraphicsMagick. Use MiniMagick::Image#details instead." if MiniMagick.graphicsmagick?
|
157
|
+
|
158
|
+
@info["data"] ||= (
|
159
|
+
json = MiniMagick::Tool::Convert.new do |convert|
|
160
|
+
convert << path
|
161
|
+
convert << "json:"
|
162
|
+
end
|
163
|
+
|
164
|
+
data = JSON.parse(json)
|
165
|
+
data = data.fetch(0) if data.is_a?(Array)
|
166
|
+
data.fetch("image")
|
167
|
+
)
|
168
|
+
end
|
169
|
+
|
170
|
+
def identify
|
171
|
+
MiniMagick::Tool::Identify.new do |builder|
|
172
|
+
yield builder if block_given?
|
173
|
+
builder << path
|
174
|
+
end
|
175
|
+
end
|
176
|
+
|
177
|
+
private
|
178
|
+
|
179
|
+
def decode_comma_separated_ascii_characters(encoded_value)
|
180
|
+
return encoded_value unless encoded_value.include?(',')
|
181
|
+
encoded_value.scan(/\d+/).map(&:to_i).map(&:chr).join
|
182
|
+
end
|
183
|
+
|
184
|
+
def path
|
185
|
+
value = @path
|
186
|
+
value += "[0]" unless value =~ /\[\d+\]$/
|
187
|
+
value
|
188
|
+
end
|
189
|
+
|
190
|
+
end
|
191
|
+
end
|
192
|
+
end
|