Files
wnsrc/lua/sui/libs/png_encoder.lua
lifestorm 94063e4369 Upload
2024-08-04 22:55:00 +03:00

215 lines
4.2 KiB
Lua

--[[
| This file was obtained through the combined efforts
| of Madbluntz & Plymouth Antiquarian Society.
|
| Credits: lifestorm, Gregory Wayne Rossel JR.,
| Maloy, DrPepper10 @ RIP, Atle!
|
| Visit for more: https://plymouth.thetwilightzone.ru/
--]]
local string = string
local table = table
local bit = bit
local char = string.char
local byte = string.byte
local insert = table.insert
local concat = table.concat
local bor = bit.bor
local bxor = bit.bxor
local band = bit.band
local bnot = bit.bnot
local lshift = bit.lshift
local rshift = bit.rshift
local ceil = math.ceil
local SIGNATURE = char(137, 80, 78, 71, 13, 10, 26, 10)
local crc_table = {}; do
local n = 0
while n < 256 do
local c = n
local k = 0
while k < 8 do
if band(c, 1) ~= 0 then
c = bxor(0xedb88320, rshift(c, 1))
else
c = rshift(c, 1)
end
k = k + 1
end
crc_table[n + 1] = c
n = n + 1
end
end
local crc = function(buf)
local c = 0xffffffff
for i = 1, #buf do
c = bxor(crc_table[band(bxor(c, byte(buf, i)), 0xff) + 1], rshift(c, 8))
end
return bxor(c, 0xffffffff)
end
local dword_as_string = function(dword)
return char(
rshift(band(dword, 0xff000000), 24),
rshift(band(dword, 0x00ff0000), 16),
rshift(band(dword, 0x0000ff00), 8),
band(dword, 0x000000ff)
)
end
local create_chunk = function(type, data, length)
local CRC = crc(type .. data)
return concat({
dword_as_string(length or #data),
type,
data,
dword_as_string(CRC)
}, "", 1, 4)
end
local create_IHDR; do
local ARGS = (
-- bit depth
char(8) ..
-- color type: 6=truecolor with alpha
char(6) ..
-- compression method: 0=deflate, only allowed value
char(0) ..
-- filtering: 0=adaptive, only allowed value
char(0) ..
-- interlacing: 0=none
char(0)
)
create_IHDR = function(w, h)
return create_chunk("IHDR", concat({
dword_as_string(w),
dword_as_string(h),
ARGS
}, "", 1, 3), 13)
end
end
local deflate_pack; do
local BASE = 6552
local NMAX = 5552
local adler32 = function(str)
local s1 = 1
local s2 = 0
local n = NMAX
for i = 1, #str do
s1 = s1 + byte(str, i)
s2 = s2 + s1
n = n - 1
if n == 0 then
s1 = s1 % BASE
s2 = s2 % BASE
n = NMAX
end
end
s1 = s1 % BASE
s2 = s2 % BASE
return bor(lshift(s2, 16), s1)
end
local splitChunks = function(chunk, chunkSize)
local len = ceil(#chunk / chunkSize)
local ret = {}
for i = 1, len do
ret[i - 1] = chunk:sub(((i - 1) * chunkSize) + 1, chunkSize)
end
return ret
end
deflate_pack = function(str)
local ret = {"\x78\x9c"}
local chunks = splitChunks(str, 0xFFFF)
local len = #chunks
local i = 0
while i < (len + 1) do
local chunk = chunks[i]
local chunk_n = #chunk
insert(ret, i < len and "\x00" or "\x01")
insert(ret, char(band(chunk_n, 0xff), band(rshift(chunk_n, 8), 0xff)))
insert(ret, char(band(bnot(chunk_n), 0xff), band(rshift(bnot(chunk_n), 8), 0xff)))
insert(ret, chunk)
i = i + 1
end
local t = adler32(str)
t = char(
band(rshift(t, 24), 0xff),
band(rshift(t, 16), 0xff),
band(rshift(t, 8), 0xff),
band(t, 0xff)
)
insert(ret, t)
return concat(ret)
end
end
local create_IDAT; do
local slice = function(a, s, e)
local ret, j = {}, 0
for i = s, e - 1 do
ret[j] = char(band(a[i] or 0, 0xFF))
j = j + 1
end
return ret
end
local array_split_chunks = function(w, h, array, chunkSize)
local ret = {}
local i = 0
local len = ceil((w * h * 4 + 4) / chunkSize)
while i < len do
ret[i] = slice(array, i * chunkSize, (i + 1) * chunkSize)
i = i + 1
end
return ret
end
create_IDAT = function(w, h, chunk)
local scanlines = array_split_chunks(w, h, chunk, w * 4)
local image_bytes = {}
for i = 0, #scanlines do
local scanline = scanlines[i]
insert(image_bytes, char(band(0, 0xFF)))
insert(image_bytes, concat(scanline, "", 0, #scanline))
end
image_bytes = deflate_pack(concat(image_bytes))
return create_chunk("IDAT", image_bytes)
end
end
local IEND = create_chunk("IEND", "", 0)
local to_return = {SIGNATURE, nil, nil, IEND}
local generate_png = function(w, h, chunk)
local IHDR = create_IHDR(w, h)
local IDAT = create_IDAT(w, h, chunk)
to_return[2] = IHDR
to_return[3] = IDAT
return concat(to_return, "", 1, 4)
end
return generate_png