mini_magick 3.7.0 → 3.8.0
Sign up to get free protection for your applications and to get access to all the features.
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
|