-
Notifications
You must be signed in to change notification settings - Fork 4
/
pngparse.lua
165 lines (136 loc) · 4.13 KB
/
pngparse.lua
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
-- pngparse.lua
-- Simple example of parsing the main sections of a PNG file.
--
-- This is mostly just an example. Not intended to be complete,
-- robust, modular, or well tested.
--
-- (c) 2008 David Manura. Licensed under the same terms as Lua (MIT license).
-- Unpack 32-bit unsigned integer (most-significant-byte, MSB, first)
-- from byte string.
local function unpack_msb_uint32(s)
local a,b,c,d = s:byte(1,#s)
local num = (((a*256) + b) * 256 + c) * 256 + d
return num
end
-- Read 32-bit unsigned integer (most-significant-byte, MSB, first) from file.
local function read_msb_uint32(fh)
return unpack_msb_uint32(fh:read(4))
end
-- Read unsigned byte (integer) from file
local function read_byte(fh)
return fh:read(1):byte()
end
local function parse_zlib(fh, len)
local byte1 = read_byte(fh)
local byte2 = read_byte(fh)
local compression_method = byte1 % 16
local compression_info = math.floor(byte1 / 16)
local fcheck = byte2 % 32
local fdict = math.floor(byte2 / 32) % 1
local flevel = math.floor(byte2 / 64)
print("compression_method=", compression_method)
print("compression_info=", compression_info)
print("fcheck=", fcheck)
print("fdict=", fdict)
print("flevel=", flevel)
fh:read(len - 6)
print("(deflate data not displayed)")
local checksum = read_msb_uint32(fh)
print("checksum=", checksum)
end
local function parse_IHDR(fh, len)
assert(len == 13, 'format error')
local width = read_msb_uint32(fh)
local height = read_msb_uint32(fh)
local bit_depth = read_byte(fh)
local color_type = read_byte(fh)
local compression_method = read_byte(fh)
local filter_method = read_byte(fh)
local interlace_method = read_byte(fh)
print("width=", width)
print("height=", height)
print("bit_depth=", bit_depth)
print("color_type=", color_type)
print("compression_method=", compression_method)
print("filter_method=", filter_method)
print("interlace_method=", interlace_method)
return compression_method
end
local function parse_sRGB(fh, len)
assert(len == 1, 'format error')
local rendering_intent = read_byte(fh)
print("rendering_intent=", rendering_intent)
end
local function parse_gAMA(fh, len)
assert(len == 4, 'format error')
local rendering_intent = read_msb_uint32(fh)
print("rendering_intent=", rendering_intent)
end
local function parse_cHRM(fh, len)
assert(len == 32, 'format error')
local white_x = read_msb_uint32(fh)
local white_y = read_msb_uint32(fh)
local red_x = read_msb_uint32(fh)
local red_y = read_msb_uint32(fh)
local green_x = read_msb_uint32(fh)
local green_y = read_msb_uint32(fh)
local blue_x = read_msb_uint32(fh)
local blue_y = read_msb_uint32(fh)
print('white_x=', white_x)
print('white_y=', white_y)
print('red_x=', red_x)
print('red_y=', red_y)
print('green_x=', green_x)
print('green_y=', green_y)
print('blue_x=', blue_x)
print('blue_y=', blue_y)
end
local function parse_IDAT(fh, len, compression_method)
if compression_method == 0 then
-- fh:read(len)
parse_zlib(fh, len)
else
print('(unrecognized compression method)')
end
end
local function parse_png(fh)
-- parse PNG header
local bytes = fh:read(8)
local expect = "\137\080\078\071\013\010\026\010"
if bytes ~= expect then
error 'not a PNG file'
end
-- parse chunks
local compression_method
while 1 do
local len = read_msb_uint32(fh)
local stype = fh:read(4)
print("chunk:", "type=", stype, "len=", len)
if stype == 'IHDR' then
compression_method = parse_IHDR(fh, len)
elseif stype == 'sRGB' then
parse_sRGB(fh, len)
elseif stype == 'gAMA' then
parse_gAMA(fh, len)
elseif stype == 'cHRM' then
parse_cHRM(fh, len)
elseif stype == 'IDAT' then
parse_IDAT(fh, len, compression_method)
else
local data = fh:read(len)
print("data=", len == 0 and "(empty)" or "(not displayed)")
end
local crc = read_msb_uint32(fh)
print("crc=", crc)
if stype == 'IEND' then
break
end
end
end
local filename = arg[1]
if not filename then
io.stderr:write("usage: lua pngparse.lua <filename>")
os.exit(1)
end
local fh = assert(io.open(filename, 'rb'))
parse_png(fh)