Module: Pdfrb::Filter::PNGPredictor
- Defined in:
- lib/pdfrb/filter/png_predictor.rb
Overview
PNG predictor (de)coding shared between FlateDecode and LZWDecode (s7.4.8.4 / RFC 2083 6.6). Extracted as a standalone module so both filters can use it without one calling the other's private methods.
Class Method Summary collapse
- .decode(bytes, predictor:, columns:, colors:, bits_per_component:) ⇒ Object
- .paeth(a, b, c) ⇒ Object
- .png_average(data, prev_row, bpp) ⇒ Object
- .png_paeth(data, prev_row, bpp) ⇒ Object
- .png_sub(data, bpp) ⇒ Object
- .png_up(data, prev_row) ⇒ Object
- .unfilter_row(filter_type, data, prev_row, bpp) ⇒ Object
Class Method Details
.decode(bytes, predictor:, columns:, colors:, bits_per_component:) ⇒ Object
12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 |
# File 'lib/pdfrb/filter/png_predictor.rb', line 12 def decode(bytes, predictor:, columns:, colors:, bits_per_component:) return bytes unless (10..15).cover?(predictor) row_len = columns * colors * (bits_per_component / 8) row_len += 1 # leading filter-type byte per row rows = bytes.each_byte.each_slice(row_len).to_a prev_row = nil bpp = (colors * (bits_per_component / 8)) || 1 bpp = 1 if bpp.zero? out = +"" rows.each do |row| filter_type = row[0] data = row[1..] unfiltered = unfilter_row(filter_type, data, prev_row, bpp) out << unfiltered.pack("C*") prev_row = unfiltered end out.force_encoding(Encoding::BINARY) end |
.paeth(a, b, c) ⇒ Object
82 83 84 85 86 87 88 89 90 91 |
# File 'lib/pdfrb/filter/png_predictor.rb', line 82 def paeth(a, b, c) 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 |
.png_average(data, prev_row, bpp) ⇒ Object
61 62 63 64 65 66 67 68 69 |
# File 'lib/pdfrb/filter/png_predictor.rb', line 61 def png_average(data, prev_row, bpp) bytes = data.dup (0...bytes.length).each do |i| left = bytes[i - bpp] || 0 up = prev_row ? (prev_row[i] || 0) : 0 bytes[i] = (bytes[i] + ((left + up) / 2)) & 0xFF end bytes end |
.png_paeth(data, prev_row, bpp) ⇒ Object
71 72 73 74 75 76 77 78 79 80 |
# File 'lib/pdfrb/filter/png_predictor.rb', line 71 def png_paeth(data, prev_row, bpp) bytes = data.dup (0...bytes.length).each do |i| left = bytes[i - bpp] || 0 up = prev_row ? (prev_row[i] || 0) : 0 up_left = prev_row ? (prev_row[i - bpp] || 0) : 0 bytes[i] = (bytes[i] + paeth(left, up, up_left)) & 0xFF end bytes end |
.png_sub(data, bpp) ⇒ Object
43 44 45 46 47 48 49 |
# File 'lib/pdfrb/filter/png_predictor.rb', line 43 def png_sub(data, bpp) bytes = data.dup bpp.upto(bytes.length - 1).each do |i| bytes[i] = (bytes[i] + bytes[i - bpp]) & 0xFF end bytes end |
.png_up(data, prev_row) ⇒ Object
51 52 53 54 55 56 57 58 59 |
# File 'lib/pdfrb/filter/png_predictor.rb', line 51 def png_up(data, prev_row) return data unless prev_row bytes = data.dup (0...bytes.length).each do |i| bytes[i] = (bytes[i] + (prev_row[i] || 0)) & 0xFF end bytes end |
.unfilter_row(filter_type, data, prev_row, bpp) ⇒ Object
33 34 35 36 37 38 39 40 41 |
# File 'lib/pdfrb/filter/png_predictor.rb', line 33 def unfilter_row(filter_type, data, prev_row, bpp) case filter_type when 1 then png_sub(data, bpp) when 2 then png_up(data, prev_row) when 3 then png_average(data, prev_row, bpp) when 4 then png_paeth(data, prev_row, bpp) else data end end |