Skip to content

Commit 46e3a2c

Browse files
committed
FEAT: extended PNG codec with chunks function
It's useful for close examination of PNG file data chunks and also for removing or adding some chunks manually. For example this short code rewrites PNG keeping only critical PNG chunks: ```rebol chunks: :codecs/png/chunks write %reduced.png chunks chunks/only %source.png ["IDAT" "IHDR" "PLTE"] ```
1 parent a5ba0fd commit 46e3a2c

File tree

1 file changed

+90
-17
lines changed

1 file changed

+90
-17
lines changed

src/mezz/codec-image-ext.reb

+90-17
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,11 @@ REBOL [
22
title: "REBOL 3 image codecs extensions"
33
name: 'codec-image-ext
44
author: "Oldes"
5-
version: 0.1.0
6-
date: 10-Nov-2020
5+
version: 0.2.0
6+
date: 8-Mar-2021
77
history: [
88
0.1.0 10-Nov-2020 "Oldes" {Extend native PNG codec with `size?` function}
9+
0.2.0 08-Mar-2021 "Oldes" {Extend native PNG with `chunks` function}
910
]
1011
]
1112

@@ -22,20 +23,92 @@ if find codecs 'png [
2223
to pair! binary/read bin [UI32 UI32]
2324
]
2425
]
25-
]
26-
27-
28-
29-
30-
31-
32-
33-
34-
35-
36-
37-
38-
39-
26+
27+
extend codecs/png 'chunks function [
28+
"Decode PNG into block of chunks (or encode back to binary from a block)"
29+
data [binary! file! url! block!] "Input data"
30+
/only tags [block!]
31+
][
32+
if block? data [
33+
;- Composing previously decoded chunks back to binary...
34+
if #{49484452} <> data/1 [
35+
sys/log/error 'PNG ["First chunk must be IHDR, but is:" as-red mold to string! tag]
36+
return none
37+
]
38+
out: binary 10000
39+
binary/write out #{89504E470D0A1A0A}
40+
foreach [tag dat] data [
41+
if tag = #{49454E44} [continue] ; IEND is added automatically
42+
unless all [binary? tag 4 = length? tag binary? dat][
43+
sys/log/error 'PNG ["Wrong chunk input!" as-red tag]
44+
return none
45+
]
46+
len: length? dat
47+
binary/write out [ui32be :len]
48+
tmp: out/buffer-write
49+
binary/write out [:tag :dat]
50+
crc: checksum tmp 'crc32
51+
binary/write out [ui32be :crc]
52+
]
53+
; add IEND
54+
binary/write out #{0000000049454E44AE426082}
55+
return copy out/buffer
56+
]
4057

58+
;- Examine inner content of PNG files converting it to block of chunks...
59+
if only [
60+
; make sure that all tag ids are as binary
61+
forall tags [
62+
unless binary? tags/1 [change tags to binary! form tags/1]
63+
]
64+
]
4165

66+
unless binary? data [ data: read data ]
67+
sys/log/info 'PNG ["^[[1;32mDecode PNG data^[[m (^[[1m" length? data "^[[mbytes )"]
68+
unless parse data [#{89504E470D0A1A0A} data: to end][ return none ]
69+
bin: binary data
70+
out: make block! 12
71+
num: -40 + query/mode console:// 'window-cols
72+
while [8 < length? bin/buffer][
73+
len: binary/read bin 'ui32be
74+
tag: copy/part bin/buffer 4
75+
; check if we are interested in specific tags
76+
if all [tags none? find tags tag][
77+
; ignore this tag
78+
sys/log/more 'PNG rejoin [form tag #" " as-red to string! tag " ^[[33m" pad len 10 "^[[35mignored"]
79+
bin/buffer: skip bin/buffer len + 8
80+
continue
81+
]
82+
; count checksum of this chunk...
83+
crc: checksum/part bin/buffer 'crc32 len + 4
84+
; skip tag which we already know...
85+
bin/buffer: skip bin/buffer 4
86+
; get raw data...
87+
dat: binary/read/with bin 'BYTES len
88+
; read CRC and compare with computed value...
89+
if crc <> binary/read bin 'si32be [
90+
sys/log/error 'PNG "CRC check failed!"
91+
return none
92+
]
93+
; use some user friendly info output for specific chunks...
94+
info: switch/default tag [
95+
#{49484452} ;IHDR
96+
[binary/read dat [UI32 UI32 UI8 UI8 UI8 UI8 UI8]]
97+
#{70485973} ;pHYs
98+
[binary/read dat [UI32 UI32 UI8]]
99+
#{69545874} ;iTXt
100+
#{74455874} ;tEXt
101+
[to string! dat]
102+
][ dat ]
103+
info: mold/flat/part info num + 3
104+
; cropped to fit on single line...
105+
if num < length? info [ change skip tail info -3 "..." ]
106+
; output info...
107+
sys/log/more 'PNG rejoin [form tag #" " as-red to string! tag " ^[[33m" pad len 10 info]
108+
; store data...
109+
append/only append out tag dat
110+
]
111+
new-line/skip out true 2
112+
out
113+
]
114+
]

0 commit comments

Comments
 (0)