mapit/pngparse.lua

166 lines
4.1 KiB
Lua

-- 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)