mini_magick 3.8.0 → 3.8.1

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: 7708f032a0b010ff31ed437bd5f28c5bdf4b269b
4
- data.tar.gz: 866153c83f7e87dfe3d1564ca32821221240d6a4
3
+ metadata.gz: 4f4ae6b4f7d224af6275ad37b108c978f3fd8817
4
+ data.tar.gz: 69d6e3f3b1289af2dd54a0309166e71fce1e2f45
5
5
  SHA512:
6
- metadata.gz: f1af9965e59c483a1566299d984f1657a2fc673c398a07e2fc07fb8e3d821eb9ec4f4f6fbcbcbb2f4497714f703f410ab64bc2b02ded74cb952b019171663ef7
7
- data.tar.gz: efe209dfdd7bedd32e7d44dc49cdda24e339a68e49fe4cfbfa900edb60c7a7b9c9627316df330d8ab90a6054e03f6db213c6360313d4ce26d35c925094437a11
6
+ metadata.gz: 248c08f2af654156c2a422bb3bb3e48a9b97087bab6dacace044bbc2175465c9a2e5de09eac05cb4110cc4efcc8a47f25424f03f6effa6df2cbb2fda85524557
7
+ data.tar.gz: 3c000c0861b8e66312d875b8858cdc3fe0b32c842332b70c979675acbf9b4fc62fcb4732c5c49db96240e0bf400974a90ee01e90a34b1c3d817eaf60444030fb
data/lib/mini_magick.rb CHANGED
@@ -1,8 +1,3 @@
1
- require 'tempfile'
2
- require 'subexec'
3
- require 'stringio'
4
- require 'pathname'
5
- require 'shellwords'
6
1
  require 'mini_magick/command_builder'
7
2
  require 'mini_magick/errors'
8
3
  require 'mini_magick/image'
@@ -16,23 +11,20 @@ module MiniMagick
16
11
  attr_accessor :processor
17
12
  attr_accessor :processor_path
18
13
  attr_accessor :timeout
14
+ attr_accessor :debug
19
15
  attr_accessor :validate_on_create
20
16
  attr_accessor :validate_on_write
21
17
 
22
18
  ##
23
- # Tries to detect the current processor based if any of the processors exist.
24
- # Mogrify have precedence over gm by default.
19
+ # Tries to detect the current processor based if any of the processors
20
+ # exist. Mogrify have precedence over gm by default.
25
21
  #
26
22
  # === Returns
27
- # * [String] The detected procesor
28
- def choose_processor
29
- self.processor = if MiniMagick::Utilities.which('mogrify')
30
- :mogrify
31
- elsif MiniMagick::Utilities.which('gm')
32
- :gm
33
- else
34
- nil
35
- end
23
+ # * [Symbol] The detected procesor
24
+ def processor
25
+ @processor ||= [:mogrify, :gm].detect do |processor|
26
+ MiniMagick::Utilities.which(processor.to_s)
27
+ end
36
28
  end
37
29
 
38
30
  ##
@@ -63,27 +55,21 @@ module MiniMagick
63
55
  end
64
56
 
65
57
  ##
66
- # Picks the right processor if it isn't set and returns whether it's mogrify or not.
58
+ # Checks whether the current processory is mogrify.
67
59
  #
68
60
  # === Returns
69
61
  # * [Boolean]
70
62
  def mogrify?
71
- choose_processor if processor.nil?
72
-
73
- return processor.to_s.downcase.to_sym == :mogrify unless processor.nil?
74
- false
63
+ processor && processor.to_sym == :mogrify
75
64
  end
76
65
 
77
66
  ##
78
- # Picks the right processor if it isn't set and returns whether it's graphicsmagick or not.
67
+ # Checks whether the current processor is graphicsmagick.
79
68
  #
80
69
  # === Returns
81
70
  # * [Boolean]
82
71
  def gm?
83
- choose_processor if processor.nil?
84
-
85
- return processor.to_s.downcase.to_sym == :gm unless processor.nil?
86
- false
72
+ processor && processor.to_sym == :gm
87
73
  end
88
74
  end
89
75
  end
@@ -13,16 +13,12 @@ module MiniMagick
13
13
  com = "#{@tool} #{args.join(' ')}".strip
14
14
  com = "#{MiniMagick.processor} #{com}" unless MiniMagick.mogrify?
15
15
 
16
- com = File.join MiniMagick.processor_path, com unless MiniMagick.processor_path.nil?
16
+ com = File.join MiniMagick.processor_path, com if MiniMagick.processor_path
17
17
  com.strip
18
18
  end
19
19
 
20
20
  def args
21
- if !MiniMagick::Utilities.windows?
22
- @args.map(&:shellescape)
23
- else
24
- @args.map { |arg| Utilities.windows_escape(arg) }
25
- end
21
+ @args.map { |arg| Utilities.escape(arg) }
26
22
  end
27
23
 
28
24
  # Add each mogrify command in both underscore and dash format
@@ -75,30 +71,18 @@ module MiniMagick
75
71
  end
76
72
 
77
73
  def +(*options)
78
- push(@args.pop.gsub(/^-/, '+'))
79
- if options.any?
80
- options.each do |o|
81
- push o
82
- end
83
- end
74
+ push(@args.pop.gsub(/\A-/, '+'))
75
+ options.to_a.each { |option| push(option) }
84
76
  end
85
77
 
86
78
  def add_command(command, *options)
87
79
  push "-#{command}"
88
- if options.any?
89
- options.each do |o|
90
- push o
91
- end
92
- end
80
+ options.to_a.each { |option| push(option) }
93
81
  end
94
82
 
95
83
  def add_creation_operator(command, *options)
96
84
  creation_command = command
97
- if options.any?
98
- options.each do |option|
99
- creation_command << ":#{option}"
100
- end
101
- end
85
+ options.to_a.each { |option| creation_command << ":#{option}" }
102
86
  push creation_command
103
87
  end
104
88
 
@@ -1,35 +1,37 @@
1
+ require 'tempfile'
2
+ require 'subexec'
3
+ require 'stringio'
4
+ require 'pathname'
5
+
1
6
  module MiniMagick
2
7
  class Image
3
8
  # @return [String] The location of the current working file
4
9
  attr_writer :path
5
10
 
6
- def path_for_windows_quote_space(path)
7
- path = Pathname.new(@path).to_s
8
- # For Windows, if a path contains space char, you need to quote it, otherwise you SHOULD NOT quote it.
9
- # If you quote a path that does not contains space, it will not work.
10
- @path.include?(' ') ? path.inspect : path
11
- end
12
-
13
11
  def path
14
12
  run_queue if @command_queued
15
- MiniMagick::Utilities.windows? ? path_for_windows_quote_space(@path) : @path
13
+ MiniMagick::Utilities.path(@path)
16
14
  end
17
15
 
18
16
  # Class Methods
19
17
  # -------------
20
18
  class << self
21
- # This is the primary loading method used by all of the other class methods.
19
+ # This is the primary loading method used by all of the other class
20
+ # methods.
22
21
  #
23
- # Use this to pass in a stream object. Must respond to Object#read(size) or be a binary string object (BLOBBBB)
22
+ # Use this to pass in a stream object. Must respond to Object#read(size)
23
+ # or be a binary string object (BLOBBBB)
24
24
  #
25
- # As a change from the old API, please try and use IOStream objects.
26
- # They are much, much better and more efficient!
25
+ # As a change from the old API, please try and use IOStream objects. They
26
+ # are much, much better and more efficient!
27
27
  #
28
- # Probably easier to use the #open method if you want to open a file or a URL.
28
+ # Probably easier to use the #open method if you want to open a file or a
29
+ # URL.
29
30
  #
30
- # @param stream [IOStream, String] Some kind of stream object that needs to be read or is a binary String blob!
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.
31
+ # @param stream [IOStream, String] Some kind of stream object that needs
32
+ # to be read or is a binary String blob!
33
+ # @param ext [String] A manual extension to use for reading the file. Not
34
+ # required, but if you are having issues, give this a try.
33
35
  # @return [Image]
34
36
  def read(stream, ext = nil)
35
37
  if stream.is_a?(String)
@@ -57,31 +59,32 @@ module MiniMagick
57
59
  create(ext) { |f| f.write(blob) }
58
60
  end
59
61
 
60
- # Creates an image object from a binary string blob which contains raw pixel data (i.e. no header data).
61
- #
62
- # === Returns
62
+ # Creates an image object from a binary string blob which contains raw
63
+ # pixel data (i.e. no header data).
63
64
  #
64
- # * [Image] The loaded image.
65
- #
66
- # === Parameters
67
- #
68
- # * [blob] <tt>String</tt> -- Binary string blob containing raw pixel data.
69
- # * [columns] <tt>Integer</tt> -- Number of columns.
70
- # * [rows] <tt>Integer</tt> -- Number of rows.
71
- # * [depth] <tt>Integer</tt> -- Bit depth of the encoded pixel data.
72
- # * [map] <tt>String</tt> -- A code for the mapping of the pixel data. Example: 'gray' or 'rgb'.
73
- # * [format] <tt>String</tt> -- The file extension of the image format to be used when creating the image object.
65
+ # @param blob [String] Binary string blob containing raw pixel data.
66
+ # @param columns [Integer] Number of columns.
67
+ # @param rows [Integer] Number of rows.
68
+ # @param depth [Integer] Bit depth of the encoded pixel data.
69
+ # @param map [String] A code for the mapping of the pixel data. Example:
70
+ # 'gray' or 'rgb'.
71
+ # @param format [String] The file extension of the image format to be
72
+ # used when creating the image object.
74
73
  # Defaults to 'png'.
74
+ # @return [Image] The loaded image.
75
75
  #
76
76
  def import_pixels(blob, columns, rows, depth, map, format = 'png')
77
77
  # Create an image object with the raw pixel data string:
78
78
  image = create('.dat', false) { |f| f.write(blob) }
79
- # Use ImageMagick to convert the raw data file to an image file of the desired format:
79
+ # Use ImageMagick to convert the raw data file to an image file of the
80
+ # desired format:
80
81
  converted_image_path = image.path[0..-4] + format
81
82
  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
+ # Example: convert -size 256x256 -depth 16 gray:blob.dat blob.png
84
+ cmd = CommandBuilder.new('convert', *arguments)
83
85
  image.run(cmd)
84
- # Update the image instance with the path of the properly formatted image, and return:
86
+ # Update the image instance with the path of the properly formatted
87
+ # image, and return:
85
88
  image.path = converted_image_path
86
89
  image
87
90
  end
@@ -90,15 +93,18 @@ module MiniMagick
90
93
  #
91
94
  # Use this if you don't want to overwrite the image file.
92
95
  #
93
- # Extension is either guessed from the path or you can specify it as a second parameter.
96
+ # Extension is either guessed from the path or you can specify it as a
97
+ # second parameter.
94
98
  #
95
- # If you pass in what looks like a URL, we require 'open-uri' before opening it.
99
+ # If you pass in what looks like a URL, we require 'open-uri' before
100
+ # opening it.
96
101
  #
97
- # @param file_or_url [String] Either a local file path or a URL that open-uri can read
102
+ # @param file_or_url [String] Either a local file path or a URL that
103
+ # open-uri can read
98
104
  # @param ext [String] Specify the extension you want to read it as
99
105
  # @return [Image] The loaded image
100
106
  def open(file_or_url, ext = nil)
101
- file_or_url = file_or_url.to_s # Force it to be a String... Hell or high water
107
+ file_or_url = file_or_url.to_s # Force String... Hell or high water
102
108
  if file_or_url.include?('://')
103
109
  require 'open-uri'
104
110
  ext ||= File.extname(URI.parse(file_or_url).path)
@@ -119,43 +125,47 @@ module MiniMagick
119
125
  open(file, ext)
120
126
  end
121
127
 
122
- # Used to create a new Image object data-copy. Not used to "paint" or that kind of thing.
128
+ # Used to create a new Image object data-copy. Not used to "paint" or
129
+ # that kind of thing.
123
130
  #
124
- # Takes an extension in a block and can be used to build a new Image object. Used
125
- # by both #open and #read to create a new object! Ensures we have a good tempfile!
131
+ # Takes an extension in a block and can be used to build a new Image
132
+ # object. Used by both #open and #read to create a new object! Ensures we
133
+ # have a good tempfile!
126
134
  #
127
135
  # @param ext [String] Specify the extension you want to read it as
128
- # @param validate [Boolean] If false, skips validation of the created image. Defaults to true.
129
- # @yield [IOStream] You can #write bits to this object to create the new Image
136
+ # @param validate [Boolean] If false, skips validation of the created
137
+ # image. Defaults to true.
138
+ # @yield [IOStream] You can #write bits to this object to create the new
139
+ # Image
130
140
  # @return [Image] The created image
131
141
  def create(ext = nil, validate = MiniMagick.validate_on_create, &block)
132
- begin
133
- tempfile = Tempfile.new(['mini_magick', ext.to_s.downcase])
134
- tempfile.binmode
135
- block.call(tempfile)
136
- tempfile.close
137
-
138
- image = new(tempfile.path, tempfile)
139
-
140
- fail MiniMagick::Invalid if validate && !image.valid?
141
- return image
142
- ensure
143
- tempfile.close if tempfile
144
- end
142
+ tempfile = Tempfile.new(['mini_magick', ext.to_s.downcase])
143
+ tempfile.binmode
144
+ block.call(tempfile)
145
+ tempfile.close
146
+
147
+ image = new(tempfile.path, tempfile)
148
+
149
+ fail MiniMagick::Invalid if validate && !image.valid?
150
+ return image
151
+ ensure
152
+ tempfile.close if tempfile
145
153
  end
146
154
  end
147
155
 
148
156
  # Create a new MiniMagick::Image object
149
157
  #
150
- # _DANGER_: The file location passed in here is the *working copy*. That is, it gets *modified*.
151
- # you can either copy it yourself or use the MiniMagick::Image.open(path) method which creates a
152
- # temporary file for you and protects your original!
158
+ # _DANGER_: The file location passed in here is the *working copy*. That
159
+ # is, it gets *modified*. you can either copy it yourself or use the
160
+ # MiniMagick::Image.open(path) method which creates a temporary file for
161
+ # you and protects your original!
153
162
  #
154
163
  # @param input_path [String] The location of an image file
155
- # @todo Allow this to accept a block that can pass off to Image#combine_options
164
+ # @todo Allow this to accept a block that can pass off to
165
+ # Image#combine_options
156
166
  def initialize(input_path, tempfile = nil)
157
167
  @path = input_path
158
- @tempfile = tempfile # ensures that the tempfile will stick around until this image is garbage collected.
168
+ @tempfile = tempfile
159
169
  @info = {}
160
170
  reset_queue
161
171
  end
@@ -168,16 +178,16 @@ module MiniMagick
168
178
 
169
179
  def run_queue
170
180
  return nil unless @command_queued
171
- @queue << (MiniMagick::Utilities.windows? ? path_for_windows_quote_space(@path) : @path)
181
+ @queue << MiniMagick::Utilities.path(@path)
172
182
  run(@queue)
173
183
  reset_queue
174
184
  end
175
185
 
176
186
  # Checks to make sure that MiniMagick can read the file and understand it.
177
187
  #
178
- # This uses the 'identify' command line utility to check the file. If you are having
179
- # issues with this, then please work directly with the 'identify' command and see if you
180
- # can figure out what the issue is.
188
+ # This uses the 'identify' command line utility to check the file. If you
189
+ # are having issues with this, then please work directly with the
190
+ # 'identify' command and see if you can figure out what the issue is.
181
191
  #
182
192
  # @return [Boolean]
183
193
  def valid?
@@ -192,8 +202,10 @@ module MiniMagick
192
202
 
193
203
  @info[key]
194
204
  end
195
- # A rather low-level way to interact with the "identify" command. No nice API here, just
196
- # the crazy stuff you find in ImageMagick. See the examples listed!
205
+
206
+ # A rather low-level way to interact with the "identify" command. No nice
207
+ # API here, just the crazy stuff you find in ImageMagick. See the examples
208
+ # listed!
197
209
  #
198
210
  # @example
199
211
  # image["format"] #=> "TIFF"
@@ -206,13 +218,15 @@ module MiniMagick
206
218
  # image["EXIF:ExifVersion"] #=> "0220" (Can read anything from Exif)
207
219
  #
208
220
  # @param format [String] A format for the "identify" command
209
- # @see For reference see http://www.imagemagick.org/script/command-line-options.php#format
210
- # @return [String, Numeric, Array, Time, Object] Depends on the method called! Defaults to String for unknown commands
221
+ # @see http://www.imagemagick.org/script/command-line-options.php#format
222
+ # @return [String, Numeric, Array, Time, Object] Depends on the method
223
+ # called! Defaults to String for unknown commands
211
224
  def [](value)
212
225
  retrieved = info(value)
213
226
  return retrieved unless retrieved.nil?
214
227
 
215
- # Why do I go to the trouble of putting in newlines? Because otherwise animated gifs screw everything up
228
+ # Why do I go to the trouble of putting in newlines? Because otherwise
229
+ # animated gifs screw everything up
216
230
  retrieved = case value.to_s
217
231
  when 'colorspace'
218
232
  run_command('identify', '-format', '%r\n', path).split("\n")[0].strip
@@ -226,7 +240,7 @@ module MiniMagick
226
240
  @info[:width] = width_height[0]
227
241
  @info[:height] = width_height[1]
228
242
  @info[:dimensions] = width_height
229
- nil
243
+ @info[value.to_sym]
230
244
  when 'size'
231
245
  File.size(path) # Do this because calling identify -format "%b" on an animated gif fails!
232
246
  when 'original_at'
@@ -247,33 +261,38 @@ module MiniMagick
247
261
  @info[value]
248
262
  end
249
263
 
250
- # Sends raw commands to imagemagick's `mogrify` command. The image path is automatically appended to the command.
264
+ # Sends raw commands to imagemagick's `mogrify` command. The image path is
265
+ # automatically appended to the command.
251
266
  #
252
- # Remember, we are always acting on this instance of the Image when messing with this.
267
+ # Remember, we are always acting on this instance of the Image when messing
268
+ # with this.
253
269
  #
254
- # @return [String] Whatever the result from the command line is. May not be terribly useful.
270
+ # @return [String] Whatever the result from the command line is. May not be
271
+ # terribly useful.
255
272
  def <<(*args)
256
273
  run_command('mogrify', *args << path)
257
274
  end
258
275
 
259
- # This is used to change the format of the image. That is, from "tiff to jpg" or something like that.
260
- # Once you run it, the instance is pointing to a new file with a new extension!
276
+ # This is used to change the format of the image. That is, from "tiff to
277
+ # jpg" or something like that. Once you run it, the instance is pointing to
278
+ # a new file with a new extension!
261
279
  #
262
- # *DANGER*: This renames the file that the instance is pointing to. So, if you manually opened the
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...
280
+ # *DANGER*: This renames the file that the instance is pointing to. So, if
281
+ # you manually opened the file with Image.new(file_path)... Then that file
282
+ # is DELETED! If you used Image.open(file) then you are OK. The original
283
+ # file will still be there. But, any changes to it might not be...
265
284
  #
266
- # Formatting an animation into a non-animated type will result in ImageMagick creating multiple
267
- # pages (starting with 0). You can choose which page you want to manipulate. We default to the
268
- # first page.
285
+ # Formatting an animation into a non-animated type will result in
286
+ # ImageMagick creating multiple pages (starting with 0). You can choose
287
+ # which page you want to manipulate. We default to the first page.
269
288
  #
270
289
  # If you would like to convert between animated formats, pass nil as your
271
290
  # page and ImageMagick will copy all of the pages.
272
291
  #
273
- # @param format [String] The target format... Like 'jpg', 'gif', 'tiff', etc.
274
- # @param page [Integer] If this is an animated gif, say which 'page' you want
275
- # with an integer. Default 0 will convert only the first page; 'nil' will
276
- # convert all pages.
292
+ # @param format [String] The target format... Like 'jpg', 'gif', 'tiff' etc.
293
+ # @param page [Integer] If this is an animated gif, say which 'page' you
294
+ # want with an integer. Default 0 will convert only the first page; 'nil'
295
+ # will convert all pages.
277
296
  # @return [nil]
278
297
  def format(format, page = 0)
279
298
  run_queue if @command_queued
@@ -300,12 +319,14 @@ module MiniMagick
300
319
  run_command('mogrify', '-quality', '100', "#{path}[0]")
301
320
  end
302
321
 
303
- # Writes the temporary file out to either a file location (by passing in a String) or by
304
- # passing in a Stream that you can #write(chunk) to repeatedly
322
+ # Writes the temporary file out to either a file location (by passing in a
323
+ # String) or by passing in a Stream that you can #write(chunk) to
324
+ # repeatedly
305
325
  #
306
- # @param output_to [IOStream, String] Some kind of stream object that needs to be read or a file path as a String
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.
308
- # Writes the temporary image that we are using for processing to the output path
326
+ # @param output_to [IOStream, String] Some kind of stream object that needs
327
+ # to be read or a file path as a String
328
+ # @return [IOStream, Boolean] If you pass in a file location [String] then
329
+ # you get a success boolean. If its a stream, you get it back.
309
330
  def write(output_to)
310
331
  run_queue if @command_queued
311
332
 
@@ -313,7 +334,7 @@ module MiniMagick
313
334
  FileUtils.copy_file path, output_to
314
335
  if MiniMagick.validate_on_write
315
336
  run_command(
316
- 'identify', MiniMagick::Utilities.windows? ? path_for_windows_quote_space(output_to.to_s) : output_to.to_s
337
+ 'identify', MiniMagick::Utilities.path(output_to.to_s)
317
338
  ) # Verify that we have a good image
318
339
  end
319
340
  else # stream
@@ -344,14 +365,17 @@ module MiniMagick
344
365
  'image/' + format.to_s.downcase
345
366
  end
346
367
 
347
- # If an unknown method is called then it is sent through the mogrify program
348
- # Look here to find all the commands (http://www.imagemagick.org/script/mogrify.php)
368
+ # If an unknown method is called then it is sent through the mogrify
369
+ # program.
370
+ #
371
+ # @see http://www.imagemagick.org/script/mogrify.php
349
372
  def method_missing(symbol, *args)
350
373
  @queue.send(symbol, *args)
351
374
  @command_queued = true
352
375
  end
353
376
 
354
- # You can use multiple commands together using this method. Very easy to use!
377
+ # You can use multiple commands together using this method. Very easy to
378
+ # use!
355
379
  #
356
380
  # @example
357
381
  # image.combine_options do |c|
@@ -393,7 +417,7 @@ module MiniMagick
393
417
 
394
418
  if command == 'identify'
395
419
  args.unshift '-ping' # -ping "efficiently determine image characteristics."
396
- args.unshift '-quiet' if MiniMagick.mogrify? # graphicsmagick has no -quiet option.
420
+ args.unshift '-quiet' if MiniMagick.mogrify? && !MiniMagick.debug # graphicsmagick has no -quiet option.
397
421
  end
398
422
 
399
423
  run(CommandBuilder.new(command, *args))
@@ -423,20 +447,15 @@ module MiniMagick
423
447
 
424
448
  def destroy!
425
449
  return if @tempfile.nil?
426
- File.unlink(path) if File.exist?(path)
450
+ File.unlink(@path) if File.exist?(@path)
427
451
  @tempfile = nil
428
452
  end
429
453
 
430
454
  private
431
455
 
432
456
  # 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)
438
- end
439
- result
457
+ def read_character_data(string)
458
+ string.scan(/\d+/).map(&:to_i).map(&:chr).join
440
459
  end
441
460
  end
442
461
  end