class Branding::PNG
This is a simple PNG
decoder, inspired and adapted from ChunkyPNG
Constants
- SIGNATURE
Attributes
color[R]
compression[R]
depth[R]
filtering[R]
height[R]
interlace[R]
width[R]
Public Class Methods
from_file(path)
click to toggle source
# File lib/branding/png.rb, line 155 def self.from_file(path) new(File.open(path, 'rb')) end
new(io)
click to toggle source
# File lib/branding/png.rb, line 159 def initialize(io) signature = io.read(SIGNATURE.length) raise 'Signature mismatch' unless signature == SIGNATURE @data = '' until io.eof? type, content = read_chunk(io) case type when 'IHDR' fields = content.unpack('NNC5') @width, @height, @depth, @color, @compression, @filtering, @interlace = fields when 'IDAT' @data << content end end unless depth == 8 raise NotImplementedError, 'only supporting 8bit color depth' end unless color == 2 || color == 6 raise NotImplementedError, 'only supporting true color, with or without alpha' end unless filtering == 0 raise NotImplementedError, 'does not supporting filtering' end unless compression == 0 raise NotImplementedError, 'only supporting deflate compression' end end
Public Instance Methods
color_channels()
click to toggle source
the number of color channels. Not the PNG
“color mode”
# File lib/branding/png.rb, line 205 def color_channels color == 2 ? 3 : 4 end
pixels()
click to toggle source
# File lib/branding/png.rb, line 195 def pixels if block_given? imagedata.each_pixel else imagedata.enum_for(:each_pixel).to_a end end
Private Instance Methods
imagedata()
click to toggle source
# File lib/branding/png.rb, line 211 def imagedata Imagedata.new(data: @data, scanline_width: width, color_channels: color_channels) end
read_bytes(io, length)
click to toggle source
# File lib/branding/png.rb, line 225 def read_bytes(io, length) data = io.read(length) if data.nil? || data.bytesize != length raise "Could not read #{length} bytes from io" end data end
read_chunk(io)
click to toggle source
# File lib/branding/png.rb, line 215 def read_chunk(io) length, type = read_bytes(io, 8).unpack('Na4') content = read_bytes(io, length) crc = read_bytes(io, 4).unpack('N').first verify_crc(type, content, crc) [type, content] end
verify_crc(type, content, found_crc)
click to toggle source
# File lib/branding/png.rb, line 235 def verify_crc(type, content, found_crc) expected_crc = Zlib.crc32(content, Zlib.crc32(type)) raise 'Chuck CRC mismatch!' if found_crc != expected_crc end