CPIv1 implementation added
This commit is contained in:
parent
ba07886a4f
commit
5872a931e1
29
cc-pic.py
29
cc-pic.py
|
@ -78,14 +78,35 @@ class Converter:
|
||||||
dark_i, bri_i = bri_i, dark_i
|
dark_i, bri_i = bri_i, dark_i
|
||||||
return out, dark_i, bri_i
|
return out, dark_i, bri_i
|
||||||
|
|
||||||
|
@staticmethod
|
||||||
|
def _write_varint(fp: BinaryIO, value: int):
|
||||||
|
value &= 0xFFFFFFFF
|
||||||
|
mask: int = 0xFFFFFF80
|
||||||
|
while True:
|
||||||
|
if (value & mask) == 0:
|
||||||
|
fp.write(bytes([value & 0xFF]))
|
||||||
|
return
|
||||||
|
fp.write(bytes([(value & 0x7F) | 0x80]))
|
||||||
|
value >>= 7
|
||||||
|
|
||||||
def export_binary(self, io: BinaryIO):
|
def export_binary(self, io: BinaryIO):
|
||||||
io.write(b"CCPI")
|
if self._img.width <= 510 and self._img.height <= 765:
|
||||||
io.write(bytes([self._img.width // 2, self._img.height // 3, 0]))
|
io.write(b"CCPI") # old format
|
||||||
io.write(bytes(self._palette[: 16 * 3]))
|
io.write(bytes([self._img.width // 2, self._img.height // 3, 0]))
|
||||||
|
io.write(bytes(self._palette[: 16 * 3]))
|
||||||
|
else:
|
||||||
|
io.write(b"CPI\x01") # CPIv1
|
||||||
|
self._write_varint(io, self._img.width // 2)
|
||||||
|
self._write_varint(io, self._img.height // 3)
|
||||||
|
io.write(bytes(self._palette[: 16 * 3]))
|
||||||
|
written = 0
|
||||||
for y in range(0, self._img.height - 2, 3):
|
for y in range(0, self._img.height - 2, 3):
|
||||||
|
line: bytearray = bytearray()
|
||||||
for x in range(0, self._img.width - 1, 2):
|
for x in range(0, self._img.width - 1, 2):
|
||||||
ch, bg, fg = self._get_block(x, y)
|
ch, bg, fg = self._get_block(x, y)
|
||||||
io.write(bytes([(ch + 0x80) & 0xFF, fg << 4 | bg]))
|
line.extend([(ch + 0x80) & 0xFF, fg << 4 | bg])
|
||||||
|
written += io.write(line)
|
||||||
|
assert written == (self._img.width // 2) * (self._img.height // 3) * 2
|
||||||
|
|
||||||
def export(self, io: TextIO):
|
def export(self, io: TextIO):
|
||||||
io.write("local m = peripheral.find('monitor')\n")
|
io.write("local m = peripheral.find('monitor')\n")
|
||||||
|
|
84
ccpi.lua
84
ccpi.lua
|
@ -1,30 +1,20 @@
|
||||||
|
|
||||||
local function load(path)
|
local decoders = {}
|
||||||
local image = { w = 0, h = 0, scale = 1.0, palette = {}, lines = {} }
|
|
||||||
|
|
||||||
local fp, err = io.open(path, "rb")
|
local function read_palette_full(palette, fp)
|
||||||
if not fp then return nil, err end
|
|
||||||
|
|
||||||
local magic = fp:read(4)
|
|
||||||
if magic ~= "CCPI" then
|
|
||||||
return nil, "Invalid header: expected CCPI got " .. magic
|
|
||||||
end
|
|
||||||
|
|
||||||
image.w, image.h = string.byte(fp:read(1)), string.byte(fp:read(1))
|
|
||||||
image.scale = 0.5 + string.byte(fp:read(1)) * 5 / 255
|
|
||||||
for i = 1, 16 do
|
for i = 1, 16 do
|
||||||
image.palette[i] = bit.blshift(string.byte(fp:read(1)), 16)
|
palette[i] = bit.blshift(string.byte(fp:read(1)), 16)
|
||||||
image.palette[i] = bit.bor(image.palette[i], bit.blshift(string.byte(fp:read(1)), 8))
|
palette[i] = bit.bor(palette[i], bit.blshift(string.byte(fp:read(1)), 8))
|
||||||
image.palette[i] = bit.bor(image.palette[i], string.byte(fp:read(1)))
|
palette[i] = bit.bor(palette[i], string.byte(fp:read(1)))
|
||||||
end
|
end
|
||||||
|
end
|
||||||
|
|
||||||
print(image.w, image.h)
|
local function read_pixeldata_v0(image, fp)
|
||||||
|
|
||||||
for y = 1, image.h do
|
for y = 1, image.h do
|
||||||
local line = { s = "", bg = "", fg = "" }
|
local line = { s = "", bg = "", fg = "" }
|
||||||
for x = 1, image.w do
|
for x = 1, image.w do
|
||||||
local data = fp:read(2)
|
local data = fp:read(2)
|
||||||
if #data == 0 then
|
if data == nil or #data == 0 then
|
||||||
return nil, string.format("Failed to read character at x=%d y=%d", x, y)
|
return nil, string.format("Failed to read character at x=%d y=%d", x, y)
|
||||||
end
|
end
|
||||||
|
|
||||||
|
@ -39,9 +29,65 @@ local function load(path)
|
||||||
end
|
end
|
||||||
table.insert(image.lines, line)
|
table.insert(image.lines, line)
|
||||||
end
|
end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function read_varint(fp)
|
||||||
|
local value = 0
|
||||||
|
local current = 0
|
||||||
|
local offset = 0
|
||||||
|
repeat
|
||||||
|
if offset >= 5 then return nil, "varint too long" end
|
||||||
|
current = string.byte(fp:read(1))
|
||||||
|
value = bit.bor(value, bit.blshift(bit.band(current, 0x7f), offset * 7))
|
||||||
|
offset = offset + 1
|
||||||
|
until bit.band(current, 0x80) == 0
|
||||||
|
return value
|
||||||
|
end
|
||||||
|
|
||||||
|
decoders[0] = function(image, fp)
|
||||||
|
image.w, image.h = string.byte(fp:read(1)), string.byte(fp:read(1))
|
||||||
|
image.scale = 0.5 + string.byte(fp:read(1)) * 5 / 255
|
||||||
|
read_palette_full(image.palette, fp)
|
||||||
|
local success, err = read_pixeldata_v0(image, fp)
|
||||||
|
if not success then return false, err end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
decoders[1] = function(image, fp)
|
||||||
|
image.w = read_varint(fp)
|
||||||
|
image.h = read_varint(fp)
|
||||||
|
image.scale = 0.5 -- CPIv1 doesn't have a scale property
|
||||||
|
read_palette_full(image.palette, fp)
|
||||||
|
local success, err = read_pixeldata_v0(image, fp)
|
||||||
|
if not success then return false, err end
|
||||||
|
return true
|
||||||
|
end
|
||||||
|
|
||||||
|
local function load(path)
|
||||||
|
local fp, err = io.open(path, "rb")
|
||||||
|
if not fp then return nil, err end
|
||||||
|
|
||||||
|
local res
|
||||||
|
local image = { w = 0, h = 0, scale = 1.0, palette = {}, lines = {} }
|
||||||
|
|
||||||
|
local magic = fp:read(4)
|
||||||
|
if magic == "CCPI" then
|
||||||
|
res, err = decoders[0](image, fp)
|
||||||
|
elseif magic:sub(1, 3) == "CPI" then
|
||||||
|
local version = magic:byte(4, 4)
|
||||||
|
if decoders[version] == nil then
|
||||||
|
fp:close()
|
||||||
|
return nil, string.format("Invalid CPI version 0x%02x", version)
|
||||||
|
end
|
||||||
|
res, err = decoders[version](image, fp)
|
||||||
|
else
|
||||||
|
fp:close()
|
||||||
|
return nil, "Invalid header: expected CCPI got " .. magic
|
||||||
|
end
|
||||||
|
|
||||||
fp:close()
|
fp:close()
|
||||||
|
if not res then return false, err end
|
||||||
return image
|
return image
|
||||||
end
|
end
|
||||||
|
|
||||||
|
|
Loading…
Reference in New Issue