def self.read_IDAT data, bit_depth, color_type, canvas
data = Zlib::Inflate.inflate(data).unpack 'C*'
pixel_size = color_type == RGBA ? 4 : 3
height = canvas.height
scanline_length = pixel_size * canvas.width + 1
row = canvas.height - 1
until data.empty? do
row_data = data.slice! 0, scanline_length
filter = row_data.shift
case filter
when NONE then
when SUB then
row_data.each_with_index do |byte, index|
left = index < pixel_size ? 0 : row_data[index - pixel_size]
row_data[index] = (byte + left) % 256
end
when UP then
row_data.each_with_index do |byte, index|
col = index / pixel_size
upper = row == 0 ? 0 : canvas[col, row + 1].values[index % pixel_size]
row_data[index] = (upper + byte) % 256
end
when AVG then
row_data.each_with_index do |byte, index|
col = index / pixel_size
upper = row == 0 ? 0 : canvas[col, row + 1].values[index % pixel_size]
left = index < pixel_size ? 0 : row_data[index - pixel_size]
row_data[index] = (byte + ((left + upper)/2).floor) % 256
end
when PAETH then
left = upper = upper_left = nil
row_data.each_with_index do |byte, index|
col = index / pixel_size
left = index < pixel_size ? 0 : row_data[index - pixel_size]
if row == height then
upper = upper_left = 0
else
upper = canvas[col, row + 1].values[index % pixel_size]
upper_left = col == 0 ? 0 :
canvas[col - 1, row + 1].values[index % pixel_size]
end
paeth = paeth left, upper, upper_left
row_data[index] = (byte + paeth) % 256
end
else
raise ArgumentError, "invalid filter algorithm #{filter}"
end
col = 0
row_data.each_slice pixel_size do |slice|
slice << 0xFF if pixel_size == 3
canvas[col, row] = PNG::Color.new(*slice)
col += 1
end
row -= 1
end
end