Module: Rpdfium::IO::PNG
- Defined in:
- lib/rpdfium/io/png.rb
Overview
PNG writer minimale, puro Ruby, zero dipendenze esterne. Supporta solo RGBA 8bpc (color type 6) — il formato che PDFium produce quando rendi con FPDF_REVERSE_BYTE_ORDER.
Riferimento: PNG spec (RFC 2083). Nessun compromesso sulla validità: genera CRC32 corretti e usa deflate via zlib stdlib.
Constant Summary collapse
- SIGNATURE =
"\x89PNG\r\n\x1a\n".b
- COLOR_RGBA =
6
Class Method Summary collapse
- .write(path, width, height, rgba_bytes, stride: nil) ⇒ Object
- .write_chunk(io, type, data) ⇒ Object
- .write_idat(io, width, height, rgba, stride) ⇒ Object
- .write_iend(io) ⇒ Object
- .write_ihdr(io, width, height) ⇒ Object
Class Method Details
.write(path, width, height, rgba_bytes, stride: nil) ⇒ Object
19 20 21 22 23 24 25 26 27 28 |
# File 'lib/rpdfium/io/png.rb', line 19 def write(path, width, height, rgba_bytes, stride: nil) stride ||= width * 4 File.open(path, "wb") do |f| f.write(SIGNATURE) write_ihdr(f, width, height) write_idat(f, width, height, rgba_bytes, stride) write_iend(f) end path end |
.write_chunk(io, type, data) ⇒ Object
56 57 58 59 60 61 62 |
# File 'lib/rpdfium/io/png.rb', line 56 def write_chunk(io, type, data) type_bin = type.b io.write([data.bytesize].pack("N")) io.write(type_bin) io.write(data) io.write([Zlib.crc32(type_bin + data)].pack("N")) end |
.write_idat(io, width, height, rgba, stride) ⇒ Object
36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 |
# File 'lib/rpdfium/io/png.rb', line 36 def write_idat(io, width, height, rgba, stride) # PNG richiede un byte di "filter type" all'inizio di ogni riga. # 0 = None (nessun filtro). Funziona ma comprime peggio. # Per semplicità usiamo None — output 1.5-2x più grande del minimo # ottimo, ma è una scelta esplicita di tradeoff complessità/zero-dep. row_bytes = width * 4 scanlines = String.new(capacity: (row_bytes + 1) * height, encoding: Encoding::ASCII_8BIT) height.times do |y| scanlines << "\x00".b scanlines << rgba.byteslice(y * stride, row_bytes) end compressed = Zlib::Deflate.deflate(scanlines, Zlib::DEFAULT_COMPRESSION) write_chunk(io, "IDAT", compressed) end |
.write_iend(io) ⇒ Object
52 53 54 |
# File 'lib/rpdfium/io/png.rb', line 52 def write_iend(io) write_chunk(io, "IEND", "".b) end |
.write_ihdr(io, width, height) ⇒ Object
30 31 32 33 34 |
# File 'lib/rpdfium/io/png.rb', line 30 def write_ihdr(io, width, height) data = [width, height].pack("N2") + [8, COLOR_RGBA, 0, 0, 0].pack("C5") write_chunk(io, "IHDR", data) end |