lib/prawn/images/png.rb in prawn-0.1.2 vs lib/prawn/images/png.rb in prawn-0.2.0
- old
+ new
@@ -28,10 +28,11 @@
data.read(8) # Skip the default header
@palette = ""
@img_data = ""
+ @transparency = {}
loop do
chunk_size = data.read(4).unpack("N")[0]
section = data.read(4)
case section
@@ -59,20 +60,21 @@
when 3
# Indexed colour, RGB. Each byte in this chunk is an alpha for
# the palette index in the PLTE ("palette") chunk up until the
# last non-opaque entry. Set up an array, stretching over all
# palette entries which will be 0 (opaque) or 1 (transparent).
- @transparency[:type] = 'indexed'
- @transparency[:data] = data.read(chunk_size).unpack("C*")
+ @transparency[:indexed] = data.read(chunk_size).unpack("C*")
+ short = 255 - @transparency[:indexed].size
+ @transparency[:indexed] += ([255] * short) if short > 0
when 0
# Greyscale. Corresponding to entries in the PLTE chunk.
# Grey is two bytes, range 0 .. (2 ^ bit-depth) - 1
- @transparency[:grayscale] = data.read(2).unpack("n")
- @transparency[:type] = 'indexed'
+ grayval = data.read(chunk_size).unpack("n").first
+ @transparency[:grayscale] = grayval
when 2
# True colour with proper alpha channel.
- @transparency[:rgb] = data.read(6).unpack("nnn")
+ @transparency[:rgb] = data.read(chunk_size).unpack("nnn")
end
when 'IEND'
# we've got everything we need, exit the loop
break
else
@@ -86,43 +88,33 @@
# if our img_data contains alpha channel data, split it out
unfilter_image_data if alpha_channel?
end
def pixel_bytes
- case @color_type
- when 0, 4 then 1
+ @pixel_bytes ||= case @color_type
+ when 0, 3, 4 then 1
when 1, 2, 6 then 3
end
end
private
def alpha_channel?
@color_type == 4 || @color_type == 6
end
- def paeth(a, b, c) # left, above, upper left
- p = a + b - c
- pa = (p - a).abs
- pb = (p - b).abs
- pc = (p - c).abs
-
- return a if pa <= pb && pa <= pc
- return b if pb <= pc
- c
- end
-
def unfilter_image_data
data = Zlib::Inflate.inflate(@img_data).unpack 'C*'
@img_data = ""
@alpha_channel = ""
# each pixel has the color bytes, plus a byte of alpha channel
pixel_length = pixel_bytes + 1
scanline_length = pixel_length * @width + 1 # for filter
row = 0
- pixels = []
+ pixels = []
+ paeth, pa, pb, pc = nil
until data.empty? do
row_data = data.slice! 0, scanline_length
filter = row_data.shift
case filter
when 0 # None
@@ -150,29 +142,42 @@
left = upper = upper_left = nil
row_data.each_with_index do |byte, index|
col = index / pixel_length
left = index < pixel_length ? 0 : row_data[index - pixel_length]
- if row == 0 then
+ if row.zero?
upper = upper_left = 0
else
upper = pixels[row-1][col][index % pixel_length]
- upper_left = col == 0 ? 0 :
+ upper_left = col.zero? ? 0 :
pixels[row-1][col-1][index % pixel_length]
end
- paeth = paeth left, upper, upper_left
+ p = left + upper - upper_left
+ pa = (p - left).abs
+ pb = (p - upper).abs
+ pc = (p - upper_left).abs
+
+ paeth = if pa <= pb && pa <= pc
+ left
+ elsif pb <= pc
+ upper
+ else
+ upper_left
+ end
+
row_data[index] = (byte + paeth) % 256
#p [byte, paeth, row_data[index]]
end
else
raise ArgumentError, "Invalid filter algorithm #{filter}"
end
- pixels << []
+ s = []
row_data.each_slice pixel_length do |slice|
- pixels.last << slice
+ s << slice
end
+ pixels << s
row += 1
end
# convert the pixel data to seperate strings for colours and alpha
pixels.each do |row|