Class: Prawn::Images::PNG
Overview
A convenience class that wraps the logic for extracting the parts of a PNG image that we need to embed them in a PDF
Extension API collapse
-
#alpha_channel ⇒ Object
readonly
Returns the value of attribute alpha_channel.
-
#bits ⇒ Object
readonly
Returns the value of attribute bits.
-
#color_type ⇒ Object
readonly
Returns the value of attribute color_type.
-
#compression_method ⇒ Object
readonly
Returns the value of attribute compression_method.
-
#filter_method ⇒ Object
readonly
Returns the value of attribute filter_method.
-
#height ⇒ Object
readonly
Returns the value of attribute height.
-
#img_data ⇒ Object
readonly
Returns the value of attribute img_data.
-
#interlace_method ⇒ Object
readonly
Returns the value of attribute interlace_method.
-
#palette ⇒ Object
readonly
Returns the value of attribute palette.
-
#scaled_height ⇒ Object
Returns the value of attribute scaled_height.
-
#scaled_width ⇒ Object
Returns the value of attribute scaled_width.
-
#transparency ⇒ Object
readonly
Returns the value of attribute transparency.
-
#width ⇒ Object
readonly
Returns the value of attribute width.
Extension API collapse
- .can_render?(image_blob) ⇒ Boolean
- #alpha_channel? ⇒ Boolean
-
#build_pdf_object(document) ⇒ Object
Build a PDF object representing this image in
document
, and return a Reference to it. -
#colors ⇒ Object
number of color components to each pixel.
-
#initialize(data) ⇒ PNG
constructor
Process a new PNG image.
-
#min_pdf_version ⇒ Object
Returns the minimum PDF version required to support this image.
-
#split_alpha_channel! ⇒ Object
split the alpha channel data from the raw image data in images where it's required.
Methods inherited from Image
Constructor Details
#initialize(data) ⇒ PNG
Process a new PNG image
data
-
A binary string of PNG data
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 |
# File 'lib/prawn/images/png.rb', line 36 def initialize(data) super() data = StringIO.new(data.dup) data.read(8) # Skip the default header @palette = +'' @img_data = +'' @transparency = {} loop do chunk_size = data.read(4).unpack1('N') section = data.read(4) case section when 'IHDR' # we can grab other interesting values from here (like width, # height, etc) values = data.read(chunk_size).unpack('NNCCCCC') @width = values[0] @height = values[1] @bits = values[2] @color_type = values[3] @compression_method = values[4] @filter_method = values[5] @interlace_method = values[6] when 'PLTE' @palette << data.read(chunk_size) when 'IDAT' @img_data << data.read(chunk_size) when 'tRNS' # This chunk can only occur once and it must occur after the # PLTE chunk and before the IDAT chunk @transparency = {} case @color_type when 3 @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 grayval = data.read(chunk_size).unpack1('n') @transparency[:grayscale] = grayval when 2 # True colour with proper alpha channel. @transparency[:rgb] = data.read(chunk_size).unpack('nnn') end when 'IEND' # we've got everything we need, exit the loop break else # unknown (or un-important) section, skip over it data.seek(data.pos + chunk_size) end data.read(4) # Skip the CRC end @img_data = Zlib::Inflate.inflate(@img_data) end |
Instance Attribute Details
#alpha_channel ⇒ Object (readonly)
Returns the value of attribute alpha_channel.
25 26 27 |
# File 'lib/prawn/images/png.rb', line 25 def alpha_channel @alpha_channel end |
#bits ⇒ Object (readonly)
Returns the value of attribute bits.
23 24 25 |
# File 'lib/prawn/images/png.rb', line 23 def bits @bits end |
#color_type ⇒ Object (readonly)
Returns the value of attribute color_type.
24 25 26 |
# File 'lib/prawn/images/png.rb', line 24 def color_type @color_type end |
#compression_method ⇒ Object (readonly)
Returns the value of attribute compression_method.
24 25 26 |
# File 'lib/prawn/images/png.rb', line 24 def compression_method @compression_method end |
#filter_method ⇒ Object (readonly)
Returns the value of attribute filter_method.
24 25 26 |
# File 'lib/prawn/images/png.rb', line 24 def filter_method @filter_method end |
#height ⇒ Object (readonly)
Returns the value of attribute height.
23 24 25 |
# File 'lib/prawn/images/png.rb', line 23 def height @height end |
#img_data ⇒ Object (readonly)
Returns the value of attribute img_data.
22 23 24 |
# File 'lib/prawn/images/png.rb', line 22 def img_data @img_data end |
#interlace_method ⇒ Object (readonly)
Returns the value of attribute interlace_method.
25 26 27 |
# File 'lib/prawn/images/png.rb', line 25 def interlace_method @interlace_method end |
#palette ⇒ Object (readonly)
Returns the value of attribute palette.
22 23 24 |
# File 'lib/prawn/images/png.rb', line 22 def palette @palette end |
#scaled_height ⇒ Object
Returns the value of attribute scaled_height.
26 27 28 |
# File 'lib/prawn/images/png.rb', line 26 def scaled_height @scaled_height end |
#scaled_width ⇒ Object
Returns the value of attribute scaled_width.
26 27 28 |
# File 'lib/prawn/images/png.rb', line 26 def scaled_width @scaled_width end |
#transparency ⇒ Object (readonly)
Returns the value of attribute transparency.
22 23 24 |
# File 'lib/prawn/images/png.rb', line 22 def transparency @transparency end |
#width ⇒ Object (readonly)
Returns the value of attribute width.
23 24 25 |
# File 'lib/prawn/images/png.rb', line 23 def width @width end |
Class Method Details
.can_render?(image_blob) ⇒ Boolean
28 29 30 |
# File 'lib/prawn/images/png.rb', line 28 def self.can_render?(image_blob) image_blob[0, 8].unpack('C*') == [137, 80, 78, 71, 13, 10, 26, 10] end |
Instance Method Details
#alpha_channel? ⇒ Boolean
120 121 122 123 124 125 |
# File 'lib/prawn/images/png.rb', line 120 def alpha_channel? return true if color_type == 4 || color_type == 6 return @transparency.any? if color_type == 3 false end |
#build_pdf_object(document) ⇒ Object
Build a PDF object representing this image in document
, and return a Reference to it.
130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 |
# File 'lib/prawn/images/png.rb', line 130 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 ) # append the actual image data to the object as a stream obj << img_data obj.stream.filters << { FlateDecode: { Predictor: 15, Colors: colors, BitsPerComponent: bits, Columns: width } } # 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!({}) 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.map { |x| [x, x] }.flatten 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: bits, ColorSpace: :DeviceGray, Decode: [0, 1] ) smask_obj.stream << alpha_channel smask_obj.stream.filters << { FlateDecode: { Predictor: 15, Colors: 1, BitsPerComponent: bits, Columns: width } } obj.data[:SMask] = smask_obj end obj end |
#colors ⇒ Object
number of color components to each pixel
98 99 100 101 102 103 104 105 |
# File 'lib/prawn/images/png.rb', line 98 def colors case color_type when 0, 3, 4 1 when 2, 6 3 end end |
#min_pdf_version ⇒ Object
Returns the minimum PDF version required to support this image.
250 251 252 253 254 255 256 257 258 259 260 |
# File 'lib/prawn/images/png.rb', line 250 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 |
#split_alpha_channel! ⇒ Object
split the alpha channel data from the raw image data in images where it's required.
110 111 112 113 114 115 116 117 118 |
# File 'lib/prawn/images/png.rb', line 110 def split_alpha_channel! if alpha_channel? if color_type == 3 generate_alpha_channel else split_image_data end end end |