aslakhellesoy-png 1.2.0

Sign up to get free protection for your applications and to get access to all the features.
Binary file
@@ -0,0 +1,73 @@
1
+ #!/usr/local/bin/ruby
2
+
3
+ require 'png/reader'
4
+
5
+ ##
6
+ # Implements a simple bitmap font by extracting letters from a PNG.
7
+
8
+ class PNG::Font
9
+ LETTERS = (('A'..'Z').to_a +
10
+ ('a'..'z').to_a +
11
+ ('0'..'9').to_a + [" "] * 16 +
12
+ '({[<!@#$%^&*?_+-=;,"/~>]})'.split(//))
13
+
14
+ attr_reader :height, :width, :canvas
15
+
16
+ def self.default
17
+ @@default ||= new(File.join(File.dirname(__FILE__), "default_font.png"))
18
+ end
19
+
20
+ def initialize(png_file)
21
+ @canvas = PNG.load_file png_file
22
+ @height, @width = canvas.height / 4, canvas.width / 26
23
+ @cache = {}
24
+ end
25
+
26
+ def coordinates c
27
+ i = LETTERS.index c
28
+
29
+ raise ArgumentError, "Can't find #{c.inspect}" unless i
30
+
31
+ x = (i % 26) * width
32
+ y = (3 - (i / 26)) * height # start from the top (3rd row)
33
+
34
+ return x, y, x+width-1, y+height-1
35
+ end
36
+
37
+ def [] c
38
+ c = c.chr unless String === c
39
+ x0, y0, x1, y1 = coordinates c
40
+
41
+ @cache[c] ||= @canvas.extract(x0, y0, x1, y1)
42
+ end
43
+ end
44
+
45
+ class PNG::Canvas
46
+ ##
47
+ # Write a string at [x, y] with font, optionally specifying a font,
48
+ # an alignment of :left, :center, or :right and the style to draw
49
+ # the annotation (see #composite).
50
+ #
51
+ # require 'png/font'
52
+
53
+ def annotate(string, x, y,
54
+ font = PNG::Font.default, align = :left, style = :overwrite)
55
+ case align
56
+ when :left then
57
+ # do nothing
58
+ when :center then
59
+ x -= string.length * font.width / 2
60
+ when :right then
61
+ x -= string.length * font.width
62
+ else
63
+ raise ArgumentError, "Unknown align: #{align.inspect}"
64
+ end
65
+
66
+ x_offset, width = 0, font.width
67
+
68
+ string.split(//).each do |char|
69
+ self.composite font[char], x + x_offset, y
70
+ x_offset += width
71
+ end
72
+ end
73
+ end
@@ -0,0 +1,47 @@
1
+ #!/usr/local/bin/ruby -w
2
+
3
+ require 'png'
4
+
5
+ class PNG
6
+ FULL = 360.0
7
+ HALF = FULL / 2
8
+
9
+ def self.angle(x, y)
10
+ return 0 if x == 0 and y == 0
11
+ rad_to_deg = 180.0 / Math::PI
12
+ (Math.atan2(-y, x) * rad_to_deg + 90) % 360
13
+ end
14
+
15
+ ##
16
+ # Makes a pie chart you can pass to PNG.new:
17
+ #
18
+ # png = PNG.new pie_chart(250, 0.30)
19
+ # png.save "pie.png"
20
+ # system 'open pie.png'
21
+
22
+ def self.pie_chart(diameter, pct_green,
23
+ good_color=PNG::Color::Green, bad_color=PNG::Color::Red)
24
+ diameter += 1 if diameter % 2 == 0
25
+ radius = (diameter / 2.0).to_i
26
+ pct_in_deg = FULL * pct_green
27
+ rad_to_deg = HALF / Math::PI
28
+
29
+ canvas = PNG::Canvas.new(diameter, diameter)
30
+
31
+ (-radius..radius).each do |x|
32
+ (-radius..radius).each do |y|
33
+ magnitude = Math.sqrt(x*x + y*y)
34
+ if magnitude <= radius then
35
+ angle = PNG.angle(x, y)
36
+ color = ((angle <= pct_in_deg) ? good_color : bad_color)
37
+
38
+ rx, ry = x+radius, y+radius
39
+
40
+ canvas[ rx, ry ] = color
41
+ end
42
+ end
43
+ end
44
+
45
+ canvas
46
+ end
47
+ end
@@ -0,0 +1,139 @@
1
+ require 'png'
2
+ require 'enumerator'
3
+
4
+ class PNG
5
+ def self.load_file path, metadata_only = false
6
+ self.load File.read(path), metadata_only
7
+ end
8
+
9
+ def self.load png, metadata_only = false
10
+ png = png.dup
11
+ signature = png.slice! 0, 8
12
+ raise ArgumentError, 'Invalid PNG signature' unless signature == SIGNATURE
13
+
14
+ ihdr = read_chunk 'IHDR', png
15
+
16
+ bit_depth, color_type, width, height = read_IHDR ihdr, metadata_only
17
+
18
+ return [width, height, bit_depth] if metadata_only
19
+
20
+ canvas = PNG::Canvas.new width, height
21
+
22
+ type = png.slice(4, 4).unpack('a4').first
23
+ read_chunk type, png if type == 'iCCP' # Ignore color profile
24
+
25
+ read_IDAT read_chunk('IDAT', png), bit_depth, color_type, canvas
26
+ read_chunk 'IEND', png
27
+
28
+ canvas
29
+ end
30
+
31
+ def self.read_chunk expected_type, png
32
+ size, type = png.slice!(0, 8).unpack 'Na4'
33
+ data, crc = png.slice!(0, size + 4).unpack "a#{size}N"
34
+
35
+ check_crc type, data, crc
36
+
37
+ raise ArgumentError, "Expected #{expected_type} chunk, not #{type}" unless
38
+ type == expected_type
39
+
40
+ return data
41
+ end
42
+
43
+ def self.check_crc type, data, crc
44
+ return true if (type + data).png_crc == crc
45
+ raise ArgumentError, "Invalid CRC encountered in #{type} chunk"
46
+ end
47
+
48
+ def self.read_IHDR data, metadata_only = false
49
+ width, height, bit_depth, color_type, *rest = data.unpack 'N2C5'
50
+
51
+ unless metadata_only then
52
+ raise ArgumentError, "Wrong bit depth: #{bit_depth}" unless
53
+ bit_depth == 8
54
+ raise ArgumentError, "Wrong color type: #{color_type}" unless
55
+ color_type == RGBA or color_type = RGB
56
+ raise ArgumentError, "Unsupported options: #{rest.inspect}" unless
57
+ rest == [0, 0, 0]
58
+ end
59
+
60
+ return bit_depth, color_type, width, height
61
+ end
62
+
63
+ def self.read_IDAT data, bit_depth, color_type, canvas
64
+ data = Zlib::Inflate.inflate(data).unpack 'C*'
65
+
66
+ pixel_size = color_type == RGBA ? 4 : 3
67
+
68
+ height = canvas.height
69
+ scanline_length = pixel_size * canvas.width + 1 # for filter
70
+
71
+ row = canvas.height - 1
72
+ until data.empty? do
73
+ row_data = data.slice! 0, scanline_length
74
+
75
+ filter = row_data.shift
76
+ case filter
77
+ when NONE then
78
+ when SUB then
79
+ row_data.each_with_index do |byte, index|
80
+ left = index < pixel_size ? 0 : row_data[index - pixel_size]
81
+ row_data[index] = (byte + left) % 256
82
+ end
83
+ when UP then
84
+ row_data.each_with_index do |byte, index|
85
+ col = index / pixel_size
86
+ upper = row == 0 ? 0 : canvas[col, row + 1].values[index % pixel_size]
87
+ row_data[index] = (upper + byte) % 256
88
+ end
89
+ when AVG then
90
+ row_data.each_with_index do |byte, index|
91
+ col = index / pixel_size
92
+ upper = row == 0 ? 0 : canvas[col, row + 1].values[index % pixel_size]
93
+ left = index < pixel_size ? 0 : row_data[index - pixel_size]
94
+
95
+ row_data[index] = (byte + ((left + upper)/2).floor) % 256
96
+ end
97
+ when PAETH then
98
+ left = upper = upper_left = nil
99
+ row_data.each_with_index do |byte, index|
100
+ col = index / pixel_size
101
+
102
+ left = index < pixel_size ? 0 : row_data[index - pixel_size]
103
+ if row == height then
104
+ upper = upper_left = 0
105
+ else
106
+ upper = canvas[col, row + 1].values[index % pixel_size]
107
+ upper_left = col == 0 ? 0 :
108
+ canvas[col - 1, row + 1].values[index % pixel_size]
109
+ end
110
+
111
+ paeth = paeth left, upper, upper_left
112
+ row_data[index] = (byte + paeth) % 256
113
+ end
114
+ else
115
+ raise ArgumentError, "invalid filter algorithm #{filter}"
116
+ end
117
+
118
+ col = 0
119
+ row_data.each_slice pixel_size do |slice|
120
+ slice << 0xFF if pixel_size == 3
121
+ canvas[col, row] = PNG::Color.new(*slice)
122
+ col += 1
123
+ end
124
+
125
+ row -= 1
126
+ end
127
+ end
128
+
129
+ def self.paeth a, b, c # left, above, upper left
130
+ p = a + b - c
131
+ pa = (p - a).abs
132
+ pb = (p - b).abs
133
+ pc = (p - c).abs
134
+
135
+ return a if pa <= pb && pa <= pc
136
+ return b if pb <= pc
137
+ c
138
+ end
139
+ end
@@ -0,0 +1,529 @@
1
+ require 'test/unit'
2
+ require 'rubygems'
3
+ require 'png'
4
+ require 'png/reader'
5
+ require 'png/pie'
6
+
7
+ class TestPng < Test::Unit::TestCase
8
+
9
+ def setup
10
+ @canvas = PNG::Canvas.new 5, 10, PNG::Color::White
11
+ @png = PNG.new @canvas
12
+
13
+ @blob = <<-EOF.unpack('m*').first
14
+ iVBORw0KGgoAAAANSUhEUgAAAAUAAAAKCAYAAAB8OZQwAAAAD0lEQVR4nGP4
15
+ jwUwDGVBALuJxzlQugpEAAAAAElFTkSuQmCC
16
+ EOF
17
+ end
18
+
19
+ def test_class_chunk
20
+ chunk = PNG.chunk 'IHDR', [10, 10, 8, 6, 0, 0, 0 ].pack('N2C5')
21
+
22
+ header_crc = "\2152\317\275"
23
+ header_data = "\000\000\000\n\000\000\000\n\b\006\000\000\000"
24
+ header_length = "\000\000\000\r"
25
+ header_chunk = "#{header_length}IHDR#{header_data}#{header_crc}"
26
+
27
+ assert_equal header_chunk, chunk
28
+ end
29
+
30
+ def test_class_chunk_empty
31
+ chunk = PNG.chunk 'IHDR'
32
+ expected = "#{0.chr * 4}IHDR#{["IHDR".png_crc].pack 'N'}"
33
+ assert_equal expected, chunk
34
+ end
35
+
36
+ def test_to_blob
37
+ assert_equal @blob, @png.to_blob
38
+ end
39
+
40
+ def test_save
41
+ path = "blah.png"
42
+ @png.save(path)
43
+ assert_equal @blob, File.read(path)
44
+ ensure
45
+ assert_equal 1, File.unlink(path)
46
+ end
47
+
48
+ end
49
+
50
+ class TestCanvas < Test::Unit::TestCase
51
+
52
+ def setup
53
+ @canvas = PNG::Canvas.new 5, 10, PNG::Color::White
54
+ end
55
+
56
+ def test_composite_default
57
+ canvas1, canvas2 = util_composite_canvases
58
+
59
+ canvas1.composite canvas2, 1, 1
60
+
61
+ expected = " xxxxxxxx
62
+ xxxxxxxx
63
+ xx..xxxx
64
+ ..xxxxxx
65
+ ".gsub(/ /, '')
66
+
67
+ assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
68
+ end
69
+
70
+ def test_composite_underlay
71
+ canvas1, canvas2 = util_composite_canvases
72
+
73
+ canvas1.composite canvas2, 1, 1, :add
74
+
75
+ expected = " xxxxxxxx
76
+ xxxx..xx
77
+ xx00xxxx
78
+ ..xxxxxx
79
+ ".gsub(/ /, '')
80
+
81
+ assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
82
+ end
83
+
84
+ def test_composite_overlay
85
+ canvas1, canvas2 = util_composite_canvases
86
+
87
+ canvas1.composite canvas2, 1, 1, :overlay
88
+
89
+ expected = " xxxxxxxx
90
+ xxxx..xx
91
+ xx..xxxx
92
+ ..xxxxxx
93
+ ".gsub(/ /, '')
94
+
95
+ assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
96
+ end
97
+
98
+ def test_composite_blend
99
+ canvas1, canvas2 = util_composite_canvases
100
+
101
+ canvas1.composite canvas2, 1, 1, :blend
102
+
103
+ expected = " xxxxxxxx
104
+ xxxx..xx
105
+ xx,,xxxx
106
+ ..xxxxxx
107
+ ".gsub(/ /, '')
108
+
109
+ assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
110
+ end
111
+
112
+ def test_composite_bad_style
113
+ canvas1, canvas2 = util_composite_canvases
114
+
115
+ assert_raises RuntimeError do
116
+ canvas1.composite canvas2, 1, 1, :bad
117
+ end
118
+ end
119
+
120
+ def test_extract
121
+ canvas1, _ = util_composite_canvases
122
+
123
+ expected = " xxxxxxxx
124
+ xxxx..xx
125
+ xx00xxxx
126
+ ..xxxxxx
127
+ ".gsub(/ /, '')
128
+
129
+ assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
130
+
131
+ canvas2 = canvas1.extract(1, 1, 2, 2)
132
+
133
+ expected = " xx..
134
+ 00xx
135
+ ".gsub(/ /, '')
136
+
137
+ assert_equal expected, canvas2.to_s.gsub(/ /, 'x')
138
+ end
139
+
140
+ def test_index
141
+ assert_equal PNG::Color::White, @canvas[1, 2]
142
+ assert_same @canvas[1, 2], @canvas.data[1][2]
143
+ end
144
+
145
+ def test_index_tall
146
+ @canvas = PNG::Canvas.new 2, 4, PNG::Color::White
147
+ @canvas[ 0, 0] = PNG::Color::Black
148
+ @canvas[ 0, 3] = PNG::Color::Background
149
+ @canvas[ 1, 0] = PNG::Color::Yellow
150
+ @canvas[ 1, 3] = PNG::Color::Blue
151
+
152
+ expected = " ,,\n0000\n0000\n..++\n"
153
+
154
+ assert_equal expected, @canvas.to_s
155
+ end
156
+
157
+ def test_index_wide
158
+ @canvas = PNG::Canvas.new 4, 2, PNG::Color::White
159
+ @canvas[ 0, 0] = PNG::Color::Black
160
+ @canvas[ 3, 0] = PNG::Color::Background
161
+ @canvas[ 0, 1] = PNG::Color::Yellow
162
+ @canvas[ 3, 1] = PNG::Color::Blue
163
+
164
+ expected = "++0000,,\n..0000 \n"
165
+
166
+ assert_equal expected, @canvas.to_s
167
+ end
168
+
169
+ def test_index_bad_x
170
+ begin
171
+ @canvas[6, 1]
172
+ rescue => e
173
+ assert_equal "bad x value 6 >= 5", e.message
174
+ else
175
+ flunk "didn't raise"
176
+ end
177
+ end
178
+
179
+ def test_index_bad_y
180
+ begin
181
+ @canvas[1, 11]
182
+ rescue => e
183
+ assert_equal "bad y value 11 >= 10", e.message
184
+ else
185
+ flunk "didn't raise"
186
+ end
187
+ end
188
+
189
+ def test_index_equals
190
+ @canvas[1, 2] = PNG::Color::Red
191
+ assert_equal PNG::Color::Red, @canvas[1, 2]
192
+ assert_same @canvas[1, 2], @canvas.data[7][1]
193
+
194
+ expected = "
195
+ 0000000000
196
+ 0000000000
197
+ 0000000000
198
+ 0000000000
199
+ 0000000000
200
+ 0000000000
201
+ 0000000000
202
+ 00,,000000
203
+ 0000000000
204
+ 0000000000".strip + "\n"
205
+ actual = @canvas.to_s
206
+ assert_equal expected, actual
207
+ end
208
+
209
+ def test_index_equals_bad_x
210
+ begin
211
+ @canvas[6, 1] = PNG::Color::Red
212
+ rescue => e
213
+ assert_equal "bad x value 6 >= 5", e.message
214
+ else
215
+ flunk "didn't raise"
216
+ end
217
+ end
218
+
219
+ def test_index_equals_bad_y
220
+ begin
221
+ @canvas[1, 11] = PNG::Color::Red
222
+ rescue => e
223
+ assert_equal "bad y value 11 >= 10", e.message
224
+ else
225
+ flunk "didn't raise"
226
+ end
227
+ end
228
+
229
+ # def test_point
230
+ # raise NotImplementedError, 'Need to write test_point'
231
+ # end
232
+
233
+ def test_inspect
234
+ assert_equal "#<PNG::Canvas 5x10>", @canvas.inspect
235
+ end
236
+
237
+ def test_point
238
+ assert_equal PNG::Color.new(0xff, 0x7f, 0xff, 0xff),
239
+ @canvas.point(0, 0, PNG::Color::Magenta)
240
+ # flunk "this doesn't test ANYTHING"
241
+ end
242
+
243
+ def test_line
244
+ @canvas.line 0, 9, 4, 0, PNG::Color::Black
245
+
246
+ expected = <<-EOF
247
+ ,,00000000
248
+ ,,00000000
249
+ ,,,,000000
250
+ 00..000000
251
+ 00,,,,0000
252
+ 0000..0000
253
+ 0000,,,,00
254
+ 000000..00
255
+ 000000,,,,
256
+ 00000000..
257
+ EOF
258
+
259
+ assert_equal expected, @canvas.to_s
260
+ end
261
+
262
+ def test_positive_slope_line
263
+ @canvas.line 0, 0, 4, 9, PNG::Color::Black
264
+
265
+ expected = <<-EOF
266
+ 00000000,,
267
+ 00000000,,
268
+ 000000,,,,
269
+ 000000..00
270
+ 0000,,,,00
271
+ 0000..0000
272
+ 00,,,,0000
273
+ 00..000000
274
+ ,,,,000000
275
+ ..00000000
276
+ EOF
277
+
278
+ assert_equal expected, @canvas.to_s
279
+ end
280
+
281
+ def test_to_s_normal
282
+ @canvas = PNG::Canvas.new 5, 10, PNG::Color::White
283
+ expected = util_ascii_art(5, 10)
284
+ assert_equal expected, @canvas.to_s
285
+ end
286
+
287
+ def test_to_s_wide
288
+ @canvas = PNG::Canvas.new 250, 10, PNG::Color::White
289
+ expected = util_ascii_art(36, 2) # scaled
290
+ assert_equal expected, @canvas.to_s
291
+ end
292
+
293
+ def test_to_s_tall
294
+ @canvas = PNG::Canvas.new 10, 250, PNG::Color::White
295
+ expected = util_ascii_art(10, 250)
296
+ assert_equal expected, @canvas.to_s
297
+ end
298
+
299
+ def test_to_s_huge
300
+ @canvas = PNG::Canvas.new 250, 250, PNG::Color::White
301
+ expected = util_ascii_art(36, 36) # scaled
302
+ assert_equal expected, @canvas.to_s
303
+ end
304
+
305
+ def util_composite_canvases
306
+ canvas1 = PNG::Canvas.new 4, 4
307
+ canvas1[0, 0] = PNG::Color::Black
308
+ canvas1[1, 1] = PNG::Color::White
309
+ canvas1[2, 2] = PNG::Color::Black
310
+
311
+ expected = " xxxxxxxx
312
+ xxxx..xx
313
+ xx00xxxx
314
+ ..xxxxxx
315
+ ".gsub(/ /, '')
316
+
317
+ assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
318
+
319
+
320
+ canvas2 = PNG::Canvas.new 2, 2
321
+ canvas2[0, 0] = PNG::Color::Black
322
+
323
+ expected = " xxxx
324
+ ..xx
325
+ ".gsub(/ /, '')
326
+
327
+ assert_equal expected, canvas2.to_s.gsub(/ /, 'x')
328
+
329
+ return canvas1, canvas2
330
+ end
331
+
332
+ def util_ascii_art(width, height)
333
+ (("0" * width * 2) + "\n") * height
334
+ end
335
+ end
336
+
337
+ class TestPng::TestColor < Test::Unit::TestCase
338
+ def setup
339
+ @color = PNG::Color.new 0x01, 0x02, 0x03, 0x04
340
+ end
341
+
342
+ def test_class_from_str
343
+ @color = PNG::Color.from "0x01020304"
344
+ test_r
345
+ test_g
346
+ test_b
347
+ test_a
348
+ end
349
+
350
+ def test_class_from_int
351
+ @color = PNG::Color.from 0x01020304
352
+ test_r
353
+ test_g
354
+ test_b
355
+ test_a
356
+ end
357
+
358
+ def test_r
359
+ assert_equal 0x01, @color.r
360
+ end
361
+
362
+ def test_g
363
+ assert_equal 0x02, @color.g
364
+ end
365
+
366
+ def test_b
367
+ assert_equal 0x03, @color.b
368
+ end
369
+
370
+ def test_a
371
+ assert_equal 0x04, @color.a
372
+ end
373
+
374
+ def test_blend
375
+ # c1 = @color
376
+ # c2 = PNG::Color.new 0xFF, 0xFE, 0xFD, 0xFC
377
+
378
+ # assert_equal PNG::Color.new(0xFB, 0xFA, 0xF9, 0xF8), c1.blend(c2)
379
+
380
+ c1 = PNG::Color::White
381
+ c2 = PNG::Color::Black
382
+
383
+ assert_equal PNG::Color::Gray, c2.blend(c1)
384
+ assert_equal PNG::Color::Gray, c1.blend(c2)
385
+ end
386
+
387
+ def test_intensity
388
+ assert_equal PNG::Color.new(0x01, 0x02, 0x03, 0x3c), @color.intensity(0xf00)
389
+ end
390
+
391
+ def test_inspect
392
+ assert_equal "#<PNG::Color 01 02 03 04>", @color.inspect
393
+ end
394
+
395
+ def test_inspect_name
396
+ assert_equal "#<PNG::Color Red>", PNG::Color::Red.inspect
397
+ end
398
+
399
+ def test_pipe
400
+ b = PNG::Color::Black
401
+ w = PNG::Color::White
402
+ t = PNG::Color::Background
403
+
404
+ # first non-transparent
405
+ assert_equal b, b | t
406
+ assert_equal b, t | b
407
+
408
+ assert_equal b, b | w
409
+ assert_equal w, w | b
410
+
411
+ assert_equal t, t | t
412
+ end
413
+
414
+ def test_to_ascii
415
+ assert_equal '00', PNG::Color::White.to_ascii, "white"
416
+ assert_equal '++', PNG::Color::Yellow.to_ascii, "yellow"
417
+ assert_equal ',,', PNG::Color::Red.to_ascii, "red"
418
+ assert_equal '..', PNG::Color::Black.to_ascii, "black"
419
+ assert_equal ' ', PNG::Color::Background.to_ascii, "background"
420
+ end
421
+
422
+ def test_to_ascii_alpha
423
+ assert_equal '00', PNG::Color.new(255,255,255,255).to_ascii
424
+ assert_equal '00', PNG::Color.new(255,255,255,192).to_ascii
425
+ assert_equal '++', PNG::Color.new(255,255,255,191).to_ascii
426
+ assert_equal ',,', PNG::Color.new(255,255,255,127).to_ascii
427
+ assert_equal ',,', PNG::Color.new(255,255,255,126).to_ascii
428
+ assert_equal ',,', PNG::Color.new(255,255,255, 64).to_ascii
429
+ assert_equal '..', PNG::Color.new(255,255,255, 63).to_ascii
430
+ assert_equal '..', PNG::Color.new(255,255,255, 1).to_ascii
431
+ assert_equal ' ', PNG::Color.new(255,255,255, 0).to_ascii
432
+ end
433
+
434
+ def test_to_s_name
435
+ assert_equal 'Red', PNG::Color::Red.to_s
436
+ end
437
+
438
+ def test_to_s
439
+ obj = PNG::Color.new(255,255,255, 0)
440
+ assert_equal '#<PNG::Color:0xXXXXXX>', obj.to_s.sub(/0x[0-9a-f]+/, '0xXXXXXX')
441
+ end
442
+
443
+ def test_equals2
444
+ assert_equal PNG::Color.new(255,255,255, 0), PNG::Color.new(255,255,255, 0)
445
+ end
446
+
447
+ def test_hash
448
+ a = PNG::Color.new(255,255,255, 0)
449
+ b = PNG::Color.new(255,255,255, 0)
450
+ assert_equal a.hash, b.hash
451
+ end
452
+
453
+ # def test_values
454
+ # raise NotImplementedError, 'Need to write test_values'
455
+ # end
456
+ end
457
+
458
+ class TestPng::TestPie < Test::Unit::TestCase
459
+ def setup
460
+
461
+ end
462
+
463
+ def test_pie_chart_odd
464
+ expected =
465
+ [" .. ",
466
+ " ,,,,,,........ ",
467
+ " ,,,,,,,,.......... ",
468
+ " ,,,,,,,,.......... ",
469
+ " ,,,,,,,,.......... ",
470
+ ",,,,,,,,,,............",
471
+ " ,,,,,,,,,,,,,,,,,, ",
472
+ " ,,,,,,,,,,,,,,,,,, ",
473
+ " ,,,,,,,,,,,,,,,,,, ",
474
+ " ,,,,,,,,,,,,,, ",
475
+ " ,, ",
476
+ nil].join("\n")
477
+
478
+ actual = PNG::pie_chart(11, 0.25, PNG::Color::Black, PNG::Color::Green)
479
+ assert_equal expected, actual.to_s
480
+ end
481
+
482
+ def test_pie_chart_even
483
+ expected =
484
+ [" .. ",
485
+ " ,,,,,,........ ",
486
+ " ,,,,,,,,.......... ",
487
+ " ,,,,,,,,.......... ",
488
+ " ,,,,,,,,.......... ",
489
+ ",,,,,,,,,,............",
490
+ " ,,,,,,,,,,,,,,,,,, ",
491
+ " ,,,,,,,,,,,,,,,,,, ",
492
+ " ,,,,,,,,,,,,,,,,,, ",
493
+ " ,,,,,,,,,,,,,, ",
494
+ " ,, ",
495
+ nil].join("\n")
496
+
497
+ actual = PNG::pie_chart(10, 0.25, PNG::Color::Black, PNG::Color::Green)
498
+ assert_equal expected, actual.to_s
499
+ end
500
+
501
+ def util_angle(expect, x, y)
502
+ actual = PNG.angle(x, y)
503
+ case expect
504
+ when Integer then
505
+ assert_equal(expect, actual,
506
+ "[#{x}, #{y}] should be == #{expect}, was #{actual}")
507
+ else
508
+ assert_in_delta(expect, actual, 0.5)
509
+ end
510
+ end
511
+
512
+ def test_math_is_hard_lets_go_shopping
513
+ util_angle 0, 0, 0
514
+ (25..500).step(25) do |n|
515
+ util_angle 0, 0, n
516
+ util_angle 90, n, 0
517
+ util_angle 180, 0, -n
518
+ util_angle 270, -n, 0
519
+ end
520
+
521
+ util_angle 359.5, -1, 250
522
+ util_angle 0.0, 0, 250
523
+ util_angle 0.5, 1, 250
524
+
525
+ util_angle 89.5, 250, 1
526
+ util_angle 90.0, 250, 0
527
+ util_angle 90.5, 250, -1
528
+ end
529
+ end