mirror of
https://github.com/appgurueu/modlib.git
synced 2024-09-12 00:06:49 +02:00
114 lines
2.5 KiB
Lua
114 lines
2.5 KiB
Lua
if minetest.encode_png then
|
|
return minetest.encode_png
|
|
end
|
|
|
|
local assert, char, ipairs, insert, concat, floor = assert, string.char, ipairs, table.insert, table.concat, math.floor
|
|
|
|
-- TODO move to modlib.bit eventually
|
|
local bit_xor = bit.xor or function(a, b)
|
|
local res = 0
|
|
local bit = 1
|
|
for _ = 1, 32 do
|
|
if a % 2 ~= b % 2 then
|
|
res = res + bit
|
|
end
|
|
a = floor(a / 2)
|
|
b = floor(b / 2)
|
|
bit = bit * 2
|
|
end
|
|
return res
|
|
end
|
|
|
|
local crc_table = {}
|
|
for i = 0, 255 do
|
|
local c = i
|
|
for _ = 0, 7 do
|
|
if c % 2 > 0 then
|
|
c = bit_xor(0xEDB88320, floor(c / 2))
|
|
else
|
|
c = floor(c / 2)
|
|
end
|
|
end
|
|
crc_table[i] = c
|
|
end
|
|
|
|
local function encode_png(width, height, data, compression, raw_write)
|
|
local write = raw_write
|
|
local function byte(value)
|
|
write(char(value))
|
|
end
|
|
local function _uint(value)
|
|
local div = 0x1000000
|
|
for _ = 1, 4 do
|
|
byte(floor(value / div) % 0x100)
|
|
div = div / 0x100
|
|
end
|
|
end
|
|
local function uint(value)
|
|
assert(value < 2^31)
|
|
_uint(value)
|
|
end
|
|
local chunk_content
|
|
local function chunk_write(text)
|
|
insert(chunk_content, text)
|
|
end
|
|
local function chunk(type)
|
|
chunk_content = {}
|
|
write = chunk_write
|
|
write(type)
|
|
end
|
|
local function end_chunk()
|
|
write = raw_write
|
|
local chunk_len = 0
|
|
for i = 2, #chunk_content do
|
|
chunk_len = chunk_len + #chunk_content[i]
|
|
end
|
|
uint(chunk_len)
|
|
write(concat(chunk_content))
|
|
local chunk_crc = 0xFFFFFFFF
|
|
for _, text in ipairs(chunk_content) do
|
|
for i = 1, #text do
|
|
chunk_crc = bit_xor(crc_table[bit_xor(chunk_crc % 0x100, text:byte(i))], floor(chunk_crc / 0x100))
|
|
end
|
|
end
|
|
_uint(bit_xor(chunk_crc, 0xFFFFFFFF))
|
|
end
|
|
-- Signature
|
|
write"\137\80\78\71\13\10\26\10"
|
|
chunk"IHDR"
|
|
uint(width)
|
|
uint(height)
|
|
-- Always use bit depth 8
|
|
byte(8)
|
|
-- Always use color type "truecolor with alpha"
|
|
byte(6)
|
|
-- Compression method: deflate
|
|
byte(0)
|
|
-- Filter method: PNG filters
|
|
byte(0)
|
|
-- No interlace
|
|
byte(0)
|
|
end_chunk()
|
|
chunk"IDAT"
|
|
local data_rope = {}
|
|
for y = 0, height - 1 do
|
|
local base_index = y * width
|
|
insert(data_rope, "\0")
|
|
for x = 1, width do
|
|
local colorspec = modlib.minetest.colorspec.from_any(data[base_index + x])
|
|
insert(data_rope, char(colorspec.r, colorspec.g, colorspec.b, colorspec.a))
|
|
end
|
|
end
|
|
write(minetest.compress(type(data) == "string" and data or concat(data_rope), "deflate", compression))
|
|
end_chunk()
|
|
chunk"IEND"
|
|
end_chunk()
|
|
end
|
|
|
|
(...).encode_png = function(width, height, data, compression)
|
|
local rope = {}
|
|
encode_png(width, height, data, compression or 9, function(text)
|
|
insert(rope, text)
|
|
end)
|
|
return concat(rope)
|
|
end |