chunky_png 1.0.0.beta2 → 1.0.0.rc1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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