png 1.1.0 → 1.2.0
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.
- data.tar.gz.sig +2 -0
- data/History.txt +59 -17
- data/Manifest.txt +5 -0
- data/Rakefile +11 -10
- data/example/lines.rb +4 -12
- data/lib/png.rb +260 -190
- data/lib/png/default_font.png +0 -0
- data/lib/png/font.rb +73 -0
- data/lib/png/pie.rb +1 -1
- data/lib/png/reader.rb +142 -0
- data/test/test_png.rb +179 -69
- data/test/test_png_font.rb +84 -0
- data/test/test_png_reader.rb +94 -0
- metadata +88 -52
- metadata.gz.sig +0 -0
| Binary file | 
    
        data/lib/png/font.rb
    ADDED
    
    | @@ -0,0 +1,73 @@ | |
| 1 | 
            +
            # encoding: BINARY
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'png/reader'
         | 
| 4 | 
            +
             | 
| 5 | 
            +
            ##
         | 
| 6 | 
            +
            # Implements a simple bitmap font by extracting letters from a PNG.
         | 
| 7 | 
            +
             | 
| 8 | 
            +
            class PNG::Font
         | 
| 9 | 
            +
              LETTERS = (('A'..'Z').to_a +
         | 
| 10 | 
            +
                         ('a'..'z').to_a +
         | 
| 11 | 
            +
                         ('0'..'9').to_a + [" "] * 16 +
         | 
| 12 | 
            +
                         '({[<!@#$%^&*?_+-=;,"/~>]})'.split(//))
         | 
| 13 | 
            +
             | 
| 14 | 
            +
              attr_reader :height, :width, :canvas
         | 
| 15 | 
            +
             | 
| 16 | 
            +
              def self.default
         | 
| 17 | 
            +
                @@default ||= new(File.join(File.dirname(__FILE__), "default_font.png"))
         | 
| 18 | 
            +
              end
         | 
| 19 | 
            +
             | 
| 20 | 
            +
              def initialize(png_file)
         | 
| 21 | 
            +
                @canvas = PNG.load_file png_file
         | 
| 22 | 
            +
                @height, @width = canvas.height / 4, canvas.width / 26
         | 
| 23 | 
            +
                @cache = {}
         | 
| 24 | 
            +
              end
         | 
| 25 | 
            +
             | 
| 26 | 
            +
              def coordinates c
         | 
| 27 | 
            +
                i = LETTERS.index c
         | 
| 28 | 
            +
             | 
| 29 | 
            +
                raise ArgumentError, "Can't find #{c.inspect}" unless i
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                x = (i % 26) * width
         | 
| 32 | 
            +
                y = (3 - (i / 26)) * height # start from the top (3rd row)
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                return x, y, x+width-1, y+height-1
         | 
| 35 | 
            +
              end
         | 
| 36 | 
            +
             | 
| 37 | 
            +
              def [] c
         | 
| 38 | 
            +
                c = c.chr unless String === c
         | 
| 39 | 
            +
                x0, y0, x1, y1 = coordinates c
         | 
| 40 | 
            +
             | 
| 41 | 
            +
                @cache[c] ||= @canvas.extract(x0, y0, x1, y1)
         | 
| 42 | 
            +
              end
         | 
| 43 | 
            +
            end
         | 
| 44 | 
            +
             | 
| 45 | 
            +
            class PNG::Canvas
         | 
| 46 | 
            +
              ##
         | 
| 47 | 
            +
              # Write a string at [x, y] with font, optionally specifying a font,
         | 
| 48 | 
            +
              # an alignment of :left, :center, or :right and the style to draw
         | 
| 49 | 
            +
              # the annotation (see #composite).
         | 
| 50 | 
            +
              #
         | 
| 51 | 
            +
              #   require 'png/font'
         | 
| 52 | 
            +
             | 
| 53 | 
            +
              def annotate(string, x, y,
         | 
| 54 | 
            +
                           font = PNG::Font.default, align = :left, style = :overwrite)
         | 
| 55 | 
            +
                case align
         | 
| 56 | 
            +
                when :left then
         | 
| 57 | 
            +
                  # do nothing
         | 
| 58 | 
            +
                when :center then
         | 
| 59 | 
            +
                  x -= string.length * font.width / 2
         | 
| 60 | 
            +
                when :right then
         | 
| 61 | 
            +
                  x -= string.length * font.width
         | 
| 62 | 
            +
                else
         | 
| 63 | 
            +
                  raise ArgumentError, "Unknown align: #{align.inspect}"
         | 
| 64 | 
            +
                end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
                x_offset, width = 0, font.width
         | 
| 67 | 
            +
             | 
| 68 | 
            +
                string.split(//).each do |char|
         | 
| 69 | 
            +
                  self.composite font[char], x + x_offset, y
         | 
| 70 | 
            +
                  x_offset += width
         | 
| 71 | 
            +
                end
         | 
| 72 | 
            +
              end
         | 
| 73 | 
            +
            end
         | 
    
        data/lib/png/pie.rb
    CHANGED
    
    
    
        data/lib/png/reader.rb
    ADDED
    
    | @@ -0,0 +1,142 @@ | |
| 1 | 
            +
            # encoding: BINARY
         | 
| 2 | 
            +
             | 
| 3 | 
            +
            require 'png'
         | 
| 4 | 
            +
            require 'enumerator'
         | 
| 5 | 
            +
             | 
| 6 | 
            +
            class PNG
         | 
| 7 | 
            +
              def self.load_file path, metadata_only = false
         | 
| 8 | 
            +
                file = File.open(path, 'rb') { |f| f.read }
         | 
| 9 | 
            +
                self.load file, metadata_only
         | 
| 10 | 
            +
              end
         | 
| 11 | 
            +
             | 
| 12 | 
            +
              def self.load png, metadata_only = false
         | 
| 13 | 
            +
                png = png.dup
         | 
| 14 | 
            +
                signature = png.slice! 0, 8
         | 
| 15 | 
            +
                raise ArgumentError, 'Invalid PNG signature' unless signature == SIGNATURE
         | 
| 16 | 
            +
             | 
| 17 | 
            +
                ihdr = read_chunk 'IHDR', png
         | 
| 18 | 
            +
             | 
| 19 | 
            +
                bit_depth, color_type, width, height = read_IHDR ihdr, metadata_only
         | 
| 20 | 
            +
             | 
| 21 | 
            +
                return [width, height, bit_depth] if metadata_only
         | 
| 22 | 
            +
             | 
| 23 | 
            +
                canvas = PNG::Canvas.new width, height
         | 
| 24 | 
            +
             | 
| 25 | 
            +
                type = png.slice(4, 4).unpack('a4').first
         | 
| 26 | 
            +
                read_chunk type, png if type == 'iCCP' # Ignore color profile
         | 
| 27 | 
            +
             | 
| 28 | 
            +
                read_IDAT read_chunk('IDAT', png), bit_depth, color_type, canvas
         | 
| 29 | 
            +
                read_chunk 'IEND', png
         | 
| 30 | 
            +
             | 
| 31 | 
            +
                canvas
         | 
| 32 | 
            +
              end
         | 
| 33 | 
            +
             | 
| 34 | 
            +
              def self.read_chunk expected_type, png
         | 
| 35 | 
            +
                size, type = png.slice!(0, 8).unpack 'Na4'
         | 
| 36 | 
            +
                data, crc = png.slice!(0, size + 4).unpack "a#{size}N"
         | 
| 37 | 
            +
             | 
| 38 | 
            +
                check_crc type, data, crc
         | 
| 39 | 
            +
             | 
| 40 | 
            +
                raise ArgumentError, "Expected #{expected_type} chunk, not #{type}" unless
         | 
| 41 | 
            +
                  type == expected_type
         | 
| 42 | 
            +
             | 
| 43 | 
            +
                return data
         | 
| 44 | 
            +
              end
         | 
| 45 | 
            +
             | 
| 46 | 
            +
              def self.check_crc type, data, crc
         | 
| 47 | 
            +
                return true if (type + data).png_crc == crc
         | 
| 48 | 
            +
                raise ArgumentError, "Invalid CRC encountered in #{type} chunk"
         | 
| 49 | 
            +
              end
         | 
| 50 | 
            +
             | 
| 51 | 
            +
              def self.read_IHDR data, metadata_only = false
         | 
| 52 | 
            +
                width, height, bit_depth, color_type, *rest = data.unpack 'N2C5'
         | 
| 53 | 
            +
             | 
| 54 | 
            +
                unless metadata_only then
         | 
| 55 | 
            +
                  raise ArgumentError, "Wrong bit depth: #{bit_depth}" unless
         | 
| 56 | 
            +
                    bit_depth == 8
         | 
| 57 | 
            +
                  raise ArgumentError, "Wrong color type: #{color_type}" unless
         | 
| 58 | 
            +
                    color_type == RGBA or color_type = RGB
         | 
| 59 | 
            +
                  raise ArgumentError, "Unsupported options: #{rest.inspect}" unless
         | 
| 60 | 
            +
                    rest == [0, 0, 0]
         | 
| 61 | 
            +
                end
         | 
| 62 | 
            +
             | 
| 63 | 
            +
                return bit_depth, color_type, width, height
         | 
| 64 | 
            +
              end
         | 
| 65 | 
            +
             | 
| 66 | 
            +
              def self.read_IDAT data, bit_depth, color_type, canvas
         | 
| 67 | 
            +
                data = Zlib::Inflate.inflate(data).unpack 'C*'
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                pixel_size = color_type == RGBA ? 4 : 3
         | 
| 70 | 
            +
             | 
| 71 | 
            +
                height = canvas.height
         | 
| 72 | 
            +
                scanline_length = pixel_size * canvas.width + 1 # for filter
         | 
| 73 | 
            +
             | 
| 74 | 
            +
                row = canvas.height - 1
         | 
| 75 | 
            +
                until data.empty? do
         | 
| 76 | 
            +
                  row_data = data.slice! 0, scanline_length
         | 
| 77 | 
            +
             | 
| 78 | 
            +
                  filter = row_data.shift
         | 
| 79 | 
            +
                  case filter
         | 
| 80 | 
            +
                  when NONE then
         | 
| 81 | 
            +
                  when SUB then
         | 
| 82 | 
            +
                    row_data.each_with_index do |byte, index|
         | 
| 83 | 
            +
                      left = index < pixel_size ? 0 : row_data[index - pixel_size]
         | 
| 84 | 
            +
                      row_data[index] = (byte + left) % 256
         | 
| 85 | 
            +
                    end
         | 
| 86 | 
            +
                  when UP then
         | 
| 87 | 
            +
                    row_data.each_with_index do |byte, index|
         | 
| 88 | 
            +
                      col = index / pixel_size
         | 
| 89 | 
            +
                      upper = row == 0 ? 0 : canvas[col, row + 1].values[index % pixel_size]
         | 
| 90 | 
            +
                      row_data[index] = (upper + byte) % 256
         | 
| 91 | 
            +
                    end
         | 
| 92 | 
            +
                  when AVG then
         | 
| 93 | 
            +
                    row_data.each_with_index do |byte, index|
         | 
| 94 | 
            +
                      col = index / pixel_size
         | 
| 95 | 
            +
                      upper = row == 0 ? 0 : canvas[col, row + 1].values[index % pixel_size]
         | 
| 96 | 
            +
                      left = index < pixel_size ? 0 : row_data[index - pixel_size]
         | 
| 97 | 
            +
             | 
| 98 | 
            +
                      row_data[index] = (byte + ((left + upper)/2).floor) % 256
         | 
| 99 | 
            +
                    end
         | 
| 100 | 
            +
                  when PAETH then
         | 
| 101 | 
            +
                    left = upper = upper_left = nil
         | 
| 102 | 
            +
                    row_data.each_with_index do |byte, index|
         | 
| 103 | 
            +
                      col = index / pixel_size
         | 
| 104 | 
            +
             | 
| 105 | 
            +
                      left = index < pixel_size ? 0 : row_data[index - pixel_size]
         | 
| 106 | 
            +
                      if row == height then
         | 
| 107 | 
            +
                        upper = upper_left = 0
         | 
| 108 | 
            +
                      else
         | 
| 109 | 
            +
                        upper = canvas[col, row + 1].values[index % pixel_size]
         | 
| 110 | 
            +
                        upper_left = col == 0 ? 0 :
         | 
| 111 | 
            +
                          canvas[col - 1, row + 1].values[index % pixel_size]
         | 
| 112 | 
            +
                      end
         | 
| 113 | 
            +
             | 
| 114 | 
            +
                      paeth = paeth left, upper, upper_left
         | 
| 115 | 
            +
                      row_data[index] = (byte + paeth) % 256
         | 
| 116 | 
            +
                    end
         | 
| 117 | 
            +
                  else
         | 
| 118 | 
            +
                    raise ArgumentError, "invalid filter algorithm #{filter}"
         | 
| 119 | 
            +
                  end
         | 
| 120 | 
            +
             | 
| 121 | 
            +
                  col = 0
         | 
| 122 | 
            +
                  row_data.each_slice pixel_size do |slice|
         | 
| 123 | 
            +
                    slice << 0xFF if pixel_size == 3
         | 
| 124 | 
            +
                    canvas[col, row] = PNG::Color.new(*slice)
         | 
| 125 | 
            +
                    col += 1
         | 
| 126 | 
            +
                  end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
                  row -= 1
         | 
| 129 | 
            +
                end
         | 
| 130 | 
            +
              end
         | 
| 131 | 
            +
             | 
| 132 | 
            +
              def self.paeth a, b, c # left, above, upper left
         | 
| 133 | 
            +
                p = a + b - c
         | 
| 134 | 
            +
                pa = (p - a).abs
         | 
| 135 | 
            +
                pb = (p - b).abs
         | 
| 136 | 
            +
                pc = (p - c).abs
         | 
| 137 | 
            +
             | 
| 138 | 
            +
                return a if pa <= pb && pa <= pc
         | 
| 139 | 
            +
                return b if pb <= pc
         | 
| 140 | 
            +
                c
         | 
| 141 | 
            +
              end
         | 
| 142 | 
            +
            end
         | 
    
        data/test/test_png.rb
    CHANGED
    
    | @@ -1,43 +1,37 @@ | |
| 1 | 
            -
             | 
| 1 | 
            +
            dir = File.expand_path "~/.ruby_inline"
         | 
| 2 | 
            +
            if test ?d, dir then
         | 
| 3 | 
            +
              require 'fileutils'
         | 
| 4 | 
            +
              puts "nuking #{dir}"
         | 
| 5 | 
            +
              # force removal, Windoze is bitching at me, something to hunt later...
         | 
| 6 | 
            +
              FileUtils.rm_r dir, :force => true
         | 
| 7 | 
            +
            end
         | 
| 8 | 
            +
             | 
| 9 | 
            +
            require 'minitest/autorun'
         | 
| 2 10 | 
             
            require 'rubygems'
         | 
| 3 11 | 
             
            require 'png'
         | 
| 12 | 
            +
            require 'png/reader'
         | 
| 4 13 | 
             
            require 'png/pie'
         | 
| 5 14 |  | 
| 6 | 
            -
            class TestPng <  | 
| 7 | 
            -
             | 
| 15 | 
            +
            class TestPng < MiniTest::Unit::TestCase
         | 
| 8 16 | 
             
              def setup
         | 
| 9 17 | 
             
                @canvas = PNG::Canvas.new 5, 10, PNG::Color::White
         | 
| 10 18 | 
             
                @png = PNG.new @canvas
         | 
| 11 19 |  | 
| 12 | 
            -
                @IHDR_length = "\000\000\000\r"
         | 
| 13 | 
            -
                @IHDR_crc = "\2152\317\275"
         | 
| 14 | 
            -
                @IHDR_crc_value = @IHDR_crc.unpack('N').first
         | 
| 15 | 
            -
                @IHDR_data = "\000\000\000\n\000\000\000\n\b\006\000\000\000"
         | 
| 16 | 
            -
                @IHDR_chunk = "#{@IHDR_length}IHDR#{@IHDR_data}#{@IHDR_crc}"
         | 
| 17 | 
            -
             | 
| 18 20 | 
             
                @blob = <<-EOF.unpack('m*').first
         | 
| 19 21 | 
             
            iVBORw0KGgoAAAANSUhEUgAAAAUAAAAKCAYAAAB8OZQwAAAAD0lEQVR4nGP4
         | 
| 20 22 | 
             
            jwUwDGVBALuJxzlQugpEAAAAAElFTkSuQmCC
         | 
| 21 23 | 
             
                EOF
         | 
| 22 24 | 
             
              end
         | 
| 23 25 |  | 
| 24 | 
            -
              def test_class_check_crc
         | 
| 25 | 
            -
                assert PNG.check_crc('IHDR', @IHDR_data, @IHDR_crc_value)
         | 
| 26 | 
            -
              end
         | 
| 27 | 
            -
             | 
| 28 | 
            -
              def test_class_check_crc_exception
         | 
| 29 | 
            -
                begin
         | 
| 30 | 
            -
                  PNG.check_crc('IHDR', @IHDR_data, @IHDR_crc_value + 1)
         | 
| 31 | 
            -
                rescue ArgumentError => e
         | 
| 32 | 
            -
                  assert_equal "Invalid CRC encountered in IHDR chunk", e.message
         | 
| 33 | 
            -
                else
         | 
| 34 | 
            -
                  flunk "exception wasn't raised"
         | 
| 35 | 
            -
                end
         | 
| 36 | 
            -
              end
         | 
| 37 | 
            -
             | 
| 38 26 | 
             
              def test_class_chunk
         | 
| 39 27 | 
             
                chunk = PNG.chunk 'IHDR', [10, 10, 8, 6, 0, 0, 0 ].pack('N2C5')
         | 
| 40 | 
            -
             | 
| 28 | 
            +
             | 
| 29 | 
            +
                header_crc = "\2152\317\275"
         | 
| 30 | 
            +
                header_data = "\000\000\000\n\000\000\000\n\b\006\000\000\000"
         | 
| 31 | 
            +
                header_length = "\000\000\000\r"
         | 
| 32 | 
            +
                header_chunk = "#{header_length}IHDR#{header_data}#{header_crc}"
         | 
| 33 | 
            +
             | 
| 34 | 
            +
                assert_equal header_chunk, chunk
         | 
| 41 35 | 
             
              end
         | 
| 42 36 |  | 
| 43 37 | 
             
              def test_class_chunk_empty
         | 
| @@ -53,17 +47,104 @@ jwUwDGVBALuJxzlQugpEAAAAAElFTkSuQmCC | |
| 53 47 | 
             
              def test_save
         | 
| 54 48 | 
             
                path = "blah.png"
         | 
| 55 49 | 
             
                @png.save(path)
         | 
| 56 | 
            -
                 | 
| 50 | 
            +
                file = File.open(path, 'rb') { |f| f.read }
         | 
| 51 | 
            +
                assert_equal @blob, file
         | 
| 57 52 | 
             
              ensure
         | 
| 58 53 | 
             
                assert_equal 1, File.unlink(path)
         | 
| 59 54 | 
             
              end
         | 
| 60 55 |  | 
| 61 | 
            -
             | 
| 56 | 
            +
            end
         | 
| 57 | 
            +
             | 
| 58 | 
            +
            class TestCanvas < MiniTest::Unit::TestCase
         | 
| 62 59 |  | 
| 63 60 | 
             
              def setup
         | 
| 64 61 | 
             
                @canvas = PNG::Canvas.new 5, 10, PNG::Color::White
         | 
| 65 62 | 
             
              end
         | 
| 66 63 |  | 
| 64 | 
            +
              def test_composite_default
         | 
| 65 | 
            +
                canvas1, canvas2 = util_composite_canvases
         | 
| 66 | 
            +
             | 
| 67 | 
            +
                canvas1.composite canvas2, 1, 1
         | 
| 68 | 
            +
             | 
| 69 | 
            +
                expected = " xxxxxxxx
         | 
| 70 | 
            +
                             xxxxxxxx
         | 
| 71 | 
            +
                             xx..xxxx
         | 
| 72 | 
            +
                             ..xxxxxx
         | 
| 73 | 
            +
                                      ".gsub(/ /, '')
         | 
| 74 | 
            +
             | 
| 75 | 
            +
                assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
         | 
| 76 | 
            +
              end
         | 
| 77 | 
            +
             | 
| 78 | 
            +
              def test_composite_underlay
         | 
| 79 | 
            +
                canvas1, canvas2 = util_composite_canvases
         | 
| 80 | 
            +
             | 
| 81 | 
            +
                canvas1.composite canvas2, 1, 1, :add
         | 
| 82 | 
            +
             | 
| 83 | 
            +
                expected = " xxxxxxxx
         | 
| 84 | 
            +
                             xxxx..xx
         | 
| 85 | 
            +
                             xx00xxxx
         | 
| 86 | 
            +
                             ..xxxxxx
         | 
| 87 | 
            +
                                      ".gsub(/ /, '')
         | 
| 88 | 
            +
             | 
| 89 | 
            +
                assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
         | 
| 90 | 
            +
              end
         | 
| 91 | 
            +
             | 
| 92 | 
            +
              def test_composite_overlay
         | 
| 93 | 
            +
                canvas1, canvas2 = util_composite_canvases
         | 
| 94 | 
            +
             | 
| 95 | 
            +
                canvas1.composite canvas2, 1, 1, :overlay
         | 
| 96 | 
            +
             | 
| 97 | 
            +
                expected = " xxxxxxxx
         | 
| 98 | 
            +
                             xxxx..xx
         | 
| 99 | 
            +
                             xx..xxxx
         | 
| 100 | 
            +
                             ..xxxxxx
         | 
| 101 | 
            +
                                      ".gsub(/ /, '')
         | 
| 102 | 
            +
             | 
| 103 | 
            +
                assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
         | 
| 104 | 
            +
              end
         | 
| 105 | 
            +
             | 
| 106 | 
            +
              def test_composite_blend
         | 
| 107 | 
            +
                canvas1, canvas2 = util_composite_canvases
         | 
| 108 | 
            +
             | 
| 109 | 
            +
                canvas1.composite canvas2, 1, 1, :blend
         | 
| 110 | 
            +
             | 
| 111 | 
            +
                expected = " xxxxxxxx
         | 
| 112 | 
            +
                             xxxx..xx
         | 
| 113 | 
            +
                             xx,,xxxx
         | 
| 114 | 
            +
                             ..xxxxxx
         | 
| 115 | 
            +
                                      ".gsub(/ /, '')
         | 
| 116 | 
            +
             | 
| 117 | 
            +
                assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
         | 
| 118 | 
            +
              end
         | 
| 119 | 
            +
             | 
| 120 | 
            +
              def test_composite_bad_style
         | 
| 121 | 
            +
                canvas1, canvas2 = util_composite_canvases
         | 
| 122 | 
            +
             | 
| 123 | 
            +
                assert_raises RuntimeError do
         | 
| 124 | 
            +
                  canvas1.composite canvas2, 1, 1, :bad
         | 
| 125 | 
            +
                end
         | 
| 126 | 
            +
              end
         | 
| 127 | 
            +
             | 
| 128 | 
            +
              def test_extract
         | 
| 129 | 
            +
                canvas1, _ = util_composite_canvases
         | 
| 130 | 
            +
             | 
| 131 | 
            +
                expected = " xxxxxxxx
         | 
| 132 | 
            +
                             xxxx..xx
         | 
| 133 | 
            +
                             xx00xxxx
         | 
| 134 | 
            +
                             ..xxxxxx
         | 
| 135 | 
            +
                                      ".gsub(/ /, '')
         | 
| 136 | 
            +
             | 
| 137 | 
            +
                assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
         | 
| 138 | 
            +
             | 
| 139 | 
            +
                canvas2 = canvas1.extract(1, 1, 2, 2)
         | 
| 140 | 
            +
             | 
| 141 | 
            +
                expected = " xx..
         | 
| 142 | 
            +
                             00xx
         | 
| 143 | 
            +
                                  ".gsub(/ /, '')
         | 
| 144 | 
            +
             | 
| 145 | 
            +
                assert_equal expected, canvas2.to_s.gsub(/ /, 'x')
         | 
| 146 | 
            +
              end
         | 
| 147 | 
            +
             | 
| 67 148 | 
             
              def test_index
         | 
| 68 149 | 
             
                assert_equal PNG::Color::White, @canvas[1, 2]
         | 
| 69 150 | 
             
                assert_same @canvas[1, 2], @canvas.data[1][2]
         | 
| @@ -162,7 +243,7 @@ class TestCanvas < Test::Unit::TestCase | |
| 162 243 | 
             
              end
         | 
| 163 244 |  | 
| 164 245 | 
             
              def test_point
         | 
| 165 | 
            -
                assert_equal PNG::Color.new( | 
| 246 | 
            +
                assert_equal PNG::Color.new(0xff, 0x7f, 0xff, 0xff),
         | 
| 166 247 | 
             
                             @canvas.point(0, 0, PNG::Color::Magenta)
         | 
| 167 248 | 
             
                # flunk "this doesn't test ANYTHING"
         | 
| 168 249 | 
             
              end
         | 
| @@ -171,15 +252,15 @@ class TestCanvas < Test::Unit::TestCase | |
| 171 252 | 
             
                @canvas.line 0, 9, 4, 0, PNG::Color::Black
         | 
| 172 253 |  | 
| 173 254 | 
             
                expected = <<-EOF
         | 
| 174 | 
            -
            ..00000000
         | 
| 175 255 | 
             
            ,,00000000
         | 
| 176 | 
            -
             | 
| 256 | 
            +
            ,,00000000
         | 
| 257 | 
            +
            ,,,,000000
         | 
| 177 258 | 
             
            00..000000
         | 
| 178 | 
            -
            00 | 
| 259 | 
            +
            00,,,,0000
         | 
| 179 260 | 
             
            0000..0000
         | 
| 180 | 
            -
            0000 | 
| 261 | 
            +
            0000,,,,00
         | 
| 181 262 | 
             
            000000..00
         | 
| 182 | 
            -
            000000 | 
| 263 | 
            +
            000000,,,,
         | 
| 183 264 | 
             
            00000000..
         | 
| 184 265 | 
             
                EOF
         | 
| 185 266 |  | 
| @@ -190,25 +271,21 @@ class TestCanvas < Test::Unit::TestCase | |
| 190 271 | 
             
                @canvas.line 0, 0, 4, 9, PNG::Color::Black
         | 
| 191 272 |  | 
| 192 273 | 
             
                expected = <<-EOF
         | 
| 193 | 
            -
            00000000..
         | 
| 194 274 | 
             
            00000000,,
         | 
| 195 | 
            -
             | 
| 275 | 
            +
            00000000,,
         | 
| 276 | 
            +
            000000,,,,
         | 
| 196 277 | 
             
            000000..00
         | 
| 197 | 
            -
            0000 | 
| 278 | 
            +
            0000,,,,00
         | 
| 198 279 | 
             
            0000..0000
         | 
| 199 | 
            -
            00 | 
| 280 | 
            +
            00,,,,0000
         | 
| 200 281 | 
             
            00..000000
         | 
| 201 | 
            -
             | 
| 282 | 
            +
            ,,,,000000
         | 
| 202 283 | 
             
            ..00000000
         | 
| 203 284 | 
             
                EOF
         | 
| 204 285 |  | 
| 205 286 | 
             
                assert_equal expected, @canvas.to_s
         | 
| 206 287 | 
             
              end
         | 
| 207 288 |  | 
| 208 | 
            -
              def util_ascii_art(width, height)
         | 
| 209 | 
            -
                (("0" * width * 2) + "\n") * height
         | 
| 210 | 
            -
              end
         | 
| 211 | 
            -
             | 
| 212 289 | 
             
              def test_to_s_normal
         | 
| 213 290 | 
             
                @canvas = PNG::Canvas.new 5, 10, PNG::Color::White
         | 
| 214 291 | 
             
                expected = util_ascii_art(5, 10)
         | 
| @@ -233,31 +310,39 @@ class TestCanvas < Test::Unit::TestCase | |
| 233 310 | 
             
                assert_equal expected, @canvas.to_s
         | 
| 234 311 | 
             
              end
         | 
| 235 312 |  | 
| 236 | 
            -
             | 
| 237 | 
            -
             | 
| 313 | 
            +
              def util_composite_canvases
         | 
| 314 | 
            +
                canvas1 = PNG::Canvas.new 4, 4
         | 
| 315 | 
            +
                canvas1[0, 0] = PNG::Color::Black
         | 
| 316 | 
            +
                canvas1[1, 1] = PNG::Color::White
         | 
| 317 | 
            +
                canvas1[2, 2] = PNG::Color::Black
         | 
| 238 318 |  | 
| 239 | 
            -
             | 
| 240 | 
            -
             | 
| 241 | 
            -
             | 
| 319 | 
            +
                expected = " xxxxxxxx
         | 
| 320 | 
            +
                             xxxx..xx
         | 
| 321 | 
            +
                             xx00xxxx
         | 
| 322 | 
            +
                             ..xxxxxx
         | 
| 323 | 
            +
                                      ".gsub(/ /, '')
         | 
| 242 324 |  | 
| 243 | 
            -
             | 
| 244 | 
            -
            #     canvas = PNG::Canvas.new 10, 10, PNG::Color::White
         | 
| 325 | 
            +
                assert_equal expected, canvas1.to_s.gsub(/ /, 'x')
         | 
| 245 326 |  | 
| 246 | 
            -
            #     data = "x\332c\370O$`\030UH_\205\000#\373\216\200"
         | 
| 247 327 |  | 
| 248 | 
            -
             | 
| 328 | 
            +
                canvas2 = PNG::Canvas.new 2, 2
         | 
| 329 | 
            +
                canvas2[0, 0] = PNG::Color::Black
         | 
| 249 330 |  | 
| 250 | 
            -
             | 
| 251 | 
            -
             | 
| 331 | 
            +
                expected = " xxxx 
         | 
| 332 | 
            +
                             ..xx
         | 
| 333 | 
            +
                                  ".gsub(/ /, '')
         | 
| 252 334 |  | 
| 253 | 
            -
             | 
| 254 | 
            -
             | 
| 255 | 
            -
             | 
| 256 | 
            -
             | 
| 257 | 
            -
             | 
| 335 | 
            +
                assert_equal expected, canvas2.to_s.gsub(/ /, 'x')
         | 
| 336 | 
            +
             | 
| 337 | 
            +
                return canvas1, canvas2
         | 
| 338 | 
            +
              end
         | 
| 339 | 
            +
             | 
| 340 | 
            +
              def util_ascii_art(width, height)
         | 
| 341 | 
            +
                (("0" * width * 2) + "\n") * height
         | 
| 342 | 
            +
              end
         | 
| 258 343 | 
             
            end
         | 
| 259 344 |  | 
| 260 | 
            -
            class TestPng::TestColor <  | 
| 345 | 
            +
            class TestPng::TestColor < MiniTest::Unit::TestCase
         | 
| 261 346 | 
             
              def setup
         | 
| 262 347 | 
             
                @color = PNG::Color.new 0x01, 0x02, 0x03, 0x04
         | 
| 263 348 | 
             
              end
         | 
| @@ -295,10 +380,16 @@ class TestPng::TestColor < Test::Unit::TestCase | |
| 295 380 | 
             
              end
         | 
| 296 381 |  | 
| 297 382 | 
             
              def test_blend
         | 
| 298 | 
            -
             | 
| 299 | 
            -
             | 
| 383 | 
            +
            #     c1 = @color
         | 
| 384 | 
            +
            #     c2 = PNG::Color.new 0xFF, 0xFE, 0xFD, 0xFC
         | 
| 385 | 
            +
             | 
| 386 | 
            +
            #     assert_equal PNG::Color.new(0xFB, 0xFA, 0xF9, 0xF8), c1.blend(c2)
         | 
| 387 | 
            +
             | 
| 388 | 
            +
                c1 = PNG::Color::White
         | 
| 389 | 
            +
                c2 = PNG::Color::Black
         | 
| 300 390 |  | 
| 301 | 
            -
                assert_equal PNG::Color | 
| 391 | 
            +
                assert_equal PNG::Color::Gray, c2.blend(c1)
         | 
| 392 | 
            +
                assert_equal PNG::Color::Gray, c1.blend(c2)
         | 
| 302 393 | 
             
              end
         | 
| 303 394 |  | 
| 304 395 | 
             
              def test_intensity
         | 
| @@ -313,6 +404,21 @@ class TestPng::TestColor < Test::Unit::TestCase | |
| 313 404 | 
             
                assert_equal "#<PNG::Color Red>", PNG::Color::Red.inspect
         | 
| 314 405 | 
             
              end
         | 
| 315 406 |  | 
| 407 | 
            +
              def test_pipe
         | 
| 408 | 
            +
                b = PNG::Color::Black
         | 
| 409 | 
            +
                w = PNG::Color::White
         | 
| 410 | 
            +
                t = PNG::Color::Background
         | 
| 411 | 
            +
             | 
| 412 | 
            +
                # first non-transparent
         | 
| 413 | 
            +
                assert_equal b, b | t
         | 
| 414 | 
            +
                assert_equal b, t | b
         | 
| 415 | 
            +
             | 
| 416 | 
            +
                assert_equal b, b | w
         | 
| 417 | 
            +
                assert_equal w, w | b
         | 
| 418 | 
            +
             | 
| 419 | 
            +
                assert_equal t, t | t
         | 
| 420 | 
            +
              end
         | 
| 421 | 
            +
             | 
| 316 422 | 
             
              def test_to_ascii
         | 
| 317 423 | 
             
                assert_equal '00', PNG::Color::White.to_ascii, "white"
         | 
| 318 424 | 
             
                assert_equal '++', PNG::Color::Yellow.to_ascii, "yellow"
         | 
| @@ -325,7 +431,7 @@ class TestPng::TestColor < Test::Unit::TestCase | |
| 325 431 | 
             
                assert_equal '00', PNG::Color.new(255,255,255,255).to_ascii
         | 
| 326 432 | 
             
                assert_equal '00', PNG::Color.new(255,255,255,192).to_ascii
         | 
| 327 433 | 
             
                assert_equal '++', PNG::Color.new(255,255,255,191).to_ascii
         | 
| 328 | 
            -
                assert_equal ' | 
| 434 | 
            +
                assert_equal ',,', PNG::Color.new(255,255,255,127).to_ascii
         | 
| 329 435 | 
             
                assert_equal ',,', PNG::Color.new(255,255,255,126).to_ascii
         | 
| 330 436 | 
             
                assert_equal ',,', PNG::Color.new(255,255,255, 64).to_ascii
         | 
| 331 437 | 
             
                assert_equal '..', PNG::Color.new(255,255,255, 63).to_ascii
         | 
| @@ -342,18 +448,22 @@ class TestPng::TestColor < Test::Unit::TestCase | |
| 342 448 | 
             
                assert_equal '#<PNG::Color:0xXXXXXX>', obj.to_s.sub(/0x[0-9a-f]+/, '0xXXXXXX')
         | 
| 343 449 | 
             
              end
         | 
| 344 450 |  | 
| 451 | 
            +
              def test_equals2
         | 
| 452 | 
            +
                assert_equal PNG::Color.new(255,255,255,  0), PNG::Color.new(255,255,255,  0)
         | 
| 453 | 
            +
              end
         | 
| 454 | 
            +
             | 
| 455 | 
            +
              def test_hash
         | 
| 456 | 
            +
                a = PNG::Color.new(255,255,255,  0)
         | 
| 457 | 
            +
                b = PNG::Color.new(255,255,255,  0)
         | 
| 458 | 
            +
                assert_equal a.hash, b.hash
         | 
| 459 | 
            +
              end
         | 
| 460 | 
            +
             | 
| 345 461 | 
             
            #   def test_values
         | 
| 346 462 | 
             
            #     raise NotImplementedError, 'Need to write test_values'
         | 
| 347 463 | 
             
            #   end
         | 
| 348 464 | 
             
            end
         | 
| 349 465 |  | 
| 350 | 
            -
             | 
| 351 | 
            -
             | 
| 352 | 
            -
            class TestPng::TestPie < Test::Unit::TestCase
         | 
| 353 | 
            -
              def setup
         | 
| 354 | 
            -
             | 
| 355 | 
            -
              end
         | 
| 356 | 
            -
             | 
| 466 | 
            +
            class TestPng::TestPie < MiniTest::Unit::TestCase
         | 
| 357 467 | 
             
              def test_pie_chart_odd
         | 
| 358 468 | 
             
                expected =
         | 
| 359 469 | 
             
                  ["          ..          ",
         |