mini_magick 3.7.0 → 3.8.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.
Potentially problematic release.
This version of mini_magick might be problematic. Click here for more details.
- checksums.yaml +4 -4
- data/Rakefile +3 -3
- data/lib/mini_magick.rb +22 -13
- data/lib/mini_magick/command_builder.rb +25 -19
- data/lib/mini_magick/image.rb +134 -97
- data/lib/mini_magick/utilities.rb +11 -6
- data/lib/mini_magick/version.rb +1 -1
- metadata +23 -18
checksums.yaml
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
---
|
2
2
|
SHA1:
|
3
|
-
metadata.gz:
|
4
|
-
data.tar.gz:
|
3
|
+
metadata.gz: 7708f032a0b010ff31ed437bd5f28c5bdf4b269b
|
4
|
+
data.tar.gz: 866153c83f7e87dfe3d1564ca32821221240d6a4
|
5
5
|
SHA512:
|
6
|
-
metadata.gz:
|
7
|
-
data.tar.gz:
|
6
|
+
metadata.gz: f1af9965e59c483a1566299d984f1657a2fc673c398a07e2fc07fb8e3d821eb9ec4f4f6fbcbcbb2f4497714f703f410ab64bc2b02ded74cb952b019171663ef7
|
7
|
+
data.tar.gz: efe209dfdd7bedd32e7d44dc49cdda24e339a68e49fe4cfbfa900edb60c7a7b9c9627316df330d8ab90a6054e03f6db213c6360313d4ce26d35c925094437a11
|
data/Rakefile
CHANGED
@@ -6,13 +6,13 @@ $:.unshift 'lib'
|
|
6
6
|
desc 'Default: run unit tests.'
|
7
7
|
task :default => [:print_version, :spec]
|
8
8
|
|
9
|
-
task :print_version do
|
9
|
+
task :print_version do
|
10
10
|
puts `mogrify --version`
|
11
11
|
end
|
12
12
|
|
13
13
|
require 'rspec/core/rake_task'
|
14
14
|
|
15
|
-
desc
|
15
|
+
desc 'Run specs'
|
16
16
|
RSpec::Core::RakeTask.new do |t|
|
17
|
-
t.pattern =
|
17
|
+
t.pattern = './spec/**/*_spec.rb'
|
18
18
|
end
|
data/lib/mini_magick.rb
CHANGED
@@ -9,10 +9,15 @@ require 'mini_magick/image'
|
|
9
9
|
require 'mini_magick/utilities'
|
10
10
|
|
11
11
|
module MiniMagick
|
12
|
+
@validate_on_create = true
|
13
|
+
@validate_on_write = true
|
14
|
+
|
12
15
|
class << self
|
13
16
|
attr_accessor :processor
|
14
17
|
attr_accessor :processor_path
|
15
18
|
attr_accessor :timeout
|
19
|
+
attr_accessor :validate_on_create
|
20
|
+
attr_accessor :validate_on_write
|
16
21
|
|
17
22
|
##
|
18
23
|
# Tries to detect the current processor based if any of the processors exist.
|
@@ -21,29 +26,31 @@ module MiniMagick
|
|
21
26
|
# === Returns
|
22
27
|
# * [String] The detected procesor
|
23
28
|
def choose_processor
|
24
|
-
if MiniMagick::Utilities.which('mogrify')
|
25
|
-
|
26
|
-
|
27
|
-
|
28
|
-
|
29
|
+
self.processor = if MiniMagick::Utilities.which('mogrify')
|
30
|
+
:mogrify
|
31
|
+
elsif MiniMagick::Utilities.which('gm')
|
32
|
+
:gm
|
33
|
+
else
|
34
|
+
nil
|
35
|
+
end
|
29
36
|
end
|
30
|
-
|
37
|
+
|
31
38
|
##
|
32
39
|
# Discovers the imagemagick version based on mogrify's output.
|
33
40
|
#
|
34
41
|
# === Returns
|
35
42
|
# * The imagemagick version
|
36
43
|
def image_magick_version
|
37
|
-
@@version ||= Gem::Version.create(`mogrify --version`.split(
|
44
|
+
@@version ||= Gem::Version.create(`mogrify --version`.split(' ')[2].split('-').first)
|
38
45
|
end
|
39
|
-
|
46
|
+
|
40
47
|
##
|
41
48
|
# The minimum allowed imagemagick version
|
42
49
|
#
|
43
50
|
# === Returns
|
44
51
|
# * The minimum imagemagick version
|
45
52
|
def minimum_image_magick_version
|
46
|
-
@@minimum_version ||= Gem::Version.create(
|
53
|
+
@@minimum_version ||= Gem::Version.create('6.6.3')
|
47
54
|
end
|
48
55
|
|
49
56
|
##
|
@@ -61,9 +68,10 @@ module MiniMagick
|
|
61
68
|
# === Returns
|
62
69
|
# * [Boolean]
|
63
70
|
def mogrify?
|
64
|
-
|
71
|
+
choose_processor if processor.nil?
|
65
72
|
|
66
|
-
|
73
|
+
return processor.to_s.downcase.to_sym == :mogrify unless processor.nil?
|
74
|
+
false
|
67
75
|
end
|
68
76
|
|
69
77
|
##
|
@@ -72,9 +80,10 @@ module MiniMagick
|
|
72
80
|
# === Returns
|
73
81
|
# * [Boolean]
|
74
82
|
def gm?
|
75
|
-
|
83
|
+
choose_processor if processor.nil?
|
76
84
|
|
77
|
-
|
85
|
+
return processor.to_s.downcase.to_sym == :gm unless processor.nil?
|
86
|
+
false
|
78
87
|
end
|
79
88
|
end
|
80
89
|
end
|
@@ -1,7 +1,7 @@
|
|
1
1
|
module MiniMagick
|
2
2
|
class CommandBuilder
|
3
|
-
MOGRIFY_COMMANDS = %w
|
4
|
-
IMAGE_CREATION_OPERATORS = %w
|
3
|
+
MOGRIFY_COMMANDS = %w(adaptive-blur adaptive-resize adaptive-sharpen adjoin affine alpha annotate antialias append attenuate authenticate auto-gamma auto-level auto-orient backdrop background bench bias black-point-compensation black-threshold blend blue-primary blue-shift blur border bordercolor borderwidth brightness-contrast cache caption cdl channel charcoal chop clamp clip clip-mask clip-path clone clut coalesce colorize colormap color-matrix colors colorspace combine comment compose composite compress contrast contrast-stretch convolve crop cycle debug decipher deconstruct define delay delete density depth descend deskew despeckle direction displace display dispose dissimilarity-threshold dissolve distort dither draw duplicate edge emboss encipher encoding endian enhance equalize evaluate evaluate-sequence extent extract family features fft fill filter flatten flip floodfill flop font foreground format frame function fuzz fx gamma gaussian-blur geometry gravity green-primary hald-clut help highlight-color iconGeometry iconic identify ift immutable implode insert intent interlace interpolate interline-spacing interword-spacing kerning label lat layers level level-colors limit linear-stretch linewidth liquid-rescale list log loop lowlight-color magnify map mask mattecolor median metric mode modulate monitor monochrome morph morphology mosaic motion-blur name negate noise normalize opaque ordered-dither orient page paint path pause pen perceptible ping pointsize polaroid poly posterize precision preview print process profile quality quantize quiet radial-blur raise random-threshold red-primary regard-warnings region remap remote render repage resample resize respect-parentheses reverse roll rotate sample sampling-factor scale scene screen seed segment selective-blur separate sepia-tone set shade shadow shared-memory sharpen shave shear sigmoidal-contrast silent size sketch smush snaps solarize sparse-color splice spread statistic stegano stereo stretch strip stroke strokewidth style subimage-search swap swirl synchronize taint text-font texture threshold thumbnail tile tile-offset tint title transform transparent transparent-color transpose transverse treedepth trim type undercolor unique-colors units unsharp update verbose version view vignette virtual-pixel visual watermark wave weight white-point white-threshold window window-group write)
|
4
|
+
IMAGE_CREATION_OPERATORS = %w(canvas caption gradient label logo pattern plasma radial radient rose text tile xc)
|
5
5
|
|
6
6
|
def initialize(tool, *options)
|
7
7
|
@tool = tool
|
@@ -17,22 +17,11 @@ module MiniMagick
|
|
17
17
|
com.strip
|
18
18
|
end
|
19
19
|
|
20
|
-
def escape_string_windows(value)
|
21
|
-
# For Windows, ^ is the escape char, equivalent to \ in Unix.
|
22
|
-
escaped = value.gsub(/\^/, '^^').gsub(/>/, '^>')
|
23
|
-
if escaped !~ /^".+"$/ && escaped.include?("'")
|
24
|
-
escaped.inspect
|
25
|
-
else
|
26
|
-
escaped
|
27
|
-
end
|
28
|
-
|
29
|
-
end
|
30
|
-
|
31
20
|
def args
|
32
21
|
if !MiniMagick::Utilities.windows?
|
33
22
|
@args.map(&:shellescape)
|
34
23
|
else
|
35
|
-
@args.map { |arg|
|
24
|
+
@args.map { |arg| Utilities.windows_escape(arg) }
|
36
25
|
end
|
37
26
|
end
|
38
27
|
|
@@ -47,18 +36,21 @@ module MiniMagick
|
|
47
36
|
# end
|
48
37
|
# alias_method :"auto-orient", :auto_orient
|
49
38
|
|
50
|
-
dashed_command = mogrify_command.to_s.gsub(
|
51
|
-
underscored_command = mogrify_command.to_s.gsub(
|
39
|
+
dashed_command = mogrify_command.to_s.gsub('_', '-')
|
40
|
+
underscored_command = mogrify_command.to_s.gsub('-', '_')
|
52
41
|
|
53
42
|
define_method(underscored_command) do |*options|
|
54
|
-
|
43
|
+
options[1] = Utilities.windows_escape(options[1]) if mogrify_command == 'annotate'
|
44
|
+
add_command(__method__.to_s.gsub('_', '-'), *options)
|
55
45
|
self
|
56
46
|
end
|
47
|
+
|
57
48
|
alias_method dashed_command, underscored_command
|
49
|
+
alias_method "mogrify_#{underscored_command}", underscored_command
|
58
50
|
end
|
59
51
|
|
60
52
|
def format(*options)
|
61
|
-
|
53
|
+
fail Error, "You must call 'format' on the image object directly!"
|
62
54
|
end
|
63
55
|
|
64
56
|
IMAGE_CREATION_OPERATORS.each do |operator|
|
@@ -66,6 +58,20 @@ module MiniMagick
|
|
66
58
|
add_creation_operator(__method__.to_s, *options)
|
67
59
|
self
|
68
60
|
end
|
61
|
+
|
62
|
+
alias_method "operator_#{operator}", operator
|
63
|
+
end
|
64
|
+
|
65
|
+
(MOGRIFY_COMMANDS & IMAGE_CREATION_OPERATORS).each do |command_or_operator|
|
66
|
+
define_method command_or_operator do |*options|
|
67
|
+
if @tool == 'mogrify'
|
68
|
+
method = self.method("mogrify_#{command_or_operator}")
|
69
|
+
else
|
70
|
+
method = self.method("operator_#{command_or_operator}")
|
71
|
+
end
|
72
|
+
method.call(*options)
|
73
|
+
end
|
74
|
+
|
69
75
|
end
|
70
76
|
|
71
77
|
def +(*options)
|
@@ -99,6 +105,6 @@ module MiniMagick
|
|
99
105
|
def push(arg)
|
100
106
|
@args << arg.to_s.strip
|
101
107
|
end
|
102
|
-
|
108
|
+
alias_method :<<, :push
|
103
109
|
end
|
104
110
|
end
|
data/lib/mini_magick/image.rb
CHANGED
@@ -1,7 +1,7 @@
|
|
1
1
|
module MiniMagick
|
2
2
|
class Image
|
3
3
|
# @return [String] The location of the current working file
|
4
|
-
|
4
|
+
attr_writer :path
|
5
5
|
|
6
6
|
def path_for_windows_quote_space(path)
|
7
7
|
path = Pathname.new(@path).to_s
|
@@ -11,13 +11,10 @@ module MiniMagick
|
|
11
11
|
end
|
12
12
|
|
13
13
|
def path
|
14
|
+
run_queue if @command_queued
|
14
15
|
MiniMagick::Utilities.windows? ? path_for_windows_quote_space(@path) : @path
|
15
16
|
end
|
16
17
|
|
17
|
-
def path=(path)
|
18
|
-
@path = path
|
19
|
-
end
|
20
|
-
|
21
18
|
# Class Methods
|
22
19
|
# -------------
|
23
20
|
class << self
|
@@ -25,12 +22,14 @@ module MiniMagick
|
|
25
22
|
#
|
26
23
|
# Use this to pass in a stream object. Must respond to Object#read(size) or be a binary string object (BLOBBBB)
|
27
24
|
#
|
28
|
-
# As a change from the old API, please try and use IOStream objects.
|
25
|
+
# As a change from the old API, please try and use IOStream objects.
|
26
|
+
# They are much, much better and more efficient!
|
29
27
|
#
|
30
28
|
# Probably easier to use the #open method if you want to open a file or a URL.
|
31
29
|
#
|
32
30
|
# @param stream [IOStream, String] Some kind of stream object that needs to be read or is a binary String blob!
|
33
|
-
# @param ext [String] A manual extension to use for reading the file. Not required, but if you are having issues,
|
31
|
+
# @param ext [String] A manual extension to use for reading the file. Not required, but if you are having issues,
|
32
|
+
# give this a try.
|
34
33
|
# @return [Image]
|
35
34
|
def read(stream, ext = nil)
|
36
35
|
if stream.is_a?(String)
|
@@ -41,7 +40,7 @@ module MiniMagick
|
|
41
40
|
if File.respond_to?(:binread)
|
42
41
|
stream = StringIO.new File.binread(stream.path.to_s)
|
43
42
|
else
|
44
|
-
stream = StringIO.new File.open(stream.path.to_s,
|
43
|
+
stream = StringIO.new File.open(stream.path.to_s, 'rb') { |f| f.read }
|
45
44
|
end
|
46
45
|
end
|
47
46
|
|
@@ -54,7 +53,7 @@ module MiniMagick
|
|
54
53
|
|
55
54
|
# @deprecated Please use Image.read instead!
|
56
55
|
def from_blob(blob, ext = nil)
|
57
|
-
warn
|
56
|
+
warn 'Warning: MiniMagick::Image.from_blob method is deprecated. Instead, please use Image.read'
|
58
57
|
create(ext) { |f| f.write(blob) }
|
59
58
|
end
|
60
59
|
|
@@ -71,15 +70,16 @@ module MiniMagick
|
|
71
70
|
# * [rows] <tt>Integer</tt> -- Number of rows.
|
72
71
|
# * [depth] <tt>Integer</tt> -- Bit depth of the encoded pixel data.
|
73
72
|
# * [map] <tt>String</tt> -- A code for the mapping of the pixel data. Example: 'gray' or 'rgb'.
|
74
|
-
# * [format] <tt>String</tt> -- The file extension of the image format to be used when creating the image object.
|
73
|
+
# * [format] <tt>String</tt> -- The file extension of the image format to be used when creating the image object.
|
74
|
+
# Defaults to 'png'.
|
75
75
|
#
|
76
|
-
def import_pixels(blob, columns, rows, depth, map, format=
|
76
|
+
def import_pixels(blob, columns, rows, depth, map, format = 'png')
|
77
77
|
# Create an image object with the raw pixel data string:
|
78
|
-
image = create(
|
78
|
+
image = create('.dat', false) { |f| f.write(blob) }
|
79
79
|
# Use ImageMagick to convert the raw data file to an image file of the desired format:
|
80
80
|
converted_image_path = image.path[0..-4] + format
|
81
|
-
arguments = [
|
82
|
-
cmd = CommandBuilder.new(
|
81
|
+
arguments = ['-size', "#{columns}x#{rows}", '-depth', "#{depth}", "#{map}:#{image.path}", "#{converted_image_path}"]
|
82
|
+
cmd = CommandBuilder.new('convert', *arguments) # Example: convert -size 256x256 -depth 16 gray:blob.dat blob.png
|
83
83
|
image.run(cmd)
|
84
84
|
# Update the image instance with the path of the properly formatted image, and return:
|
85
85
|
image.path = converted_image_path
|
@@ -98,24 +98,24 @@ module MiniMagick
|
|
98
98
|
# @param ext [String] Specify the extension you want to read it as
|
99
99
|
# @return [Image] The loaded image
|
100
100
|
def open(file_or_url, ext = nil)
|
101
|
-
file_or_url = file_or_url.to_s # Force it to be a String...
|
102
|
-
if file_or_url.include?(
|
101
|
+
file_or_url = file_or_url.to_s # Force it to be a String... Hell or high water
|
102
|
+
if file_or_url.include?('://')
|
103
103
|
require 'open-uri'
|
104
104
|
ext ||= File.extname(URI.parse(file_or_url).path)
|
105
|
-
Kernel
|
106
|
-
|
105
|
+
Kernel.open(file_or_url) do |f|
|
106
|
+
read(f, ext)
|
107
107
|
end
|
108
108
|
else
|
109
109
|
ext ||= File.extname(file_or_url)
|
110
|
-
File.open(file_or_url,
|
111
|
-
|
110
|
+
File.open(file_or_url, 'rb') do |f|
|
111
|
+
read(f, ext)
|
112
112
|
end
|
113
113
|
end
|
114
114
|
end
|
115
115
|
|
116
116
|
# @deprecated Please use MiniMagick::Image.open(file_or_url) now
|
117
117
|
def from_file(file, ext = nil)
|
118
|
-
warn
|
118
|
+
warn 'Warning: MiniMagick::Image.from_file is now deprecated. Please use Image.open'
|
119
119
|
open(file, ext)
|
120
120
|
end
|
121
121
|
|
@@ -128,18 +128,16 @@ module MiniMagick
|
|
128
128
|
# @param validate [Boolean] If false, skips validation of the created image. Defaults to true.
|
129
129
|
# @yield [IOStream] You can #write bits to this object to create the new Image
|
130
130
|
# @return [Image] The created image
|
131
|
-
def create(ext = nil, validate =
|
131
|
+
def create(ext = nil, validate = MiniMagick.validate_on_create, &block)
|
132
132
|
begin
|
133
133
|
tempfile = Tempfile.new(['mini_magick', ext.to_s.downcase])
|
134
134
|
tempfile.binmode
|
135
135
|
block.call(tempfile)
|
136
136
|
tempfile.close
|
137
137
|
|
138
|
-
image =
|
138
|
+
image = new(tempfile.path, tempfile)
|
139
139
|
|
140
|
-
if validate
|
141
|
-
raise MiniMagick::Invalid
|
142
|
-
end
|
140
|
+
fail MiniMagick::Invalid if validate && !image.valid?
|
143
141
|
return image
|
144
142
|
ensure
|
145
143
|
tempfile.close if tempfile
|
@@ -158,6 +156,21 @@ module MiniMagick
|
|
158
156
|
def initialize(input_path, tempfile = nil)
|
159
157
|
@path = input_path
|
160
158
|
@tempfile = tempfile # ensures that the tempfile will stick around until this image is garbage collected.
|
159
|
+
@info = {}
|
160
|
+
reset_queue
|
161
|
+
end
|
162
|
+
|
163
|
+
def reset_queue
|
164
|
+
@command_queued = false
|
165
|
+
@queue = MiniMagick::CommandBuilder.new('mogrify')
|
166
|
+
@info.clear
|
167
|
+
end
|
168
|
+
|
169
|
+
def run_queue
|
170
|
+
return nil unless @command_queued
|
171
|
+
@queue << (MiniMagick::Utilities.windows? ? path_for_windows_quote_space(@path) : @path)
|
172
|
+
run(@queue)
|
173
|
+
reset_queue
|
161
174
|
end
|
162
175
|
|
163
176
|
# Checks to make sure that MiniMagick can read the file and understand it.
|
@@ -168,12 +181,17 @@ module MiniMagick
|
|
168
181
|
#
|
169
182
|
# @return [Boolean]
|
170
183
|
def valid?
|
171
|
-
run_command(
|
184
|
+
run_command('identify', path)
|
172
185
|
true
|
173
186
|
rescue MiniMagick::Invalid
|
174
187
|
false
|
175
188
|
end
|
176
189
|
|
190
|
+
def info(key)
|
191
|
+
run_queue if @command_queued
|
192
|
+
|
193
|
+
@info[key]
|
194
|
+
end
|
177
195
|
# A rather low-level way to interact with the "identify" command. No nice API here, just
|
178
196
|
# the crazy stuff you find in ImageMagick. See the examples listed!
|
179
197
|
#
|
@@ -191,33 +209,42 @@ module MiniMagick
|
|
191
209
|
# @see For reference see http://www.imagemagick.org/script/command-line-options.php#format
|
192
210
|
# @return [String, Numeric, Array, Time, Object] Depends on the method called! Defaults to String for unknown commands
|
193
211
|
def [](value)
|
212
|
+
retrieved = info(value)
|
213
|
+
return retrieved unless retrieved.nil?
|
214
|
+
|
194
215
|
# Why do I go to the trouble of putting in newlines? Because otherwise animated gifs screw everything up
|
195
|
-
case value.to_s
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
205
|
-
|
206
|
-
|
207
|
-
|
208
|
-
|
209
|
-
|
210
|
-
|
211
|
-
|
212
|
-
|
213
|
-
|
214
|
-
|
215
|
-
|
216
|
-
|
217
|
-
|
218
|
-
|
219
|
-
|
220
|
-
|
216
|
+
retrieved = case value.to_s
|
217
|
+
when 'colorspace'
|
218
|
+
run_command('identify', '-format', '%r\n', path).split("\n")[0].strip
|
219
|
+
when 'format'
|
220
|
+
run_command('identify', '-format', '%m\n', path).split("\n")[0]
|
221
|
+
when 'dimensions', 'width', 'height'
|
222
|
+
width_height = run_command(
|
223
|
+
'identify', '-format', MiniMagick::Utilities.windows? ? '"%w %h\n"' : '%w %h\n', path
|
224
|
+
).split("\n")[0].split.map { |v| v.to_i }
|
225
|
+
|
226
|
+
@info[:width] = width_height[0]
|
227
|
+
@info[:height] = width_height[1]
|
228
|
+
@info[:dimensions] = width_height
|
229
|
+
nil
|
230
|
+
when 'size'
|
231
|
+
File.size(path) # Do this because calling identify -format "%b" on an animated gif fails!
|
232
|
+
when 'original_at'
|
233
|
+
# Get the EXIF original capture as a Time object
|
234
|
+
Time.local(*self['EXIF:DateTimeOriginal'].split(/:|\s+/)) rescue nil
|
235
|
+
when /^EXIF\:/i
|
236
|
+
result = run_command('identify', '-format', "%[#{value}]", path).chomp
|
237
|
+
if result.include?(',')
|
238
|
+
read_character_data(result)
|
239
|
+
else
|
240
|
+
result
|
241
|
+
end
|
242
|
+
else
|
243
|
+
run_command('identify', '-format', value, path).split("\n")[0]
|
244
|
+
end
|
245
|
+
|
246
|
+
@info[value] = retrieved unless retrieved.nil?
|
247
|
+
@info[value]
|
221
248
|
end
|
222
249
|
|
223
250
|
# Sends raw commands to imagemagick's `mogrify` command. The image path is automatically appended to the command.
|
@@ -226,15 +253,15 @@ module MiniMagick
|
|
226
253
|
#
|
227
254
|
# @return [String] Whatever the result from the command line is. May not be terribly useful.
|
228
255
|
def <<(*args)
|
229
|
-
run_command(
|
256
|
+
run_command('mogrify', *args << path)
|
230
257
|
end
|
231
258
|
|
232
259
|
# This is used to change the format of the image. That is, from "tiff to jpg" or something like that.
|
233
260
|
# Once you run it, the instance is pointing to a new file with a new extension!
|
234
261
|
#
|
235
262
|
# *DANGER*: This renames the file that the instance is pointing to. So, if you manually opened the
|
236
|
-
# file with Image.new(file_path)...
|
237
|
-
# you are
|
263
|
+
# file with Image.new(file_path)... Then that file is DELETED! If you used Image.open(file) then
|
264
|
+
# you are OK. The original file will still be there. But, any changes to it might not be...
|
238
265
|
#
|
239
266
|
# Formatting an animation into a non-animated type will result in ImageMagick creating multiple
|
240
267
|
# pages (starting with 0). You can choose which page you want to manipulate. We default to the
|
@@ -243,34 +270,34 @@ module MiniMagick
|
|
243
270
|
# If you would like to convert between animated formats, pass nil as your
|
244
271
|
# page and ImageMagick will copy all of the pages.
|
245
272
|
#
|
246
|
-
# @param format [String] The target format...
|
273
|
+
# @param format [String] The target format... Like 'jpg', 'gif', 'tiff', etc.
|
247
274
|
# @param page [Integer] If this is an animated gif, say which 'page' you want
|
248
275
|
# with an integer. Default 0 will convert only the first page; 'nil' will
|
249
276
|
# convert all pages.
|
250
277
|
# @return [nil]
|
251
278
|
def format(format, page = 0)
|
279
|
+
run_queue if @command_queued
|
280
|
+
|
252
281
|
c = CommandBuilder.new('mogrify', '-format', format)
|
253
282
|
yield c if block_given?
|
254
|
-
|
255
|
-
c << "#{path}[#{page}]"
|
256
|
-
else
|
257
|
-
c << path
|
258
|
-
end
|
283
|
+
c << (page ? "#{path}[#{page}]" : path)
|
259
284
|
run(c)
|
260
285
|
|
261
286
|
old_path = path
|
262
|
-
|
287
|
+
|
288
|
+
self.path = path.sub(/(\.\w*)?$/, (page ? ".#{format}" : "-0.#{format}"))
|
289
|
+
|
263
290
|
File.delete(old_path) if old_path != path
|
264
291
|
|
265
|
-
unless File.
|
266
|
-
|
292
|
+
unless File.exist?(path)
|
293
|
+
fail MiniMagick::Error, "Unable to format to #{format}"
|
267
294
|
end
|
268
295
|
end
|
269
296
|
|
270
|
-
# Collapse images with sequences to the first frame (
|
297
|
+
# Collapse images with sequences to the first frame (i.e. animated gifs) and
|
271
298
|
# preserve quality
|
272
299
|
def collapse!
|
273
|
-
run_command(
|
300
|
+
run_command('mogrify', '-quality', '100', "#{path}[0]")
|
274
301
|
end
|
275
302
|
|
276
303
|
# Writes the temporary file out to either a file location (by passing in a String) or by
|
@@ -280,11 +307,17 @@ module MiniMagick
|
|
280
307
|
# @return [IOStream, Boolean] If you pass in a file location [String] then you get a success boolean. If its a stream, you get it back.
|
281
308
|
# Writes the temporary image that we are using for processing to the output path
|
282
309
|
def write(output_to)
|
283
|
-
if
|
310
|
+
run_queue if @command_queued
|
311
|
+
|
312
|
+
if output_to.kind_of?(String) || output_to.kind_of?(Pathname) || !output_to.respond_to?(:write)
|
284
313
|
FileUtils.copy_file path, output_to
|
285
|
-
|
314
|
+
if MiniMagick.validate_on_write
|
315
|
+
run_command(
|
316
|
+
'identify', MiniMagick::Utilities.windows? ? path_for_windows_quote_space(output_to.to_s) : output_to.to_s
|
317
|
+
) # Verify that we have a good image
|
318
|
+
end
|
286
319
|
else # stream
|
287
|
-
File.open(path,
|
320
|
+
File.open(path, 'rb') do |f|
|
288
321
|
f.binmode
|
289
322
|
while chunk = f.read(8192)
|
290
323
|
output_to.write(chunk)
|
@@ -297,6 +330,8 @@ module MiniMagick
|
|
297
330
|
# Gives you raw image data back
|
298
331
|
# @return [String] binary string
|
299
332
|
def to_blob
|
333
|
+
run_queue if @command_queued
|
334
|
+
|
300
335
|
f = File.new path
|
301
336
|
f.binmode
|
302
337
|
f.read
|
@@ -306,15 +341,14 @@ module MiniMagick
|
|
306
341
|
|
307
342
|
def mime_type
|
308
343
|
format = self[:format]
|
309
|
-
|
344
|
+
'image/' + format.to_s.downcase
|
310
345
|
end
|
311
346
|
|
312
347
|
# If an unknown method is called then it is sent through the mogrify program
|
313
348
|
# Look here to find all the commands (http://www.imagemagick.org/script/mogrify.php)
|
314
349
|
def method_missing(symbol, *args)
|
315
|
-
|
316
|
-
|
317
|
-
end
|
350
|
+
@queue.send(symbol, *args)
|
351
|
+
@command_queued = true
|
318
352
|
end
|
319
353
|
|
320
354
|
# You can use multiple commands together using this method. Very easy to use!
|
@@ -327,16 +361,15 @@ module MiniMagick
|
|
327
361
|
# end
|
328
362
|
#
|
329
363
|
# @yieldparam command [CommandBuilder]
|
330
|
-
def combine_options
|
331
|
-
|
332
|
-
|
333
|
-
|
334
|
-
|
335
|
-
c << path
|
336
|
-
run(c)
|
364
|
+
def combine_options
|
365
|
+
if block_given?
|
366
|
+
yield @queue
|
367
|
+
@command_queued = true
|
368
|
+
end
|
337
369
|
end
|
338
370
|
|
339
|
-
def composite(other_image, output_extension = 'jpg', &block)
|
371
|
+
def composite(other_image, output_extension = 'jpg', mask = nil, &block)
|
372
|
+
run_queue if @command_queued
|
340
373
|
begin
|
341
374
|
second_tempfile = Tempfile.new(output_extension)
|
342
375
|
second_tempfile.binmode
|
@@ -344,17 +377,20 @@ module MiniMagick
|
|
344
377
|
second_tempfile.close
|
345
378
|
end
|
346
379
|
|
347
|
-
command = CommandBuilder.new(
|
380
|
+
command = CommandBuilder.new('composite')
|
348
381
|
block.call(command) if block
|
349
382
|
command.push(other_image.path)
|
350
|
-
command.push(
|
383
|
+
command.push(path)
|
384
|
+
command.push(mask.path) unless mask.nil?
|
351
385
|
command.push(second_tempfile.path)
|
352
386
|
|
353
387
|
run(command)
|
354
|
-
|
388
|
+
Image.new(second_tempfile.path, second_tempfile)
|
355
389
|
end
|
356
390
|
|
357
391
|
def run_command(command, *args)
|
392
|
+
run_queue if @command_queued
|
393
|
+
|
358
394
|
if command == 'identify'
|
359
395
|
args.unshift '-ping' # -ping "efficiently determine image characteristics."
|
360
396
|
args.unshift '-quiet' if MiniMagick.mogrify? # graphicsmagick has no -quiet option.
|
@@ -374,11 +410,11 @@ module MiniMagick
|
|
374
410
|
|
375
411
|
# Raise the appropriate error
|
376
412
|
if sub.output =~ /no decode delegate/i || sub.output =~ /did not return an image/i
|
377
|
-
|
413
|
+
fail Invalid, sub.output
|
378
414
|
else
|
379
415
|
# TODO: should we do something different if the command times out ...?
|
380
|
-
# its definitely better for logging..
|
381
|
-
|
416
|
+
# its definitely better for logging.. Otherwise we don't really know
|
417
|
+
fail Error, "Command (#{command.inspect.gsub("\\", "")}) failed: #{{ :status_code => sub.exitstatus, :output => sub.output }.inspect}"
|
382
418
|
end
|
383
419
|
else
|
384
420
|
sub.output
|
@@ -387,19 +423,20 @@ module MiniMagick
|
|
387
423
|
|
388
424
|
def destroy!
|
389
425
|
return if @tempfile.nil?
|
390
|
-
File.unlink(path) if File.
|
426
|
+
File.unlink(path) if File.exist?(path)
|
391
427
|
@tempfile = nil
|
392
428
|
end
|
393
429
|
|
394
430
|
private
|
395
|
-
|
396
|
-
|
397
|
-
|
398
|
-
|
399
|
-
|
400
|
-
|
401
|
-
|
402
|
-
result
|
431
|
+
|
432
|
+
# Sometimes we get back a list of character values
|
433
|
+
def read_character_data(list_of_characters)
|
434
|
+
chars = list_of_characters.gsub(' ', '').split(',')
|
435
|
+
result = ''
|
436
|
+
chars.each do |val|
|
437
|
+
result << ('%c' % val.to_i)
|
403
438
|
end
|
439
|
+
result
|
440
|
+
end
|
404
441
|
end
|
405
442
|
end
|
@@ -9,12 +9,12 @@ module MiniMagick
|
|
9
9
|
def which(cmd)
|
10
10
|
exts = ENV['PATHEXT'] ? ENV['PATHEXT'].split(';') : ['']
|
11
11
|
ENV['PATH'].split(File::PATH_SEPARATOR).each do |path|
|
12
|
-
exts.each
|
12
|
+
exts.each do |ext|
|
13
13
|
exe = File.join(path, "#{cmd}#{ext}")
|
14
14
|
return exe if File.executable? exe
|
15
|
-
|
15
|
+
end
|
16
16
|
end
|
17
|
-
|
17
|
+
nil
|
18
18
|
end
|
19
19
|
|
20
20
|
# Finds out if the host OS is windows
|
@@ -22,10 +22,15 @@ module MiniMagick
|
|
22
22
|
RbConfig::CONFIG['host_os'] =~ /mswin|mingw|cygwin/
|
23
23
|
end
|
24
24
|
|
25
|
-
def windows_escape(
|
26
|
-
|
25
|
+
def windows_escape(value)
|
26
|
+
# For Windows, ^ is the escape char, equivalent to \ in Unix.
|
27
|
+
escaped = value.gsub(/\^/, '^^').gsub(/>/, '^>')
|
28
|
+
if escaped !~ /^".+"$/ && escaped.include?("'")
|
29
|
+
escaped.inspect
|
30
|
+
else
|
31
|
+
escaped
|
32
|
+
end
|
27
33
|
end
|
28
34
|
end
|
29
35
|
end
|
30
36
|
end
|
31
|
-
|
data/lib/mini_magick/version.rb
CHANGED
metadata
CHANGED
@@ -1,92 +1,96 @@
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
2
2
|
name: mini_magick
|
3
3
|
version: !ruby/object:Gem::Version
|
4
|
-
version: 3.
|
4
|
+
version: 3.8.0
|
5
5
|
platform: ruby
|
6
6
|
authors:
|
7
7
|
- Corey Johnson
|
8
8
|
- Hampton Catlin
|
9
9
|
- Peter Kieltyka
|
10
|
+
- James Miller
|
11
|
+
- Thiago Fernandes Massa
|
10
12
|
autorequire:
|
11
13
|
bindir: bin
|
12
14
|
cert_chain: []
|
13
|
-
date:
|
15
|
+
date: 2014-07-22 00:00:00.000000000 Z
|
14
16
|
dependencies:
|
15
17
|
- !ruby/object:Gem::Dependency
|
16
18
|
name: subexec
|
17
19
|
requirement: !ruby/object:Gem::Requirement
|
18
20
|
requirements:
|
19
|
-
- - ~>
|
21
|
+
- - "~>"
|
20
22
|
- !ruby/object:Gem::Version
|
21
23
|
version: 0.2.1
|
22
24
|
type: :runtime
|
23
25
|
prerelease: false
|
24
26
|
version_requirements: !ruby/object:Gem::Requirement
|
25
27
|
requirements:
|
26
|
-
- - ~>
|
28
|
+
- - "~>"
|
27
29
|
- !ruby/object:Gem::Version
|
28
30
|
version: 0.2.1
|
29
31
|
- !ruby/object:Gem::Dependency
|
30
32
|
name: rake
|
31
33
|
requirement: !ruby/object:Gem::Requirement
|
32
34
|
requirements:
|
33
|
-
- -
|
35
|
+
- - ">="
|
34
36
|
- !ruby/object:Gem::Version
|
35
37
|
version: '0'
|
36
38
|
type: :development
|
37
39
|
prerelease: false
|
38
40
|
version_requirements: !ruby/object:Gem::Requirement
|
39
41
|
requirements:
|
40
|
-
- -
|
42
|
+
- - ">="
|
41
43
|
- !ruby/object:Gem::Version
|
42
44
|
version: '0'
|
43
45
|
- !ruby/object:Gem::Dependency
|
44
46
|
name: test-unit
|
45
47
|
requirement: !ruby/object:Gem::Requirement
|
46
48
|
requirements:
|
47
|
-
- -
|
49
|
+
- - ">="
|
48
50
|
- !ruby/object:Gem::Version
|
49
51
|
version: '0'
|
50
52
|
type: :development
|
51
53
|
prerelease: false
|
52
54
|
version_requirements: !ruby/object:Gem::Requirement
|
53
55
|
requirements:
|
54
|
-
- -
|
56
|
+
- - ">="
|
55
57
|
- !ruby/object:Gem::Version
|
56
58
|
version: '0'
|
57
59
|
- !ruby/object:Gem::Dependency
|
58
60
|
name: rspec
|
59
61
|
requirement: !ruby/object:Gem::Requirement
|
60
62
|
requirements:
|
61
|
-
- -
|
63
|
+
- - ">="
|
62
64
|
- !ruby/object:Gem::Version
|
63
65
|
version: '0'
|
64
66
|
type: :development
|
65
67
|
prerelease: false
|
66
68
|
version_requirements: !ruby/object:Gem::Requirement
|
67
69
|
requirements:
|
68
|
-
- -
|
70
|
+
- - ">="
|
69
71
|
- !ruby/object:Gem::Version
|
70
72
|
version: '0'
|
71
73
|
- !ruby/object:Gem::Dependency
|
72
74
|
name: mocha
|
73
75
|
requirement: !ruby/object:Gem::Requirement
|
74
76
|
requirements:
|
75
|
-
- -
|
77
|
+
- - ">="
|
76
78
|
- !ruby/object:Gem::Version
|
77
79
|
version: '0'
|
78
80
|
type: :development
|
79
81
|
prerelease: false
|
80
82
|
version_requirements: !ruby/object:Gem::Requirement
|
81
83
|
requirements:
|
82
|
-
- -
|
84
|
+
- - ">="
|
83
85
|
- !ruby/object:Gem::Version
|
84
86
|
version: '0'
|
85
|
-
description:
|
87
|
+
description:
|
86
88
|
email:
|
87
89
|
- probablycorey@gmail.com
|
88
90
|
- hcatlin@gmail.com
|
89
91
|
- peter@nulayer.com
|
92
|
+
- bensie@gmail.com
|
93
|
+
- thiagown@gmail.com
|
90
94
|
executables: []
|
91
95
|
extensions: []
|
92
96
|
extra_rdoc_files: []
|
@@ -94,14 +98,15 @@ files:
|
|
94
98
|
- MIT-LICENSE
|
95
99
|
- Rakefile
|
96
100
|
- lib/mini_gmagick.rb
|
101
|
+
- lib/mini_magick.rb
|
97
102
|
- lib/mini_magick/command_builder.rb
|
98
103
|
- lib/mini_magick/errors.rb
|
99
104
|
- lib/mini_magick/image.rb
|
100
105
|
- lib/mini_magick/utilities.rb
|
101
106
|
- lib/mini_magick/version.rb
|
102
|
-
- lib/mini_magick.rb
|
103
107
|
homepage: https://github.com/minimagick/minimagick
|
104
|
-
licenses:
|
108
|
+
licenses:
|
109
|
+
- MIT
|
105
110
|
metadata: {}
|
106
111
|
post_install_message:
|
107
112
|
rdoc_options: []
|
@@ -109,18 +114,18 @@ require_paths:
|
|
109
114
|
- lib
|
110
115
|
required_ruby_version: !ruby/object:Gem::Requirement
|
111
116
|
requirements:
|
112
|
-
- -
|
117
|
+
- - ">="
|
113
118
|
- !ruby/object:Gem::Version
|
114
119
|
version: '0'
|
115
120
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
116
121
|
requirements:
|
117
|
-
- -
|
122
|
+
- - ">="
|
118
123
|
- !ruby/object:Gem::Version
|
119
124
|
version: '0'
|
120
125
|
requirements:
|
121
126
|
- You must have ImageMagick or GraphicsMagick installed
|
122
127
|
rubyforge_project:
|
123
|
-
rubygems_version: 2.
|
128
|
+
rubygems_version: 2.2.2
|
124
129
|
signing_key:
|
125
130
|
specification_version: 4
|
126
131
|
summary: Manipulate images with minimal use of memory via ImageMagick / GraphicsMagick
|