Add modlib.minetest.encode_png

master
Lars Mueller 2021-10-21 15:40:04 +02:00
parent e5a3f0c9d8
commit 578d504575
2 changed files with 120 additions and 1 deletions

View File

@ -6,7 +6,8 @@ for _, value in pairs{
"raycast",
"schematic",
"colorspec",
"media"
"media",
"encode_png",
} do
components[value] = value
end

118
minetest/encode_png.lua Normal file
View File

@ -0,0 +1,118 @@
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_bytestring = {}
for y = 0, height - 1 do
local base = y * width
insert(data_bytestring, "\0")
for x = 1, width do
local color_int = data[base + x]
local a = floor(color_int / 0x1000000) % 0x100
local r = floor(color_int / 0x10000) % 0x100
local g = floor(color_int / 0x100) % 0x100
local b = color_int % 0x100
insert(data_bytestring, char(r, g, b, a))
end
end
write(minetest.compress(concat(data_bytestring), "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