painter 0.0.4

Sign up to get free protection for your applications and to get access to all the features.
data/README ADDED
File without changes
File without changes
@@ -0,0 +1,133 @@
1
+ require 'ffi'
2
+ require 'painter/image_struct'
3
+ require 'painter/stdio'
4
+ require 'painter/cgd2'
5
+ require 'painter/operation'
6
+ require 'painter/image'
7
+ require 'painter/font'
8
+ require 'painter/canvas'
9
+ require 'painter/color'
10
+ require 'painter/rect'
11
+ require 'painter/pixel'
12
+ require 'painter/text'
13
+ require 'painter/point'
14
+ require 'painter/line'
15
+
16
+ class Painter
17
+ attr_reader :image_pointer
18
+
19
+ def self.write(path, x, y, file_format)
20
+ instance = new
21
+ instance.initializeFromCreate(x,y)
22
+ yield instance
23
+ File.open(path, 'w') do |f|
24
+ instance.format(file_format) do |data|
25
+ f.write data
26
+ end
27
+ end
28
+ ensure
29
+ instance.release!
30
+ end
31
+
32
+ def self.open(path, format = nil)
33
+ instance = new
34
+ instance.initializeFromOpen(path, format)
35
+ yield instance
36
+ ensure
37
+ instance.release!
38
+ end
39
+
40
+ def release!
41
+ CGD2::gdImageDestroy(@image_pointer)
42
+ end
43
+
44
+ def degrees(n)
45
+ n * 2 * Math::PI / 360
46
+ end
47
+
48
+ ALPHA_MAX = 127
49
+ ALPHA_OPAQUE = 0
50
+ ALPHA_TRANSPARENT = 127
51
+ RGB_MAX = 255
52
+
53
+ def release(ptr)
54
+ CGD2::gdImageDestroy(ptr)
55
+ end
56
+
57
+ def initializeFromCreate(x, y, options = {})
58
+ @image_pointer = FFI::Pointer.new(CGD2::gdImageCreateTrueColor(x, y))
59
+ end
60
+
61
+
62
+ FORMAT_TO_FUNCTION = {
63
+ 'jpg' => :gdImageCreateFromJpeg,
64
+ 'png' => :gdImageCreateFromPng,
65
+ 'gif' => :gdImageCreateFromGif,
66
+ 'gd' => :gdImageCreateFromGd,
67
+ 'gd2' => :gdImageCreateFromGd2,
68
+ 'wbmp' => :gdImageCreateFromWBMP,
69
+ 'xbm' => :gdImageCreateFromXbm
70
+ }
71
+
72
+ def format_from_filename(path)
73
+ path[/\.([^.]*)$/, 1].downcase
74
+ end
75
+
76
+ def initializeFromOpen(path, format = nil)
77
+ f = Painter::Stdio.fopen(path, "rb")
78
+ format ||= format_from_filename(path)
79
+ function_name = FORMAT_TO_FUNCTION[format.to_s]
80
+ raise "Unknown format: #{format}" unless function_name
81
+ @image_pointer = CGD2.send(function_name, f)
82
+ Painter::Stdio.fclose(f)
83
+ end
84
+
85
+ def info
86
+ @info ||= Painter::ImageStruct.new @image_pointer
87
+ end
88
+
89
+ # Operations
90
+ {'pixel' => 'Pixel', 'rect' => 'Rect', 'text' => 'Text', 'line' => 'Line'}.each do |op, klass|
91
+ class_eval <<-END
92
+ def #{op}
93
+ #{op}_instance = #{klass}.new(self)
94
+ yield #{op}_instance
95
+ #{op}_instance.draw
96
+ end
97
+ END
98
+ end
99
+
100
+ def resize_to(destination)
101
+ CGD2::gdImageCopyResampled(destination.image_pointer, self.image_pointer,
102
+ 0, 0, 0, 0,
103
+ destination.info.x, destination.info.y, self.info.x, self.info.y)
104
+ end
105
+
106
+ OUTPUT_FORMAT_TO_FUNCTION = {
107
+ 'gif' => :gdImageGifPtr,
108
+ 'jpeg' => :gdImageJpegPtr,
109
+ 'jpg' => :gdImageJpegPtr,
110
+ 'png' => :gdImagePngPtr,
111
+ 'wbmp' => :gdImageWBMPPtr,
112
+ 'gd' => :gdImageGdPtr,
113
+ 'gd2' => :gdImageGd2
114
+ }
115
+ def format(file_format, quality = 100)
116
+ size = FFI::MemoryPointer.new(:pointer)
117
+ function_name = OUTPUT_FORMAT_TO_FUNCTION[file_format.to_s]
118
+ raise "Unknown format: #{file_format}" unless function_name
119
+ args = [@image_pointer, size]
120
+ if function_name == :gdImageJpegPtr
121
+ args << quality
122
+ end
123
+ begin
124
+ ip = CGD2.send(function_name, *args)
125
+ size = size.get_int(0)
126
+ data = ip.get_bytes(0, size)
127
+ yield data
128
+ ensure
129
+ CGD2::gdFree(ip)
130
+ end
131
+ end
132
+
133
+ end
@@ -0,0 +1,43 @@
1
+ class Painter
2
+ module CGD2
3
+ extend FFI::Library
4
+ local_path = ["/opt/local/lib/libgd.2.dylib", '/usr/lib/libgd.so.2'].detect do |lib|
5
+ File.exists?(lib)
6
+ end
7
+ ffi_lib local_path
8
+
9
+ # BGD_DECLARE(gdImagePtr) gdImageCreate (int sx, int sy)
10
+ attach_function :gdImageCreate, [:int, :int], :pointer
11
+ attach_function :gdImageCreateTrueColor, [:int, :int], :pointer
12
+
13
+ # void gdImageFilledRectangle(gdImagePtr im, int x1, int y1, int x2, int y2, int color) (FUNCTION)
14
+ attach_function :gdImageFilledRectangle, [:pointer, :int, :int, :int, :int, :int], :void
15
+
16
+ attach_function :gdImageSetPixel, [:pointer, :int, :int, :int], :void
17
+ attach_function :gdImageLine, [:pointer, :int, :int, :int, :int, :int], :void
18
+
19
+ #char *gdImageStringFT(gdImagePtr im, int *brect, int fg, char *fontname, double ptsize, double angle, int x, int y, char *string) (FUNCTION)
20
+ attach_function :gdImageStringFT, [:pointer, :pointer, :int, :string, :double, :double, :int, :int, :string], :pointer
21
+
22
+ # void* gdImagePngPtr(gdImagePtr im, int *size) (FUNCTION)
23
+ [:gdImageGifPtr, :gdImagePngPtr, :gdImageWBMPPtr,
24
+ :gdImageGdPtr, :gdImageGd2].each do |format_function|
25
+ attach_function format_function, [:pointer, :pointer], :pointer
26
+ end
27
+
28
+ attach_function :gdImageJpegPtr, [:pointer, :pointer, :int], :pointer
29
+
30
+ [:gdImageCreateFromJpeg, :gdImageCreateFromPng, :gdImageCreateFromGif,
31
+ :gdImageCreateFromGd, :gdImageCreateFromGd2, :gdImageCreateFromWBMP,
32
+ :gdImageCreateFromXbm].each do |format_function|
33
+ attach_function format_function, [:pointer], :pointer
34
+ end
35
+
36
+ #Resizing
37
+ attach_function :gdImageCopyResampled, [:pointer, :pointer, :int, :int, :int, :int, :int, :int, :int, :int], :void
38
+
39
+ # gdImageDestroy(gdImagePtr im) (FUNCTION)
40
+ attach_function :gdImageDestroy, [:pointer], :void
41
+ attach_function :gdFree, [:pointer], :void
42
+ end
43
+ end
@@ -0,0 +1,110 @@
1
+ class Painter
2
+ class Color
3
+ attr_reader :rgba
4
+ alias :to_i :rgba
5
+ class << self
6
+ alias [] new
7
+ end
8
+
9
+ def initialize(r, g, b, a = ALPHA_OPAQUE)
10
+ r = self.class.normalize(r, RGB_MAX, :red)
11
+ g = self.class.normalize(g, RGB_MAX, :green)
12
+ b = self.class.normalize(b, RGB_MAX, :blue)
13
+ a = self.class.normalize(a, ALPHA_MAX, :alpha)
14
+
15
+ init_with_rgba(self.class.pack(r, g, b, a))
16
+ end
17
+
18
+ def init_with_rgba(rgba, index = nil, palette = nil) #:nodoc:
19
+ @rgba = rgba
20
+ @index = index
21
+ @palette = palette
22
+ self
23
+ end
24
+
25
+ def self.pack(r, g, b, a) #:nodoc:
26
+ (a << 24) + (r << 16) + (g << 8) + b
27
+ end
28
+
29
+ def to_s
30
+ s = 'RGB'
31
+ s += "A" if alpha != ALPHA_OPAQUE
32
+ s += "[#{@index}]" if @index
33
+ s += '#' + [red, green, blue].map { |e| '%02X' % e }.join('')
34
+ s += '%02X' % alpha if alpha != ALPHA_OPAQUE
35
+ s
36
+ end
37
+
38
+
39
+ def self.normalize(value, max, component = nil) #:nodoc:
40
+ case value
41
+ when Integer
42
+ (value < 0) ? 0 : (value > max) ? max : value
43
+ when Float
44
+ normalize((value * max).round, max, component)
45
+ when Color
46
+ value.send(component)
47
+ else
48
+ return normalize(value.to_i, max) if value.respond_to?(:to_i)
49
+ raise TypeError
50
+ end
51
+ end
52
+ # Return the red component of this color (0..RGB_MAX).
53
+ def red
54
+ (rgba & 0xFF0000) >> 16
55
+ end
56
+ alias r red
57
+
58
+ # Modify the red component of this color. If this color is associated
59
+ # with a palette entry, this also modifies the palette.
60
+ #def red=(value)
61
+ # self.rgba = (rgba & ~0xFF0000) |
62
+ # (self.class.normalize(value, RGB_MAX, :red) << 16)
63
+ #end
64
+ #alias r= red=
65
+
66
+ # Return the green component of this color (0..RGB_MAX).
67
+ def green
68
+ (rgba & 0x00FF00) >> 8
69
+ end
70
+ alias g green
71
+
72
+ # Modify the green component of this color. If this color is associated
73
+ # with a palette entry, this also modifies the palette.
74
+ #def green=(value)
75
+ # self.rgba = (rgba & ~0x00FF00) |
76
+ # (self.class.normalize(value, RGB_MAX, :green) << 8)
77
+ #end
78
+ #alias g= green=
79
+
80
+ # Return the blue component of this color (0..RGB_MAX).
81
+ def blue
82
+ rgba & 0x0000FF
83
+ end
84
+ alias b blue
85
+
86
+ # Modify the blue component of this color. If this color is associated
87
+ # with a palette entry, this also modifies the palette.
88
+ #def blue=(value)
89
+ # self.rgba = (rgba & ~0x0000FF) |
90
+ # self.class.normalize(value, RGB_MAX, :blue)
91
+ #end
92
+ #alias b= blue=
93
+
94
+ # Return the alpha component of this color (0..ALPHA_MAX).
95
+ def alpha
96
+ (rgba & 0x7F000000) >> 24
97
+ end
98
+ alias a alpha
99
+
100
+ # Modify the alpha component of this color. If this color is associated
101
+ # with a palette entry, this also modifies the palette.
102
+ def alpha=(value)
103
+ self.rgba = (rgba & ~0xFF000000) |
104
+ (self.class.normalize(value, ALPHA_MAX, :alpha) << 24)
105
+ end
106
+ alias a= alpha=
107
+
108
+
109
+ end
110
+ end
@@ -0,0 +1,35 @@
1
+ class Painter
2
+ class ImageStruct < FFI::Struct
3
+ MAXCOLORS = 256
4
+ layout :pixels, :pointer,
5
+ :sx, :int,
6
+ :sy, :int,
7
+ :colorsTotal, :int,
8
+ :red, [:int, MAXCOLORS],
9
+ :green, [:int, MAXCOLORS],
10
+ :blue, [:int, MAXCOLORS],
11
+ :open, [:int, MAXCOLORS],
12
+ :transparent, :int,
13
+ :polyInts, :pointer,
14
+ :polyAllocated, :int,
15
+ :brush, :pointer,
16
+ :tile, :pointer,
17
+ :brushColorMap, [:int, MAXCOLORS],
18
+ :tileColorMap, [:int, MAXCOLORS],
19
+ :styleLength, :int,
20
+ :stylePos, :int,
21
+ :style, :pointer,
22
+ :interlace, :int,
23
+ :alpha, [:int, MAXCOLORS],
24
+ :trueColor, :int,
25
+ :tpixels, :pointer,
26
+ :alphaBlendingFlag, :int,
27
+ :saveAlphaFlag, :int
28
+ def x
29
+ self[:sx]
30
+ end
31
+ def y
32
+ self[:sy]
33
+ end
34
+ end
35
+ end
@@ -0,0 +1,8 @@
1
+ class Painter
2
+ class Line < Operation
3
+ def draw
4
+ ::Painter::CGD2::gdImageLine(@image.image_pointer,
5
+ @_from.x, @_from.y, @_to.x, @_to.y, _color.rgba)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,45 @@
1
+ class Painter
2
+ class Operation
3
+ def self.pretty_accessor(*names)
4
+ names.each do |n|
5
+ attr_reader n.to_sym
6
+ class_eval <<-END
7
+ def #{n}(v)
8
+ @_#{n} = v
9
+ end
10
+ def _#{n}
11
+ @_#{n}
12
+ end
13
+ END
14
+ end
15
+ end
16
+ def initialize(i)
17
+ @image = i
18
+ end
19
+
20
+ pretty_accessor :at
21
+
22
+ %w[at from to].each do |point|
23
+ class_eval <<-END
24
+ def #{point}(x,y)
25
+ @_#{point} = Point.new(x,y)
26
+ end
27
+ END
28
+ end
29
+
30
+ def angle(n)
31
+ @_angle = (n * Math::PI / 180.0)
32
+ end
33
+
34
+ def _angle
35
+ @_angle || 0
36
+ end
37
+
38
+ def color(r,g,b,a = nil)
39
+ @_color = Painter::Color.new(r,g,b,a)
40
+ end
41
+ def _color
42
+ @_color || Painter::Color.new(1, 1, 1)
43
+ end
44
+ end
45
+ end
@@ -0,0 +1,8 @@
1
+ class Painter
2
+ class Pixel < Operation
3
+ def draw
4
+ ::Painter::CGD2::gdImageSetPixel(@image.image_pointer,
5
+ @_at.x, @_at.y, _color.rgba)
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,4 @@
1
+ class Painter
2
+ class Point < Struct.new(:x,:y)
3
+ end
4
+ end
@@ -0,0 +1,19 @@
1
+ class Painter
2
+ class Rect < Operation
3
+ pretty_accessor :bottomX, :bottomY
4
+
5
+ def topLeft(x,y)
6
+ @_topLeft = Point.new(x,y)
7
+ end
8
+
9
+ def bottomRight(x,y)
10
+ @_bottomRight = Point.new(x,y)
11
+ end
12
+
13
+ def draw
14
+ ::Painter::CGD2::gdImageFilledRectangle(@image.image_pointer,
15
+ @_topLeft.x, @_topLeft.y,
16
+ @_bottomRight.x, @_bottomRight.y, _color.rgba)
17
+ end
18
+ end
19
+ end
@@ -0,0 +1,8 @@
1
+ class Painter
2
+ module Stdio
3
+ extend FFI::Library
4
+ ffi_lib FFI::Library::LIBC
5
+ attach_function :fopen, [:string, :string], :pointer
6
+ attach_function :fclose, [:pointer], :int
7
+ end
8
+ end
@@ -0,0 +1,23 @@
1
+ class Painter
2
+ class Text < Operation
3
+ class BlankFontError < StandardError
4
+ end
5
+ class MissingFontError < StandardError
6
+ end
7
+ pretty_accessor :font, :size, :text, :point
8
+
9
+ def draw
10
+ raise BlankFontError if _font.nil?
11
+ raise MissingFontError, _font unless File.exists?(_font)
12
+ brect = FFI::MemoryPointer.new(:int, 8)
13
+ error = CGD2::gdImageStringFT(@image.image_pointer, brect, _color.rgba, _font,
14
+ _size.to_f, _angle.to_f, _at.x, _at.y, _text.gsub('&', '&amp;'))
15
+ raise "Drawing error: #{error}" unless error.null?
16
+ brect = brect.read_array_of_int(8)
17
+ { :lower_left => [brect[0], brect[1]],
18
+ :lower_right => [brect[2], brect[3]],
19
+ :upper_right => [brect[4], brect[5]],
20
+ :upper_left => [brect[6], brect[7]]}
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,36 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
2
+
3
+ describe Painter::Color do
4
+ it "should initialize from int" do
5
+ Painter::Color.new(50,100,200).rgba.should eql(3302600)
6
+ end
7
+
8
+ it "should initialize with []" do
9
+ Painter::Color[50,100,200].rgba.should eql(3302600)
10
+ end
11
+
12
+ it "should have to_i" do
13
+ color = Painter::Color[50,100,200]
14
+ color.rgba.should eql(3302600)
15
+ color.to_i.should eql(color.rgba)
16
+ end
17
+
18
+ [
19
+ [:red, 50],
20
+ [:green, 100],
21
+ [:blue, 200]
22
+ ].each do |color_name, value|
23
+ it "should return the #{color_name} value" do
24
+ color = Painter::Color[50,100,200]
25
+ color.send(color_name).should eql(value)
26
+ end
27
+
28
+ it "should return color #{color_name} by first letter" do
29
+ color_name = color_name.to_s[0..0].to_sym
30
+ color = Painter::Color[50,100,200]
31
+ color.send(color_name).should eql(value)
32
+ end
33
+ end
34
+
35
+
36
+ end
Binary file
Binary file
@@ -0,0 +1,24 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
2
+
3
+ describe Painter::Image::TrueColor do
4
+ it_should_behave_like "painter"
5
+
6
+ before do
7
+ Painter::CGD2.stub!(:gdFree)
8
+ end
9
+
10
+ it "should generate png string" do
11
+ image = Painter::Image::TrueColor.new(100, 100)
12
+ Painter::CGD2.should_receive(:gdImagePngPtr).and_return(mock("Pointer", :get_bytes => ''))
13
+ image.png do |data|
14
+ data.size.should > 0
15
+ end
16
+ end
17
+
18
+ it "should read the image struct" do
19
+ Painter.open("#{File.dirname(__FILE__)}/fixtures/sample.jpg", :jpg) do |i|
20
+ i.info.x.should == 438
21
+ end
22
+ end
23
+
24
+ end
@@ -0,0 +1,52 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
2
+
3
+ describe 'integration' do
4
+ it "should draw an image" do
5
+ srand(Time.now.to_i)
6
+ Painter.write("#{File.dirname(__FILE__)}/output/captcha.png", 200, 100, :png) do |painter|
7
+ painter.rect do |rect|
8
+ rect.color 255, 255, 255
9
+ rect.topLeft 0, 0
10
+ rect.bottomRight 200, 100
11
+ end
12
+ painter.text do |text|
13
+ text.font "#{File.dirname(__FILE__)}/fixtures/Vera.ttf"
14
+ text.at 10, 50
15
+ text.text "Hello World"
16
+ text.angle rand(20)
17
+ text.size 14
18
+ end
19
+ offset = rand(10)
20
+ 0.upto(300) do |i|
21
+ painter.pixel do |pixel|
22
+ pixel.at i, ((Math.sin((i + offset) / (4 * Math::PI)) * 30).to_i + 50)
23
+ pixel.color(rand(5), rand(5), rand(5))
24
+ end
25
+ end
26
+ painter.line do |line|
27
+ line.from 0, (25 + rand(50))
28
+ line.to 200, (25 + rand(50))
29
+ line.color rand(10), rand(10), rand(10)
30
+ end
31
+ end
32
+ end
33
+
34
+ it "should write to a variety of formats" do
35
+ [:jpg, :png, :wbmp, :gif].each do |format|
36
+ Painter.write("#{File.dirname(__FILE__)}/output/format.#{format}", 48, 48, format) do |output|
37
+ Painter.open("#{File.dirname(__FILE__)}/fixtures/sample.jpg", :jpg) do |source|
38
+ source.resize_to(output)
39
+ end
40
+ end
41
+ end
42
+ end
43
+
44
+ it "should resize images" do
45
+ Painter.write("#{File.dirname(__FILE__)}/output/resized.png", 48, 48, :png) do |output|
46
+ Painter.open("#{File.dirname(__FILE__)}/fixtures/sample.jpg", :jpg) do |source|
47
+ source.resize_to(output)
48
+ end
49
+ end
50
+ end
51
+
52
+ end
Binary file
Binary file
Binary file
Binary file
Binary file
Binary file
@@ -0,0 +1,27 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
2
+
3
+ describe "rect" do
4
+ it_should_behave_like "painter"
5
+ before(:each) do
6
+ @painter = Painter.new
7
+ @painter.initializeFromCreate(640, 480)
8
+ end
9
+
10
+ it "should call GD draw function" do
11
+ Painter::CGD2.should_receive(:gdImageFilledRectangle).with(@painter.image_pointer, 0, 0, 10, 10, @white.rgba)
12
+ @painter.rect do |rect|
13
+ rect.topLeft 0, 0
14
+ rect.bottomRight 10, 10
15
+ end
16
+ end
17
+
18
+ it "should convert Color to int" do
19
+ Painter::CGD2.should_receive(:gdImageFilledRectangle).with(@painter.image_pointer, 0, 0, 10, 10, @black.rgba)
20
+ @painter.rect do |rect|
21
+ rect.color 0, 0, 0
22
+ rect.topLeft 0, 0
23
+ rect.bottomRight 10, 10
24
+ end
25
+ end
26
+
27
+ end
@@ -0,0 +1,12 @@
1
+ require 'rubygems'
2
+ require 'rbconfig'
3
+ require 'spec'
4
+
5
+ $: << 'lib'
6
+ require 'painter'
7
+ describe "painter", :shared => true do
8
+ before(:each) do
9
+ @white = Painter::Color.new(1, 1, 1)
10
+ @black = Painter::Color.new(0, 0, 0)
11
+ end
12
+ end
@@ -0,0 +1,23 @@
1
+ require File.expand_path(File.join(File.dirname(__FILE__), "spec_helper"))
2
+
3
+ describe "text" do
4
+ it_should_behave_like "painter"
5
+ before(:each) do
6
+ @painter = Painter.new
7
+ @painter.initializeFromCreate(640, 480)
8
+ end
9
+
10
+ it "should call C function on draw" do
11
+ Painter::CGD2.should_receive(:gdImageStringFT).
12
+ with(@painter.image_pointer, anything, @black.rgba, "#{File.dirname(__FILE__)}/fixtures/Vera.ttf", 14.0, 0.0, 100, 50, "Hello World").
13
+ and_return(mock("Pointer", :null? => true))
14
+ @painter.text do |text|
15
+ text.color 0, 0, 0
16
+ text.font "#{File.dirname(__FILE__)}/fixtures/Vera.ttf"
17
+ text.at 100, 50
18
+ text.text "Hello World"
19
+ text.angle 0
20
+ text.size 14
21
+ end
22
+ end
23
+ end
metadata ADDED
@@ -0,0 +1,111 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: painter
3
+ version: !ruby/object:Gem::Version
4
+ hash: 23
5
+ prerelease: false
6
+ segments:
7
+ - 0
8
+ - 0
9
+ - 4
10
+ version: 0.0.4
11
+ platform: ruby
12
+ authors:
13
+ - Ben Sandofsky
14
+ autorequire:
15
+ bindir: bin
16
+ cert_chain: []
17
+
18
+ date: 2010-05-20 00:00:00 -07:00
19
+ default_executable:
20
+ dependencies:
21
+ - !ruby/object:Gem::Dependency
22
+ name: ffi
23
+ prerelease: false
24
+ requirement: &id001 !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ">="
28
+ - !ruby/object:Gem::Version
29
+ hash: 3
30
+ segments:
31
+ - 0
32
+ version: "0"
33
+ type: :runtime
34
+ version_requirements: *id001
35
+ description: A clean wrapper around the GD2 graphics library, based on gd2-ffi
36
+ email: sandofsky@gmail.com
37
+ executables: []
38
+
39
+ extensions: []
40
+
41
+ extra_rdoc_files: []
42
+
43
+ files:
44
+ - lib/painter/cgd2.rb
45
+ - lib/painter/color.rb
46
+ - lib/painter/image_struct.rb
47
+ - lib/painter/line.rb
48
+ - lib/painter/operation.rb
49
+ - lib/painter/pixel.rb
50
+ - lib/painter/point.rb
51
+ - lib/painter/rect.rb
52
+ - lib/painter/stdio.rb
53
+ - lib/painter/text.rb
54
+ - lib/painter.rb
55
+ - spec/color_spec.rb
56
+ - spec/fixtures/sample.jpg
57
+ - spec/fixtures/Vera.ttf
58
+ - spec/image_spec.rb
59
+ - spec/integration.rb
60
+ - spec/output/captcha.png
61
+ - spec/output/format.gif
62
+ - spec/output/format.jpg
63
+ - spec/output/format.png
64
+ - spec/output/format.wbmp
65
+ - spec/output/resized.png
66
+ - spec/rect_spec.rb
67
+ - spec/spec_helper.rb
68
+ - spec/text_spec.rb
69
+ - README
70
+ - Rakefile
71
+ has_rdoc: true
72
+ homepage: http://github.com/sandofsky/painter
73
+ licenses: []
74
+
75
+ post_install_message:
76
+ rdoc_options: []
77
+
78
+ require_paths:
79
+ - lib
80
+ required_ruby_version: !ruby/object:Gem::Requirement
81
+ none: false
82
+ requirements:
83
+ - - ">="
84
+ - !ruby/object:Gem::Version
85
+ hash: 3
86
+ segments:
87
+ - 0
88
+ version: "0"
89
+ required_rubygems_version: !ruby/object:Gem::Requirement
90
+ none: false
91
+ requirements:
92
+ - - ">="
93
+ - !ruby/object:Gem::Version
94
+ hash: 3
95
+ segments:
96
+ - 0
97
+ version: "0"
98
+ requirements: []
99
+
100
+ rubyforge_project:
101
+ rubygems_version: 1.3.7
102
+ signing_key:
103
+ specification_version: 3
104
+ summary: A clean wrapper around the GD2 graphics library, based on gd2-ffi
105
+ test_files:
106
+ - spec/color_spec.rb
107
+ - spec/image_spec.rb
108
+ - spec/image_spec.rb
109
+ - spec/rect_spec.rb
110
+ - spec/text_spec.rb
111
+ - spec/spec_helper.rb