mini_magick 1.3.3 → 2.0.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.

@@ -51,6 +51,14 @@ Need to combine several options?
51
51
  end
52
52
  image.write("output.jpg")
53
53
 
54
+ Want to composite two images? Super easy! (Aka, put a watermark on!)
55
+
56
+ image = Image.from_file("original.png")
57
+ result = image.composite(Image.open("watermark.png", "jpg") do |c|
58
+ c.gravity "center"
59
+ end
60
+ result.write("my_output_file.jpg")
61
+
54
62
  Want to manipulate an image at its source (You won't have to write it
55
63
  out because the transformations are done on that file)
56
64
 
data/VERSION CHANGED
@@ -1 +1 @@
1
- 1.3.3
1
+ 2.0.0
@@ -1,20 +1,14 @@
1
1
  require 'tempfile'
2
+ require 'subexec'
2
3
 
3
4
  module MiniMagick
4
5
  class << self
5
6
  attr_accessor :processor
6
- attr_accessor :use_subexec
7
7
  attr_accessor :timeout
8
8
  end
9
9
 
10
10
  MOGRIFY_COMMANDS = %w{adaptive-blur adaptive-resize adaptive-sharpen adjoin affine alpha annotate antialias append authenticate auto-gamma auto-level auto-orient background bench iterations bias black-threshold blue-primary point blue-shift factor blur border bordercolor brightness-contrast caption string cdl filename channel type charcoal radius chop clip clamp clip-mask filename clip-path id clone index clut contrast-stretch coalesce colorize color-matrix colors colorspace type combine comment string compose operator composite compress type contrast convolve coefficients crop cycle amount decipher filename debug events define format:option deconstruct delay delete index density depth despeckle direction type display server dispose method distort type coefficients dither method draw string edge radius emboss radius encipher filename encoding type endian type enhance equalize evaluate operator evaluate-sequence operator extent extract family name fft fill filter type flatten flip floodfill flop font name format string frame function name fuzz distance fx expression gamma gaussian-blur geometry gravity type green-primary point help identify ifft implode amount insert index intent type interlace type interline-spacing interpolate method interword-spacing kerning label string lat layers method level limit type linear-stretch liquid-rescale log format loop iterations mask filename mattecolor median radius modulate monitor monochrome morph morphology method kernel motion-blur negate noise radius normalize opaque ordered-dither NxN orient type page paint radius ping pointsize polaroid angle posterize levels precision preview type print string process image-filter profile filename quality quantizespace quiet radial-blur angle raise random-threshold low,high red-primary point regard-warnings region remap filename render repage resample resize respect-parentheses roll rotate degrees sample sampling-factor scale scene seed segments selective-blur separate sepia-tone threshold set attribute shade degrees shadow sharpen shave shear sigmoidal-contrast size sketch solarize threshold splice spread radius strip stroke strokewidth stretch type style type swap indexes swirl degrees texture filename threshold thumbnail tile filename tile-offset tint transform transparent transparent-color transpose transverse treedepth trim type type undercolor unique-colors units type unsharp verbose version view vignette virtual-pixel method wave weight type white-point point white-threshold write filename}
11
-
12
- # Subexec only works with 1.9
13
- if RUBY_VERSION[0..2].to_f < 1.8
14
- self.use_subexec = true
15
- require 'subexec'
16
- end
17
-
11
+
18
12
  class Error < RuntimeError; end
19
13
  class Invalid < StandardError; end
20
14
 
@@ -35,7 +29,11 @@ module MiniMagick
35
29
  tempfile.close if tempfile
36
30
  end
37
31
 
38
- return self.new(tempfile.path, tempfile)
32
+ image = self.new(tempfile.path, tempfile)
33
+ if !image.valid?
34
+ raise MiniMagick::Invalid
35
+ end
36
+ image
39
37
  end
40
38
 
41
39
  # Use this if you don't want to overwrite the image file
@@ -52,9 +50,13 @@ module MiniMagick
52
50
  def initialize(input_path, tempfile=nil)
53
51
  @path = input_path
54
52
  @tempfile = tempfile # ensures that the tempfile will stick around until this image is garbage collected.
55
-
56
- # Ensure that the file is an image
53
+ end
54
+
55
+ def valid?
57
56
  run_command("identify", @path)
57
+ true
58
+ rescue MiniMagick::Invalid
59
+ false
58
60
  end
59
61
 
60
62
  # For reference see http://www.imagemagick.org/script/command-line-options.php#format
@@ -152,15 +154,34 @@ module MiniMagick
152
154
 
153
155
  # You can use multiple commands together using this method
154
156
  def combine_options(&block)
155
- c = CommandBuilder.new
157
+ c = CommandBuilder.new('mogrify')
156
158
  block.call c
157
- run_command("mogrify", *c.args << @path)
159
+ c << @path
160
+ run(c)
158
161
  end
159
162
 
160
163
  # Check to see if we are running on win32 -- we need to escape things differently
161
164
  def windows?
162
165
  !(RUBY_PLATFORM =~ /win32/).nil?
163
166
  end
167
+
168
+ def composite(other_image, output_extension = 'jpg', &block)
169
+ begin
170
+ tempfile = Tempfile.new(output_extension)
171
+ tempfile.binmode
172
+ ensure
173
+ tempfile.close
174
+ end
175
+
176
+ command = CommandBuilder.new("composite")
177
+ block.call(command) if block
178
+ command.push(other_image.path)
179
+ command.push(self.path)
180
+ command.push(tempfile.path)
181
+
182
+ run(command)
183
+ return Image.new(tempfile.path)
184
+ end
164
185
 
165
186
  # Outputs a carriage-return delimited format string for Unix and Windows
166
187
  def format_option(format)
@@ -168,40 +189,28 @@ module MiniMagick
168
189
  end
169
190
 
170
191
  def run_command(command, *args)
171
- args.collect! do |arg|
172
- # args can contain characters like '>' so we must escape them, but don't quote switches
173
- if arg !~ /^[\+\-]/
174
- "\"#{arg}\""
175
- else
176
- arg.to_s
177
- end
178
- end
192
+ run(CommandBuilder.new(command, *args))
193
+ end
194
+
195
+ def run(command_builder)
196
+ command = command_builder.command
179
197
 
180
- command = "#{MiniMagick.processor} #{command} #{args.join(' ')}".strip
198
+ sub = Subexec.run(command, :timeout => MiniMagick.timeout)
181
199
 
182
- if ::MiniMagick.use_subexec
183
- sub = Subexec.run(command, :timeout => MiniMagick.timeout)
184
- exit_status = sub.exitstatus
185
- output = sub.output
186
- else
187
- output = `#{command} 2>&1`
188
- exit_status = $?.exitstatus
189
- end
190
-
191
- if exit_status != 0
200
+ if sub.exitstatus != 0
192
201
  # Clean up after ourselves in case of an error
193
202
  destroy!
194
203
 
195
204
  # Raise the appropriate error
196
- if output =~ /no decode delegate/i || output =~ /did not return an image/i
197
- raise Invalid, output
205
+ if sub.output =~ /no decode delegate/i || sub.output =~ /did not return an image/i
206
+ raise Invalid, sub.output
198
207
  else
199
208
  # TODO: should we do something different if the command times out ...?
200
209
  # its definitely better for logging.. otherwise we dont really know
201
- raise Error, "Command (#{command.inspect}) failed: #{{:status_code => exit_status, :output => output}.inspect}"
210
+ raise Error, "Command (#{command.inspect}) failed: #{{:status_code => sub.exitstatus, :output => sub.output}.inspect}"
202
211
  end
203
212
  else
204
- output
213
+ sub.output
205
214
  end
206
215
  end
207
216
 
@@ -225,18 +234,44 @@ module MiniMagick
225
234
 
226
235
  class CommandBuilder
227
236
  attr :args
237
+ attr :command
228
238
 
229
- def initialize
239
+ def initialize(command, *options)
240
+ @command = command
230
241
  @args = []
242
+
243
+ options.each { |val| push(val) }
231
244
  end
232
-
245
+
246
+ def command
247
+ "#{MiniMagick.processor} #{@command} #{@args.join(' ')}".strip
248
+ end
249
+
233
250
  def method_missing(symbol, *args)
234
- @args << "-#{symbol.to_s.gsub('_','-')}"
235
- @args += args
251
+ guessed_command_name = symbol.to_s.gsub('_','-')
252
+ if MOGRIFY_COMMANDS.include?(guessed_command_name)
253
+ # This makes sure we always quote if we are passed a single
254
+ # arguement with spaces in it
255
+ if (args.size == 1) && (args.first.to_s.include?(' '))
256
+ push("-#{guessed_command_name}")
257
+ push(args.join(" "))
258
+ else
259
+ push("-#{guessed_command_name} #{args.join(" ")}")
260
+ end
261
+ else
262
+ super(symbol, *args)
263
+ end
264
+ end
265
+
266
+ def push(value)
267
+ # args can contain characters like '>' so we must escape them, but don't quote switches
268
+ @args << ((value !~ /^[\+\-]/) ? "\"#{value}\"" : value.to_s.strip)
236
269
  end
270
+ alias :<< :push
237
271
 
238
272
  def +(value)
239
- @args << "+#{value}"
273
+ puts "MINI_MAGICK: The + command has been deprecated. Please use c << '+#{value}')"
274
+ push "+#{value}"
240
275
  end
241
276
  end
242
277
  end
@@ -6,21 +6,39 @@ class CommandBuilderTest < Test::Unit::TestCase
6
6
  include MiniMagick
7
7
 
8
8
  def test_basic
9
- c = CommandBuilder.new
9
+ c = CommandBuilder.new("test")
10
10
  c.resize "30x40"
11
11
  assert_equal "-resize 30x40", c.args.join(" ")
12
12
  end
13
13
 
14
14
  def test_complicated
15
- c = CommandBuilder.new
15
+ c = CommandBuilder.new("test")
16
16
  c.resize "30x40"
17
- c.input 1, 3, 4
18
- c.lingo "mome fingo"
19
- assert_equal "-resize 30x40 -input 1 3 4 -lingo mome fingo", c.args.join(" ")
17
+ c.alpha 1, 3, 4
18
+ c.resize "mome fingo"
19
+ assert_equal "-resize 30x40 -alpha 1 3 4 -resize \"mome fingo\"", c.args.join(" ")
20
+ end
21
+
22
+ def test_valid_command
23
+ begin
24
+ c = CommandBuilder.new("test", "path")
25
+ c.input 2
26
+ assert false
27
+ rescue NoMethodError
28
+ assert true
29
+ end
30
+ end
31
+
32
+ def test_full_command
33
+ c = CommandBuilder.new("test")
34
+ c.resize "30x40"
35
+ c.alpha 1, 3, 4
36
+ c.resize "mome fingo"
37
+ assert_equal "test -resize 30x40 -alpha 1 3 4 -resize \"mome fingo\"", c.command
20
38
  end
21
39
 
22
40
  def test_dashed
23
- c = CommandBuilder.new
41
+ c = CommandBuilder.new("test")
24
42
  c.auto_orient
25
43
  assert_equal "-auto-orient", c.args.join(" ")
26
44
  end
Binary file
@@ -15,7 +15,6 @@ class ImageTest < Test::Unit::TestCase
15
15
  NOT_AN_IMAGE_PATH = CURRENT_DIR + "not_an_image.php"
16
16
  GIF_WITH_JPG_EXT = CURRENT_DIR + "actually_a_gif.jpg"
17
17
  EXIF_IMAGE_PATH = CURRENT_DIR + "trogdor.jpg"
18
- ORIENTED_IMAGE_PATH = CURRENT_DIR + "oliver.jpg"
19
18
  ANIMATION_PATH = CURRENT_DIR + "animation.gif"
20
19
 
21
20
  def test_image_from_blob
@@ -49,9 +48,15 @@ class ImageTest < Test::Unit::TestCase
49
48
  end
50
49
 
51
50
  def test_not_an_image
51
+ image = Image.new(NOT_AN_IMAGE_PATH)
52
+ assert_equal false, image.valid?
53
+ image.destroy!
54
+ end
55
+
56
+ def test_throw_on_openining_not_an_image
52
57
  assert_raise(MiniMagick::Invalid) do
53
- image = Image.new(NOT_AN_IMAGE_PATH)
54
- image.destroy!
58
+ image = Image.open(NOT_AN_IMAGE_PATH)
59
+ image.destroy
55
60
  end
56
61
  end
57
62
 
@@ -141,15 +146,6 @@ class ImageTest < Test::Unit::TestCase
141
146
  assert_equal('', image["EXIF:ExifVersion"])
142
147
  image.destroy!
143
148
  end
144
-
145
- # The test here isn't really to check to see if
146
- # the auto-orient function of ImageMagick works,
147
- # but to make sure we can send dashed commands.
148
- def test_auto_rotate
149
- image = Image.from_file(EXIF_IMAGE_PATH)
150
- image.auto_orient
151
- image.destroy!
152
- end
153
149
 
154
150
  def test_original_at
155
151
  image = Image.from_file(EXIF_IMAGE_PATH)
@@ -191,6 +187,14 @@ class ImageTest < Test::Unit::TestCase
191
187
  assert true #we made it this far without error
192
188
  image.destroy!
193
189
  end
190
+
191
+ def test_simple_composite
192
+ image = Image.from_file(EXIF_IMAGE_PATH)
193
+ result = image.composite(Image.open(TIFF_IMAGE_PATH)) do |c|
194
+ c.gravity "center"
195
+ end
196
+ assert `diff -s #{result.path} test/composited.jpg`.include?("identical")
197
+ end
194
198
 
195
199
  # def test_mini_magick_error_when_referencing_not_existing_page
196
200
  # image = Image.from_file(ANIMATION_PATH)
metadata CHANGED
@@ -3,15 +3,15 @@ name: mini_magick
3
3
  version: !ruby/object:Gem::Version
4
4
  prerelease: false
5
5
  segments:
6
- - 1
7
- - 3
8
- - 3
9
- version: 1.3.3
6
+ - 2
7
+ - 0
8
+ - 0
9
+ version: 2.0.0
10
10
  platform: ruby
11
11
  authors:
12
12
  - Corey Johnson
13
- - Peter Kieltyka
14
13
  - Hampton Catlin
14
+ - Peter Kieltyka
15
15
  autorequire:
16
16
  bindir: bin
17
17
  cert_chain: []
@@ -37,8 +37,8 @@ dependencies:
37
37
  description: ""
38
38
  email:
39
39
  - probablycorey@gmail.com
40
- - peter@nulayer.com
41
40
  - hcatlin@gmail.com
41
+ - peter@nulayer.com
42
42
  executables: []
43
43
 
44
44
  extensions: []
@@ -55,6 +55,7 @@ files:
55
55
  - test/actually_a_gif.jpg
56
56
  - test/animation.gif
57
57
  - test/command_builder_test.rb
58
+ - test/composited.jpg
58
59
  - test/image_test.rb
59
60
  - test/leaves.tiff
60
61
  - test/not_an_image.php
@@ -97,6 +98,7 @@ test_files:
97
98
  - test/actually_a_gif.jpg
98
99
  - test/animation.gif
99
100
  - test/command_builder_test.rb
101
+ - test/composited.jpg
100
102
  - test/image_test.rb
101
103
  - test/leaves.tiff
102
104
  - test/not_an_image.php