Skip to content

Commit

Permalink
Refactor AnimatedGif into a class rather than singleton methods.
Browse files Browse the repository at this point in the history
  • Loading branch information
dark-panda committed May 7, 2019
1 parent fa0f98e commit 020191e
Show file tree
Hide file tree
Showing 5 changed files with 138 additions and 50 deletions.
24 changes: 17 additions & 7 deletions lib/gd2-ffij.rb
Original file line number Diff line number Diff line change
Expand Up @@ -187,14 +187,24 @@ def self.gd_library_name
ALPHA_TRANSPARENT = 127

class LibraryError < StandardError; end
end

require 'gd2/image'
require 'gd2/color'
require 'gd2/palette'
require 'gd2/canvas'
require 'gd2/font'
require 'gd2/ffi_struct'
GD2_BASE = File.join(File.dirname(__FILE__), 'gd2')

autoload :Image,
File.join(GD2_BASE, 'image')
autoload :Color,
File.join(GD2_BASE, 'color')
autoload :Palette,
File.join(GD2_BASE, 'palette')
autoload :Canvas,
File.join(GD2_BASE, 'canvas')
autoload :Font,
File.join(GD2_BASE, 'font')
autoload :FFIStruct,
File.join(GD2_BASE, 'ffi_struct')
autoload :AnimatedGif,
File.join(GD2_BASE, 'animated_gif')
end

class Numeric
if not self.instance_methods.include? 'degrees'
Expand Down
79 changes: 79 additions & 0 deletions lib/gd2/animated_gif.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
# frozen_string_literal: true; encoding: ASCII-8BIT
#
# See COPYRIGHT for license details.

class GD2::AnimatedGif
class Frame < Struct.new(:ptr, :size)
def read
ptr.get_bytes(0, size.get_int(0))
end
end

def add(ptr, options = {})
size = FFI::MemoryPointer.new(:int)

frame_ptr = if frames.empty?
::GD2::GD2FFI.send(:gdImageGifAnimBeginPtr, ptr.image_ptr, size, -1, 0)
else
previous_frame_ptr = if options[:previous_frame]
options[:previous_frame].image_ptr
else
FFI::Pointer::NULL
end

::GD2::GD2FFI.send(:gdImageGifAnimAddPtr, ptr.image_ptr, size, 0, 0, 0, options[:delay].to_i, 1, previous_frame_ptr)
end

raise LibraryError if frame_ptr.null?

frames << Frame.new(frame_ptr, size)
end

def end
size = FFI::MemoryPointer.new(:int)

frame_ptr = ::GD2::GD2FFI.send(:gdImageGifAnimEndPtr, size)

raise LibraryError if frame_ptr.null?

frames << Frame.new(frame_ptr, size)
end

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

frames.each do |frame|
output.write(frame.read)
end

output.flush
output.rewind

output
end

private

def frames
return @frames if defined?(@frames)

@frames = []

ObjectSpace.define_finalizer(@frames, frames_finalizer)

@frames
end

def frames_finalizer
proc do
each do |frame|
::GD2::GD2FFI.send(:gdFree, frame[:frame_ptr])
end
end
end
end
43 changes: 0 additions & 43 deletions lib/gd2/image.rb
Original file line number Diff line number Diff line change
Expand Up @@ -806,47 +806,4 @@ def sharpen(pct) #:nodoc:
self
end
end

#
# = Description
#
# AnimtedGif class represents methods to generate animated gif output
#

class AnimatedGif

def self.pal_copy(to, from) #:nodoc:
::GD2::GD2FFI.send(:gdImagePaletteCopy, to.image_ptr, from.image_ptr)
end

def self.gif_anim_begin(ptr) #:nodoc:
size = FFI::MemoryPointer.new(:int)
ptr = ::GD2::GD2FFI.send(:gdImageGifAnimBeginPtr, ptr.image_ptr, size, -1, 0)
raise LibraryError if ptr.null?
ptr.get_bytes(0, size.get_int(0))
ensure
::GD2::GD2FFI.send(:gdFree, ptr)
end

def self.gif_anim_add(ptr, prevptr, delay) #:nodoc:
size = FFI::MemoryPointer.new(:int)
ptr = ::GD2::GD2FFI.send(:gdImageGifAnimAddPtr, ptr.image_ptr, size, 0, 0, 0, delay, 1,
(prevptr.nil? ? FFI::Pointer::NULL : prevptr.image_ptr))
raise LibraryError if ptr.null?
ptr.get_bytes(0, size.get_int(0))
ensure
::GD2::GD2FFI.send(:gdFree, ptr)
end

def self.gif_anim_end() #:nodoc:
size = FFI::MemoryPointer.new(:int)
ptr = ::GD2::GD2FFI.send(:gdImageGifAnimEndPtr, size)
raise LibraryError if ptr.null?
ptr.get_bytes(0, size.get_int(0))
ensure
::GD2::GD2FFI.send(:gdFree, ptr)
end

end

end
42 changes: 42 additions & 0 deletions test/animated_gif_tests.rb
Original file line number Diff line number Diff line change
@@ -0,0 +1,42 @@
# frozen_string_literal: true; encoding: ASCII-8BIT

require './test/test_helper'

class AnimatedGifTest < Minitest::Test
include TestHelper

def test_animation
image1 = GD2::Image::IndexedColor.new(256, 256)

black = image1.palette.allocate(GD2::Color[0, 0, 0])
white = image1.palette.allocate(GD2::Color[255, 255, 255])
lime = image1.palette.allocate(GD2::Color[0, 255, 0])

image1.draw do |pen|
pen.color = white
pen.line(64, 64, 192, 192)
end

image2 = GD2::Image::IndexedColor.new(256, 256)
black = image2.palette.allocate(GD2::Color[0, 0, 0])
white = image2.palette.allocate(GD2::Color[255, 255, 255])
lime = image2.palette.allocate(GD2::Color[0, 255, 0])

image2.draw do |pen|
pen.color = lime
pen.rectangle(32, 64, 192, 192)
end

anim = GD2::AnimatedGif.new
anim.add(image1)
anim.add(image2, delay: 50)
anim.add(image1, delay: 50)
anim.end

output = StringIO.new

anim.export(output)

assert(output.read == File.read('test/images/test_animated_gif.gif'))
end
end
Binary file added test/images/test_animated_gif.gif
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.

0 comments on commit 020191e

Please sign in to comment.