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 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