@@ -2,10 +2,11 @@ REBOL [
2
2
title: "REBOL 3 image codecs extensions"
3
3
name: 'codec-image-ext
4
4
author: "Oldes"
5
- version: 0.1 .0
6
- date: 10-Nov-2020
5
+ version: 0.2 .0
6
+ date: 8-Mar-2021
7
7
history: [
8
8
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}
9
10
]
10
11
]
11
12
@@ -22,20 +23,92 @@ if find codecs 'png [
22
23
to pair! binary/read bin [UI32 UI32]
23
24
]
24
25
]
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
+ ]
40
57
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
+ ]
41
65
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