Skip to content

Commit

Permalink
Added support for transparency in indexed PNG images
Browse files Browse the repository at this point in the history
  • Loading branch information
pointlessone committed Nov 22, 2015
1 parent 62da6cd commit 823df34
Show file tree
Hide file tree
Showing 6 changed files with 66 additions and 9 deletions.
Binary file added data/images/indexed_transparency.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Binary file added data/images/indexed_transparency_alpha.dat
Binary file not shown.
Binary file added data/images/indexed_transparency_color.dat
Binary file not shown.
Binary file removed data/images/pal_bk.png
Binary file not shown.
45 changes: 40 additions & 5 deletions lib/prawn/images/png.rb
Original file line number Diff line number Diff line change
Expand Up @@ -68,9 +68,7 @@ def initialize(data)
@transparency = {}
case @color_type
when 3
fail Errors::UnsupportedImageType,
"Pallete-based transparency in PNG is not currently supported.\n" \
"See https://github.com/prawnpdf/prawn/issues/783"
@transparency[:palette] = data.read(chunk_size).unpack('C*')
when 0
# Greyscale. Corresponding to entries in the PLTE chunk.
# Grey is two bytes, range 0 .. (2 ^ bit-depth) - 1
Expand Down Expand Up @@ -109,11 +107,17 @@ def colors
# where it's required.
#
def split_alpha_channel!
split_image_data if alpha_channel?
if alpha_channel?
if color_type == 3
generate_alpha_channel
else
split_image_data
end
end
end

def alpha_channel?
@color_type == 4 || @color_type == 6
[3, 4, 6].include? color_type
end

# Build a PDF object representing this image in +document+, and return
Expand Down Expand Up @@ -285,6 +289,37 @@ def split_image_data

@img_data = color_data
end

def generate_alpha_channel
alpha_palette = Hash.new(0xff)
0.upto(palette.bytesize / 3) do |n|
alpha_palette[n] = @transparency[:palette][n] || 0xff
end

scanline_length = width + 1
scanlines = @img_data.bytesize / scanline_length
pixels = width * height

data = StringIO.new(@img_data)
data.binmode

@alpha_channel = [0x00].pack('C') * (pixels + scanlines)
alpha = StringIO.new(@alpha_channel)
alpha.binmode

scanlines.times do |line|
data.seek(line * scanline_length)

filter = data.getbyte

alpha.putc filter

width.times do
color = data.read(1).unpack('C').first
alpha.putc alpha_palette[color]
end
end
end
end
end
end
30 changes: 26 additions & 4 deletions spec/png_spec.rb
Original file line number Diff line number Diff line change
Expand Up @@ -95,10 +95,32 @@
end

describe "When reading an indexed color PNG file with transparency (color type 3)" do
it "raises a not supported error" do
bin = File.binread("#{Prawn::DATADIR}/images/pal_bk.png")
expect { Prawn::Images::PNG.new(bin) }.to(
raise_error(Prawn::Errors::UnsupportedImageType))
let(:filename) { "#{Prawn::DATADIR}/images/indexed_transparency.png" }
let(:color_filename) { "#{Prawn::DATADIR}/images/indexed_transparency_color.dat" }
let(:transparency_filename) { "#{Prawn::DATADIR}/images/indexed_transparency_alpha.dat" }
let(:img_data) { File.binread(filename) }
let(:png) { Prawn::Images::PNG.new(img_data) }

it "reads the attributes from the header chunk correctly" do
expect(png.width).to eq(200)
expect(png.height).to eq(200)
expect(png.bits).to eq(8)
expect(png.color_type).to eq(3)
expect(png.compression_method).to eq(0)
expect(png.filter_method).to eq(0)
expect(png.interlace_method).to eq(0)
end

it "reads the image data correctly" do
data = Zlib::Inflate.inflate(File.binread(color_filename))
expect(png.img_data).to eq(data)
end

it "reads the image transparency correctly" do
png.split_alpha_channel!

data = Zlib::Inflate.inflate(File.binread(transparency_filename))
expect(png.alpha_channel).to eq(data)
end
end

Expand Down

0 comments on commit 823df34

Please sign in to comment.