Created
July 2, 2023 13:32
-
-
Save visy/9eb16a207c5e9394846519fecd905887 to your computer and use it in GitHub Desktop.
TIC-80 LZW graphics compression
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
pixal="abcdefghijklmnop" | |
function compressLZW(input) | |
local dictionary = {} | |
local result = {} | |
local dictSize = 256 | |
local p = "" | |
for i = 0, 255 do | |
dictionary[string.char(i)] = i | |
end | |
local inputLen = #input | |
local i = 1 | |
while i <= inputLen do | |
local c = input:sub(i, i) | |
local pc = p .. c | |
if dictionary[pc] then | |
p = pc | |
else | |
table.insert(result, dictionary[p]) | |
dictionary[pc] = dictSize | |
dictSize = dictSize + 1 | |
p = c | |
end | |
i = i + 1 | |
end | |
if p ~= "" then | |
table.insert(result, dictionary[p]) | |
end | |
return result | |
end | |
function decompressLZW(input) | |
local dictionary = {} | |
local result = {} | |
local dictSize = 256 | |
for i = 0, 255 do | |
dictionary[i] = string.char(i) | |
end | |
local inputLen = #input | |
local i = 1 | |
local p = dictionary[input[i]] | |
table.insert(result, p) | |
i = i + 1 | |
while i <= inputLen do | |
local code = input[i] | |
local entry | |
if dictionary[code] then | |
entry = dictionary[code] | |
elseif code == dictSize then | |
entry = p .. p:sub(1, 1) | |
else | |
return nil, "Invalid compressed data" | |
end | |
table.insert(result, entry) | |
dictionary[dictSize] = p .. entry:sub(1, 1) | |
dictSize = dictSize + 1 | |
p = entry | |
i = i + 1 | |
end | |
return table.concat(result) | |
end | |
function sget(x,y) | |
local addr=0x4000+(x//8+y//8*16)*32 | |
return peek4(addr*2+x%8+y%8*8) | |
end | |
function sput(x,y,c) | |
local addr=0x4000+(x//8+y//8*16)*32 | |
return poke4(addr*2+x%8+y%8*8,c) | |
end | |
-- Test the compress and decompress functions | |
local input = "" | |
for y = 0, 256 do | |
for x = 0, 128 do | |
local c = sget(x,y) | |
c=math.floor(c) | |
input = input .. string.sub(pixal,c,c) | |
end | |
end | |
trace("Input len: "..#input,0,0) | |
local compressed = compressLZW(input) | |
trace("Compressed len: " .. #compressed,0,7) | |
# compressed data | |
# local gfxdata = {54,256,257,258,259,54,... etc. | |
local compressed = gfxdata | |
local decompressed = decompressLZW(compressed) | |
function decomp() | |
-- print("please wait, LZW decompressing") | |
local i = 1 | |
for y=0,255 do | |
for x=0,128 do | |
local cc = string.sub(decompressed,i,i) | |
local c = 15 | |
if cc == "0" then | |
c = 0 | |
end | |
if cc == "1" then | |
c = 1 | |
end | |
if cc == "2" then | |
c = 2 | |
end | |
if cc == "3" then | |
c = 3 | |
end | |
if cc == "4" then | |
c = 4 | |
end | |
if cc == "5" then | |
c = 5 | |
end | |
if cc == "6" then | |
c = 6 | |
end | |
if cc == "7" then | |
c = 7 | |
end | |
if cc == "8" then | |
c = 8 | |
end | |
if cc == "9" then | |
c = 9 | |
end | |
if cc == "A" then | |
c = 10 | |
end | |
if cc == "B" then | |
c = 11 | |
end | |
if cc == "C" then | |
c = 12 | |
end | |
if cc == "D" then | |
c = 13 | |
end | |
if cc == "E" then | |
c = 14 | |
end | |
if cc == "F" then | |
c = 15 | |
end | |
sput(x,y,c) | |
i = i + 1 | |
end | |
end | |
end | |
trace("Decompressed len: " .. #decompressed .. "",0,14) | |
trace(string.format("Size diff: %.2f", 100-((#compressed)/(#input)*100)) .. "%",0,22) | |
trace("compressed data: '" .. table.concat(compressed, ",") .. "'") |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment