mini_magick 1.3.2 → 2.0.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.
data/README.rdoc CHANGED
@@ -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.2
1
+ 2.0.1
data/lib/mini_magick.rb CHANGED
@@ -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
@@ -139,9 +141,11 @@ module MiniMagick
139
141
  # If an unknown method is called then it is sent through the morgrify program
140
142
  # Look here to find all the commands (http://www.imagemagick.org/script/mogrify.php)
141
143
  def method_missing(symbol, *args)
142
- if MOGRIFY_COMMANDS.include?(symbol.to_s)
144
+ guessed_command_name = symbol.to_s.gsub('_','-')
145
+
146
+ if MOGRIFY_COMMANDS.include?(guessed_command_name)
143
147
  args.push(@path) # push the path onto the end
144
- run_command("mogrify", "-#{symbol}", *args)
148
+ run_command("mogrify", "-#{guessed_command_name}", *args)
145
149
  self
146
150
  else
147
151
  super(symbol, *args)
@@ -150,15 +154,34 @@ module MiniMagick
150
154
 
151
155
  # You can use multiple commands together using this method
152
156
  def combine_options(&block)
153
- c = CommandBuilder.new
157
+ c = CommandBuilder.new('mogrify')
154
158
  block.call c
155
- run_command("mogrify", *c.args << @path)
159
+ c << @path
160
+ run(c)
156
161
  end
157
162
 
158
163
  # Check to see if we are running on win32 -- we need to escape things differently
159
164
  def windows?
160
165
  !(RUBY_PLATFORM =~ /win32/).nil?
161
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
162
185
 
163
186
  # Outputs a carriage-return delimited format string for Unix and Windows
164
187
  def format_option(format)
@@ -166,40 +189,28 @@ module MiniMagick
166
189
  end
167
190
 
168
191
  def run_command(command, *args)
169
- args.collect! do |arg|
170
- # args can contain characters like '>' so we must escape them, but don't quote switches
171
- if arg !~ /^[\+\-]/
172
- "\"#{arg}\""
173
- else
174
- arg.to_s
175
- end
176
- end
177
-
178
- command = "#{MiniMagick.processor} #{command} #{args.join(' ')}".strip
192
+ run(CommandBuilder.new(command, *args))
193
+ end
194
+
195
+ def run(command_builder)
196
+ command = command_builder.command
179
197
 
180
- if ::MiniMagick.use_subexec
181
- sub = Subexec.run(command, :timeout => MiniMagick.timeout)
182
- exit_status = sub.exitstatus
183
- output = sub.output
184
- else
185
- output = `#{command} 2>&1`
186
- exit_status = $?.exitstatus
187
- end
198
+ sub = Subexec.run(command, :timeout => MiniMagick.timeout)
188
199
 
189
- if exit_status != 0
200
+ if sub.exitstatus != 0
190
201
  # Clean up after ourselves in case of an error
191
202
  destroy!
192
203
 
193
204
  # Raise the appropriate error
194
- if output =~ /no decode delegate/i || output =~ /did not return an image/i
195
- raise Invalid, output
205
+ if sub.output =~ /no decode delegate/i || sub.output =~ /did not return an image/i
206
+ raise Invalid, sub.output
196
207
  else
197
208
  # TODO: should we do something different if the command times out ...?
198
209
  # its definitely better for logging.. otherwise we dont really know
199
- 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}"
200
211
  end
201
212
  else
202
- output
213
+ sub.output
203
214
  end
204
215
  end
205
216
 
@@ -223,18 +234,44 @@ module MiniMagick
223
234
 
224
235
  class CommandBuilder
225
236
  attr :args
237
+ attr :command
226
238
 
227
- def initialize
239
+ def initialize(command, *options)
240
+ @command = command
228
241
  @args = []
242
+
243
+ options.each { |val| push(val) }
229
244
  end
230
-
245
+
246
+ def command
247
+ "#{MiniMagick.processor} #{@command} #{@args.join(' ')}".strip
248
+ end
249
+
231
250
  def method_missing(symbol, *args)
232
- @args << "-#{symbol}"
233
- @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?(' ') || 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)
234
269
  end
270
+ alias :<< :push
235
271
 
236
272
  def +(value)
237
- @args << "+#{value}"
273
+ puts "MINI_MAGICK: The + command has been deprecated. Please use c << '+#{value}')"
274
+ push "+#{value}"
238
275
  end
239
276
  end
240
277
  end
@@ -6,16 +6,41 @@ 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
+ c.background "#000000"
38
+ assert_equal "test -resize 30x40 -alpha 1 3 4 -resize \"mome fingo\" -background \"#000000\"", c.command
39
+ end
40
+
41
+ def test_dashed
42
+ c = CommandBuilder.new("test")
43
+ c.auto_orient
44
+ assert_equal "-auto-orient", c.args.join(" ")
20
45
  end
21
46
  end
Binary file
data/test/image_test.rb CHANGED
@@ -48,9 +48,15 @@ class ImageTest < Test::Unit::TestCase
48
48
  end
49
49
 
50
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
51
57
  assert_raise(MiniMagick::Invalid) do
52
- image = Image.new(NOT_AN_IMAGE_PATH)
53
- image.destroy!
58
+ image = Image.open(NOT_AN_IMAGE_PATH)
59
+ image.destroy
54
60
  end
55
61
  end
56
62
 
@@ -125,9 +131,11 @@ class ImageTest < Test::Unit::TestCase
125
131
 
126
132
  def test_image_combine_options_with_filename_with_minusses_in_it
127
133
  image = Image.from_file(SIMPLE_IMAGE_PATH)
134
+ background = "#000000"
128
135
  assert_nothing_raised do
129
136
  image.combine_options do |c|
130
137
  c.draw "image Over 0,0 10,10 '#{MINUS_IMAGE_PATH}'"
138
+ c.background background
131
139
  end
132
140
  end
133
141
  image.destroy!
@@ -181,6 +189,14 @@ class ImageTest < Test::Unit::TestCase
181
189
  assert true #we made it this far without error
182
190
  image.destroy!
183
191
  end
192
+
193
+ def test_simple_composite
194
+ image = Image.from_file(EXIF_IMAGE_PATH)
195
+ result = image.composite(Image.open(TIFF_IMAGE_PATH)) do |c|
196
+ c.gravity "center"
197
+ end
198
+ assert `diff -s #{result.path} test/composited.jpg`.include?("identical")
199
+ end
184
200
 
185
201
  # def test_mini_magick_error_when_referencing_not_existing_page
186
202
  # image = Image.from_file(ANIMATION_PATH)
data/test/trogdor.jpg CHANGED
Binary file
metadata CHANGED
@@ -1,23 +1,22 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: mini_magick
3
3
  version: !ruby/object:Gem::Version
4
- hash: 31
5
4
  prerelease: false
6
5
  segments:
7
- - 1
8
- - 3
9
6
  - 2
10
- version: 1.3.2
7
+ - 0
8
+ - 1
9
+ version: 2.0.1
11
10
  platform: ruby
12
11
  authors:
13
12
  - Corey Johnson
14
- - Peter Kieltyka
15
13
  - Hampton Catlin
14
+ - Peter Kieltyka
16
15
  autorequire:
17
16
  bindir: bin
18
17
  cert_chain: []
19
18
 
20
- date: 2010-08-02 00:00:00 -07:00
19
+ date: 2010-08-24 00:00:00 -04:00
21
20
  default_executable:
22
21
  dependencies:
23
22
  - !ruby/object:Gem::Dependency
@@ -28,7 +27,6 @@ dependencies:
28
27
  requirements:
29
28
  - - ~>
30
29
  - !ruby/object:Gem::Version
31
- hash: 23
32
30
  segments:
33
31
  - 0
34
32
  - 0
@@ -39,8 +37,8 @@ dependencies:
39
37
  description: ""
40
38
  email:
41
39
  - probablycorey@gmail.com
42
- - peter@nulayer.com
43
40
  - hcatlin@gmail.com
41
+ - peter@nulayer.com
44
42
  executables: []
45
43
 
46
44
  extensions: []
@@ -57,6 +55,7 @@ files:
57
55
  - test/actually_a_gif.jpg
58
56
  - test/animation.gif
59
57
  - test/command_builder_test.rb
58
+ - test/composited.jpg
60
59
  - test/image_test.rb
61
60
  - test/leaves.tiff
62
61
  - test/not_an_image.php
@@ -77,7 +76,6 @@ required_ruby_version: !ruby/object:Gem::Requirement
77
76
  requirements:
78
77
  - - ">="
79
78
  - !ruby/object:Gem::Version
80
- hash: 3
81
79
  segments:
82
80
  - 0
83
81
  version: "0"
@@ -86,7 +84,6 @@ required_rubygems_version: !ruby/object:Gem::Requirement
86
84
  requirements:
87
85
  - - ">="
88
86
  - !ruby/object:Gem::Version
89
- hash: 3
90
87
  segments:
91
88
  - 0
92
89
  version: "0"
@@ -101,6 +98,7 @@ test_files:
101
98
  - test/actually_a_gif.jpg
102
99
  - test/animation.gif
103
100
  - test/command_builder_test.rb
101
+ - test/composited.jpg
104
102
  - test/image_test.rb
105
103
  - test/leaves.tiff
106
104
  - test/not_an_image.php