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 CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 095e582679936f6e2e1a42ea57b449867fa6eb75
4
- data.tar.gz: eb49ba1a91002faa50fc14d512e95668f55e398d
3
+ metadata.gz: 7708f032a0b010ff31ed437bd5f28c5bdf4b269b
4
+ data.tar.gz: 866153c83f7e87dfe3d1564ca32821221240d6a4
5
5
  SHA512:
6
- metadata.gz: 0de53204c54171eae9d42c7789b62b7e11733b1019c2994656c76ca2c43040268e47a1f6c30baa9f41675880ff36cf5e22f47a028a3a8d9a2260d0340b570c0c
7
- data.tar.gz: c03b97bb8c6be54b917afbc80ef3d738ced59c705ed209f3001c32cfe753bb4dc1e831397a1d0fb617b02cc95b9cb2d2a1574e2adc1334b90113e42d03556e4b
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 "Run specs"
15
+ desc 'Run specs'
16
16
  RSpec::Core::RakeTask.new do |t|
17
- t.pattern = "./spec/**/*_spec.rb"
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').size > 0
25
- self.processor = 'mogrify'
26
- elsif MiniMagick::Utilities.which('gm').size > 0
27
- self.processor = "gm"
28
- end
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(" ")[2].split("-").first)
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("6.6.3")
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
- self.choose_processor if self.processor.nil?
71
+ choose_processor if processor.nil?
65
72
 
66
- self.processor == 'mogrify'
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
- self.choose_processor if self.processor.nil?
83
+ choose_processor if processor.nil?
76
84
 
77
- self.processor == 'gm'
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{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 }
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| escape_string_windows(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
- add_command(__method__.to_s.gsub("_","-"), *options)
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
- raise Error, "You must call 'format' on the image object directly!"
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
- alias :<< :push
108
+ alias_method :<<, :push
103
109
  end
104
110
  end
@@ -1,7 +1,7 @@
1
1
  module MiniMagick
2
2
  class Image
3
3
  # @return [String] The location of the current working file
4
- attr_accessor :path
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. They are much, much better and more efficient!
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, give this a try.
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,"rb") { |f| f.read }
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 "Warning: MiniMagick::Image.from_blob method is deprecated. Instead, please use Image.read"
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. Defaults to 'png'.
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="png")
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(".dat", validate = false) { |f| f.write(blob) }
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 = ["-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
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... hell or highwater
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::open(file_or_url) do |f|
106
- self.read(f, ext)
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, "rb") do |f|
111
- self.read(f, ext)
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 "Warning: MiniMagick::Image.from_file is now deprecated. Please use Image.open"
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 = true, &block)
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 = self.new(tempfile.path, tempfile)
138
+ image = new(tempfile.path, tempfile)
139
139
 
140
- if validate and !image.valid?
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("identify", path)
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
- when "colorspace"
197
- run_command("identify", "-format", '%r\n', path).split("\n")[0].strip
198
- when "format"
199
- run_command("identify", "-format", '%m\n', path).split("\n")[0]
200
- when "height"
201
- run_command("identify", "-format", '%h\n', path).split("\n")[0].to_i
202
- when "width"
203
- run_command("identify", "-format", '%w\n', path).split("\n")[0].to_i
204
- when "dimensions"
205
- run_command("identify", "-format", MiniMagick::Utilities.windows? ? '"%w %h\n"' : '%w %h\n', path).split("\n")[0].split.map{|v|v.to_i}
206
- when "size"
207
- File.size(path) # Do this because calling identify -format "%b" on an animated gif fails!
208
- when "original_at"
209
- # Get the EXIF original capture as a Time object
210
- Time.local(*self["EXIF:DateTimeOriginal"].split(/:|\s+/)) rescue nil
211
- when /^EXIF\:/i
212
- result = run_command('identify', '-format', "%[#{value}]", path).chomp
213
- if result.include?(",")
214
- read_character_data(result)
215
- else
216
- result
217
- end
218
- else
219
- run_command('identify', '-format', value, path).split("\n")[0]
220
- end
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("mogrify", *args << path)
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)... then that file is DELETED! If you used Image.open(file) then
237
- # you are ok. The original file will still be there. But, any changes to it might not be...
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... like 'jpg', 'gif', 'tiff', etc.
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
- if page
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
- self.path = path.sub(/(\.\w*)?$/, ".#{format}")
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.exists?(path)
266
- raise MiniMagick::Error, "Unable to format to #{format}"
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 (ie. animated gifs) and
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("mogrify", "-quality", "100", "#{path}[0]")
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 output_to.kind_of?(String) || !output_to.respond_to?(:write)
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
- run_command "identify", MiniMagick::Utilities.windows? ? path_for_windows_quote_space(output_to.to_s) : output_to.to_s # Verify that we have a good image
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, "rb") do |f|
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
- "image/" + format.to_s.downcase
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
- combine_options do |c|
316
- c.send(symbol, *args)
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(tool = "mogrify", &block)
331
- c = CommandBuilder.new(tool)
332
-
333
- c << path if tool.to_s == "convert"
334
- block.call(c)
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("composite")
380
+ command = CommandBuilder.new('composite')
348
381
  block.call(command) if block
349
382
  command.push(other_image.path)
350
- command.push(self.path)
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
- return Image.new(second_tempfile.path, second_tempfile)
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
- raise Invalid, sub.output
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.. otherwise we dont really know
381
- raise Error, "Command (#{command.inspect.gsub("\\", "")}) failed: #{{:status_code => sub.exitstatus, :output => sub.output}.inspect}"
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.exists?(path)
426
+ File.unlink(path) if File.exist?(path)
391
427
  @tempfile = nil
392
428
  end
393
429
 
394
430
  private
395
- # Sometimes we get back a list of character values
396
- def read_character_data(list_of_characters)
397
- chars = list_of_characters.gsub(" ", "").split(",")
398
- result = ""
399
- chars.each do |val|
400
- result << ("%c" % val.to_i)
401
- end
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 { |ext|
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
- return nil
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(cmdline)
26
- '"' + cmdline.gsub(/\\(?=\\*\")/, "\\\\\\").gsub(/\"/, "\\\"").gsub(/\\$/, "\\\\\\").gsub("%", "%%") + '"'
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
-
@@ -1,3 +1,3 @@
1
1
  module MiniMagick
2
- VERSION = "3.7.0"
2
+ VERSION = '3.8.0'
3
3
  end
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.7.0
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: 2013-11-26 00:00:00.000000000 Z
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.0.3
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