Class: Pura::Png::Decoder
- Inherits:
-
Object
- Object
- Pura::Png::Decoder
- Defined in:
- lib/pura/png/decoder.rb
Constant Summary collapse
- PNG_SIGNATURE =
[137, 80, 78, 71, 13, 10, 26, 10].pack("C8")
- GRAYSCALE =
Color types
0- RGB =
2- INDEXED =
3- GRAYSCALE_ALPHA =
4- RGBA =
6- DEFAULT_MAX_INPUT_BYTES =
64 * 1024 * 1024
- DEFAULT_MAX_PIXELS =
40_000_000- DEFAULT_MAX_DECODED_BYTES =
256 * 1024 * 1024
- BIT_DEPTHS =
{ 0 => [1, 2, 4, 8, 16], 2 => [8, 16], 3 => [1, 2, 4, 8], 4 => [8, 16], 6 => [8, 16] }.freeze
Class Method Summary collapse
Instance Method Summary collapse
- #decode ⇒ Object
-
#initialize(data, max_pixels: DEFAULT_MAX_PIXELS, max_decoded_bytes: DEFAULT_MAX_DECODED_BYTES) ⇒ Decoder
constructor
A new instance of Decoder.
Constructor Details
#initialize(data, max_pixels: DEFAULT_MAX_PIXELS, max_decoded_bytes: DEFAULT_MAX_DECODED_BYTES) ⇒ Decoder
Returns a new instance of Decoder.
41 42 43 44 45 46 47 48 49 50 |
# File 'lib/pura/png/decoder.rb', line 41 def initialize(data, max_pixels: DEFAULT_MAX_PIXELS, max_decoded_bytes: DEFAULT_MAX_DECODED_BYTES) unless [max_pixels, max_decoded_bytes].all? { |value| value.is_a?(Integer) && value.positive? } raise ArgumentError, "decode limits must be positive integers" end @max_pixels = max_pixels @max_decoded_bytes = max_decoded_bytes @data = data @pos = 0 end |
Class Method Details
.decode(input, max_input_bytes: DEFAULT_MAX_INPUT_BYTES, **options) ⇒ Object
26 27 28 29 30 31 32 33 34 35 36 37 38 39 |
# File 'lib/pura/png/decoder.rb', line 26 def self.decode(input, max_input_bytes: DEFAULT_MAX_INPUT_BYTES, **) unless max_input_bytes.is_a?(Integer) && max_input_bytes.positive? raise ArgumentError, "max_input_bytes must be a positive integer" end data = if input.is_a?(String) && !input.include?("\x00") && input.bytesize < 4096 && File.exist?(input) File.binread(input, max_input_bytes + 1) else input.b end raise LimitExceeded, "PNG input limit exceeded" if data.bytesize > max_input_bytes new(data, **).decode end |
Instance Method Details
#decode ⇒ Object
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 95 |
# File 'lib/pura/png/decoder.rb', line 52 def decode read_signature ihdr = nil palette = nil transparency = nil idat_chunks = [] loop do length, type = read_chunk_header chunk_data = read_bytes(length) crc = read_uint32 raise DecodeError, "Invalid PNG CRC for #{type}" unless crc == Zlib.crc32(type + chunk_data) raise DecodeError, "IHDR must be the first chunk" if !ihdr && type != "IHDR" case type when "IHDR" raise DecodeError, "Duplicate IHDR chunk" if ihdr ihdr = parse_ihdr(chunk_data) when "PLTE" palette = parse_plte(chunk_data) when "tRNS" transparency = chunk_data when "IDAT" idat_chunks << chunk_data when "IEND" raise DecodeError, "IEND must be empty" unless chunk_data.empty? break else raise DecodeError, "Unknown critical PNG chunk: #{type}" if type.getbyte(0).allbits?(0x20) == false end end raise DecodeError, "Missing IHDR chunk" unless ihdr raise DecodeError, "Missing IDAT chunk" if idat_chunks.empty? compressed = idat_chunks.join raw = inflate_scanlines(compressed, ihdr) pixels = reconstruct(raw, ihdr, palette, transparency) Image.new(ihdr[:width], ihdr[:height], pixels) end |