rpdfium 0.4.1

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,65 @@
1
+ # frozen_string_literal: true
2
+
3
+ require "zlib"
4
+
5
+ module Rpdfium
6
+ module IO
7
+ # PNG writer minimale, puro Ruby, zero dipendenze esterne.
8
+ # Supporta solo RGBA 8bpc (color type 6) — il formato che PDFium produce
9
+ # quando rendi con FPDF_REVERSE_BYTE_ORDER.
10
+ #
11
+ # Riferimento: PNG spec (RFC 2083). Nessun compromesso sulla validità:
12
+ # genera CRC32 corretti e usa deflate via zlib stdlib.
13
+ module PNG
14
+ SIGNATURE = "\x89PNG\r\n\x1a\n".b
15
+ COLOR_RGBA = 6
16
+
17
+ module_function
18
+
19
+ def write(path, width, height, rgba_bytes, stride: nil)
20
+ stride ||= width * 4
21
+ File.open(path, "wb") do |f|
22
+ f.write(SIGNATURE)
23
+ write_ihdr(f, width, height)
24
+ write_idat(f, width, height, rgba_bytes, stride)
25
+ write_iend(f)
26
+ end
27
+ path
28
+ end
29
+
30
+ def write_ihdr(io, width, height)
31
+ data = [width, height].pack("N2") +
32
+ [8, COLOR_RGBA, 0, 0, 0].pack("C5")
33
+ write_chunk(io, "IHDR", data)
34
+ end
35
+
36
+ def write_idat(io, width, height, rgba, stride)
37
+ # PNG richiede un byte di "filter type" all'inizio di ogni riga.
38
+ # 0 = None (nessun filtro). Funziona ma comprime peggio.
39
+ # Per semplicità usiamo None — output 1.5-2x più grande del minimo
40
+ # ottimo, ma è una scelta esplicita di tradeoff complessità/zero-dep.
41
+ row_bytes = width * 4
42
+ scanlines = String.new(capacity: (row_bytes + 1) * height,
43
+ encoding: Encoding::ASCII_8BIT)
44
+ height.times do |y|
45
+ scanlines << "\x00".b
46
+ scanlines << rgba.byteslice(y * stride, row_bytes)
47
+ end
48
+ compressed = Zlib::Deflate.deflate(scanlines, Zlib::DEFAULT_COMPRESSION)
49
+ write_chunk(io, "IDAT", compressed)
50
+ end
51
+
52
+ def write_iend(io)
53
+ write_chunk(io, "IEND", "".b)
54
+ end
55
+
56
+ def write_chunk(io, type, data)
57
+ type_bin = type.b
58
+ io.write([data.bytesize].pack("N"))
59
+ io.write(type_bin)
60
+ io.write(data)
61
+ io.write([Zlib.crc32(type_bin + data)].pack("N"))
62
+ end
63
+ end
64
+ end
65
+ end