mirror of
https://github.com/lifestorm/wnsrc.git
synced 2025-12-16 21:33:46 +03:00
215 lines
4.2 KiB
Lua
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 |