添加全彩

This commit is contained in:
nnwang
2025-12-21 18:42:45 +08:00
parent fe4d7917a7
commit 12fc9a8d94
54 changed files with 379 additions and 770 deletions

313
lib/1.lua
View File

@@ -1,313 +0,0 @@
local f1 = {
{
"\159\143\159\143\139\143",
"ffffff",
"000000",
},
{
"\128\149\159\137\143\155",
"00ffff",
"ff0000",
},
{
"\130\151\128\148\148\148",
"000000",
"ffffff",
},
{
"\136\135\159\133\149\138",
"00f00f",
"ff0ff0",
},
}
local f2 = {
{
"\159\143\159\143\139\143",
"ffffff",
"000000",
},
{
"\128\149\151\157\153\151",
"00ffff",
"ff0000",
},
{
"\130\151\157\140\136\140",
"00ffff",
"ff0000",
},
{
"\136\135\149\142\134\145",
"00f00f",
"ff0ff0",
},
}
local f3 = {
{
"\159\143\132\159\128\148",
"ff0f00",
"00f0ff",
},
{
"\159\133\144\144\129\149",
"ff0000",
"00ffff",
},
{
"\128\129\144\130\143\157",
"0f00f0",
"f0ff0f",
},
{
"\130\149\128\131\128\149",
"0f0000",
"f0ffff",
},
}
local f4 = {
{
"\128\148\128\128\148\128",
"000000",
"ffffff",
},
{
"\130\151\130\131\151\131",
"000000",
"ffffff",
},
{
"\136\151\149\131\131\149",
"00f000",
"ff0fff",
},
{
"\159\149\143\153\153\143",
"f0f0ff",
"0f0f00",
},
}
local n = {" ","ffffff","ffffff"}
-- 创建 img 表结构
local img = {}
for i1 = 1, 8 do
img[i1] = {}
for i2 = 1, 4 do
img[i1][i2] = {}
end
end
-- ✅ 关键修复:将 logon 改为函数,每次返回新表
local function logon()
return {
" ",
"fffffffffffffffffffffffff",
"fffffffffffffffffffffffff"
}
end
-- 定义 logo 为普通表(不是函数)
local logo = {
{
" \139 ",
"fffffff0000000f000fffffff",
"ffffffffffffff0ffffffffff"
},
{
" \143\129\149 \132 ",
"fffffff0000ff00000fffffff",
"fffffffffff00f00fffffffff"
},
{
" \159\135 \149\143\158\135\149 ",
"fffffff0ff00000ff0fffffff",
"ffffffff00000ff00ffffffff"
},
{
" \149 \143\150\144 \131\133 ",
"ffffffff00000f0000fffffff",
"fffffff00000f0fffffffffff"
},
{
" \149 \136 \149 \131\144 ",
"ffffffff00f00f0f00fffffff",
"fffffff0000ff000fffffffff"
},
{
" \138 \131\133 \149 ",
"fffffff00000ff0000fffffff",
"ffffffff00000000fffffffff"
},
{
" \130\139\144 \149 ",
"fffffff000f0000000fffffff",
"ffffffffff000000fffffffff"
},
{
" \143\131 \135 ",
"fffffff00ff0000000fffffff",
"fffffffff000000ffffffffff"
},
{
" \143\131 ",
"fffffff00000000000fffffff",
"fffffffff000fffffffffffff"
},
{
" \143\135\129 ",
"fffffff00000000000fffffff",
"fffffffffffffffffffffffff"
},
}
local logo1 = {{},{},{},{}}
-- 第一组
for i = 1, 3 do
table.insert(logo1[1], logon())
end
-- 插入 logo 的每一帧
for _, frame in ipairs(logo) do
table.insert(logo1[1], frame)
end
for i = 1, 2 do
table.insert(logo1[1], logon())
end
logo1[1].duration = 1
-- 第二组
for i = 1, 2 do
table.insert(logo1[2], logon())
end
for _, frame in ipairs(logo) do
table.insert(logo1[2], frame)
end
for i = 1, 3 do
table.insert(logo1[2], logon())
end
-- 第三组
table.insert(logo1[3], logon())
for _, frame in ipairs(logo) do
table.insert(logo1[3], frame)
end
for i = 1, 4 do
table.insert(logo1[3], logon())
end
-- 第四组
for _, frame in ipairs(logo) do
table.insert(logo1[4], frame)
end
for i = 1, 5 do
table.insert(logo1[4], logon())
end
-- 填充 img 前 4 行
for i = 1, 4 do
img[i] = logo1[i]
end
-- 清理临时变量
logo1 = nil
logo = nil
-- 构建 img[5] 到 img[8]
for i=1,3 do
img[5][1][i] = n[i] .. f2[4][i] .. n[i] .. f4[4][i]
end
for i=1,3 do
img[5][2][i] = n[i] .. n[i] .. n[i] .. n[i]
end
for i=1,3 do
img[5][3][i] = n[i] .. n[i] .. n[i] .. n[i]
end
for i=1,3 do
img[5][4][i] = f1[1][i] .. n[i] .. f3[1][i] .. n[i]
end
for i=1,3 do
img[6][1][i] = n[i] .. f2[3][i] .. n[i] .. f4[3][i]
end
for i=1,3 do
img[6][2][i] = n[i] .. f2[4][i] .. n[i] .. f4[4][i]
end
for i=1,3 do
img[6][3][i] = f1[1][i] .. n[i] .. f3[1][i] .. n[i]
end
for i=1,3 do
img[6][4][i] = f1[2][i] .. n[i] .. f3[2][i] .. n[i]
end
for i=1,3 do
img[7][1][i] = n[i] .. f2[2][i] .. n[i] .. f4[2][i]
end
for i=1,3 do
img[7][2][i] = f1[1][i] .. f2[3][i] .. f3[1][i] .. f4[3][i]
end
for i=1,3 do
img[7][3][i] = f1[2][i] .. f2[4][i] .. f3[2][i] .. f4[4][i]
end
for i=1,3 do
img[7][4][i] = f1[3][i] .. n[i] .. f3[3][i] .. n[i]
end
for i=1,3 do
img[8][1][i] = f1[1][i] .. f2[1][i] .. f3[1][i] .. f4[1][i]
end
for i=1,3 do
img[8][2][i] = f1[2][i] .. f2[2][i] .. f3[2][i] .. f4[2][i]
end
for i=1,3 do
img[8][3][i] = f1[3][i] .. f2[3][i] .. f3[3][i] .. f4[3][i]
end
for i=1,3 do
img[8][4][i] = f1[4][i] .. f2[4][i] .. f3[4][i] .. f4[4][i]
end
-- 清理
f1 = nil
f2 = nil
f3 = nil
f4 = nil
n = nil
img.animation = true
img.secondsPerFrame = 0.1
-- ✅ 现在可以安全序列化
print(textutils.serialize(img[1]))
local function drawFrame(frame, term)
for y, row in ipairs(frame) do
term.setCursorPos(1, y)
term.blit(table.unpack(row))
end
if frame.palette then for i = 0, #frame.palette do
local c = frame.palette[i]
if type(c) == "table" then term.setPaletteColor(2^i, table.unpack(c))
else term.setPaletteColor(2^i, c) end
end end
if img.multiMonitor then term.setTextScale(img.multiMonitor.scale or 0.5) end
end
term.clear()
for i, frame in ipairs(img) do
drawFrame(frame, term)
if img.animation then sleep(frame.duration or img.secondsPerFrame or 0.05)
else read() break end
end
read()
term.setBackgroundColor(colors.black)
term.setTextColor(colors.white)
term.clear()
term.setCursorPos(1, 1)
for i = 0, 15 do term.setPaletteColor(2^i, term.nativePaletteColor(2^i)) end

284
lib/1.py Normal file
View File

@@ -0,0 +1,284 @@
import json
import struct
import sys
from pathlib import Path
# Base64 字母表CC:Tweaked 使用的自定义顺序)
B64STR = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/"
B64MAP = {ch: i for i, ch in enumerate(B64STR)}
def custom_b64decode(s):
"""使用自定义字母表解码 base64 字符串(忽略 '='"""
val = 0
bits = 0
out = bytearray()
for ch in s:
if ch == '=':
continue
val = (val << 6) | B64MAP[ch]
bits += 6
if bits >= 8:
bits -= 8
out.append((val >> bits) & 0xFF)
return bytes(out)
def decode_frame(data):
# 验证头部
assert data[:4] == b'\x00\x00\x00\x00', "Invalid frame header (first 4 bytes)"
assert data[8:16] == b'\x00\x00\x00\x00\x00\x00\x00\x00', "Invalid frame header (bytes 8-15)"
width, height = struct.unpack('<HH', data[4:8])
total_chars = width * height
# === 解码字符 RLE 流 ===
text_bytes = []
pos = 16
remaining = total_chars
while remaining > 0:
char_byte = data[pos]
count = data[pos + 1]
pos += 2
text_bytes.extend([char_byte] * count)
remaining -= count
assert len(text_bytes) == total_chars, "Character RLE length mismatch"
# === 解码颜色 RLE 流 ===
color_bytes = []
remaining = total_chars
while remaining > 0:
color_byte = data[pos]
count = data[pos + 1]
pos += 2
color_bytes.extend([color_byte] * count)
remaining -= count
assert len(color_bytes) == total_chars, "Color RLE length mismatch"
# === 读取调色板16 色 × RGB===
palette_raw = data[pos:pos + 48]
assert len(palette_raw) == 48, "Palette must be 48 bytes"
palette = []
for i in range(16):
r = palette_raw[i * 3]
g = palette_raw[i * 3 + 1]
b = palette_raw[i * 3 + 2]
palette.append([r, g, b])
# === 构建行数据 ===
text_rows = []
fg_rows = []
bg_rows = []
idx = 0
for y in range(height):
row_text_parts = []
row_fg = ''
row_bg = ''
for x in range(width):
b = text_bytes[idx]
row_text_parts.append(f"\\{b:03d}") # 如 \130
c = color_bytes[idx]
fg = c & 0x0F
bg = (c >> 4) & 0x0F
row_fg += f"{fg:x}"
row_bg += f"{bg:x}"
idx += 1
text_rows.append(''.join(row_text_parts))
fg_rows.append(row_fg)
bg_rows.append(row_bg)
return {
"width": width,
"height": height,
"text": text_rows,
"foreground": fg_rows,
"background": bg_rows,
"palette": palette
}
def encode_frame(frame):
width = frame["width"]
height = frame["height"]
total = width * height
# === 从 \ddd 序列还原字节 ===
full_text = ''.join(frame["text"])
text_bytes = []
i = 0
while i < len(full_text):
if full_text[i] == '\\' and i + 4 <= len(full_text):
try:
num_str = full_text[i+1:i+4]
num = int(num_str)
if 0 <= num <= 255:
text_bytes.append(num)
i += 4
continue
except ValueError:
pass
raise ValueError(f"Invalid escape sequence at position {i}: expected \\ddd, got {full_text[i:i+5]}")
assert len(text_bytes) == total, "Text byte count mismatch"
# === 编码字符 RLE ===
char_rle = []
i = 0
while i < total:
b = text_bytes[i]
j = i
while j < total and text_bytes[j] == b and (j - i + 1) <= 255:
j += 1
count = j - i
char_rle.extend([b, count])
i = j
# === 构建颜色流 ===
color_stream = []
for y in range(height):
fg_row = frame["foreground"][y]
bg_row = frame["background"][y]
assert len(fg_row) == len(bg_row) == width, f"Row {y} length mismatch"
for x in range(width):
fg = int(fg_row[x], 16) & 0x0F
bg = int(bg_row[x], 16) & 0x0F
color_stream.append((bg << 4) | fg)
assert len(color_stream) == total
# === 编码颜色 RLE ===
color_rle = []
i = 0
while i < total:
c = color_stream[i]
j = i
while j < total and color_stream[j] == c and (j - i + 1) <= 255:
j += 1
count = j - i
color_rle.extend([c, count])
i = j
# === 调色板 ===
palette_bytes = []
for rgb in frame["palette"]:
assert len(rgb) == 3
r, g, b = rgb
assert 0 <= r <= 255 and 0 <= g <= 255 and 0 <= b <= 255
palette_bytes.extend([r, g, b])
assert len(palette_bytes) == 48
# === 拼接二进制数据 ===
header = b'\x00\x00\x00\x00' + struct.pack('<HH', width, height) + b'\x00' * 8
body = bytes(char_rle) + bytes(color_rle) + bytes(palette_bytes)
full_data = header + body
# === 自定义 Base64 编码 ===
b64 = ""
val = 0
bits = 0
for byte in full_data:
val = (val << 8) | byte
bits += 8
while bits >= 6:
bits -= 6
b64 += B64STR[(val >> bits) & 0x3F]
if bits:
b64 += B64STR[(val << (6 - bits)) & 0x3F]
# 补齐到 4 的倍数(虽然 CC 可能不检查,但保持兼容)
while len(b64) % 4:
b64 += '='
# 使用 !CPD 格式12 位十六进制长度)
hex_len = f"{len(b64):012x}"
return f"!CPD{hex_len}{b64}"
def vid_to_json(vid_path, json_path):
with open(vid_path, 'r', encoding='latin1') as f:
lines = [line.rstrip('\n\r') for line in f]
if not lines or lines[0] != "32Vid 1.1":
raise ValueError("Not a valid .32vid file: missing header")
fps_str = lines[1] if len(lines) > 1 else "0"
try:
fps = float(fps_str)
except ValueError:
fps = 0.0
frame_lines = []
for line in lines[2:]:
if line.strip() == "":
continue
if line.startswith("!CP"):
frame_lines.append(line)
frames = []
for line in frame_lines:
mode = line[3]
if mode == 'C':
length = int(line[4:8], 16)
b64data = line[8:8 + length]
elif mode == 'D':
length = int(line[4:16], 16)
b64data = line[16:16 + length]
else:
raise ValueError(f"Unknown frame mode: {mode}")
binary_data = custom_b64decode(b64data)
frame = decode_frame(binary_data)
frames.append(frame)
result = {
"header": {
"magic": "32Vid 1.1",
"fps": fps
},
"frames": frames
}
with open(json_path, 'w', encoding='utf-8') as f:
json.dump(result, f, indent=2, ensure_ascii=False)
def json_to_vid(json_path, vid_path):
with open(json_path, 'r', encoding='utf-8') as f:
data = json.load(f)
fps = data["header"]["fps"]
frames = data["frames"]
with open(vid_path, 'w', encoding='latin1') as f:
f.write("32Vid 1.1\n")
f.write(f"{fps}\n")
for frame in frames:
line = encode_frame(frame)
f.write(line + "\n")
# ======================
# CLI 入口
# ======================
def main():
if len(sys.argv) != 4:
print("Usage:")
print(" python 32vid_converter.py to-json input.32vid output.json")
print(" python 32vid_converter.py to-vid input.json output.32vid")
sys.exit(1)
command = sys.argv[1]
input_path = sys.argv[2]
output_path = sys.argv[3]
if command == "to-json":
vid_to_json(input_path, output_path)
print(f"✅ Converted: {input_path}{output_path}")
elif command == "to-vid":
json_to_vid(input_path, output_path)
print(f"✅ Converted: {input_path}{output_path}")
else:
print(f"❌ Unknown command: {command}")
sys.exit(1)
if __name__ == "__main__":
main()

View File

@@ -1,53 +0,0 @@
-- 压缩函数
function rleCompress(str)
local result = {}
local i = 1
while i <= #str do
local char = str:sub(i, i)
local count = 1
while i + count <= #str and str:sub(i + count, i + count) == char do
count = count + 1
end
if count > 2 then
table.insert(result, ("[%d]%s"):format(count, char))
else
table.insert(result, char:rep(count))
end
i = i + count
end
return table.concat(result)
end
-- 解压函数
function rleDecompress(str)
local result = {}
local i = 1
while i <= #str do
if str:sub(i, i) == "[" then
local j = str:find("]", i)
local num = tonumber(str:sub(i+1, j-1))
local char = str:sub(j+1, j+1)
table.insert(result, char:rep(num))
i = j + 2
else
table.insert(result, str:sub(i, i))
i = i + 1
end
end
return table.concat(result)
end
-- 测试
file = fs.open("1.bimg","r")
original = file.readAll()
file.close()
local compressed = rleCompress(original)
print("原始:", original)
print("压缩:", compressed)
print("解压:", rleDecompress(compressed))
file = fs.open("12.bimg","w")
file.write(compressed)
file.close()