quick_magick 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of quick_magick might be problematic. Click here for more details.

data/README CHANGED
@@ -33,7 +33,7 @@ Resize and image
33
33
  i.save "resized_image.jpg"
34
34
 
35
35
  or
36
- i.append_to_args 'resize', "300x300!"
36
+ i.append_to_operators 'resize', "300x300!"
37
37
 
38
38
  or
39
39
  i.resize 300, 300, nil, nil, QuickMagick::AspectGeometry
@@ -60,5 +60,27 @@ You can also display an image to Xserver
60
60
  i = QuickMagick::Image.read('test.jpg')
61
61
  i.display
62
62
 
63
+ QuickMagick supports also ImageLists
64
+ il = QuickMagick::ImageList.new('test.jpg', 'test2.jpg')
65
+ il << QuickMagick::Image.read('test3.jpg')
66
+ il.format = 'gif'
67
+ il.resize "300x300>"
68
+ il.save!
69
+
70
+ You can also create images from scratch
71
+ # Create a 300x300 gradient image from yellow to red
72
+ i1 = QuickMagick::Image::gradient(300, 300, QuickMagick::RadialGradient, :yellow, :red)
73
+ i1.save 'gradient.png'
74
+
75
+ # Create a 100x200 CheckerBoard image
76
+ i1 = QuickMagick::Image::pattern(100, 200, :checkerboard)
77
+ i1.display
78
+
79
+ ... and draw primitives on them
80
+ i = QuickMagick::Image::solid(100, 100, :white)
81
+ i.draw_line(0,0,50,50)
82
+ i.draw_text(30, 30, "Hello world!", :rotate=>45)
83
+ i.save 'hello.jpg'
84
+
63
85
  Check all command line options of ImageMagick at
64
86
  http://www.imagemagick.org/script/convert.php
data/Rakefile CHANGED
@@ -2,7 +2,7 @@ require 'rubygems'
2
2
  require 'rake'
3
3
  require 'echoe'
4
4
 
5
- Echoe.new('quick_magick', '0.1.0') do |p|
5
+ Echoe.new('quick_magick', '0.2.0') do |p|
6
6
  p.description = "QuickMagick allows you to access ImageMagick command line functions using Ruby interface."
7
7
  p.url = "http://quickmagick.rubyforge.org/"
8
8
  p.author = "Ahmed ElDawy"
@@ -16,7 +16,7 @@ module QuickMagick
16
16
  # create an array of images from the given file
17
17
  def read(filename, &proc)
18
18
  info = identify(%Q<"#{filename}">)
19
- if info.empty?
19
+ unless $?.success?
20
20
  raise QuickMagick::QuickMagickError, "Illegal file \"#{filename}\""
21
21
  end
22
22
  info_lines = info.split(/[\r\n]/)
@@ -34,6 +34,8 @@ module QuickMagick
34
34
 
35
35
  alias open read
36
36
 
37
+ # Creates a new image initially set to gradient
38
+ # Default gradient is linear gradient from black to white
37
39
  def gradient(width, height, type=QuickMagick::LinearGradient, color1=nil, color2=nil)
38
40
  template_name = type + ":"
39
41
  template_name << color1.to_s if color1
@@ -63,9 +65,10 @@ module QuickMagick
63
65
 
64
66
  # returns info for an image using <code>identify</code> command
65
67
  def identify(filename)
66
- `identify #{filename}`
68
+ `identify #{filename} 2>&1`
67
69
  end
68
70
 
71
+ # Encodes a geometry string with the given options
69
72
  def retrieve_geometry(width, height=nil, x=nil, y=nil, flag=nil)
70
73
  geometry_string = ""
71
74
  geometry_string << width.to_s if width
@@ -79,14 +82,15 @@ module QuickMagick
79
82
 
80
83
  # append the given option, value pair to the args for the current image
81
84
  def append_to_operators(arg, value="")
82
- @operators << %Q<-#{arg} #{value}>
85
+ @operators << %Q<-#{arg} "#{value}">
83
86
  end
84
87
 
85
88
  # append the given option, value pair to the settings of the current image
86
89
  def append_to_settings(arg, value="")
87
- @settings << %Q<-#{arg} #{value}>
90
+ @settings << %Q<-#{arg} "#{value}">
88
91
  end
89
92
 
93
+ # Image settings supported by ImageMagick
90
94
  IMAGE_SETTINGS_METHODS = %w{
91
95
  adjoin affine alpha antialias authenticate attenuate background bias black-point-compensation
92
96
  blue-primary bordercolor caption channel colors colorspace comment compose compress define
@@ -99,6 +103,7 @@ module QuickMagick
99
103
  density page sampling-factor size tile-offset
100
104
  }
101
105
 
106
+ # Image operators supported by ImageMagick
102
107
  IMAGE_OPERATORS_METHODS = %w{
103
108
  alpha auto-orient bench black-threshold bordercolor charcoal clip clip-mask clip-path colorize
104
109
  contrast convolve cycle decipher deskew despeckle distort draw edge encipher emboss enhance equalize
@@ -117,16 +122,19 @@ module QuickMagick
117
122
  crop
118
123
  }
119
124
 
125
+ # fills a rectangle with a solid color
120
126
  def floodfill(width, height=nil, x=nil, y=nil, flag=nil, color=nil)
121
127
  # TODO do a special method for floodfill
122
128
  end
123
129
 
130
+ # methods that are called with (=)
124
131
  WITH_EQUAL_METHODS =
125
132
  %w{alpha antialias background bias black-point-compensation blue-primary border bordercolor caption
126
133
  cahnnel colors colorspace comment compose compress depth density encoding endian family fill filter
127
134
  font format frame fuzz geometry gravity label mattecolor page pointsize quality undercolor units weight
128
135
  brodercolor transparent type size}
129
136
 
137
+ # methods that takes geometry options
130
138
  WITH_GEOMETRY_METHODS =
131
139
  %w{density page sampling-factor size tile-offset adaptive-blur adaptive-resize adaptive-sharpen
132
140
  annotate blur border chop contrast-stretch extent extract floodfill frame gaussian-blur
@@ -137,15 +145,15 @@ module QuickMagick
137
145
  IMAGE_SETTINGS_METHODS.each do |method|
138
146
  if WITH_EQUAL_METHODS.include?(method)
139
147
  define_method((method+'=').to_sym) do |arg|
140
- append_to_settings(method, %Q<"#{arg}"> )
148
+ append_to_settings(method, arg)
141
149
  end
142
150
  elsif WITH_GEOMETRY_METHODS.include?(method)
143
151
  define_method((method).to_sym) do |*args|
144
- append_to_settings(method, %Q<"#{QuickMagick::Image.retrieve_geometry(*args) }"> )
152
+ append_to_settings(method, QuickMagick::Image.retrieve_geometry(*args) )
145
153
  end
146
154
  else
147
155
  define_method(method.to_sym) do |*args|
148
- append_to_settings(method, args.collect{|arg| %Q<"#{arg}"> }.join(" "))
156
+ append_to_settings(method, args.join(" "))
149
157
  end
150
158
  end
151
159
  end
@@ -153,15 +161,15 @@ module QuickMagick
153
161
  IMAGE_OPERATORS_METHODS.each do |method|
154
162
  if WITH_EQUAL_METHODS.include?(method)
155
163
  define_method((method+'=').to_sym) do |arg|
156
- append_to_operators(method, %Q<"#{arg}"> )
164
+ append_to_operators(method, arg )
157
165
  end
158
166
  elsif WITH_GEOMETRY_METHODS.include?(method)
159
167
  define_method((method).to_sym) do |*args|
160
- append_to_operators(method, %Q<"#{QuickMagick::Image.retrieve_geometry(*args) }"> )
168
+ append_to_operators(method, QuickMagick::Image.retrieve_geometry(*args) )
161
169
  end
162
170
  else
163
171
  define_method(method.to_sym) do |*args|
164
- append_to_operators(method, args.collect{|arg| %Q<"#{arg}"> }.join(" "))
172
+ append_to_operators(method, args.join(" "))
165
173
  end
166
174
  end
167
175
  end
@@ -176,27 +184,172 @@ module QuickMagick
176
184
  @pseudo_image = pseudo_image
177
185
  if info_line
178
186
  @image_infoline = info_line.split
179
- @image_infoline[0..1] = @image_infoline[0..1].join(' ') while !@image_infoline[0].start_with?(image_filename)
187
+ @image_infoline[0..1] = @image_infoline[0..1].join(' ') while @image_infoline.size > 1 && !@image_infoline[0].start_with?(image_filename)
180
188
  end
181
189
  @operators = ""
182
190
  @settings = ""
183
191
  end
184
192
 
193
+ # The command line so far that will be used to convert or save the image
185
194
  def command_line
186
195
  %Q<#{@settings} "#{image_filename}" #{@operators}>
187
196
  end
188
197
 
198
+ # An information line about the image obtained using 'identify' command line
189
199
  def image_infoline
190
200
  unless @image_infoline
191
201
  @image_infoline = QuickMagick::Image::identify(command_line).split
192
- @image_infoline[0..1] = @image_infoline[0..1].join(' ') while !@image_infoline[0].start_with?(image_filename)
202
+ @image_infoline[0..1] = @image_infoline[0..1].join(' ') while @image_infoline.size > 1 && !@image_infoline[0].start_with?(image_filename)
193
203
  end
194
204
  @image_infoline
195
205
  end
196
206
 
207
+ # converts options passed to any primitive to a string that can be passed to ImageMagick
208
+ # options allowed are:
209
+ # * rotate degrees
210
+ # * translate dx,dy
211
+ # * scale sx,sy
212
+ # * skewX degrees
213
+ # * skewY degrees
214
+ # * gravity NorthWest, North, NorthEast, West, Center, East, SouthWest, South, or SouthEast
215
+ # The rotate primitive rotates subsequent shape primitives and text primitives about the origin of the main image.
216
+ # If you set the region before the draw command, the origin for transformations is the upper left corner of the region.
217
+ # The translate primitive translates subsequent shape and text primitives.
218
+ # The scale primitive scales them.
219
+ # The skewX and skewY primitives skew them with respect to the origin of the main image or the region.
220
+ # The text gravity primitive only affects the placement of text and does not interact with the other primitives.
221
+ # It is equivalent to using the gravity method, except that it is limited in scope to the draw_text option in which it appears.
222
+ def options_to_str(options)
223
+ options.to_a.flatten.join " "
224
+ end
225
+
226
+ # Converts an array of coordinates to a string that can be passed to polygon, polyline and bezier
227
+ def points_to_str(points)
228
+ raise QuickMagick::QuickMagickError, "Points must be an even number of coordinates" if points.size.odd?
229
+ points_str = ""
230
+ points.each_slice(2) do |point|
231
+ points_str << point.join(",") << " "
232
+ end
233
+ points_str
234
+ end
235
+
236
+ # The shape primitives are drawn in the color specified by the preceding -fill setting.
237
+ # For unfilled shapes, use -fill none.
238
+ # You can optionally control the stroke (the "outline" of a shape) with the -stroke and -strokewidth settings.
239
+
240
+ # draws a point at the given location in pixels
241
+ # A point primitive is specified by a single point in the pixel plane, that is, by an ordered pair
242
+ # of integer coordinates, x,y.
243
+ # (As it involves only a single pixel, a point primitive is not affected by -stroke or -strokewidth.)
244
+ def draw_point(x, y, options={})
245
+ append_to_operators("draw", "#{options_to_str(options)} point #{x},#{y}")
246
+ end
247
+
248
+ # draws a line between the given two points
249
+ # A line primitive requires a start point and end point.
250
+ def draw_line(x0, y0, x1, y1, options={})
251
+ append_to_operators("draw", "#{options_to_str(options)} line #{x0},#{y0} #{x1},#{y1}")
252
+ end
253
+
254
+ # draw a rectangle with the given two corners
255
+ # A rectangle primitive is specified by the pair of points at the upper left and lower right corners.
256
+ def draw_rectangle(x0, y0, x1, y1, options={})
257
+ append_to_operators("draw", "#{options_to_str(options)} rectangle #{x0},#{y0} #{x1},#{y1}")
258
+ end
259
+
260
+ # draw a rounded rectangle with the given two corners
261
+ # wc and hc are the width and height of the arc
262
+ # A roundRectangle primitive takes the same corner points as a rectangle
263
+ # followed by the width and height of the rounded corners to be removed.
264
+ def draw_round_rectangle(x0, y0, x1, y1, wc, hc, options={})
265
+ append_to_operators("draw", "#{options_to_str(options)} roundRectangle #{x0},#{y0} #{x1},#{y1} #{wc},#{hc}")
266
+ end
267
+
268
+ # The arc primitive is used to inscribe an elliptical segment in to a given rectangle.
269
+ # An arc requires the two corners used for rectangle (see above) followed by
270
+ # the start and end angles of the arc of the segment segment (e.g. 130,30 200,100 45,90).
271
+ # The start and end points produced are then joined with a line segment and the resulting segment of an ellipse is filled.
272
+ def draw_arc(x0, y0, x1, y1, a0, a1, options={})
273
+ append_to_operators("draw", "#{options_to_str(options)} arc #{x0},#{y0} #{x1},#{y1} #{a0},#{a1}")
274
+ end
275
+
276
+ # Use ellipse to draw a partial (or whole) ellipse.
277
+ # Give the center point, the horizontal and vertical "radii"
278
+ # (the semi-axes of the ellipse) and start and end angles in degrees (e.g. 100,100 100,150 0,360).
279
+ def draw_ellipse(x0, y0, rx, ry, a0, a1, options={})
280
+ append_to_operators("draw", "#{options_to_str(options)} ellipse #{x0},#{y0} #{rx},#{ry} #{a0},#{a1}")
281
+ end
282
+
283
+ # The circle primitive makes a disk (filled) or circle (unfilled). Give the center and any point on the perimeter (boundary).
284
+ def draw_circle(x0, y0, x1, y1, options={})
285
+ append_to_operators("draw", "#{options_to_str(options)} circle #{x0},#{y0} #{x1},#{y1}")
286
+ end
287
+
288
+ # The polyline primitive requires three or more points to define their perimeters.
289
+ # A polyline is simply a polygon in which the final point is not stroked to the start point.
290
+ # When unfilled, this is a polygonal line. If the -stroke setting is none (the default), then a polyline is identical to a polygon.
291
+ def draw_polyline(points, options={})
292
+ append_to_operators("draw", "#{options_to_str(options)} polyline #{points_to_str(points)}")
293
+ end
294
+
295
+ # The polygon primitive requires three or more points to define their perimeters.
296
+ # A polyline is simply a polygon in which the final point is not stroked to the start point.
297
+ # When unfilled, this is a polygonal line. If the -stroke setting is none (the default), then a polyline is identical to a polygon.
298
+ def draw_polygon(points, options={})
299
+ append_to_operators("draw", "#{options_to_str(options)} polygon #{points_to_str(points)}")
300
+ end
301
+
302
+ # The Bezier primitive creates a spline curve and requires three or points to define its shape.
303
+ # The first and last points are the knots and these points are attained by the curve,
304
+ # while any intermediate coordinates are control points.
305
+ # If two control points are specified, the line between each end knot and its sequentially
306
+ # respective control point determines the tangent direction of the curve at that end.
307
+ # If one control point is specified, the lines from the end knots to the one control point
308
+ # determines the tangent directions of the curve at each end.
309
+ # If more than two control points are specified, then the additional control points
310
+ # act in combination to determine the intermediate shape of the curve.
311
+ # In order to draw complex curves, it is highly recommended either to use the path primitive
312
+ # or to draw multiple four-point bezier segments with the start and end knots of each successive segment repeated.
313
+ def draw_bezier(points, options={})
314
+ append_to_operators("draw", "#{options_to_str(options)} bezier #{points_to_str(points)}")
315
+ end
316
+
317
+ # A path represents an outline of an object, defined in terms of moveto
318
+ # (set a new current point), lineto (draw a straight line), curveto (draw a Bezier curve),
319
+ # arc (elliptical or circular arc) and closepath (close the current shape by drawing a
320
+ # line to the last moveto) elements.
321
+ # Compound paths (i.e., a path with subpaths, each consisting of a single moveto followed by
322
+ # one or more line or curve operations) are possible to allow effects such as donut holes in objects.
323
+ # (See http://www.w3.org/TR/SVG/paths.html)
324
+ def draw_path(path_spec, options={})
325
+ append_to_operators("draw", "#{options_to_str(options)} path #{path_spec}")
326
+ end
327
+
328
+ # Use image to composite an image with another image. Follow the image keyword
329
+ # with the composite operator, image location, image size, and filename
330
+ # You can use 0,0 for the image size, which means to use the actual dimensions found in the image header.
331
+ # Otherwise, it is scaled to the given dimensions. See -compose for a description of the composite operators.
332
+ def draw_image(operator, x0, y0, w, h, image_filename, options={})
333
+ append_to_operators("draw", "#{options_to_str(options)} image #{operator} #{x0},#{y0} #{w},#{h} \"#{image_filename}\"")
334
+ end
335
+
336
+ # Use text to annotate an image with text. Follow the text coordinates with a string.
337
+ def draw_text(x0, y0, text, options={})
338
+ append_to_operators("draw", "#{options_to_str(options)} text #{x0},#{y0} '#{text}'")
339
+ end
340
+
197
341
  # saves the current image to the given filename
198
342
  def save(output_filename)
199
- `convert #{command_line} "#{output_filename}"`
343
+ result = `convert #{command_line} "#{output_filename}" 2>&1`
344
+ if $?.success?
345
+ return result
346
+ else
347
+ error_message = <<-ERROR
348
+ Error executing command: convert #{command_line} "#{output_filename}"
349
+ Result is: #{result}
350
+ ERROR
351
+ raise QuickMagick::QuickMagickError, error_message
352
+ end
200
353
  end
201
354
 
202
355
  alias write save
@@ -205,36 +358,51 @@ module QuickMagick
205
358
  # saves the current image overwriting the original image file
206
359
  def save!
207
360
  raise QuickMagick::QuickMagickError, "Cannot mogrify a pseudo image" if @pseudo_image
208
- `mogrify #{command_line}`
361
+ result = `mogrify #{command_line}`
362
+ if $?.success?
363
+ return result
364
+ else
365
+ error_message = <<-ERROR
366
+ Error executing command: mogrify #{command_line}
367
+ Result is: #{result}
368
+ ERROR
369
+ raise QuickMagick::QuickMagickError, error_message
370
+ end
209
371
  end
210
372
 
211
373
  alias write! save!
212
374
  alias mogrify! save!
213
375
 
376
+ # image file format
214
377
  def format
215
378
  image_infoline[1]
216
379
  end
217
380
 
381
+ # columns of image in pixels
218
382
  def columns
219
383
  image_infoline[2].split('x').first.to_i
220
384
  end
221
385
 
222
386
  alias width columns
223
387
 
388
+ # rows of image in pixels
224
389
  def rows
225
390
  image_infoline[2].split('x').last.to_i
226
391
  end
227
392
 
228
393
  alias height rows
229
394
 
395
+ # Bit depth
230
396
  def bit_depth
231
397
  image_infoline[4].to_i
232
398
  end
233
399
 
400
+ # Number of different colors used in this image
234
401
  def colors
235
402
  image_infoline[6].to_i
236
403
  end
237
404
 
405
+ # returns size of image in bytes
238
406
  def size
239
407
  File.size?(image_filename)
240
408
  end
data/quick_magick.gemspec CHANGED
@@ -2,11 +2,11 @@
2
2
 
3
3
  Gem::Specification.new do |s|
4
4
  s.name = %q{quick_magick}
5
- s.version = "0.1.0"
5
+ s.version = "0.2.0"
6
6
 
7
7
  s.required_rubygems_version = Gem::Requirement.new(">= 1.2") if s.respond_to? :required_rubygems_version=
8
8
  s.authors = ["Ahmed ElDawy"]
9
- s.date = %q{2009-07-29}
9
+ s.date = %q{2009-07-30}
10
10
  s.description = %q{QuickMagick allows you to access ImageMagick command line functions using Ruby interface.}
11
11
  s.email = %q{ahmed.eldawy@badrit.com}
12
12
  s.extra_rdoc_files = ["README", "lib/quick_magick/image.rb", "lib/quick_magick/image_list.rb", "lib/quick_magick.rb"]
data/test/image_test.rb CHANGED
@@ -122,4 +122,24 @@ class ImageTest < Test::Unit::TestCase
122
122
  i = QuickMagick::Image.gradient(100, 100, QuickMagick::RadialGradient, :yellow, :blue)
123
123
  assert_equal 100, i.width
124
124
  end
125
+
126
+ def test_line_primitive
127
+ i = QuickMagick::Image.solid(100, 100, :white)
128
+ i.draw_line(0, 0, 50, 50)
129
+ out_filename = File.join($base_dir, "line_test.gif")
130
+ i.save out_filename
131
+ ensure
132
+ # clean up
133
+ File.delete(out_filename) if out_filename && File.exists?(out_filename)
134
+ end
135
+
136
+ def test_text_primitive
137
+ i = QuickMagick::Image.solid(100, 100, :white)
138
+ i.draw_text(0, 50, "Ahmed Eldawy")
139
+ out_filename = File.join($base_dir, "text_test.gif")
140
+ i.save out_filename
141
+ ensure
142
+ # clean up
143
+ File.delete(out_filename) if out_filename && File.exists?(out_filename)
144
+ end
125
145
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quick_magick
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Ahmed ElDawy
@@ -9,7 +9,7 @@ autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
11
 
12
- date: 2009-07-29 00:00:00 +03:00
12
+ date: 2009-07-30 00:00:00 +03:00
13
13
  default_executable:
14
14
  dependencies: []
15
15