lib/prawn/images/png.rb in prawn-0.11.1.pre vs lib/prawn/images/png.rb in prawn-0.11.1
- old
+ new
@@ -127,9 +127,139 @@
#
def alpha_channel_bits
8
end
+ # Build a PDF object representing this image in +document+, and return
+ # a Reference to it.
+ #
+ def build_pdf_object(document)
+ if compression_method != 0
+ raise Errors::UnsupportedImageType,
+ 'PNG uses an unsupported compression method'
+ end
+
+ if filter_method != 0
+ raise Errors::UnsupportedImageType,
+ 'PNG uses an unsupported filter method'
+ end
+
+ if interlace_method != 0
+ raise Errors::UnsupportedImageType,
+ 'PNG uses unsupported interlace method'
+ end
+
+ # some PNG types store the colour and alpha channel data together,
+ # which the PDF spec doesn't like, so split it out.
+ split_alpha_channel!
+
+ case colors
+ when 1
+ color = :DeviceGray
+ when 3
+ color = :DeviceRGB
+ else
+ raise Errors::UnsupportedImageType,
+ "PNG uses an unsupported number of colors (#{png.colors})"
+ end
+
+ # build the image dict
+ obj = document.ref!(
+ :Type => :XObject,
+ :Subtype => :Image,
+ :Height => height,
+ :Width => width,
+ :BitsPerComponent => bits,
+ :Length => img_data.size,
+ :Filter => :FlateDecode
+ )
+
+ unless alpha_channel
+ obj.data[:DecodeParms] = {:Predictor => 15,
+ :Colors => colors,
+ :BitsPerComponent => bits,
+ :Columns => width}
+ end
+
+ # append the actual image data to the object as a stream
+ obj << img_data
+
+ # sort out the colours of the image
+ if palette.empty?
+ obj.data[:ColorSpace] = color
+ else
+ # embed the colour palette in the PDF as a object stream
+ palette_obj = document.ref!(:Length => palette.size)
+ palette_obj << palette
+
+ # build the color space array for the image
+ obj.data[:ColorSpace] = [:Indexed,
+ :DeviceRGB,
+ (palette.size / 3) -1,
+ palette_obj]
+ end
+
+ # *************************************
+ # add transparency data if necessary
+ # *************************************
+
+ # For PNG color types 0, 2 and 3, the transparency data is stored in
+ # a dedicated PNG chunk, and is exposed via the transparency attribute
+ # of the PNG class.
+ if transparency[:grayscale]
+ # Use Color Key Masking (spec section 4.8.5)
+ # - An array with N elements, where N is two times the number of color
+ # components.
+ val = transparency[:grayscale]
+ obj.data[:Mask] = [val, val]
+ elsif transparency[:rgb]
+ # Use Color Key Masking (spec section 4.8.5)
+ # - An array with N elements, where N is two times the number of color
+ # components.
+ rgb = transparency[:rgb]
+ obj.data[:Mask] = rgb.collect { |x| [x,x] }.flatten
+ elsif transparency[:indexed]
+ # TODO: broken. I was attempting to us Color Key Masking, but I think
+ # we need to construct an SMask i think. Maybe do it inside
+ # the PNG class, and store it in alpha_channel
+ #obj.data[:Mask] = transparency[:indexed]
+ end
+
+ # For PNG color types 4 and 6, the transparency data is stored as a alpha
+ # channel mixed in with the main image data. The PNG class seperates
+ # it out for us and makes it available via the alpha_channel attribute
+ if alpha_channel?
+ smask_obj = document.ref!(
+ :Type => :XObject,
+ :Subtype => :Image,
+ :Height => height,
+ :Width => width,
+ :BitsPerComponent => alpha_channel_bits,
+ :Length => alpha_channel.size,
+ :Filter => :FlateDecode,
+ :ColorSpace => :DeviceGray,
+ :Decode => [0, 1]
+ )
+ smask_obj << alpha_channel
+ obj.data[:SMask] = smask_obj
+ end
+
+ obj
+ end
+
+ # Returns the minimum PDF version required to support this image.
+ def min_pdf_version
+ if bits > 8
+ # 16-bit color only supported in 1.5+ (ISO 32000-1:2008 8.9.5.1)
+ 1.5
+ elsif alpha_channel?
+ # Need transparency for SMask
+ 1.4
+ else
+ 1.0
+ end
+ end
+
private
def unfilter_image_data
data = Zlib::Inflate.inflate(@img_data).unpack 'C*'
@img_data = ""