Class: QuickMagick::Image

Inherits:
Object
  • Object
show all
Defined in:
lib/quick_magick/image.rb

Constant Summary collapse

IMAGE_SETTINGS_METHODS =

Image settings supported by ImageMagick

%w{
  adjoin affine alpha authenticate attenuate background bias black-point-compensation
  blue-primary bordercolor caption channel colors colorspace comment compose compress define
  delay depth display dispose dither encoding endian family fill filter font format fuzz gravity
  green-primary intent interlace interpolate interword-spacing kerning label limit loop mask
  mattecolor monitor orient ping pointsize preview quality quiet red-primary regard-warnings
  remap respect-parentheses scene seed stretch stroke strokewidth style taint texture treedepth
  transparent-color undercolor units verbose view virtual-pixel weight white-point

  density page sampling-factor size tile-offset
}
IMAGE_OPERATORS_METHODS =

Image operators supported by ImageMagick

%w{
alpha auto-orient bench black-threshold bordercolor charcoal clip clip-mask clip-path colorize
contrast convolve cycle decipher deskew despeckle distort edge encipher emboss enhance equalize
evaluate flip flop function gamma identify implode layers level level-colors median modulate monochrome
negate noise normalize opaque ordered-dither NxN paint polaroid posterize print profile quantize
radial-blur Raise random-threshold recolor render rotate segment sepia-tone set shade solarize
sparse-color spread strip swirl threshold tile tint transform transparent transpose transverse trim
type unique-colors white-threshold

adaptive-blur adaptive-resize adaptive-sharpen annotate blur border chop contrast-stretch extent
extract frame gaussian-blur geometry lat linear-stretch liquid-rescale motion-blur region repage
resample resize roll sample scale selective-blur shadow sharpen shave shear sigmoidal-contrast
sketch splice thumbnail unsharp vignette wave

append average clut coalesce combine composite deconstruct flatten fx hald-clut morph mosaic process reverse separate write
crop
}
WITH_EQUAL_METHODS =

methods that are called with (=)

%w{alpha background bias black-point-compensation blue-primary border bordercolor caption
cahnnel colors colorspace comment compose compress depth density encoding endian family fill filter
font format frame fuzz geometry gravity label mattecolor page pointsize quality stroke strokewidth
undercolor units weight
brodercolor transparent type size}
WITH_GEOMETRY_METHODS =

methods that takes geometry options

%w{density page sampling-factor size tile-offset adaptive-blur adaptive-resize adaptive-sharpen
annotate blur border chop contrast-stretch extent extract frame gaussian-blur
geometry lat linear-stretch liquid-rescale motion-blur region repage resample resize roll
sample scale selective-blur shadow sharpen shave shear sigmoidal-contrast sketch
splice thumbnail unsharp vignette wave crop}
SPECIAL_COMMANDS =

Methods that need special treatment. This array is used just to keep track of them.

%w{floodfill antialias draw}

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(filename, index = 0, info_line = nil, pseudo_image = false) ⇒ Image

constructor



200
201
202
203
204
205
206
207
208
209
# File 'lib/quick_magick/image.rb', line 200

def initialize(filename, index=0, info_line=nil, pseudo_image=false)
  @image_filename = filename
  @index = index
  @pseudo_image = pseudo_image
  if info_line
    @image_infoline = info_line.split
    @image_infoline[0..1] = @image_infoline[0..1].join(' ') while @image_infoline.size > 1 && !@image_infoline[0].start_with?(image_filename)
  end
  @arguments = ""
end

Instance Attribute Details

#image_filenameObject (readonly) Also known as: original_filename

define attribute readers (getters)



196
197
198
# File 'lib/quick_magick/image.rb', line 196

def image_filename
  @image_filename
end

Class Method Details

.from_blob(blob, &proc) ⇒ Object

create an array of images from the given blob data



9
10
11
12
13
14
15
# File 'lib/quick_magick/image.rb', line 9

def from_blob(blob, &proc)
  file = Tempfile.new(QuickMagick::random_string)
  file.binmode
  file.write(blob)
  file.close
  self.read(file.path, &proc)
end

.gradient(width, height, type = QuickMagick::LinearGradient, color1 = nil, color2 = nil) {|i| ... } ⇒ Object

Creates a new image initially set to gradient Default gradient is linear gradient from black to white

Yields:

  • (i)


33
34
35
36
37
38
39
40
41
# File 'lib/quick_magick/image.rb', line 33

def gradient(width, height, type=QuickMagick::LinearGradient, color1=nil, color2=nil)
  template_name = type + ":"
  template_name << color1.to_s if color1
  template_name << '-' << color2.to_s if color2
  i = self.new(template_name, 0, nil, true)
  i.size = QuickMagick::geometry(width, height)
  yield(i) if block_given?
  i
end

.identify(filename) ⇒ Object

returns info for an image using identify command



64
65
66
# File 'lib/quick_magick/image.rb', line 64

def identify(filename)
  QuickMagick.exec3 "identify #{QuickMagick.c filename}"
end

.pattern(width, height, pattern) {|i| ... } ⇒ Object

Creates an image from pattern

Yields:

  • (i)

Raises:



54
55
56
57
58
59
60
61
# File 'lib/quick_magick/image.rb', line 54

def pattern(width, height, pattern)
  raise QuickMagick::QuickMagickError, "Invalid pattern '#{pattern.to_s}'" unless QuickMagick::Patterns.include?(pattern.to_s)
  template_name = "pattern:#{pattern.to_s}"
  i = self.new(template_name, 0, nil, true)
  i.size = QuickMagick::geometry(width, height)
  yield(i) if block_given?
  i
end

.read(filename, &proc) ⇒ Object Also known as: open

create an array of images from the given file



18
19
20
21
22
23
24
25
26
27
# File 'lib/quick_magick/image.rb', line 18

def read(filename, &proc)
  info = identify(filename)
  info_lines = info.split(/[\r\n]/)
  images = []
  info_lines.each_with_index do |info_line, i|
    images << Image.new(filename, i, info_line)
  end
  images.each(&proc) if block_given?
  return images
end

.solid(width, height, color = nil) {|i| ... } ⇒ Object

Creates an image with solid color

Yields:

  • (i)


44
45
46
47
48
49
50
51
# File 'lib/quick_magick/image.rb', line 44

def solid(width, height, color=nil)
  template_name = QuickMagick::SolidColor+":"
  template_name << color.to_s if color
  i = self.new(template_name, 0, nil, true)
  i.size = QuickMagick::geometry(width, height)
  yield(i) if block_given?
  i
end

Instance Method Details

#animateObject

displays the current image as animated image



486
487
488
# File 'lib/quick_magick/image.rb', line 486

def animate
  `animate #{command_line}`
end

#antialias=(flag) ⇒ Object

Enables/Disables flood fill. Pass a boolean argument.



191
192
193
# File 'lib/quick_magick/image.rb', line 191

def antialias=(flag)
	append_basic flag ? '-antialias' : '+antialias'
end

#append_basic(arg) ⇒ Object

append the given string as is. Used to append special arguments like antialias or debug



78
79
80
# File 'lib/quick_magick/image.rb', line 78

def append_basic(arg)
  @arguments << arg << ' '
end

#append_to_operators(arg, value = nil) ⇒ Object

append the given option, value pair to the args for the current image



96
97
98
99
100
101
102
103
104
105
# File 'lib/quick_magick/image.rb', line 96

def append_to_operators(arg, value=nil)
  is_draw = (arg == 'draw')
  if @last_is_draw && is_draw
    @arguments.insert(@arguments.rindex('"'), " #{value}")
  else
    @arguments << %Q<-#{arg} #{QuickMagick.c value} >
  end
  @last_is_draw = is_draw
  self
end

#append_to_settings(arg, value = nil) ⇒ Object

append the given option, value pair to the settings of the current image



71
72
73
74
75
# File 'lib/quick_magick/image.rb', line 71

def append_to_settings(arg, value=nil)
  @arguments << "-#{arg} #{QuickMagick.c value} "
  @last_is_draw = false
  self
end

#bit_depthObject

Bit depth



430
431
432
# File 'lib/quick_magick/image.rb', line 430

def bit_depth
  image_infoline[4].to_i
end

#colorsObject

Number of different colors used in this image



435
436
437
# File 'lib/quick_magick/image.rb', line 435

def colors
  image_infoline[6].to_i
end

#columnsObject Also known as: width

columns of image in pixels



416
417
418
# File 'lib/quick_magick/image.rb', line 416

def columns
  image_infoline[2].split('x').first.to_i
end

#command_lineObject

The command line so far that will be used to convert or save the image



212
213
214
# File 'lib/quick_magick/image.rb', line 212

def command_line
  %Q< "(" #{@arguments} #{QuickMagick.c(image_filename + (@pseudo_image ? "" : "[#{@index}]"))} ")" >
end

#detailsObject

Returns details of the image as found by “identify -verbose” command



454
455
456
457
458
459
460
461
462
463
464
465
466
467
468
469
470
471
472
473
474
475
476
477
478
479
480
481
482
483
# File 'lib/quick_magick/image.rb', line 454

def details
  str_details = QuickMagick.exec3("identify -verbose #{QuickMagick.c image_filename}[#@index]")
  # This is something like breadcrumb for hashes visited at any time
  hash_stack = []
  # Current indentation. Used to infer nesting using indentation
  current_indent = ""
  # Last key inserted in the hash. Used to determine which key is the parent of a nested hash
  last_key = nil
  # Start with top level empty hash
  hash_stack.push({})
  str_details.each_line do |line|
    key, value = line.split(":", 2)
    key_indent = key[/^\s*/]
    if key_indent.length < current_indent.length
      # Must go one level up
      hash_stack.pop
    elsif key_indent.length > current_indent.length
      # Must go one level deeper using last key
      hash_stack.last[last_key] = {}
      hash_stack.push hash_stack.last[last_key]
    end
    current_indent = key_indent

    key = key.strip
    value = value.strip
    hash_stack.last[key] = value
    last_key = key
  end
  hash_stack.first
end

#displayObject

displays the current image to the x-windowing system



491
492
493
# File 'lib/quick_magick/image.rb', line 491

def display
  `display #{command_line}`
end

#draw_arc(x0, y0, x1, y1, a0, a1, options = {}) ⇒ Object

The arc primitive is used to inscribe an elliptical segment in to a given rectangle. An arc requires the two corners used for rectangle (see above) followed by the start and end angles of the arc of the segment segment (e.g. 130,30 200,100 45,90). The start and end points produced are then joined with a line segment and the resulting segment of an ellipse is filled.



293
294
295
# File 'lib/quick_magick/image.rb', line 293

def draw_arc(x0, y0, x1, y1, a0, a1, options={})
  append_to_operators("draw", "#{options_to_str(options)} arc #{x0},#{y0} #{x1},#{y1} #{a0},#{a1}")
end

#draw_bezier(points, options = {}) ⇒ Object

The Bezier primitive creates a spline curve and requires three or points to define its shape. The first and last points are the knots and these points are attained by the curve, while any intermediate coordinates are control points. If two control points are specified, the line between each end knot and its sequentially respective control point determines the tangent direction of the curve at that end. If one control point is specified, the lines from the end knots to the one control point determines the tangent directions of the curve at each end. If more than two control points are specified, then the additional control points act in combination to determine the intermediate shape of the curve. In order to draw complex curves, it is highly recommended either to use the path primitive or to draw multiple four-point bezier segments with the start and end knots of each successive segment repeated.



338
339
340
# File 'lib/quick_magick/image.rb', line 338

def draw_bezier(points, options={})
  append_to_operators("draw", "#{options_to_str(options)} bezier #{points_to_str(points)}")
end

#draw_circle(x0, y0, x1, y1, options = {}) ⇒ Object

The circle primitive makes a disk (filled) or circle (unfilled). Give the center and any point on the perimeter (boundary).



305
306
307
# File 'lib/quick_magick/image.rb', line 305

def draw_circle(x0, y0, x1, y1, options={})
  append_to_operators("draw", "#{options_to_str(options)} circle #{x0},#{y0} #{x1},#{y1}")
end

#draw_ellipse(x0, y0, rx, ry, a0, a1, options = {}) ⇒ Object

Use ellipse to draw a partial (or whole) ellipse. Give the center point, the horizontal and vertical “radii” (the semi-axes of the ellipse) and start and end angles in degrees (e.g. 100,100 100,150 0,360).



300
301
302
# File 'lib/quick_magick/image.rb', line 300

def draw_ellipse(x0, y0, rx, ry, a0, a1, options={})
  append_to_operators("draw", "#{options_to_str(options)} ellipse #{x0},#{y0} #{rx},#{ry} #{a0},#{a1}")
end

#draw_image(operator, x0, y0, w, h, image_filename, options = {}) ⇒ Object

Use image to composite an image with another image. Follow the image keyword with the composite operator, image location, image size, and filename You can use 0,0 for the image size, which means to use the actual dimensions found in the image header. Otherwise, it is scaled to the given dimensions. See -compose for a description of the composite operators.



357
358
359
# File 'lib/quick_magick/image.rb', line 357

def draw_image(operator, x0, y0, w, h, image_filename, options={})
  append_to_operators("draw", "#{options_to_str(options)} image #{operator} #{x0},#{y0} #{w},#{h} \"#{image_filename}\"")
end

#draw_line(x0, y0, x1, y1, options = {}) ⇒ Object

draws a line between the given two points A line primitive requires a start point and end point.



271
272
273
# File 'lib/quick_magick/image.rb', line 271

def draw_line(x0, y0, x1, y1, options={})
  append_to_operators("draw", "#{options_to_str(options)} line #{x0},#{y0} #{x1},#{y1}")
end

#draw_path(path_spec, options = {}) ⇒ Object

A path represents an outline of an object, defined in terms of moveto (set a new current point), lineto (draw a straight line), curveto (draw a Bezier curve), arc (elliptical or circular arc) and closepath (close the current shape by drawing a line to the last moveto) elements. Compound paths (i.e., a path with subpaths, each consisting of a single moveto followed by one or more line or curve operations) are possible to allow effects such as donut holes in objects. (See www.w3.org/TR/SVG/paths.html)



349
350
351
# File 'lib/quick_magick/image.rb', line 349

def draw_path(path_spec, options={})
  append_to_operators("draw", "#{options_to_str(options)} path #{path_spec}")
end

#draw_point(x, y, options = {}) ⇒ Object

draws a point at the given location in pixels A point primitive is specified by a single point in the pixel plane, that is, by an ordered pair of integer coordinates, x,y. (As it involves only a single pixel, a point primitive is not affected by -stroke or -strokewidth.)



265
266
267
# File 'lib/quick_magick/image.rb', line 265

def draw_point(x, y, options={})
  append_to_operators("draw", "#{options_to_str(options)} point #{x},#{y}")
end

#draw_polygon(points, options = {}) ⇒ Object

The polygon primitive requires three or more points to define their perimeters. A polyline is simply a polygon in which the final point is not stroked to the start point. When unfilled, this is a polygonal line. If the -stroke setting is none (the default), then a polyline is identical to a polygon.

points - A single array with each pair forming a coordinate in the form (x, y).

e.g. [0,0,100,100,100,0] will draw a polygon between points (0,0)-(100,100)-(100,0)



323
324
325
# File 'lib/quick_magick/image.rb', line 323

def draw_polygon(points, options={})
  append_to_operators("draw", "#{options_to_str(options)} polygon #{points_to_str(points)}")
end

#draw_polyline(points, options = {}) ⇒ Object

The polyline primitive requires three or more points to define their perimeters. A polyline is simply a polygon in which the final point is not stroked to the start point. When unfilled, this is a polygonal line. If the -stroke setting is none (the default), then a polyline is identical to a polygon.

points - A single array with each pair forming a coordinate in the form (x, y).

e.g. [0,0,100,100,100,0] will draw a polyline between points (0,0)-(100,100)-(100,0)



314
315
316
# File 'lib/quick_magick/image.rb', line 314

def draw_polyline(points, options={})
  append_to_operators("draw", "#{options_to_str(options)} polyline #{points_to_str(points)}")
end

#draw_rectangle(x0, y0, x1, y1, options = {}) ⇒ Object

draw a rectangle with the given two corners A rectangle primitive is specified by the pair of points at the upper left and lower right corners.



277
278
279
# File 'lib/quick_magick/image.rb', line 277

def draw_rectangle(x0, y0, x1, y1, options={})
  append_to_operators("draw", "#{options_to_str(options)} rectangle #{x0},#{y0} #{x1},#{y1}")
end

#draw_round_rectangle(x0, y0, x1, y1, wc, hc, options = {}) ⇒ Object

draw a rounded rectangle with the given two corners wc and hc are the width and height of the arc A roundRectangle primitive takes the same corner points as a rectangle followed by the width and height of the rounded corners to be removed.



285
286
287
# File 'lib/quick_magick/image.rb', line 285

def draw_round_rectangle(x0, y0, x1, y1, wc, hc, options={})
  append_to_operators("draw", "#{options_to_str(options)} roundRectangle #{x0},#{y0} #{x1},#{y1} #{wc},#{hc}")
end

#draw_text(x0, y0, text, options = {}) ⇒ Object

Use text to annotate an image with text. Follow the text coordinates with a string.



362
363
364
# File 'lib/quick_magick/image.rb', line 362

def draw_text(x0, y0, text, options={})
  append_to_operators("draw", "#{options_to_str(options)} text #{x0},#{y0} '#{text.gsub('"', '\"').gsub("'", "\\\\'")}'")
end

#floodfill(width, height = nil, x = nil, y = nil, flag = nil, color = nil) ⇒ Object

Fills a rectangle with a solid color



186
187
188
# File 'lib/quick_magick/image.rb', line 186

def floodfill(width, height=nil, x=nil, y=nil, flag=nil, color=nil)
  append_to_operators "floodfill", QuickMagick::geometry(width, height, x, y, flag), color
end

#formatObject

image file format



411
412
413
# File 'lib/quick_magick/image.rb', line 411

def format
  image_infoline[1]
end

#get_pixel(x, y) ⇒ Object

Reads a pixel from the image. WARNING: This is done through command line which is very slow. It is not recommended at all to use this method for image processing for example.



447
448
449
450
451
# File 'lib/quick_magick/image.rb', line 447

def get_pixel(x, y)
  result = QuickMagick.exec3("identify -verbose -crop #{QuickMagick::geometry(1,1,x,y)} #{QuickMagick.c image_filename}[#{@index}]")
  result =~ /Histogram:\s*\d+:\s*\(\s*(\d+),\s*(\d+),\s*(\d+)\)/
  return [$1.to_i, $2.to_i, $3.to_i]
end

#image_infolineObject

An information line about the image obtained using ‘identify’ command line



217
218
219
220
221
222
223
224
# File 'lib/quick_magick/image.rb', line 217

def image_infoline
  return nil if @pseudo_image
  unless @image_infoline
    @image_infoline = QuickMagick::Image::identify(command_line).split
    @image_infoline[0..1] = @image_infoline[0..1].join(' ') while @image_infoline.size > 1 && !@image_infoline[0].start_with?(image_filename)
  end
  @image_infoline
end

#options_to_str(options) ⇒ Object

converts options passed to any primitive to a string that can be passed to ImageMagick options allowed are:

  • rotate degrees

  • translate dx,dy

  • scale sx,sy

  • skewX degrees

  • skewY degrees

  • gravity NorthWest, North, NorthEast, West, Center, East, SouthWest, South, or SouthEast

  • stroke color

  • fill color

The rotate primitive rotates subsequent shape primitives and text primitives about the origin of the main image. If you set the region before the draw command, the origin for transformations is the upper left corner of the region. The translate primitive translates subsequent shape and text primitives. The scale primitive scales them. The skewX and skewY primitives skew them with respect to the origin of the main image or the region. The text gravity primitive only affects the placement of text and does not interact with the other primitives. It is equivalent to using the gravity method, except that it is limited in scope to the draw_text option in which it appears.



243
244
245
# File 'lib/quick_magick/image.rb', line 243

def options_to_str(options)
  options.to_a.flatten.join " "
end

#points_to_str(points) ⇒ Object

Converts an array of coordinates to a string that can be passed to polygon, polyline and bezier



248
249
250
251
252
253
254
255
# File 'lib/quick_magick/image.rb', line 248

def points_to_str(points)
  raise QuickMagick::QuickMagickError, "Points must be an even number of coordinates" if points.size.odd?
  points_str = ""
  points.each_slice(2) do |point|
    points_str << point.join(",") << " "
  end
  points_str
end

#revert!Object

Reverts this image to its last saved state. Note that you cannot revert an image created from scratch.



109
110
111
112
# File 'lib/quick_magick/image.rb', line 109

def revert!
  raise QuickMagick::QuickMagickError, "Cannot revert a pseudo image" if @pseudo_image
  @arguments = ""
end

#rowsObject Also known as: height

rows of image in pixels



423
424
425
# File 'lib/quick_magick/image.rb', line 423

def rows
  image_infoline[2].split('x').last.to_i
end

#save(output_filename) ⇒ Object Also known as: write, convert

saves the current image to the given filename



367
368
369
370
371
372
373
374
375
# File 'lib/quick_magick/image.rb', line 367

def save(output_filename)
  result = QuickMagick.exec3 "convert #{command_line} #{QuickMagick.c output_filename}" 
	if @pseudo_image
		# since it's been saved, convert it to normal image (not pseudo)
		initialize(output_filename)
 	revert!
	end
  return result 
end

#save!Object Also known as: write!, mogrify!

saves the current image overwriting the original image file



381
382
383
384
385
386
387
# File 'lib/quick_magick/image.rb', line 381

def save!
  raise QuickMagick::QuickMagickError, "Cannot mogrify a pseudo image" if @pseudo_image
  result = QuickMagick.exec3 "mogrify #{command_line}"
  # remove all operations to avoid duplicate operations
  revert!
  return result 
end

#sizeObject

returns size of image in bytes



440
441
442
# File 'lib/quick_magick/image.rb', line 440

def size
  File.size?(image_filename)
end

#to_blobObject



392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
408
# File 'lib/quick_magick/image.rb', line 392

def to_blob
	tmp_file = Tempfile.new(QuickMagick::random_string)
	if command_line =~ /-format\s(\S+)\s/
		# use format set up by user
		blob_format = $1
	elsif !@pseudo_image
		# use original image format
		blob_format = self.format
	else
	# default format is jpg
	blob_format = 'jpg'
	end
	save "#{blob_format}:#{tmp_file.path}"
	blob = nil
	File.open(tmp_file.path, 'rb') { |f| blob = f.read}
	blob
end