chunky_png 1.0.0.beta2 → 1.0.0.rc1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (44) hide show
  1. data/.infinity_test +1 -1
  2. data/README.rdoc +2 -2
  3. data/chunky_png.gemspec +4 -4
  4. data/lib/chunky_png.rb +14 -8
  5. data/lib/chunky_png/canvas.rb +110 -38
  6. data/lib/chunky_png/canvas/drawing.rb +175 -34
  7. data/lib/chunky_png/canvas/masking.rb +91 -0
  8. data/lib/chunky_png/canvas/operations.rb +141 -112
  9. data/lib/chunky_png/canvas/png_decoding.rb +13 -13
  10. data/lib/chunky_png/canvas/resampling.rb +42 -0
  11. data/lib/chunky_png/color.rb +252 -11
  12. data/lib/chunky_png/compatibility.rb +5 -5
  13. data/lib/chunky_png/dimension.rb +106 -0
  14. data/lib/chunky_png/point.rb +110 -0
  15. data/lib/chunky_png/vector.rb +92 -0
  16. data/spec/chunky_png/canvas/drawing_spec.rb +107 -14
  17. data/spec/chunky_png/canvas/masking_spec.rb +51 -0
  18. data/spec/chunky_png/canvas/operations_spec.rb +142 -75
  19. data/spec/chunky_png/canvas/resampling_spec.rb +31 -0
  20. data/spec/chunky_png/canvas/stream_exporting_spec.rb +20 -0
  21. data/spec/chunky_png/canvas/stream_importing_spec.rb +22 -0
  22. data/spec/chunky_png/canvas_spec.rb +151 -22
  23. data/spec/chunky_png/color_spec.rb +53 -0
  24. data/spec/chunky_png/dimension_spec.rb +43 -0
  25. data/spec/chunky_png/point_spec.rb +71 -0
  26. data/spec/chunky_png/vector_spec.rb +58 -0
  27. data/spec/resources/circles.png +0 -0
  28. data/spec/resources/clock_nn_xdown_ydown.png +0 -0
  29. data/spec/resources/clock_nn_xdown_yup.png +0 -0
  30. data/spec/resources/clock_nn_xup_yup.png +0 -0
  31. data/spec/resources/lines.png +0 -0
  32. data/spec/resources/partial_circles.png +0 -0
  33. data/spec/resources/polygon_filled_horizontal.png +0 -0
  34. data/spec/resources/polygon_filled_vertical.png +0 -0
  35. data/spec/resources/polygon_triangle_filled.png +0 -0
  36. data/spec/resources/polygon_unfilled.png +0 -0
  37. data/spec/resources/rect.png +0 -0
  38. metadata +31 -9
  39. data/spec/resources/clock_flip_horizontally.png +0 -0
  40. data/spec/resources/clock_flip_vertically.png +0 -0
  41. data/spec/resources/clock_rotate_180.png +0 -0
  42. data/spec/resources/clock_rotate_left.png +0 -0
  43. data/spec/resources/clock_rotate_right.png +0 -0
  44. data/spec/resources/clock_stubbed.png +0 -0
@@ -1,6 +1,6 @@
1
1
  infinity_test do
2
2
 
3
- use :rubies => %w(1.8.7 1.9.2 ree jruby rbx), :test_framework => :rspec
3
+ use :rubies => %w(1.8.6 1.8.7 1.9.2 ree jruby rbx), :test_framework => :rspec
4
4
 
5
5
  before(:each_ruby) do |environment|
6
6
  environment.system('bundle install')
@@ -35,13 +35,13 @@ provides a massive speed boost to encoding and decoding.
35
35
  # Creating an image from scratch, save as an interlaced PNG
36
36
  png = ChunkyPNG::Image.new(16, 16, ChunkyPNG::Color::TRANSPARENT)
37
37
  png[1,1] = ChunkyPNG::Color.rgba(10, 20, 30, 128)
38
- png[2,1] = ChunkyPNG::Color.rgba(0, 0, 0, 128)
38
+ png[2,1] = ChunkyPNG::Color('black @ 0.5')
39
39
  png.save('filename.png', :interlace => true)
40
40
 
41
41
  # Compose images using alpha blending.
42
42
  avatar = ChunkyPNG::Image.from_file('avatar.png')
43
43
  badge = ChunkyPNG::Image.from_file('no_ie_badge.png')
44
- avatar.compose(badge, 10, 10)
44
+ avatar.compose!(badge, 10, 10)
45
45
  avatar.save('composited.png', :fast_rgba) # Force the fast saving routine.
46
46
 
47
47
  # Accessing metadata
@@ -3,8 +3,8 @@ Gem::Specification.new do |s|
3
3
 
4
4
  # Do not change the version and date fields by hand. This will be done
5
5
  # automatically by the gem release script.
6
- s.version = "1.0.0.beta2"
7
- s.date = "2011-01-28"
6
+ s.version = "1.0.0.rc1"
7
+ s.date = "2011-02-24"
8
8
 
9
9
  s.summary = "Pure ruby library for read/write, chunk-level access to PNG files"
10
10
  s.description = <<-EOT
@@ -38,6 +38,6 @@ Gem::Specification.new do |s|
38
38
 
39
39
  # Do not change the files and test_files fields by hand. This will be done
40
40
  # automatically by the gem release script.
41
- s.files = %w(.gitignore .infinity_test .yardopts BENCHMARKS.rdoc Gemfile LICENSE README.rdoc Rakefile benchmarks/decoding_benchmark.rb benchmarks/encoding_benchmark.rb benchmarks/filesize_benchmark.rb chunky_png.gemspec lib/chunky_png.rb lib/chunky_png/canvas.rb lib/chunky_png/canvas/adam7_interlacing.rb lib/chunky_png/canvas/drawing.rb lib/chunky_png/canvas/operations.rb lib/chunky_png/canvas/png_decoding.rb lib/chunky_png/canvas/png_encoding.rb lib/chunky_png/canvas/stream_exporting.rb lib/chunky_png/canvas/stream_importing.rb lib/chunky_png/chunk.rb lib/chunky_png/color.rb lib/chunky_png/compatibility.rb lib/chunky_png/datastream.rb lib/chunky_png/image.rb lib/chunky_png/palette.rb lib/chunky_png/rmagick.rb spec/chunky_png/canvas/adam7_interlacing_spec.rb spec/chunky_png/canvas/drawing_spec.rb spec/chunky_png/canvas/operations_spec.rb spec/chunky_png/canvas/png_decoding_spec.rb spec/chunky_png/canvas/png_encoding_spec.rb spec/chunky_png/canvas_spec.rb spec/chunky_png/color_spec.rb spec/chunky_png/datastream_spec.rb spec/chunky_png/image_spec.rb spec/chunky_png/rmagick_spec.rb spec/chunky_png_spec.rb spec/png_suite/background_chunks/bgai4a08.png spec/png_suite/background_chunks/bgai4a16.png spec/png_suite/background_chunks/bgan6a08.png spec/png_suite/background_chunks/bgan6a16.png spec/png_suite/background_chunks/bgbn4a08.png spec/png_suite/background_chunks/bggn4a16.png spec/png_suite/background_chunks/bgwn6a08.png spec/png_suite/background_chunks/bgyn6a16.png spec/png_suite/basic/basi0g01.png spec/png_suite/basic/basi0g01.rgba spec/png_suite/basic/basi0g02.png spec/png_suite/basic/basi0g02.rgba spec/png_suite/basic/basi0g04.png spec/png_suite/basic/basi0g04.rgba spec/png_suite/basic/basi0g08.png spec/png_suite/basic/basi0g08.rgba spec/png_suite/basic/basi0g16.png spec/png_suite/basic/basi0g16.rgba spec/png_suite/basic/basi2c08.png spec/png_suite/basic/basi2c08.rgba spec/png_suite/basic/basi2c16.png spec/png_suite/basic/basi2c16.rgba spec/png_suite/basic/basi3p01.png spec/png_suite/basic/basi3p01.rgba spec/png_suite/basic/basi3p02.png spec/png_suite/basic/basi3p02.rgba spec/png_suite/basic/basi3p04.png spec/png_suite/basic/basi3p04.rgba spec/png_suite/basic/basi3p08.png spec/png_suite/basic/basi3p08.rgba spec/png_suite/basic/basi4a08.png spec/png_suite/basic/basi4a08.rgba spec/png_suite/basic/basi4a16.png spec/png_suite/basic/basi4a16.rgba spec/png_suite/basic/basi6a08.png spec/png_suite/basic/basi6a08.rgba spec/png_suite/basic/basi6a16.png spec/png_suite/basic/basi6a16.rgba spec/png_suite/basic/basn0g01.png spec/png_suite/basic/basn0g01.rgba spec/png_suite/basic/basn0g02.png spec/png_suite/basic/basn0g02.rgba spec/png_suite/basic/basn0g04.png spec/png_suite/basic/basn0g04.rgba spec/png_suite/basic/basn0g08.png spec/png_suite/basic/basn0g08.rgba spec/png_suite/basic/basn0g16.png spec/png_suite/basic/basn0g16.rgba spec/png_suite/basic/basn2c08.png spec/png_suite/basic/basn2c08.rgba spec/png_suite/basic/basn2c16.png spec/png_suite/basic/basn2c16.rgba spec/png_suite/basic/basn3p01.png spec/png_suite/basic/basn3p01.rgba spec/png_suite/basic/basn3p02.png spec/png_suite/basic/basn3p02.rgba spec/png_suite/basic/basn3p04.png spec/png_suite/basic/basn3p04.rgba spec/png_suite/basic/basn3p08.png spec/png_suite/basic/basn3p08.rgba spec/png_suite/basic/basn4a08.png spec/png_suite/basic/basn4a08.rgba spec/png_suite/basic/basn4a16.png spec/png_suite/basic/basn4a16.rgba spec/png_suite/basic/basn6a08.png spec/png_suite/basic/basn6a08.rgba spec/png_suite/basic/basn6a16.png spec/png_suite/basic/basn6a16.rgba spec/png_suite/broken/x00n0g01.png spec/png_suite/broken/xcrn0g04.png spec/png_suite/broken/xlfn0g04.png spec/png_suite/chunk_ordering/oi1n0g16.png spec/png_suite/chunk_ordering/oi1n2c16.png spec/png_suite/chunk_ordering/oi2n0g16.png spec/png_suite/chunk_ordering/oi2n2c16.png spec/png_suite/chunk_ordering/oi4n0g16.png spec/png_suite/chunk_ordering/oi4n2c16.png spec/png_suite/chunk_ordering/oi9n0g16.png spec/png_suite/chunk_ordering/oi9n2c16.png spec/png_suite/compression_levels/z00n2c08.png spec/png_suite/compression_levels/z03n2c08.png spec/png_suite/compression_levels/z06n2c08.png spec/png_suite/compression_levels/z09n2c08.png spec/png_suite/filtering/f00n0g08.png spec/png_suite/filtering/f00n0g08.rgba spec/png_suite/filtering/f00n0g08_reference.png spec/png_suite/filtering/f00n0g08_reference.rgba spec/png_suite/filtering/f00n2c08.png spec/png_suite/filtering/f00n2c08.rgba spec/png_suite/filtering/f00n2c08_reference.png spec/png_suite/filtering/f00n2c08_reference.rgba spec/png_suite/filtering/f01n0g08.png spec/png_suite/filtering/f01n0g08.rgba spec/png_suite/filtering/f01n0g08_reference.png spec/png_suite/filtering/f01n0g08_reference.rgba spec/png_suite/filtering/f01n2c08.png spec/png_suite/filtering/f01n2c08.rgba spec/png_suite/filtering/f01n2c08_reference.png spec/png_suite/filtering/f01n2c08_reference.rgba spec/png_suite/filtering/f02n0g08.png spec/png_suite/filtering/f02n0g08.rgba spec/png_suite/filtering/f02n0g08_reference.png spec/png_suite/filtering/f02n0g08_reference.rgba spec/png_suite/filtering/f02n2c08.png spec/png_suite/filtering/f02n2c08.rgba spec/png_suite/filtering/f02n2c08_reference.png spec/png_suite/filtering/f02n2c08_reference.rgba spec/png_suite/filtering/f03n0g08.png spec/png_suite/filtering/f03n0g08.rgba spec/png_suite/filtering/f03n0g08_reference.png spec/png_suite/filtering/f03n0g08_reference.rgba spec/png_suite/filtering/f03n2c08.png spec/png_suite/filtering/f03n2c08.rgba spec/png_suite/filtering/f03n2c08_reference.png spec/png_suite/filtering/f03n2c08_reference.rgba spec/png_suite/filtering/f04n0g08.png spec/png_suite/filtering/f04n0g08.rgba spec/png_suite/filtering/f04n0g08_reference.png spec/png_suite/filtering/f04n0g08_reference.rgba spec/png_suite/filtering/f04n2c08.png spec/png_suite/filtering/f04n2c08.rgba spec/png_suite/filtering/f04n2c08_reference.png spec/png_suite/filtering/f04n2c08_reference.rgba spec/png_suite/gamma/g03n0g16.png spec/png_suite/gamma/g03n2c08.png spec/png_suite/gamma/g03n3p04.png spec/png_suite/gamma/g04n0g16.png spec/png_suite/gamma/g04n2c08.png spec/png_suite/gamma/g04n3p04.png spec/png_suite/gamma/g05n0g16.png spec/png_suite/gamma/g05n2c08.png spec/png_suite/gamma/g05n3p04.png spec/png_suite/gamma/g07n0g16.png spec/png_suite/gamma/g07n2c08.png spec/png_suite/gamma/g07n3p04.png spec/png_suite/gamma/g10n0g16.png spec/png_suite/gamma/g10n2c08.png spec/png_suite/gamma/g10n3p04.png spec/png_suite/gamma/g25n0g16.png spec/png_suite/gamma/g25n2c08.png spec/png_suite/gamma/g25n3p04.png spec/png_suite/metadata/cm0n0g04.png spec/png_suite/metadata/cm7n0g04.png spec/png_suite/metadata/cm9n0g04.png spec/png_suite/other/ccwn2c08.png spec/png_suite/other/ccwn3p08.png spec/png_suite/other/cdfn2c08.png spec/png_suite/other/cdhn2c08.png spec/png_suite/other/cdsn2c08.png spec/png_suite/other/cdun2c08.png spec/png_suite/other/ch1n3p04.png spec/png_suite/other/ch2n3p08.png spec/png_suite/other/cs3n2c16.png spec/png_suite/other/cs3n3p08.png spec/png_suite/other/cs5n2c08.png spec/png_suite/other/cs5n3p08.png spec/png_suite/other/cs8n2c08.png spec/png_suite/other/cs8n3p08.png spec/png_suite/other/ct0n0g04.png spec/png_suite/other/ct1n0g04.png spec/png_suite/other/ctzn0g04.png spec/png_suite/other/pp0n2c16.png spec/png_suite/other/pp0n6a08.png spec/png_suite/other/ps1n0g08.png spec/png_suite/other/ps1n2c16.png spec/png_suite/other/ps2n0g08.png spec/png_suite/other/ps2n2c16.png spec/png_suite/sizes/s01i3p01.png spec/png_suite/sizes/s01n3p01.png spec/png_suite/sizes/s02i3p01.png spec/png_suite/sizes/s02n3p01.png spec/png_suite/sizes/s03i3p01.png spec/png_suite/sizes/s03n3p01.png spec/png_suite/sizes/s04i3p01.png spec/png_suite/sizes/s04n3p01.png spec/png_suite/sizes/s05i3p02.png spec/png_suite/sizes/s05n3p02.png spec/png_suite/sizes/s06i3p02.png spec/png_suite/sizes/s06n3p02.png spec/png_suite/sizes/s07i3p02.png spec/png_suite/sizes/s07n3p02.png spec/png_suite/sizes/s08i3p02.png spec/png_suite/sizes/s08n3p02.png spec/png_suite/sizes/s09i3p02.png spec/png_suite/sizes/s09n3p02.png spec/png_suite/sizes/s32i3p04.png spec/png_suite/sizes/s32n3p04.png spec/png_suite/sizes/s33i3p04.png spec/png_suite/sizes/s33n3p04.png spec/png_suite/sizes/s34i3p04.png spec/png_suite/sizes/s34n3p04.png spec/png_suite/sizes/s35i3p04.png spec/png_suite/sizes/s35n3p04.png spec/png_suite/sizes/s36i3p04.png spec/png_suite/sizes/s36n3p04.png spec/png_suite/sizes/s37i3p04.png spec/png_suite/sizes/s37n3p04.png spec/png_suite/sizes/s38i3p04.png spec/png_suite/sizes/s38n3p04.png spec/png_suite/sizes/s39i3p04.png spec/png_suite/sizes/s39n3p04.png spec/png_suite/sizes/s40i3p04.png spec/png_suite/sizes/s40n3p04.png spec/png_suite/transparency/tbbn1g04.png spec/png_suite/transparency/tbbn2c16.png spec/png_suite/transparency/tbbn3p08.png spec/png_suite/transparency/tbgn2c16.png spec/png_suite/transparency/tbgn3p08.png spec/png_suite/transparency/tbrn2c08.png spec/png_suite/transparency/tbwn1g16.png spec/png_suite/transparency/tbwn3p08.png spec/png_suite/transparency/tbyn3p08.png spec/png_suite/transparency/tp0n1g08.png spec/png_suite/transparency/tp0n2c08.png spec/png_suite/transparency/tp0n3p08.png spec/png_suite/transparency/tp1n3p08.png spec/png_suite_spec.rb spec/resources/adam7.png spec/resources/clock.png spec/resources/clock_base.png spec/resources/clock_flip_horizontally.png spec/resources/clock_flip_vertically.png spec/resources/clock_mask.png spec/resources/clock_mask_updated.png spec/resources/clock_rotate_180.png spec/resources/clock_rotate_left.png spec/resources/clock_rotate_right.png spec/resources/clock_stubbed.png spec/resources/clock_updated.png spec/resources/composited.png spec/resources/cropped.png spec/resources/damaged_chunk.png spec/resources/damaged_signature.png spec/resources/lines.png spec/resources/operations.png spec/resources/pixelstream.rgb spec/resources/pixelstream.rgba spec/resources/pixelstream_best_compression.png spec/resources/pixelstream_fast_rgba.png spec/resources/pixelstream_reference.png spec/resources/rect.png spec/resources/replaced.png spec/resources/text_chunk.png spec/resources/ztxt_chunk.png spec/spec_helper.rb tasks/benchmarks.rake tasks/github-gem.rake)
42
- s.test_files = %w(spec/chunky_png/canvas/adam7_interlacing_spec.rb spec/chunky_png/canvas/drawing_spec.rb spec/chunky_png/canvas/operations_spec.rb spec/chunky_png/canvas/png_decoding_spec.rb spec/chunky_png/canvas/png_encoding_spec.rb spec/chunky_png/canvas_spec.rb spec/chunky_png/color_spec.rb spec/chunky_png/datastream_spec.rb spec/chunky_png/image_spec.rb spec/chunky_png/rmagick_spec.rb spec/chunky_png_spec.rb spec/png_suite_spec.rb)
41
+ s.files = %w(.gitignore .infinity_test .yardopts BENCHMARKS.rdoc Gemfile LICENSE README.rdoc Rakefile benchmarks/decoding_benchmark.rb benchmarks/encoding_benchmark.rb benchmarks/filesize_benchmark.rb chunky_png.gemspec lib/chunky_png.rb lib/chunky_png/canvas.rb lib/chunky_png/canvas/adam7_interlacing.rb lib/chunky_png/canvas/drawing.rb lib/chunky_png/canvas/masking.rb lib/chunky_png/canvas/operations.rb lib/chunky_png/canvas/png_decoding.rb lib/chunky_png/canvas/png_encoding.rb lib/chunky_png/canvas/resampling.rb lib/chunky_png/canvas/stream_exporting.rb lib/chunky_png/canvas/stream_importing.rb lib/chunky_png/chunk.rb lib/chunky_png/color.rb lib/chunky_png/compatibility.rb lib/chunky_png/datastream.rb lib/chunky_png/dimension.rb lib/chunky_png/image.rb lib/chunky_png/palette.rb lib/chunky_png/point.rb lib/chunky_png/rmagick.rb lib/chunky_png/vector.rb spec/chunky_png/canvas/adam7_interlacing_spec.rb spec/chunky_png/canvas/drawing_spec.rb spec/chunky_png/canvas/masking_spec.rb spec/chunky_png/canvas/operations_spec.rb spec/chunky_png/canvas/png_decoding_spec.rb spec/chunky_png/canvas/png_encoding_spec.rb spec/chunky_png/canvas/resampling_spec.rb spec/chunky_png/canvas/stream_exporting_spec.rb spec/chunky_png/canvas/stream_importing_spec.rb spec/chunky_png/canvas_spec.rb spec/chunky_png/color_spec.rb spec/chunky_png/datastream_spec.rb spec/chunky_png/dimension_spec.rb spec/chunky_png/image_spec.rb spec/chunky_png/point_spec.rb spec/chunky_png/rmagick_spec.rb spec/chunky_png/vector_spec.rb spec/chunky_png_spec.rb spec/png_suite/background_chunks/bgai4a08.png spec/png_suite/background_chunks/bgai4a16.png spec/png_suite/background_chunks/bgan6a08.png spec/png_suite/background_chunks/bgan6a16.png spec/png_suite/background_chunks/bgbn4a08.png spec/png_suite/background_chunks/bggn4a16.png spec/png_suite/background_chunks/bgwn6a08.png spec/png_suite/background_chunks/bgyn6a16.png spec/png_suite/basic/basi0g01.png spec/png_suite/basic/basi0g01.rgba spec/png_suite/basic/basi0g02.png spec/png_suite/basic/basi0g02.rgba spec/png_suite/basic/basi0g04.png spec/png_suite/basic/basi0g04.rgba spec/png_suite/basic/basi0g08.png spec/png_suite/basic/basi0g08.rgba spec/png_suite/basic/basi0g16.png spec/png_suite/basic/basi0g16.rgba spec/png_suite/basic/basi2c08.png spec/png_suite/basic/basi2c08.rgba spec/png_suite/basic/basi2c16.png spec/png_suite/basic/basi2c16.rgba spec/png_suite/basic/basi3p01.png spec/png_suite/basic/basi3p01.rgba spec/png_suite/basic/basi3p02.png spec/png_suite/basic/basi3p02.rgba spec/png_suite/basic/basi3p04.png spec/png_suite/basic/basi3p04.rgba spec/png_suite/basic/basi3p08.png spec/png_suite/basic/basi3p08.rgba spec/png_suite/basic/basi4a08.png spec/png_suite/basic/basi4a08.rgba spec/png_suite/basic/basi4a16.png spec/png_suite/basic/basi4a16.rgba spec/png_suite/basic/basi6a08.png spec/png_suite/basic/basi6a08.rgba spec/png_suite/basic/basi6a16.png spec/png_suite/basic/basi6a16.rgba spec/png_suite/basic/basn0g01.png spec/png_suite/basic/basn0g01.rgba spec/png_suite/basic/basn0g02.png spec/png_suite/basic/basn0g02.rgba spec/png_suite/basic/basn0g04.png spec/png_suite/basic/basn0g04.rgba spec/png_suite/basic/basn0g08.png spec/png_suite/basic/basn0g08.rgba spec/png_suite/basic/basn0g16.png spec/png_suite/basic/basn0g16.rgba spec/png_suite/basic/basn2c08.png spec/png_suite/basic/basn2c08.rgba spec/png_suite/basic/basn2c16.png spec/png_suite/basic/basn2c16.rgba spec/png_suite/basic/basn3p01.png spec/png_suite/basic/basn3p01.rgba spec/png_suite/basic/basn3p02.png spec/png_suite/basic/basn3p02.rgba spec/png_suite/basic/basn3p04.png spec/png_suite/basic/basn3p04.rgba spec/png_suite/basic/basn3p08.png spec/png_suite/basic/basn3p08.rgba spec/png_suite/basic/basn4a08.png spec/png_suite/basic/basn4a08.rgba spec/png_suite/basic/basn4a16.png spec/png_suite/basic/basn4a16.rgba spec/png_suite/basic/basn6a08.png spec/png_suite/basic/basn6a08.rgba spec/png_suite/basic/basn6a16.png spec/png_suite/basic/basn6a16.rgba spec/png_suite/broken/x00n0g01.png spec/png_suite/broken/xcrn0g04.png spec/png_suite/broken/xlfn0g04.png spec/png_suite/chunk_ordering/oi1n0g16.png spec/png_suite/chunk_ordering/oi1n2c16.png spec/png_suite/chunk_ordering/oi2n0g16.png spec/png_suite/chunk_ordering/oi2n2c16.png spec/png_suite/chunk_ordering/oi4n0g16.png spec/png_suite/chunk_ordering/oi4n2c16.png spec/png_suite/chunk_ordering/oi9n0g16.png spec/png_suite/chunk_ordering/oi9n2c16.png spec/png_suite/compression_levels/z00n2c08.png spec/png_suite/compression_levels/z03n2c08.png spec/png_suite/compression_levels/z06n2c08.png spec/png_suite/compression_levels/z09n2c08.png spec/png_suite/filtering/f00n0g08.png spec/png_suite/filtering/f00n0g08.rgba spec/png_suite/filtering/f00n0g08_reference.png spec/png_suite/filtering/f00n0g08_reference.rgba spec/png_suite/filtering/f00n2c08.png spec/png_suite/filtering/f00n2c08.rgba spec/png_suite/filtering/f00n2c08_reference.png spec/png_suite/filtering/f00n2c08_reference.rgba spec/png_suite/filtering/f01n0g08.png spec/png_suite/filtering/f01n0g08.rgba spec/png_suite/filtering/f01n0g08_reference.png spec/png_suite/filtering/f01n0g08_reference.rgba spec/png_suite/filtering/f01n2c08.png spec/png_suite/filtering/f01n2c08.rgba spec/png_suite/filtering/f01n2c08_reference.png spec/png_suite/filtering/f01n2c08_reference.rgba spec/png_suite/filtering/f02n0g08.png spec/png_suite/filtering/f02n0g08.rgba spec/png_suite/filtering/f02n0g08_reference.png spec/png_suite/filtering/f02n0g08_reference.rgba spec/png_suite/filtering/f02n2c08.png spec/png_suite/filtering/f02n2c08.rgba spec/png_suite/filtering/f02n2c08_reference.png spec/png_suite/filtering/f02n2c08_reference.rgba spec/png_suite/filtering/f03n0g08.png spec/png_suite/filtering/f03n0g08.rgba spec/png_suite/filtering/f03n0g08_reference.png spec/png_suite/filtering/f03n0g08_reference.rgba spec/png_suite/filtering/f03n2c08.png spec/png_suite/filtering/f03n2c08.rgba spec/png_suite/filtering/f03n2c08_reference.png spec/png_suite/filtering/f03n2c08_reference.rgba spec/png_suite/filtering/f04n0g08.png spec/png_suite/filtering/f04n0g08.rgba spec/png_suite/filtering/f04n0g08_reference.png spec/png_suite/filtering/f04n0g08_reference.rgba spec/png_suite/filtering/f04n2c08.png spec/png_suite/filtering/f04n2c08.rgba spec/png_suite/filtering/f04n2c08_reference.png spec/png_suite/filtering/f04n2c08_reference.rgba spec/png_suite/gamma/g03n0g16.png spec/png_suite/gamma/g03n2c08.png spec/png_suite/gamma/g03n3p04.png spec/png_suite/gamma/g04n0g16.png spec/png_suite/gamma/g04n2c08.png spec/png_suite/gamma/g04n3p04.png spec/png_suite/gamma/g05n0g16.png spec/png_suite/gamma/g05n2c08.png spec/png_suite/gamma/g05n3p04.png spec/png_suite/gamma/g07n0g16.png spec/png_suite/gamma/g07n2c08.png spec/png_suite/gamma/g07n3p04.png spec/png_suite/gamma/g10n0g16.png spec/png_suite/gamma/g10n2c08.png spec/png_suite/gamma/g10n3p04.png spec/png_suite/gamma/g25n0g16.png spec/png_suite/gamma/g25n2c08.png spec/png_suite/gamma/g25n3p04.png spec/png_suite/metadata/cm0n0g04.png spec/png_suite/metadata/cm7n0g04.png spec/png_suite/metadata/cm9n0g04.png spec/png_suite/other/ccwn2c08.png spec/png_suite/other/ccwn3p08.png spec/png_suite/other/cdfn2c08.png spec/png_suite/other/cdhn2c08.png spec/png_suite/other/cdsn2c08.png spec/png_suite/other/cdun2c08.png spec/png_suite/other/ch1n3p04.png spec/png_suite/other/ch2n3p08.png spec/png_suite/other/cs3n2c16.png spec/png_suite/other/cs3n3p08.png spec/png_suite/other/cs5n2c08.png spec/png_suite/other/cs5n3p08.png spec/png_suite/other/cs8n2c08.png spec/png_suite/other/cs8n3p08.png spec/png_suite/other/ct0n0g04.png spec/png_suite/other/ct1n0g04.png spec/png_suite/other/ctzn0g04.png spec/png_suite/other/pp0n2c16.png spec/png_suite/other/pp0n6a08.png spec/png_suite/other/ps1n0g08.png spec/png_suite/other/ps1n2c16.png spec/png_suite/other/ps2n0g08.png spec/png_suite/other/ps2n2c16.png spec/png_suite/sizes/s01i3p01.png spec/png_suite/sizes/s01n3p01.png spec/png_suite/sizes/s02i3p01.png spec/png_suite/sizes/s02n3p01.png spec/png_suite/sizes/s03i3p01.png spec/png_suite/sizes/s03n3p01.png spec/png_suite/sizes/s04i3p01.png spec/png_suite/sizes/s04n3p01.png spec/png_suite/sizes/s05i3p02.png spec/png_suite/sizes/s05n3p02.png spec/png_suite/sizes/s06i3p02.png spec/png_suite/sizes/s06n3p02.png spec/png_suite/sizes/s07i3p02.png spec/png_suite/sizes/s07n3p02.png spec/png_suite/sizes/s08i3p02.png spec/png_suite/sizes/s08n3p02.png spec/png_suite/sizes/s09i3p02.png spec/png_suite/sizes/s09n3p02.png spec/png_suite/sizes/s32i3p04.png spec/png_suite/sizes/s32n3p04.png spec/png_suite/sizes/s33i3p04.png spec/png_suite/sizes/s33n3p04.png spec/png_suite/sizes/s34i3p04.png spec/png_suite/sizes/s34n3p04.png spec/png_suite/sizes/s35i3p04.png spec/png_suite/sizes/s35n3p04.png spec/png_suite/sizes/s36i3p04.png spec/png_suite/sizes/s36n3p04.png spec/png_suite/sizes/s37i3p04.png spec/png_suite/sizes/s37n3p04.png spec/png_suite/sizes/s38i3p04.png spec/png_suite/sizes/s38n3p04.png spec/png_suite/sizes/s39i3p04.png spec/png_suite/sizes/s39n3p04.png spec/png_suite/sizes/s40i3p04.png spec/png_suite/sizes/s40n3p04.png spec/png_suite/transparency/tbbn1g04.png spec/png_suite/transparency/tbbn2c16.png spec/png_suite/transparency/tbbn3p08.png spec/png_suite/transparency/tbgn2c16.png spec/png_suite/transparency/tbgn3p08.png spec/png_suite/transparency/tbrn2c08.png spec/png_suite/transparency/tbwn1g16.png spec/png_suite/transparency/tbwn3p08.png spec/png_suite/transparency/tbyn3p08.png spec/png_suite/transparency/tp0n1g08.png spec/png_suite/transparency/tp0n2c08.png spec/png_suite/transparency/tp0n3p08.png spec/png_suite/transparency/tp1n3p08.png spec/png_suite_spec.rb spec/resources/adam7.png spec/resources/circles.png spec/resources/clock.png spec/resources/clock_base.png spec/resources/clock_mask.png spec/resources/clock_mask_updated.png spec/resources/clock_nn_xdown_ydown.png spec/resources/clock_nn_xdown_yup.png spec/resources/clock_nn_xup_yup.png spec/resources/clock_updated.png spec/resources/composited.png spec/resources/cropped.png spec/resources/damaged_chunk.png spec/resources/damaged_signature.png spec/resources/lines.png spec/resources/operations.png spec/resources/partial_circles.png spec/resources/pixelstream.rgb spec/resources/pixelstream.rgba spec/resources/pixelstream_best_compression.png spec/resources/pixelstream_fast_rgba.png spec/resources/pixelstream_reference.png spec/resources/polygon_filled_horizontal.png spec/resources/polygon_filled_vertical.png spec/resources/polygon_triangle_filled.png spec/resources/polygon_unfilled.png spec/resources/rect.png spec/resources/replaced.png spec/resources/text_chunk.png spec/resources/ztxt_chunk.png spec/spec_helper.rb tasks/benchmarks.rake tasks/github-gem.rake)
42
+ s.test_files = %w(spec/chunky_png/canvas/adam7_interlacing_spec.rb spec/chunky_png/canvas/drawing_spec.rb spec/chunky_png/canvas/masking_spec.rb spec/chunky_png/canvas/operations_spec.rb spec/chunky_png/canvas/png_decoding_spec.rb spec/chunky_png/canvas/png_encoding_spec.rb spec/chunky_png/canvas/resampling_spec.rb spec/chunky_png/canvas/stream_exporting_spec.rb spec/chunky_png/canvas/stream_importing_spec.rb spec/chunky_png/canvas_spec.rb spec/chunky_png/color_spec.rb spec/chunky_png/datastream_spec.rb spec/chunky_png/dimension_spec.rb spec/chunky_png/image_spec.rb spec/chunky_png/point_spec.rb spec/chunky_png/rmagick_spec.rb spec/chunky_png/vector_spec.rb spec/chunky_png_spec.rb spec/png_suite_spec.rb)
43
43
  end
@@ -1,20 +1,26 @@
1
+ # Basic requirements from standard library
1
2
  require 'set'
2
3
  require 'zlib'
3
4
  require 'stringio'
4
5
  require 'enumerator'
5
6
 
7
+ # Ruby 1.8 / 1.9 compatibility
6
8
  require 'chunky_png/compatibility'
9
+
10
+ # PNG file structure
7
11
  require 'chunky_png/datastream'
8
12
  require 'chunky_png/chunk'
13
+
14
+ # Colors
9
15
  require 'chunky_png/palette'
10
16
  require 'chunky_png/color'
11
- require 'chunky_png/canvas/png_encoding'
12
- require 'chunky_png/canvas/png_decoding'
13
- require 'chunky_png/canvas/adam7_interlacing'
14
- require 'chunky_png/canvas/stream_exporting'
15
- require 'chunky_png/canvas/stream_importing'
16
- require 'chunky_png/canvas/operations'
17
- require 'chunky_png/canvas/drawing'
17
+
18
+ # Geometry
19
+ require 'chunky_png/point'
20
+ require 'chunky_png/vector'
21
+ require 'chunky_png/dimension'
22
+
23
+ # Canvas / Image classes
18
24
  require 'chunky_png/canvas'
19
25
  require 'chunky_png/image'
20
26
 
@@ -28,7 +34,7 @@ module ChunkyPNG
28
34
 
29
35
  # The current version of ChunkyPNG. This value will be updated automatically
30
36
  # by them gem:release rake task.
31
- VERSION = "1.0.0.beta2"
37
+ VERSION = "1.0.0.rc1"
32
38
 
33
39
  ###################################################
34
40
  # PNG international standard defined constants
@@ -1,3 +1,13 @@
1
+ require 'chunky_png/canvas/png_encoding'
2
+ require 'chunky_png/canvas/png_decoding'
3
+ require 'chunky_png/canvas/adam7_interlacing'
4
+ require 'chunky_png/canvas/stream_exporting'
5
+ require 'chunky_png/canvas/stream_importing'
6
+ require 'chunky_png/canvas/operations'
7
+ require 'chunky_png/canvas/drawing'
8
+ require 'chunky_png/canvas/resampling'
9
+ require 'chunky_png/canvas/masking'
10
+
1
11
  module ChunkyPNG
2
12
 
3
13
  # The ChunkPNG::Canvas class represents a raster image as a matrix of
@@ -30,6 +40,8 @@ module ChunkyPNG
30
40
 
31
41
  include Operations
32
42
  include Drawing
43
+ include Resampling
44
+ include Masking
33
45
 
34
46
  # @return [Integer] The number of columns in this canvas
35
47
  attr_reader :width
@@ -61,10 +73,10 @@ module ChunkyPNG
61
73
 
62
74
  if initial.kind_of?(Integer)
63
75
  @pixels = Array.new(width * height, initial)
64
- elsif initial.kind_of?(Array) && initial.size == width * height
76
+ elsif initial.kind_of?(Array) && initial.length == width * height
65
77
  @pixels = initial
66
78
  else
67
- raise ChunkyPNG::ExpectationFailed, "Cannot use this value as initial canvas: #{initial.inspect}!"
79
+ raise ChunkyPNG::ExpectationFailed, "Cannot use this value as initial #{width}x#{height} canvas: #{initial.inspect}!"
68
80
  end
69
81
  end
70
82
 
@@ -87,41 +99,90 @@ module ChunkyPNG
87
99
  # PROPERTIES
88
100
  #################################################################
89
101
 
90
- # Returns the size ([width, height]) for this canvas.
91
- # @return Array An array with the width and height of this canvas as elements.
92
- def size
93
- [@width, @height]
102
+ # Returns the dimension (width x height) for this canvas.
103
+ # @return [ChunkyPNG::Dimension] A dimension instante with the width and height set for this canvas.
104
+ def dimension
105
+ ChunkyPNG::Dimension.new(width, height)
106
+ end
107
+
108
+ # Returns the area of this canvas in number of pixels.
109
+ # @return [Integer] The number of pixels in this canvas
110
+ def area
111
+ pixels.length
94
112
  end
95
113
 
96
114
  # Replaces a single pixel in this canvas.
97
- # @param [Integer] x The x-coordinate of the pixel (column)
98
- # @param [Integer] y The y-coordinate of the pixel (row)
99
- # @param [ChunkyPNG::Color] pixel The new pixel for the provided coordinates.
100
- # @return [Integer] the new pixel value, i.e. <tt>color</tt>.
115
+ #
116
+ # @overload []=(x, y, color)
117
+ # Sets the color value of a pixel given a x- and y-coordinate
118
+ # @param [Integer] x The x-coordinate of the pixel (column)
119
+ # @param [Integer] y The y-coordinate of the pixel (row)
120
+ # @param [Integer] color The new color for the provided coordinates.
121
+ # @return [Integer] The new color value for this pixel, i.e. <tt>color</tt>.
122
+ #
123
+ # @overload []=(point, color)
124
+ # Sets the color value of a pixel given point-like value.
125
+ # @param [ChunkyPNG::Point, ...] point The point on the canvas to replace.
126
+ # @param [Integer] color The new color for the provided coordinates.
127
+ # @return [Integer] The new color value for this pixel, i.e. <tt>color</tt>.
128
+ #
101
129
  # @raise [ChunkyPNG::OutOfBounds] when the coordinates are outside of the image's dimensions.
102
- def []=(x, y, color)
103
- assert_xy!(x, y)
104
- @pixels[y * width + x] = color
130
+ # @see #set_pixel
131
+ def []=(*args)
132
+ point = args.length == 2 ? ChunkyPNG::Point(args.first) : ChunkyPNG::Point(args[0], args[1])
133
+ assert_xy!(point.x, point.y)
134
+ @pixels[point.y * width + point.x] = args.last
105
135
  end
106
136
 
107
137
  # Replaces a single pixel in this canvas, without bounds checking.
108
- # @param (see #[]=)
109
- # @return [Integer] the new pixel value, i.e. <tt>color</tt>.
138
+ #
139
+ # This method return value and effects are undefined for coordinates
140
+ # out of bounds of the canvas.
141
+ #
142
+ # @param [Integer] x The x-coordinate of the pixel (column)
143
+ # @param [Integer] y The y-coordinate of the pixel (row)
144
+ # @param [Inteer] pixel The new color for the provided coordinates.
145
+ # @return [Integer] The new color value for this pixel, i.e. <tt>color</tt>.
110
146
  def set_pixel(x, y, color)
111
147
  @pixels[y * width + x] = color
112
148
  end
113
-
114
- # Returns a single pixel from this canvas.
149
+
150
+ # Replaces a single pixel in this canvas, with bounds checking. It will do
151
+ # noting if the provided coordinates are out of bounds.
152
+ #
115
153
  # @param [Integer] x The x-coordinate of the pixel (column)
116
154
  # @param [Integer] y The y-coordinate of the pixel (row)
117
- # @return [ChunkyPNG::Color] The current pixel at the provided coordinates.
155
+ # @param [CInteger] pixel The new color value for the provided coordinates.
156
+ # @return [Integer] The new color value for this pixel, i.e. <tt>color</tt>, or
157
+ # <tt>nil</tt> if the coordinates are out of bounds.
158
+ def set_pixel_if_within_bounds(x, y, color)
159
+ return unless include_xy?(x, y)
160
+ @pixels[y * width + x] = color
161
+ end
162
+
163
+ # Returns a single pixel's color value from this canvas.
164
+ #
165
+ # @overload [](point)
166
+ # Returns the color value given a point-like value.
167
+ # @param [ChunkyPNG::Point, ...] point The coordinates of the pixel as point.
168
+ # @return [Integer] The current color value at the provided coordinates.
169
+ #
170
+ # @overload [](x, y)
171
+ # Returns the color value given a x- and y-coordinate.
172
+ # @param [Integer] x The x-coordinate of the pixel (column)
173
+ # @param [Integer] y The y-coordinate of the pixel (row)
174
+ # @return [Integer] The current color value at the provided coordinates.
175
+ #
118
176
  # @raise [ChunkyPNG::OutOfBounds] when the coordinates are outside of the image's dimensions.
119
- def [](x, y)
120
- assert_xy!(x, y)
121
- @pixels[y * width + x]
177
+ # @see #get_pixel
178
+ def [](*args)
179
+ point = ChunkyPNG::Point(*args)
180
+ assert_xy!(point.x, point.y)
181
+ @pixels[point.y * width + point.x]
122
182
  end
123
183
 
124
- # Returns a single pixel from this canvas, without checking bounds.
184
+ # Returns a single pixel from this canvas, without checking bounds. The return value for
185
+ # this method is undefined if the coordinates are out of bounds.
125
186
  # @param (see #[])
126
187
  # @return [ChunkyPNG::Color] The current pixel at the provided coordinates.
127
188
  def get_pixel(x, y)
@@ -163,16 +224,17 @@ module ChunkyPNG
163
224
  end
164
225
 
165
226
  # Checks whether the given coordinates are in the range of the canvas
166
- # @param [Integer] x The x-coordinate of the pixel (column)
167
- # @param [Integer] y The y-coordinate of the pixel (row)
168
- # @return [true, false] True if the x and y coordinate are in the range
169
- # of this canvas.
170
- def include_xy?(x, y)
171
- include_x?(x) && include_y?(y)
227
+ # @param [ChunkyPNG::Point, Array, Hash, String] point_like The point to check.
228
+ # @return [true, false] True if the x and y coordinates of the point are
229
+ # within the limits of this canvas.
230
+ # @see ChunkyPNG::Point.single
231
+ def include_point?(*point_like)
232
+ dimension.include?(ChunkyPNG::Point(*point_like))
172
233
  end
173
234
 
174
- alias_method :include?, :include_xy?
175
-
235
+ alias_method :include?, :include_point?
236
+ alias_method :include_xy?, :include_point?
237
+
176
238
  # Checks whether the given y-coordinate is in the range of the canvas
177
239
  # @param [Integer] y The y-coordinate of the pixel (row)
178
240
  # @return [true, false] True if the y-coordinate is in the range of this canvas.
@@ -227,34 +289,44 @@ module ChunkyPNG
227
289
 
228
290
  protected
229
291
 
292
+ # Replaces the image, given a new width, new height, and a new pixel array.
293
+ def replace_canvas!(new_width, new_height, new_pixels)
294
+ raise ChunkyPNG::ExpectationFailed, "The provided pixel array should have #{new_width * new_height} items" unless new_pixels.length == new_width * new_height
295
+ @width, @height, @pixels = new_width, new_height, new_pixels
296
+ return self
297
+ end
298
+
230
299
  # Throws an exception if the x-coordinate is out of bounds.
231
300
  def assert_x!(x)
232
- raise ChunkyPNG::OutOfBounds, "Column index out of bounds!" unless include_x?(x)
301
+ raise ChunkyPNG::OutOfBounds, "Column index #{x} out of bounds!" unless include_x?(x)
233
302
  return true
234
303
  end
235
304
 
236
305
  # Throws an exception if the y-coordinate is out of bounds.
237
306
  def assert_y!(y)
238
- raise ChunkyPNG::OutOfBounds, "Row index out of bounds!" unless include_y?(y)
307
+ raise ChunkyPNG::OutOfBounds, "Row index #{y} out of bounds!" unless include_y?(y)
239
308
  return true
240
309
  end
241
310
 
242
311
  # Throws an exception if the x- or y-coordinate is out of bounds.
243
312
  def assert_xy!(x, y)
244
- raise ChunkyPNG::OutOfBounds, "Coordinates out of bounds!" unless include_xy?(x, y)
313
+ raise ChunkyPNG::OutOfBounds, "Coordinates (#{x},#{y}) out of bounds!" unless include_xy?(x, y)
245
314
  return true
246
315
  end
247
-
316
+
317
+ # Throws an exception if the vector_length does not match this canvas' height.
248
318
  def assert_height!(vector_length)
249
- raise ChunkyPNG::ExpectationFailed, "The length of the vector does not match the canvas height!" if height != vector_length
319
+ raise ChunkyPNG::ExpectationFailed, "The length of the vector (#{vector_length}) does not match the canvas height (#{height})!" if height != vector_length
250
320
  return true
251
321
  end
252
-
322
+
323
+ # Throws an exception if the vector_length does not match this canvas' width.
253
324
  def assert_width!(vector_length)
254
- raise ChunkyPNG::ExpectationFailed, "The length of the vector does not match the canvas width!" if width != vector_length
325
+ raise ChunkyPNG::ExpectationFailed, "The length of the vector (#{vector_length}) does not match the canvas width (#{width})!" if width != vector_length
255
326
  return true
256
327
  end
257
-
328
+
329
+ # Throws an exception if the matrix width and height does not match this canvas' dimensions.
258
330
  def assert_size!(matrix_width, matrix_height)
259
331
  raise ChunkyPNG::ExpectationFailed, "The width of the matrix does not match the canvas width!" if width != matrix_width
260
332
  raise ChunkyPNG::ExpectationFailed, "The height of the matrix does not match the canvas height!" if height != matrix_height
@@ -1,63 +1,91 @@
1
1
  module ChunkyPNG
2
2
  class Canvas
3
3
 
4
+ # Module that adds some primitive drawing methods to {ChunkyPNG::Canvas}.
5
+ #
6
+ # All of these methods change the current canvas instance and do not create a new one,
7
+ # even though the method names do not end with a bang.
8
+ #
9
+ # @note Drawing operations will not fail when something is drawn outside of the bounds
10
+ # of the canvas; these pixels will simply be ignored.
11
+ # @see ChunkyPNG::Canvas
4
12
  module Drawing
5
13
 
6
- # Sets a point on the canvas by composing a pixel with its background color.
7
- def point(x, y, color)
8
- set_pixel(x, y, ChunkyPNG::Color.compose(color, get_pixel(x, y)))
14
+ # Composes a pixel on the canvas by alpha blending a color with its background color.
15
+ # @overload compose_pixel(x, y, color)
16
+ # @param [Integer] x The x-coordinate of the pixel to blend.
17
+ # @param [Integer] y The y-coordinate of the pixel to blend.
18
+ # @param [Integer] color The foreground color to blend with
19
+ # @overload compose_pixel(point, color)
20
+ # @param [ChunkyPNG::Point, ...] point The point on the canvas to blend.
21
+ # @param [Integer] color The foreground color to blend with
22
+ def compose_pixel(*args)
23
+ point = args.length == 2 ? ChunkyPNG::Point(args.first) : ChunkyPNG::Point(args[0], args[1])
24
+ return unless include?(point)
25
+ set_pixel(point.x, point.y, ChunkyPNG::Color.compose(args.last, get_pixel(point.x, point.y)))
9
26
  end
10
27
 
11
28
  # Draws an anti-aliased line using Xiaolin Wu's algorithm.
12
29
  #
13
- def line_xiaolin_wu(x0, y0, x1, y1, color)
14
- y0, y1, x0, x1 = y1, y0, x1, x0 if y0 > y1
30
+ # @param [Integer] x0 The x-coordinate of the first control point.
31
+ # @param [Integer] y0 The y-coordinate of the first control point.
32
+ # @param [Integer] x1 The x-coordinate of the second control point.
33
+ # @param [Integer] y1 The y-coordinate of the second control point.
34
+ # @param [Integer] stroke_color The color to use for this line.
35
+ # @param [true, false] inclusive Whether to draw the last pixel.
36
+ # Set to false when drawing multiplelines in a path.
37
+ # @return [ChunkyPNG::Canvas] Itself, with the line drawn.
38
+ def line_xiaolin_wu(x0, y0, x1, y1, stroke_color, inclusive = true)
15
39
  dx = x1 - x0
16
40
  sx = dx < 0 ? -1 : 1
17
41
  dx *= sx
18
42
  dy = y1 - y0
43
+ sy = dy < 0 ? -1 : 1
44
+ dy *= sy
19
45
 
20
46
  if dy == 0 # vertical line
21
- Range.new(*[x0,x1].sort).each do |x|
22
- point(x, y0, color)
47
+ x0.step(inclusive ? x1 : x1 - sx, sx) do |x|
48
+ compose_pixel(x, y0, stroke_color)
23
49
  end
50
+
24
51
  elsif dx == 0 # horizontal line
25
- (y0..y1).each do |y|
26
- point(x0, y, color)
52
+ y0.step(inclusive ? y1 : y1 - sy, sy) do |y|
53
+ compose_pixel(x0, y, stroke_color)
27
54
  end
55
+
28
56
  elsif dx == dy # diagonal
29
- x0.step(x1, sx) do |x|
30
- point(x, y0, color)
31
- y0 += 1
57
+ x0.step(inclusive ? x1 : x1 - sx, sx) do |x|
58
+ compose_pixel(x, y0, stroke_color)
59
+ y0 += sy
32
60
  end
33
61
 
34
62
  elsif dy > dx # vertical displacement
35
- point(x0, y0, color)
36
- e_acc = 0
63
+ compose_pixel(x0, y0, stroke_color)
64
+ e_acc = 0
37
65
  e = ((dx << 16) / dy.to_f).round
38
- (y0...y1-1).each do |i|
66
+ (dy - 1).downto(0) do |i|
39
67
  e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xffff
40
- x0 = x0 + sx if (e_acc <= e_acc_temp)
68
+ x0 += sx if (e_acc <= e_acc_temp)
41
69
  w = 0xff - (e_acc >> 8)
42
- point(x0, y0, ChunkyPNG::Color.fade(color, w)) if include_xy?(x0, y0)
43
- y0 = y0 + 1
44
- point(x0 + sx, y0, ChunkyPNG::Color.fade(color, 0xff - w)) if include_xy?(x0 + sx, y0)
70
+ compose_pixel(x0, y0, ChunkyPNG::Color.fade(stroke_color, w))
71
+ compose_pixel(x0 + sx, y0 + sy, ChunkyPNG::Color.fade(stroke_color, 0xff - w)) if inclusive || i > 0
72
+ y0 += sy
45
73
  end
46
- point(x1, y1, color)
74
+ compose_pixel(x1, y1, stroke_color) if inclusive
47
75
 
48
76
  else # horizontal displacement
49
- point(x0, y0, color)
77
+ compose_pixel(x0, y0, stroke_color)
50
78
  e_acc = 0
51
- e = (dy << 16) / dx
79
+ e = ((dy << 16) / dx.to_f).round
52
80
  (dx - 1).downto(0) do |i|
53
81
  e_acc_temp, e_acc = e_acc, (e_acc + e) & 0xffff
54
- y0 += 1 if (e_acc <= e_acc_temp)
82
+ y0 += sy if (e_acc <= e_acc_temp)
55
83
  w = 0xff - (e_acc >> 8)
56
- point(x0, y0, ChunkyPNG::Color.fade(color, w)) if include_xy?(x0, y0)
84
+ compose_pixel(x0, y0, ChunkyPNG::Color.fade(stroke_color, w))
85
+ compose_pixel(x0 + sx, y0 + sy, ChunkyPNG::Color.fade(stroke_color, 0xff - w)) if inclusive || i > 0
57
86
  x0 += sx
58
- point(x0, y0 + 1, ChunkyPNG::Color.fade(color, 0xff - w)) if include_xy?(x0, y0 + 1)
59
87
  end
60
- point(x1, y1, color)
88
+ compose_pixel(x1, y1, stroke_color) if inclusive
61
89
  end
62
90
 
63
91
  return self
@@ -65,23 +93,136 @@ module ChunkyPNG
65
93
 
66
94
  alias_method :line, :line_xiaolin_wu
67
95
 
68
- def rect(x0, y0, x1, y1, line_color, fill_color = ChunkyPNG::Color::TRANSPARENT)
96
+
97
+ # Draws a polygon on the canvas using the stroke_color, filled using the fill_color if any.
98
+ #
99
+ # @param [Array, String] The control point vector. Accepts everything {ChunkyPNG.Vector} accepts.
100
+ # @param [Integer] stroke_color The stroke color to use for this polygon.
101
+ # @param [Integer] fill_color The fill color to use for this polygon.
102
+ # @return [ChunkyPNG::Canvas] Itself, with the polygon drawn.
103
+ def polygon(path, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT)
104
+
105
+ vector = ChunkyPNG::Vector(*path)
106
+ raise ChunkyPNG::ExpectationFailed, "A polygon requires at least 3 points" if path.length < 3
107
+
108
+ # Fill
109
+ unless fill_color == ChunkyPNG::Color::TRANSPARENT
110
+ vector.y_range.each do |y|
111
+ intersections = []
112
+ vector.edges.each do |p1, p2|
113
+ if (p1.y < y && p2.y >= y) || (p2.y < y && p1.y >= y)
114
+ intersections << (p1.x + (y - p1.y).to_f / (p2.y - p1.y) * (p2.x - p1.x)).round
115
+ end
116
+ end
117
+
118
+ intersections.sort!
119
+ 0.step(intersections.length - 1, 2) do |i|
120
+ intersections[i].upto(intersections[i + 1]) do |x|
121
+ compose_pixel(x, y, fill_color)
122
+ end
123
+ end
124
+ end
125
+ end
126
+
127
+ # Stroke
128
+ vector.each_edge do |(from_x, from_y), (to_x, to_y)|
129
+ line(from_x, from_y, to_x, to_y, stroke_color, false)
130
+ end
131
+
132
+ return self
133
+ end
134
+
135
+ # Draws a rectangle on the canvas, using two control points.
136
+ #
137
+ # @param [Integer] x0 The x-coordinate of the first control point.
138
+ # @param [Integer] y0 The y-coordinate of the first control point.
139
+ # @param [Integer] x1 The x-coordinate of the second control point.
140
+ # @param [Integer] y1 The y-coordinate of the second control point.
141
+ # @param [Integer] stroke_color The line color to use for this rectangle.
142
+ # @param [Integer] fill_color The fill color to use for this rectangle.
143
+ # @return [ChunkyPNG::Canvas] Itself, with the rectangle drawn.
144
+ def rect(x0, y0, x1, y1, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT)
69
145
 
70
146
  # Fill
71
- [x0, x1].min.upto([x0, x1].max) do |x|
72
- [y0, y1].min.upto([y0, y1].max) do |y|
73
- point(x, y, fill_color)
147
+ unless fill_color == ChunkyPNG::Color::TRANSPARENT
148
+ [x0, x1].min.upto([x0, x1].max) do |x|
149
+ [y0, y1].min.upto([y0, y1].max) do |y|
150
+ compose_pixel(x, y, fill_color)
151
+ end
74
152
  end
75
153
  end
76
154
 
77
155
  # Stroke
78
- line(x0, y0, x0, y1, line_color)
79
- line(x0, y1, x1, y1, line_color)
80
- line(x1, y1, x1, y0, line_color)
81
- line(x1, y0, x0, y0, line_color)
156
+ line(x0, y0, x0, y1, stroke_color, false)
157
+ line(x0, y1, x1, y1, stroke_color, false)
158
+ line(x1, y1, x1, y0, stroke_color, false)
159
+ line(x1, y0, x0, y0, stroke_color, false)
82
160
 
83
161
  return self
84
162
  end
163
+
164
+ # Draws a circle on the canvas.
165
+ #
166
+ # @param [Integer] x0 The x-coordinate of the center of the circle.
167
+ # @param [Integer] y0 The y-coordinate of the center of the circle.
168
+ # @param [Integer] radius The radius of the circle from the center point.
169
+ # @param [Integer] stroke_color The color to use for the line.
170
+ # @param [Integer] fill_color The color to use that fills the circle.
171
+ # @return [ChunkyPNG::Canvas] Itself, with the circle drawn.
172
+ def circle(x0, y0, radius, stroke_color = ChunkyPNG::Color::BLACK, fill_color = ChunkyPNG::Color::TRANSPARENT)
173
+
174
+ f = 1 - radius
175
+ ddF_x = 1
176
+ ddF_y = -2 * radius
177
+ x = 0
178
+ y = radius
179
+
180
+ compose_pixel(x0, y0 + radius, stroke_color)
181
+ compose_pixel(x0, y0 - radius, stroke_color)
182
+ compose_pixel(x0 + radius, y0, stroke_color)
183
+ compose_pixel(x0 - radius, y0, stroke_color)
184
+
185
+ lines = [radius - 1] unless fill_color == ChunkyPNG::Color::TRANSPARENT
186
+
187
+ while x < y
188
+
189
+ if f >= 0
190
+ y -= 1
191
+ ddF_y += 2
192
+ f += ddF_y
193
+ end
194
+
195
+ x += 1
196
+ ddF_x += 2
197
+ f += ddF_x
198
+
199
+ unless fill_color == ChunkyPNG::Color::TRANSPARENT
200
+ lines[y] = lines[y] ? [lines[y], x - 1].min : x - 1
201
+ lines[x] = lines[x] ? [lines[x], y - 1].min : y - 1
202
+ end
203
+
204
+ compose_pixel(x0 + x, y0 + y, stroke_color)
205
+ compose_pixel(x0 - x, y0 + y, stroke_color)
206
+ compose_pixel(x0 + x, y0 - y, stroke_color)
207
+ compose_pixel(x0 - x, y0 - y, stroke_color)
208
+
209
+ unless x == y
210
+ compose_pixel(x0 + y, y0 + x, stroke_color)
211
+ compose_pixel(x0 - y, y0 + x, stroke_color)
212
+ compose_pixel(x0 + y, y0 - x, stroke_color)
213
+ compose_pixel(x0 - y, y0 - x, stroke_color)
214
+ end
215
+ end
216
+
217
+ unless fill_color == ChunkyPNG::Color::TRANSPARENT
218
+ lines.each_with_index do |length, y|
219
+ line(x0 - length, y0 - y, x0 + length, y0 - y, fill_color) if length > 0
220
+ line(x0 - length, y0 + y, x0 + length, y0 + y, fill_color) if length > 0 && y > 0
221
+ end
222
+ end
223
+
224
+ return self
225
+ end
85
226
  end
86
227
  end
87
228
  end