Class: GD2::Image

Inherits:
Object
  • Object
show all
Includes:
Enumerable
Defined in:
lib/gd2/image.rb

Overview

Introduction

Image is the abstract base class for Image::IndexedColor and Image::TrueColor.

Creating and Importing

Image objects are created either as a blank array of pixels:

image = Image::IndexedColor.new(width, height)
image = Image::TrueColor.new(width, height)

or by loading image data from a file or a string containing one of the supported image formats:

image = Image.load(file)
image = Image.load(string)

or by importing image data from a file given by its pathname:

image = Image.import(filename)

Exporting

After manipulating an image, it can be exported to a string in one of the supported image formats:

image.jpeg(quality = nil)
image.png(level = nil)
image.gif
image.wbmp(fgcolor)
image.gd
image.gd2(fmt = FMT_COMPRESSED)

or to a file in a format determined by the filename extension:

image.export(filename, options = {})

Direct Known Subclasses

IndexedColor, TrueColor

Defined Under Namespace

Classes: IndexedColor, MemoryAllocationError, TrueColor, UnrecognizedImageTypeError

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Instance Attribute Details

#image_ptrObject (readonly)

:nodoc:



49
50
51
# File 'lib/gd2/image.rb', line 49

def image_ptr
  @image_ptr
end

#paletteObject (readonly)

The Palette object for this image



52
53
54
# File 'lib/gd2/image.rb', line 52

def palette
  @palette
end

Class Method Details

.create_image_ptr(sx, sy, alpha_blending = true) ⇒ Object

:nodoc:

Raises:

  • (ArgumentError)


229
230
231
232
233
234
235
236
237
238
239
240
241
242
# File 'lib/gd2/image.rb', line 229

def self.create_image_ptr(sx, sy, alpha_blending = true)  #:nodoc:
  x = sx.to_i
  y = sy.to_i

  raise ArgumentError, "sx must be > 0" unless x.positive?
  raise ArgumentError, "sy must be > 0" unless y.positive?

  ptr = FFIStruct::ImagePtr.new(::GD2::GD2FFI.send(create_image_sym, x, y))

  raise MemoryAllocationError, "Could not allocation memory for image" if ptr.null?

  ::GD2::GD2FFI.send(:gdImageAlphaBlending, ptr, alpha_blending ? 1 : 0)
  ptr
end

.extract_format(filename_or_io, options) ⇒ Object



135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
# File 'lib/gd2/image.rb', line 135

def self.extract_format(filename_or_io, options)
  format = options[:format]

  if !format
    case filename_or_io
    when String
      md = filename_or_io.match(/\.([^.]+)\z/)
      format = md ? md[1].downcase : nil
    else
      magic = filename_or_io.read(4)
      filename_or_io.seek(-magic.bytes.length, IO::SEEK_CUR)
      format = data_type(magic.strip)
    end
  end

  format = format.to_sym if format
  format
end

.import(filename_or_io, options = {}) ⇒ Object

Import an image from a file with the given filename. The :format option or the file extension is used to determine the image type (jpeg, png, gif, wbmp, gd, gd2, xbm, or xpm). The resulting image will be either of class Image::TrueColor or Image::IndexedColor.

If the file format is gd2, it is optionally possible to extract only a part of the image. Use options :x, :y, :width, and :height to specify the part of the image to import.

Raises:



162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
# File 'lib/gd2/image.rb', line 162

def self.import(filename_or_io, options = {})
  format = extract_format(filename_or_io, options)

  ptr = # TODO: implement xpm and xbm imports

  #if format == :xpm
    #raise ArgumentError, "Unexpected options #{options.inspect}" unless options.empty?
    #::GD2::GD2FFI.send(:gdImageCreateFromXpm, filename)
  #elsif format == :xbm
    #::GD2::GD2FFI.send(:gdImageCreateFromXbm, filename)

  if format == :gd2 && !options.empty?
    x, y, width, height =
      options.delete(:x) || 0, options.delete(:y) || 0,
      options.delete(:width)  || options.delete(:w),
      options.delete(:height) || options.delete(:h)
    raise ArgumentError, "Unexpected options #{options.inspect}" unless
      options.empty?
    raise ArgumentError, 'Missing required option :width' if width.nil?
    raise ArgumentError, 'Missing required option :height' if height.nil?
    # TODO:
    ptr = File.open(filename, 'rb') do |file|
      ::GD2::GD2FFI.send(:gdImageCreateFromGd2Part, file, x.to_i, y.to_i, width.to_i, height.to_i)
    end
  else
    raise ArgumentError, "Unexpected options #{options.inspect}" unless
      options.empty?
    create_sym = {
      :jpeg => :gdImageCreateFromJpegPtr,
      :jpg  => :gdImageCreateFromJpegPtr,
      :png  => :gdImageCreateFromPngPtr,
      :gif  => :gdImageCreateFromGifPtr,
      :wbmp => :gdImageCreateFromWBMPPtr,
      :gd   => :gdImageCreateFromGdPtr,
      :gd2  => :gdImageCreateFromGd2Ptr
    }[format]
    raise UnrecognizedImageTypeError,
      'Format (or file extension) is not recognized' unless create_sym

    output = case filename_or_io
    when String
      File.open(filename_or_io, 'rb').read
    else
      filename_or_io.read
    end

    output = output.force_encoding("ASCII-8BIT") if output.respond_to? :force_encoding
    file_ptr = FFI::MemoryPointer.new(output.size, 1, false)
    file_ptr.put_bytes(0, output)

    ::GD2::GD2FFI.send(create_sym, output.size, file_ptr)
  end
  raise LibraryError if ptr.null?

  ptr = FFIStruct::ImagePtr.new(ptr)

  image = (image_true_color?(ptr) ?
    TrueColor : IndexedColor).allocate.init_with_image(ptr)

  block_given? ? yield(image) : image
end

.load(src) ⇒ Object

Load an image from a file or a string. The image type is detected automatically (JPEG, PNG, GIF, WBMP, or GD2). The resulting image will be either of class Image::TrueColor or Image::IndexedColor.

Raises:



73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
# File 'lib/gd2/image.rb', line 73

def self.load(src)
  src = src.force_encoding("ASCII-8BIT") if src.respond_to? :force_encoding
  case src
  when File
    pos = src.pos
    magic = src.read(4)
    src.pos = pos

    data = if FFI::Platform.windows?
      File.open(src.path, 'rb').read[pos..-1]
    else
      data = src.read
    end

    data = data.force_encoding("ASCII-8BIT") if data.respond_to? :force_encoding
    args = [ data.length, data ]
  when String
    magic = src.slice(0, 4)
    args = [ src.length, src ]
  else
    raise TypeError, 'Unexpected argument type'
  end

  create = {
    :jpeg => :gdImageCreateFromJpegPtr,
    :png  => :gdImageCreateFromPngPtr,
    :gif  => :gdImageCreateFromGifPtr,
    :wbmp => :gdImageCreateFromWBMPPtr,
    :gd2  => :gdImageCreateFromGd2Ptr
  }

  type = data_type(magic) or
    raise UnrecognizedImageTypeError, 'Image data format is not recognized'
  ptr = ::GD2::GD2FFI.send(create[type], *args)
  raise LibraryError if ptr.null?

  ptr = FFIStruct::ImagePtr.new(ptr)

  image = (image_true_color?(ptr) ?
    TrueColor : IndexedColor).allocate.init_with_image(ptr)

  block_given? ? yield(image) : image
end

.new(w, h) ⇒ Object Also known as: []

Create a new image of the specified dimensions. The default image class is Image::TrueColor; call this method on Image::IndexedColor instead if a palette image is desired.



59
60
61
62
63
64
# File 'lib/gd2/image.rb', line 59

def self.new(w, h)
  image = (self == Image) ?
    TrueColor.new(w, h) : allocate.init_with_size(w, h)

  block_given? ? yield(image) : image
end

Instance Method Details

#==(other) ⇒ Object

Compare this image with another image. Returns false if the images are not identical.



279
280
281
# File 'lib/gd2/image.rb', line 279

def ==(other)
  (compare(other) & CMP_IMAGE).zero?
end

#[](x, y) ⇒ Object

Return the color of the pixel at image location (x, y).



325
326
327
# File 'lib/gd2/image.rb', line 325

def [](x, y)
  pixel2color(get_pixel(x, y))
end

#[]=(x, y, color) ⇒ Object

Set the color of the pixel at image location (x, y).



330
331
332
# File 'lib/gd2/image.rb', line 330

def []=(x, y, color)
  set_pixel(x, y, color2pixel(color))
end

#alpha_blending=(bool) ⇒ Object

Set whether colors should be alpha blended with existing colors when pixels are modified. Alpha blending is not available for IndexedColor images.



378
379
380
# File 'lib/gd2/image.rb', line 378

def alpha_blending=(bool)
  ::GD2::GD2FFI.send(:gdImageAlphaBlending, image_ptr, bool ? 1 : 0)
end

#alpha_blending?Boolean

Return true if colors will be alpha blended into the image when pixels are modified. Returns false if colors will be copied verbatim into the image without alpha blending when pixels are modified.

Returns:

  • (Boolean)


371
372
373
# File 'lib/gd2/image.rb', line 371

def alpha_blending?
  not image_ptr[:alphaBlendingFlag].zero?
end

#aspectObject

Return the aspect ratio of this image, as a floating point ratio of the width to the height.



308
309
310
# File 'lib/gd2/image.rb', line 308

def aspect
  width.to_f / height
end

#clippingObject

Return the current clipping rectangle. Use Image#with_clipping to temporarily modify the clipping rectangle.



409
410
411
412
413
414
415
416
417
# File 'lib/gd2/image.rb', line 409

def clipping
  x1 = FFI::MemoryPointer.new(:pointer)
  y1 = FFI::MemoryPointer.new(:pointer)
  x2 = FFI::MemoryPointer.new(:pointer)
  y2 = FFI::MemoryPointer.new(:pointer)

  ::GD2::GD2FFI.send(:gdImageGetClip, image_ptr, x1, y1, x2, y2)
  [ x1.read_int, y1.read_int, x2.read_int, y2.read_int ]
end

#clips?(x, y) ⇒ Boolean

Return true if the current clipping rectangle excludes the given point.

Returns:

  • (Boolean)


434
435
436
# File 'lib/gd2/image.rb', line 434

def clips?(x, y)
  ::GD2::GD2FFI.send(:gdImageBoundsSafe, image_ptr, x.to_i, y.to_i).zero?
end

#color2pixel(color) ⇒ Object

Return a pixel value for the given color object.



352
353
354
# File 'lib/gd2/image.rb', line 352

def color2pixel(color)
  color.rgba
end

#compare(other) ⇒ Object

Compare this image with another image. Returns 0 if the images are identical, otherwise a bit field indicating the differences. See the GD2::CMP_* constants for individual bit flags.



273
274
275
# File 'lib/gd2/image.rb', line 273

def compare(other)
  ::GD2::GD2FFI.send(:gdImageCompare, image_ptr, other.image_ptr)
end

#copy_from(other, dst_x, dst_y, src_x, src_y, dst_w, dst_h, src_w = nil, src_h = nil) ⇒ Object

Copy a portion of another image to this image. If src_w and src_h are specified, the indicated portion of the source image will be resized (and resampled) to fit the indicated dimensions of the destination.

Raises:

  • (ArgumentError)


577
578
579
580
581
582
583
584
585
586
587
588
# File 'lib/gd2/image.rb', line 577

def copy_from(other, dst_x, dst_y, src_x, src_y,
    dst_w, dst_h, src_w = nil, src_h = nil)
  raise ArgumentError unless src_w.nil? == src_h.nil?
  if src_w
    ::GD2::GD2FFI.send(:gdImageCopyResampled, image_ptr, other.image_ptr,
      dst_x.to_i, dst_y.to_i, src_x.to_i, src_y.to_i, dst_w.to_i, dst_h.to_i, src_w.to_i, src_h.to_i)
  else
    ::GD2::GD2FFI.send(:gdImageCopy, image_ptr, other.image_ptr,
      dst_x.to_i, dst_y.to_i, src_x.to_i, src_y.to_i, dst_w.to_i, dst_h.to_i)
  end
  self
end

#copy_from_rotated(other, dst_x, dst_y, src_x, src_y, w, h, angle) ⇒ Object

Copy a portion of another image to this image, rotating the source portion first by the indicated angle (in radians). The dst_x and dst_y arguments indicate the center of the desired destination, and may be floating point.



594
595
596
597
598
# File 'lib/gd2/image.rb', line 594

def copy_from_rotated(other, dst_x, dst_y, src_x, src_y, w, h, angle)
  ::GD2::GD2FFI.send(:gdImageCopyRotated, image_ptr, other.image_ptr,
    dst_x.to_f, dst_y.to_f, src_x.to_i, src_y.to_i, w.to_i, h.to_i, angle.to_degrees.round.to_i)
  self
end

#crop(x, y, w, h) ⇒ Object

Like Image#crop! except a new image is returned.



633
634
635
# File 'lib/gd2/image.rb', line 633

def crop(x, y, w, h)
  clone.crop!(x, y, w, h)
end

#crop!(x, y, w, h) ⇒ Object

Crop this image to the specified dimensions, such that (x, y) becomes (0, 0).



626
627
628
629
630
# File 'lib/gd2/image.rb', line 626

def crop!(x, y, w, h)
  ptr = self.class.create_image_ptr(w, h, alpha_blending?)
  ::GD2::GD2FFI.send(:gdImageCopy, ptr, image_ptr, 0, 0, x.to_i, y.to_i, w.to_i, h.to_i)
  init_with_image(ptr)
end

#draw {|Canvas.new(self)| ... } ⇒ Object

Provide a drawing environment for a block. See GD2::Canvas.

Yields:



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

def draw  #:yields: canvas
  yield Canvas.new(self)
  self
end

#dupObject

Duplicate this image, copying all pixels to a new image. Contrast with Image#clone which produces a shallow copy and shares internal pixel data.



266
267
268
# File 'lib/gd2/image.rb', line 266

def dup
  self.class.superclass.load(gd2(FMT_RAW))
end

#eachObject

Iterate over each row of pixels in the image, returning an array of pixel values.



336
337
338
339
340
341
342
343
344
# File 'lib/gd2/image.rb', line 336

def each
  (0...height).each do |y|
    row = (0...width).inject(Array.new(width)) do |r, x|
      r[x] = get_pixel(x, y)
      r
    end
    yield row
  end
end

#export(filename_or_io, options = {}) ⇒ Object

Export this image to a file or stream with the given filename. The image format is determined by the :format option, or by the file extension (jpeg, png, gif, wbmp, gd, or gd2). Returns the size of the written image data. Additional options are as arguments for the Image#jpeg, Image#png, Image#wbmp, or Image#gd2 methods.



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
484
485
486
487
488
489
490
491
492
493
494
495
496
497
498
499
500
501
502
503
504
505
# File 'lib/gd2/image.rb', line 456

def export(filename_or_io, options = {})
  format = self.class.extract_format(filename_or_io, options)

  size = FFI::MemoryPointer.new(:pointer)

  case format
  when :jpeg, :jpg
    write_sym = :gdImageJpegPtr
    args = [ size, options.delete(:quality) || -1 ]
  when :png
    write_sym = :gdImagePngPtrEx
    args = [ size, options.delete(:level) || -1 ]
  when :gif
    write_sym = :gdImageGifPtr
    args = [ size ]
  when :wbmp
    write_sym = :gdImageWBMPPtr
    fgcolor = options.delete(:fgcolor)
    raise ArgumentError, 'Missing required option :fgcolor' if fgcolor.nil?
    args = [size, color2pixel(fgcolor)]
  when :gd
    write_sym = :gdImageGdPtr
    args = [ size ]
  when :gd2
    write_sym = :gdImageGd2Ptr
    args = [ options.delete(:chunk_size) || 0, options.delete(:fmt) || FMT_COMPRESSED, size ]
  else
    raise UnrecognizedImageTypeError,
      'Format (or file extension) is not recognized'
  end

  output = case filename_or_io
    when String
      File.open(filename_or_io, 'wb')
    else
      filename_or_io
  end

  begin
    img = ::GD2::GD2FFI.send(write_sym, image_ptr, *args)
    output.write(img.get_bytes(0, size.get_int(0)))
  ensure
    ::GD2::GD2FFI.gdFree(img)
  end

  output.flush
  output.rewind

  output
end

#gdObject

Encode and return data for this image in ???.gd??? format. This is an internal format used by the gd library to quickly read and write images.



555
556
557
558
559
560
561
# File 'lib/gd2/image.rb', line 555

def gd
  size = FFI::MemoryPointer.new(:pointer)
  ptr = ::GD2::GD2FFI.send(:gdImageGdPtr, image_ptr, size)
  ptr.get_bytes(0, size.get_int(0))
ensure
  ::GD2::GD2FFI.send(:gdFree, ptr)
end

#gd2(fmt = FMT_COMPRESSED, chunk_size = 0) ⇒ Object

Encode and return data for this image in ???.gd2??? format. This is an internal format used by the gd library to quickly read and write images. The specified fmt may be either GD2::FMT_RAW or GD2::FMT_COMPRESSED.



566
567
568
569
570
571
572
# File 'lib/gd2/image.rb', line 566

def gd2(fmt = FMT_COMPRESSED, chunk_size = 0)
  size = FFI::MemoryPointer.new(:pointer)
  ptr = ::GD2::GD2FFI.send(:gdImageGd2Ptr, image_ptr, chunk_size.to_i, fmt.to_i, size)
  ptr.get_bytes(0, size.get_int(0))
ensure
  ::GD2::GD2FFI.send(:gdFree, ptr)
end

#get_pixel(x, y) ⇒ Object Also known as: pixel

Return the pixel value at image location (x, y).



313
314
315
# File 'lib/gd2/image.rb', line 313

def get_pixel(x, y)
  ::GD2::GD2FFI.send(:gdImageGetPixel, @image_ptr, x.to_i, y.to_i)
end

#gifObject

Encode and return data for this image in GIF format. Note that GIF only supports palette images; TrueColor images will be automatically converted to IndexedColor internally in order to create the GIF. Use Image#to_indexed_color to control this conversion more precisely.



533
534
535
536
537
538
539
# File 'lib/gd2/image.rb', line 533

def gif
  size = FFI::MemoryPointer.new(:pointer)
  ptr = ::GD2::GD2FFI.send(:gdImageGifPtr, image_ptr, size)
  ptr.get_bytes(0, size.get_int(0))
ensure
  ::GD2::GD2FFI.send(:gdFree, ptr)
end

#heightObject Also known as: h

Return the height of this image, in pixels.



296
297
298
# File 'lib/gd2/image.rb', line 296

def height
  image_ptr[:sy]
end

#init_with_image(ptr) ⇒ Object

:nodoc:



248
249
250
251
252
253
254
255
256
257
258
# File 'lib/gd2/image.rb', line 248

def init_with_image(ptr)  #:nodoc:
  @image_ptr = if ptr.is_a?(FFIStruct::ImagePtr)
    ptr
  else
    FFIStruct::ImagePtr.new(ptr)
  end

  @palette = self.class.palette_class.new(self) unless
    defined?(@palette) && @palette.image == self
  self
end

#init_with_size(sx, sy) ⇒ Object

:nodoc:



244
245
246
# File 'lib/gd2/image.rb', line 244

def init_with_size(sx, sy)  #:nodoc:
  init_with_image self.class.create_image_ptr(sx, sy)
end

#inspectObject

:nodoc:



260
261
262
# File 'lib/gd2/image.rb', line 260

def inspect   #:nodoc:
  "#<#{self.class} #{size.inspect}>"
end

#interlaced=(bool) ⇒ Object

Set whether this image will be stored in interlaced form when output as PNG or JPEG.



364
365
366
# File 'lib/gd2/image.rb', line 364

def interlaced=(bool)
  ::GD2::GD2FFI.send(:gdImageInterlace, image_ptr, bool ? 1 : 0)
end

#interlaced?Boolean

Return true if this image will be stored in interlaced form when output as PNG or JPEG.

Returns:

  • (Boolean)


358
359
360
# File 'lib/gd2/image.rb', line 358

def interlaced?
  not image_ptr[:interlace].zero?
end

#jpeg(quality = nil) ⇒ Object

Encode and return data for this image in JPEG format. The quality argument should be in the range 0???95, with higher quality values usually implying both higher quality and larger sizes.



510
511
512
513
514
515
516
# File 'lib/gd2/image.rb', line 510

def jpeg(quality = nil)
  size = FFI::MemoryPointer.new(:pointer)
  ptr = ::GD2::GD2FFI.send(:gdImageJpegPtr, image_ptr, size, quality || -1)
  ptr.get_bytes(0, size.get_int(0))
ensure
  ::GD2::GD2FFI.send(:gdFree, ptr)
end

#merge_from(other, dst_x, dst_y, src_x, src_y, w, h, pct) ⇒ Object

Merge a portion of another image into this one by the amount specified as pct (a percentage). A percentage of 1.0 is identical to Image#copy_from; a percentage of 0.0 is a no-op. Note that alpha channel information from the source image is ignored.



604
605
606
607
608
# File 'lib/gd2/image.rb', line 604

def merge_from(other, dst_x, dst_y, src_x, src_y, w, h, pct)
  ::GD2::GD2FFI.send(:gdImageCopyMerge, image_ptr, other.image_ptr,
    dst_x.to_i, dst_y.to_i, src_x.to_i, src_y.to_i, w.to_i, h.to_i, pct.to_percent.round.to_i)
  self
end

#optimize_paletteObject

Consolidate duplicate colors in this image, and eliminate all unused palette entries. This only has an effect on IndexedColor images, and is rather expensive. Returns the number of palette entries deallocated.



447
448
449
# File 'lib/gd2/image.rb', line 447

def optimize_palette
  # implemented by subclass
end

#pixel2color(pixel) ⇒ Object

Return a Color object for the given pixel value.



347
348
349
# File 'lib/gd2/image.rb', line 347

def pixel2color(pixel)
  Color.new_from_rgba(pixel)
end

#png(level = nil) ⇒ Object

Encode and return data for this image in PNG format. The level argument should be in the range 0???9 indicating the level of lossless compression (0 = none, 1 = minimal but fast, 9 = best but slow).



521
522
523
524
525
526
527
# File 'lib/gd2/image.rb', line 521

def png(level = nil)
  size = FFI::MemoryPointer.new(:pointer)
  ptr = ::GD2::GD2FFI.send(:gdImagePngPtrEx, image_ptr, size, level.to_i || -1)
  ptr.get_bytes(0, size.get_int(0))
ensure
  ::GD2::GD2FFI.send(:gdFree, ptr)
end

#polar_transform(radius) ⇒ Object

Like Image#polar_transform! except a new image is returned.



681
682
683
# File 'lib/gd2/image.rb', line 681

def polar_transform(radius)
  clone.polar_transform!(radius)
end

#polar_transform!(radius) ⇒ Object

Transform this image into a new image of width and height radius??????2, in which the X axis of the original has been remapped to ?? (angle) and the Y axis of the original has been remapped to ?? (distance from center). Note that the original image must be square.

Raises:



673
674
675
676
677
678
# File 'lib/gd2/image.rb', line 673

def polar_transform!(radius)
  raise 'Image must be square' unless width == height
  ptr = ::GD2::GD2FFI.send(:gdImageSquareToCircle, image_ptr, radius.to_i)
  raise LibraryError if ptr.null?
  init_with_image(ptr)
end

#resize(w, h, resample = true) ⇒ Object

Like Image#resize! except a new image is returned.



665
666
667
# File 'lib/gd2/image.rb', line 665

def resize(w, h, resample = true)
  clone.resize!(w, h, resample)
end

#resize!(w, h, resample = true) ⇒ Object

Resize this image to the given dimensions. If resample is true, the image pixels will be resampled; otherwise they will be stretched or shrunk as necessary without resampling.



654
655
656
657
658
659
660
661
662
# File 'lib/gd2/image.rb', line 654

def resize!(w, h, resample = true)
  ptr = self.class.create_image_ptr(w, h, false)
  ::GD2::GD2FFI.send(resample ? :gdImageCopyResampled : :gdImageCopyResized,
    ptr, image_ptr, 0, 0, 0, 0, w.to_i, h.to_i, width.to_i, height.to_i)
  alpha_blending = alpha_blending?
  init_with_image(ptr)
  self.alpha_blending = alpha_blending
  self
end

#rotate(angle, axis_x = width / 2.0, axis_y = height / 2.0) ⇒ Object

Like Image#rotate! except a new image is returned.



620
621
622
# File 'lib/gd2/image.rb', line 620

def rotate(angle, axis_x = width / 2.0, axis_y = height / 2.0)
  clone.rotate!(angle, axis_x, axis_y)
end

#rotate!(angle, axis_x = width / 2.0, axis_y = height / 2.0) ⇒ Object

Rotate this image by the given angle (in radians) about the given axis coordinates. Note that some of the edges of the image may be lost.



612
613
614
615
616
617
# File 'lib/gd2/image.rb', line 612

def rotate!(angle, axis_x = width / 2.0, axis_y = height / 2.0)
  ptr = self.class.create_image_ptr(width, height, alpha_blending?)
  ::GD2::GD2FFI.send(:gdImageCopyRotated, ptr, image_ptr,
    axis_x.to_f, axis_y.to_f, 0, 0, width.to_i, height.to_i, angle.to_degrees.round.to_i)
  init_with_image(ptr)
end

#save_alpha=(bool) ⇒ Object

Set whether this image will be stored with full alpha channel information when output as PNG.



390
391
392
# File 'lib/gd2/image.rb', line 390

def save_alpha=(bool)
  ::GD2::GD2FFI.send(:gdImageSaveAlpha, image_ptr, bool ? 1 : 0)
end

#save_alpha?Boolean

Return true if this image will be stored with full alpha channel information when output as PNG.

Returns:

  • (Boolean)


384
385
386
# File 'lib/gd2/image.rb', line 384

def save_alpha?
  not image_ptr[:saveAlphaFlag].zero?
end

#set_pixel(x, y, value) ⇒ Object

Set the pixel value at image location (x, y).



319
320
321
322
# File 'lib/gd2/image.rb', line 319

def set_pixel(x, y, value)
  ::GD2::GD2FFI.send(:gdImageSetPixel, @image_ptr, x.to_i, y.to_i, value.to_i)
  nil
end

#sharpen(pct) ⇒ Object

Sharpen this image by pct (a percentage) which can be greater than 1.0. Transparency/alpha channel are not altered. This has no effect on IndexedColor images.



688
689
690
# File 'lib/gd2/image.rb', line 688

def sharpen(pct)
  self
end

#sizeObject

Return the size of this image as an array [width, height], in pixels.



302
303
304
# File 'lib/gd2/image.rb', line 302

def size
  [width, height]
end

#to_indexed_color(colors = MAX_COLORS, dither = true) ⇒ Object

Return this image as an IndexedColor image, creating a copy if necessary. colors indicates the maximum number of palette colors to use, and dither controls whether dithering is used.

Raises:



700
701
702
703
704
705
706
707
708
709
710
711
712
713
# File 'lib/gd2/image.rb', line 700

def to_indexed_color(colors = MAX_COLORS, dither = true)
  ptr = ::GD2::GD2FFI.send(:gdImageCreatePaletteFromTrueColor,
    to_true_color.image_ptr, dither ? 1 : 0, colors.to_i)
  raise LibraryError if ptr.null?

  obj = IndexedColor.allocate.init_with_image(ptr)

  # fix for gd bug where image->open[] is not properly initialized
  (0...obj.image_ptr[:colorsTotal]).each do |i|
    obj.image_ptr[:open][i] = 0
  end

  obj
end

#to_true_colorObject

Return this image as a TrueColor image, creating a copy if necessary.



693
694
695
# File 'lib/gd2/image.rb', line 693

def to_true_color
  self
end

#transparentObject

Return the transparent color for this image, or nil if none has been set.



396
397
398
399
# File 'lib/gd2/image.rb', line 396

def transparent
  pixel = image_ptr[:transparent]
  pixel == -1 ? nil : pixel2color(pixel)
end

#transparent=(color) ⇒ Object

Set or unset the transparent color for this image.



402
403
404
405
# File 'lib/gd2/image.rb', line 402

def transparent=(color)
  ::GD2::GD2FFI.send(:gdImageColorTransparent, image_ptr,
    color.nil? ? -1 : color2pixel(color))
end

#true_color?Boolean

Return true if this image is a TrueColor image.

Returns:

  • (Boolean)


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

def true_color?
  kind_of?(TrueColor)
  # self.class.image_true_color?(image_ptr)
end

#uncrop(x1, y1 = x1, x2 = x1, y2 = y1) ⇒ Object

Like Image#uncrop! except a new image is returned.



647
648
649
# File 'lib/gd2/image.rb', line 647

def uncrop(x1, y1 = x1, x2 = x1, y2 = y1)
  clone.uncrop!(x1, y1, x2, y2)
end

#uncrop!(x1, y1 = x1, x2 = x1, y2 = y1) ⇒ Object

Expand the left, top, right, and bottom borders of this image by the given number of pixels.



639
640
641
642
643
644
# File 'lib/gd2/image.rb', line 639

def uncrop!(x1, y1 = x1, x2 = x1, y2 = y1)
  ptr = self.class.create_image_ptr(x1 + width + x2, y1 + height + y2,
    alpha_blending?)
  ::GD2::GD2FFI.send(:gdImageCopy, ptr, image_ptr, x1.to_i, y1.to_i, 0, 0, width.to_i, height.to_i)
  init_with_image(ptr)
end

#wbmp(fgcolor) ⇒ Object

Encode and return data for this image in WBMP format. WBMP currently supports only black and white images; the specified fgcolor will be used as the foreground color (black), and all other colors will be considered ???background??? (white).



545
546
547
548
549
550
551
# File 'lib/gd2/image.rb', line 545

def wbmp(fgcolor)
  size = FFI::MemoryPointer.new(:pointer)
  ptr = ::GD2::GD2FFI.send(:gdImageWBMPPtr, image_ptr, size, color2pixel(fgcolor))
  ptr.get_bytes(0, size.get_int(0))
ensure
  ::GD2::GD2FFI.send(:gdFree, ptr)
end

#widthObject Also known as: w

Return the width of this image, in pixels.



290
291
292
# File 'lib/gd2/image.rb', line 290

def width
  image_ptr[:sx]
end

#with_clipping(x1, y1, x2, y2) ⇒ Object

Temporarily set the clipping rectangle during the execution of a block. Pixels outside this rectangle will not be modified by drawing or copying operations.



422
423
424
425
426
427
428
429
430
431
# File 'lib/gd2/image.rb', line 422

def with_clipping(x1, y1, x2, y2)   #:yields: image
  clip = clipping
  begin
    ::GD2::GD2FFI.send(:gdImageSetClip, image_ptr, x1.to_i, y1.to_i, x2.to_i, y2.to_i)
    yield self
    self
  ensure
    ::GD2::GD2FFI.send(:gdImageSetClip, image_ptr, *clip)
  end
end