Compare commits

8 Commits
1.0.0 ... main

Author SHA1 Message Date
da070bc9dd 更新 utf8display/README.md 2025-12-09 15:08:07 +08:00
78db749cb8 添加strToBimg,并让其他显示基于strToBimg 2025-12-08 19:29:43 +08:00
a81c44106a 更新 utf8display/README.md 2025-12-08 19:29:01 +08:00
8f32e8b3d6 更新 utf8display/README.md 2025-12-08 16:36:44 +08:00
e4bb015e77 更新 utf8display/README.md 2025-12-08 16:33:58 +08:00
765d760177 更新 utf8display/README.md 2025-12-08 16:32:28 +08:00
0f95039951 添加utf8display库 2025-12-08 16:29:32 +08:00
87ea387834 添加 utf8print12px.lua 2025-11-16 01:04:08 +08:00
3 changed files with 983 additions and 0 deletions

210
utf8display/README.md Normal file
View File

@@ -0,0 +1,210 @@
# UTF-8 Display Library for ComputerCraft
> 一个支持中文与 UTF-8 字符的高性能像素字体显示库,适用于 **ComputerCraft**(包括 CC:Tweaked环境。
---
## 📦 安装
### 方法一:本地加载(推荐)
#### 下载到本地
```shell
wget https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/utf8display/utf8display.lua utf8display.lua
```
#### 在 Lua 脚本中使用
```lua
local utf8display = require("utf8display")
```
### 方法二:远程加载(无需存储)
```lua
local utf8display = load(http.get("https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/utf8display/utf8display.lua").readAll())()
```
---
## ⚙️ 配置
默认配置如下:
```lua
utf8display.config = {
fontUrl = "https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/fonts/fusion-pixel-8px-proportional-zh_hans.lua",
fontPath = nil, -- 本地字体路径(若设置则优先使用)
cacheFont = true, -- 是否缓存已加载字体(提升性能)
}
```
### 修改配置
```lua
-- 示例:使用本地字体
utf8display.setConfig("fontPath", "/fonts/my_font.lua")
-- 示例:更换远程字体
utf8display.setConfig("fontUrl", "https://example.com/my_font.lua")
```
> ✅ 支持的配置项:`fontUrl`、`fontPath`、`cacheFont`
---
## 🧰 主要函数
### `utf8display.write(str, [textColor, backgroundColor])`
- **用途**:不自动换行地输出文本(适合标题、状态栏等)
- **行为**
- 换行符 `\n` 会被替换为空格
- 若内容超出屏幕,光标回退至起始位置
- 支持统一颜色或逐字颜色(见下文"颜色控制"
- **返回值**`{success, info}`
### `utf8display.print(str, [textColor, backgroundColor])`
- **用途**:自动换行输出文本(类似传统 `print`
- **行为**
- 正常处理 `\n` 换行
- 根据终端宽度自动换行
- 光标最终位于输出内容**下一行开头**
- **返回值**`{success, info}`
### `utf8display.blit(str, textColorStr, backgroundColorStr)`
- **用途**:高级颜色控制输出(逐字符指定颜色)
- **参数**
- `textColorStr`:前景色字符串(如 `"123456"`,每个字符对应一个 blit 颜色码)
- `backgroundColorStr`:背景色字符串(同上)
- **注意**`\n` 同样被替换为空格
- **返回值**`{success, info}`
### `utf8display.strToBimg(str, textColor, backgroundColor, [width])`
- **参数说明**
- `str`:要转换的字符串
- `textColor`:前景色,可以是:
- `colors.xxx`(如 `colors.red`
- blit颜色字符串`"fff"`
- `backgroundColor`:背景色,可以是:
- `colors.xxx`(如 `colors.black`
- blit颜色字符串`"000"`
- `[width]`:行宽限制(可选),如果输入数字则根据此大小进行自动换行
- **用途**:将字符串转换为 `bimg` 格式(用于自定义渲染)
- **返回值**:符合 `term.blit()` 格式的多帧图像结构(当前仅单帧)
### `utf8display.loadFont()`
- **用途**:手动加载字体资源
- **行为**:根据配置加载远程或本地字体
- **返回值**`{success, error_message}`
---
## 🎨 颜色控制
### 统一颜色(数字)
```lua
utf8display.write("Hello 世界!", colors.red, colors.black)
```
### 逐字颜色(字符串)
```lua
utf8display.blit("ABC", "123", "000")
```
> 💡 颜色字符串长度不足时,后续字符使用默认色
---
## 📝 使用示例
### 基础用法
```lua
local utf8display = require("utf8display")
-- 自动初始化字体(首次调用 write/print 时触发)
utf8display.write("你好ComputerCraft")
utf8display.print("这是一段\n包含换行的\n中文文本。")
```
### 彩色输出
```lua
-- 统一颜色
utf8display.write("警告!", colors.orange, colors.black)
-- 逐字变色(彩虹效果)
utf8display.blit("RAINBOW", "1234567", "0000000")
```
### 使用本地字体
```lua
utf8display.setConfig("fontPath", "/my_fonts/chinese_font.lua")
utf8display.write("使用本地字体!")
```
### 手动加载字体
```lua
local success, error_msg = utf8display.loadFont()
if success then
print("字体加载成功!")
else
print("字体加载失败:" .. error_msg)
end
```
### 自动换行功能
```lua
-- 使用strToBimg的宽度参数进行自动换行
local bimg = utf8display.strToBimg("这是一段很长的文本,需要自动换行显示", colors.white, colors.black, 20)
-- 文本将在第20个cc字符位置自动换行
-- 或者在print中自动换行
utf8display.print("这是一段很长的文本,会自动换行显示", colors.white, colors.black)
```
---
## 🔙 返回值说明
所有显示函数均返回以下结构:
```lua
{
success = true,
startX = 1, -- 起始光标 X
startY = 1, -- 起始光标 Y
endX = 10, -- 结束光标 X
endY = 2, -- 结束光标 Y
charCount = 5, -- 显示的字符数UTF-8 计数)
fontHeight = 8, -- 字体高度(行高)
overflowX = false, -- 水平溢出write/blit
overflowY = false, -- 垂直溢出write/blit
lineCount = 3 -- 行数(仅 print
}
```
---
## ⚠️ 注意事项
1. **换行行为**
- `write` / `blit``\n` → 空格
- `print``\n` → 实际换行 + 自动折行
2. **性能**
- 首次使用会自动加载字体(网络或本地)
- 启用 `cacheFont = true` 可避免重复加载
3. **渲染机制**
- 使用 `term.blit()` 高效绘制
---
## 🛠 如何制作自定义字体
- 字体文件返回一个table键值为utf8编码值为和对应字体的bitmap。
- bitmap为一个包含等长string的tablestring中的char属于computer craft定义的2*3像素点阵如需使用右下角像素将char的码值减128表示反转backgroundColor 和 textColor
- 单个字体文件中可以有不同尺寸的bitmap且**需要**有'H'(ascII:72)的bitmap表示该文件中最大bitmap高度
- 会以FontFamily出现的最大bitmap高度为基准最终输出下对齐的文本
- FontFamily中**需要**'-'(ascII:45)的bitmap以供自动换行时可能的切断单词使用

564
utf8display/utf8display.lua Normal file
View File

@@ -0,0 +1,564 @@
-- UTF-8 Display Library for ComputerCraft (完整修正版)
-- 文件名: utf8display.lua
local utf8display = {}
-- 配置参数
utf8display.config = {
fontUrl = "https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/fonts/fusion-pixel-8px-proportional-zh_hans.lua",
fontPath = nil,
cacheFont = true,
autoScroll = true
}
-- 内部状态
local state = {
font = nil,
fontHeight = 8,
loadedFonts = {}
}
-- 字体管理模块
local fontManager = {}
function fontManager.loadRemoteFont(url)
if state.loadedFonts[url] then
return state.loadedFonts[url]
end
local response = http.get(url)
if not response then
return nil, "无法连接到字体服务器: " .. url
end
if response.getResponseCode() ~= 200 then
return nil, "字体服务器返回错误: " .. response.getResponseCode()
end
local content = response.readAll()
response.close()
local sandbox = {}
local chunk, err = load(content, "=remoteFont", "t", sandbox)
if not chunk then
return nil, "加载字体失败: " .. err
end
local success, result = pcall(chunk)
if not success then
return nil, "执行字体脚本失败: " .. result
end
local fontData = sandbox.font or sandbox[1] or result
if utf8display.config.cacheFont then
state.loadedFonts[url] = fontData
end
return fontData
end
function fontManager.loadLocalFont(path)
if state.loadedFonts[path] then
return state.loadedFonts[path]
end
if not fs.exists(path) then
return nil, "字体文件不存在: " .. path
end
local file = fs.open(path, "r")
local content = file.readAll()
file.close()
local sandbox = {}
local chunk, err = load(content, "=localFont", "t", sandbox)
if not chunk then
return nil, "加载本地字体失败: " .. err
end
local success, result = pcall(chunk)
if not success then
return nil, "执行本地字体脚本失败: " .. result
end
local fontData = sandbox.font or sandbox[1] or result
if utf8display.config.cacheFont then
state.loadedFonts[path] = fontData
end
return fontData
end
function fontManager.getFont()
if not state.font then
local success, err = utf8display.loadFont()
if not success then
error("字体加载失败: " .. err)
end
end
return state.font
end
function fontManager.getFontHeight()
local font = fontManager.getFont()
if font and font[72] then -- 'H' (ASCII 72) 表示最大高度
return #font[72]
elseif font and font[32] then
return #font[32]
end
return state.fontHeight
end
-- 渲染引擎模块
local renderer = {}
function renderer.utf8Decode(str)
local i = 1
return function()
if i > #str then return end
local b1 = string.byte(str, i)
i = i + 1
if b1 < 0x80 then
return b1
elseif b1 >= 0xC0 and b1 < 0xE0 then
local b2 = string.byte(str, i) or 0
i = i + 1
return (b1 - 0xC0) * 64 + (b2 - 0x80)
elseif b1 >= 0xE0 and b1 < 0xF0 then
local b2 = string.byte(str, i) or 0
i = i + 1
local b3 = string.byte(str, i) or 0
i = i + 1
return (b1 - 0xE0) * 4096 + (b2 - 0x80) * 64 + (b3 - 0x80)
else
return 32
end
end
end
-- 公共API函数
function utf8display.setConfig(key, value)
if utf8display.config[key] ~= nil then
utf8display.config[key] = value
return true
end
return false, "配置项不存在"
end
function utf8display.getConfig(key)
if utf8display.config[key] ~= nil then
return utf8display.config[key]
end
return nil, "配置项不存在"
end
function utf8display.loadFont()
if utf8display.config.fontPath then
state.font, err = fontManager.loadLocalFont(utf8display.config.fontPath)
if not state.font then
return false, err
end
else
state.font, err = fontManager.loadRemoteFont(utf8display.config.fontUrl)
if not state.font then
return false, err
end
end
state.fontHeight = fontManager.getFontHeight()
return true
end
-- 将字符串转换为bimg格式完整修正版支持逐字颜色
function utf8display.strToBimg(str, textColor, backgroundColor, width)
str = tostring(str)
local font = fontManager.getFont()
local fontHeight = fontManager.getFontHeight()
-- 判断颜色参数类型
local textIsString = type(textColor) == "string"
local bgIsString = type(backgroundColor) == "string"
-- 获取默认颜色
local defaultTextColor = term.getTextColor()
local defaultBgColor = term.getBackgroundColor()
-- 处理统一颜色(数字)或逐字颜色(字符串)
local uniformTextBlit, uniformBgBlit
if not textIsString then
uniformTextBlit = colors.toBlit(type(textColor) == "number" and textColor or defaultTextColor)
end
if not bgIsString then
uniformBgBlit = colors.toBlit(type(backgroundColor) == "number" and backgroundColor or defaultBgColor)
end
-- 初始化bimg结构
local bimg = {}
-- 处理换行符
local lines = {}
local start = 1
while start <= #str do
local nl_pos = str:find("\n", start, true)
if nl_pos then
local line = str:sub(start, nl_pos - 1)
table.insert(lines, line)
start = nl_pos + 1
else
-- 到末尾了
local line = str:sub(start)
table.insert(lines, line)
break
end
end
for _, lineStr in ipairs(lines) do
-- 收集该行所有字符信息
local allChars = {}
for code in renderer.utf8Decode(lineStr) do
local charMap = font[code] or font[32]
local charWidth = #charMap[1]
table.insert(allChars, {code = code, map = charMap, width = charWidth})
end
if width then
-- 有宽度限制,需要处理自动换行
local segments = {}
local currentSegment = {}
local currentLineWidth = 0
-- 遍历字符
for i, charInfo in ipairs(allChars) do
-- 检查是否需要换行
if currentLineWidth + charInfo.width > width then
-- 将当前段添加到segments
if #currentSegment > 0 then
table.insert(segments, currentSegment)
end
-- 开始新段
currentSegment = {}
currentLineWidth = 0
end
-- 添加字符到当前段
table.insert(currentSegment, charInfo)
currentLineWidth = currentLineWidth + charInfo.width
end
-- 添加最后一段(如果存在)
if #currentSegment > 0 then
table.insert(segments, currentSegment)
end
-- 渲染每个段(每个段高度 = fontHeight
for _, segment in ipairs(segments) do
-- 为该段构建每行的 text/colors/bg
for row = 1, fontHeight do
local lineText = ""
local lineTextColors = ""
local lineBgColors = ""
-- 为每个字符计算颜色(如果使用字符串颜色)
local charIndexInLine = 1
for _, char in ipairs(segment) do
local fgBlit, bgBlit
if textIsString then
local colorChar = string.sub(textColor, charIndexInLine, charIndexInLine)
fgBlit = colorChar ~= "" and colorChar or "f" -- 默认白色
else
fgBlit = uniformTextBlit
end
if bgIsString then
local colorChar = string.sub(backgroundColor, charIndexInLine, charIndexInLine)
bgBlit = colorChar ~= "" and colorChar or "0" -- 默认黑色
else
bgBlit = uniformBgBlit
end
-- 处理该字符的当前行
if row <= #char.map then
local rowStr = char.map[row]
for col = 1, #rowStr do
local byte = string.byte(rowStr, col)
local displayByte
if byte < 128 then
-- 颜色反转
displayByte = byte + 128
lineText = lineText .. string.char(displayByte)
lineTextColors = lineTextColors .. bgBlit -- 原背景色变前景
lineBgColors = lineBgColors .. fgBlit -- 原前景色变背景
else
-- 正常
displayByte = byte
lineText = lineText .. string.char(displayByte)
lineTextColors = lineTextColors .. fgBlit
lineBgColors = lineBgColors .. bgBlit
end
end
end
charIndexInLine = charIndexInLine + 1
end
table.insert(bimg, {lineText, lineTextColors, lineBgColors})
end
end
else
-- 无宽度限制,整行处理
if #allChars > 0 then
-- 为该行构建每行的 text/colors/bg
for row = 1, fontHeight do
local lineText = ""
local lineTextColors = ""
local lineBgColors = ""
-- 为每个字符计算颜色(如果使用字符串颜色)
local charIndexInLine = 1
for _, char in ipairs(allChars) do
local fgBlit, bgBlit
if textIsString then
local colorChar = string.sub(textColor, charIndexInLine, charIndexInLine)
fgBlit = colorChar ~= "" and colorChar or "f" -- 默认白色
else
fgBlit = uniformTextBlit
end
if bgIsString then
local colorChar = string.sub(backgroundColor, charIndexInLine, charIndexInLine)
bgBlit = colorChar ~= "" and colorChar or "0" -- 默认黑色
else
bgBlit = uniformBgBlit
end
-- 处理该字符的当前行
if row <= #char.map then
local rowStr = char.map[row]
for col = 1, #rowStr do
local byte = string.byte(rowStr, col)
local displayByte
if byte < 128 then
-- 颜色反转
displayByte = byte + 128
lineText = lineText .. string.char(displayByte)
lineTextColors = lineTextColors .. bgBlit -- 原背景色变前景
lineBgColors = lineBgColors .. fgBlit -- 原前景色变背景
else
-- 正常
displayByte = byte
lineText = lineText .. string.char(displayByte)
lineTextColors = lineTextColors .. fgBlit
lineBgColors = lineBgColors .. bgBlit
end
end
end
charIndexInLine = charIndexInLine + 1
end
table.insert(bimg, {lineText, lineTextColors, lineBgColors})
end
else
-- 空行也需要保留
table.insert(bimg, {"", "", ""})
end
end
end
-- 如果没有内容,创建一个空行
if #bimg == 0 then
table.insert(bimg, {"", "", ""})
end
-- 将所有行包装在第一帧中
return {{unpack(bimg)}}
end
local function clampCursorPos(x, y, width, height)
return math.min(math.max(x, 1), width), math.min(math.max(y, 1), height)
end
function utf8display.write(raw_str, textColor, backgroundColor)
local str = tostring(raw_str)
str = string.gsub(str, "\n", " ") -- 替换换行为空格
local startX, startY = term.getCursorPos()
local termWidth, termHeight = term.getSize()
-- 获取 bimg无宽度限制所以不会自动换行
local bimg = utf8display.strToBimg(str, textColor, backgroundColor)
local frame = bimg[1]
if #frame == 0 then
-- 空内容,直接返回
return true, { charCount = 0, overflowX = false, overflowY = false }
end
local firstLineWidth = #frame[1][1]
local totalHeight = #frame
-- 渲染每一行
for i, row in ipairs(frame) do
local drawY = startY + i - 1
if drawY > termHeight then
-- 超出底部,跳过绘制
break
end
term.setCursorPos(startX, drawY)
term.blit(row[1], row[2], row[3])
end
-- 判断是否纵向溢出
local verticalOverflow = (startY + totalHeight - 1) > termHeight
local horizontalOverflow = firstLineWidth >= termWidth
local finalX, finalY
if verticalOverflow then
-- 情况3纵向溢出 → 回退到起点
finalX, finalY = startX, startY
elseif horizontalOverflow then
-- 情况2宽但不高 → 光标移到块下方
finalX, finalY = startX, startY + totalHeight
else
-- 情况1窄且不高 → 横向推进(仅第一行宽度)
finalX, finalY = startX + firstLineWidth, startY
end
finalX, finalY = clampCursorPos(finalX, finalY, termWidth, termHeight)
term.setCursorPos(finalX, finalY)
return true, {
startX = startX,
startY = startY,
endX = finalX,
endY = finalY,
charCount = utf8.len(str), -- 假设有 utf8.len或可估算
fontHeight = fontManager.getFontHeight(),
overflowX = horizontalOverflow,
overflowY = verticalOverflow
}
end
function utf8display.blit(raw_str, textColorStr, backgroundColorStr)
local str = tostring(raw_str)
str = string.gsub(str, "\n", " ")
local startX, startY = term.getCursorPos()
local termWidth, termHeight = term.getSize()
-- 直接传入颜色字符串
local bimg = utf8display.strToBimg(str, textColorStr, backgroundColorStr)
local frame = bimg[1]
if #frame == 0 then
return true, { charCount = 0, overflowX = false, overflowY = false }
end
local firstLineWidth = #frame[1][1]
local totalHeight = #frame
-- 渲染
for i, row in ipairs(frame) do
local drawY = startY + i - 1
if drawY > termHeight then
break
end
term.setCursorPos(startX, drawY)
term.blit(row[1], row[2], row[3])
end
local verticalOverflow = (startY + totalHeight - 1) > termHeight
local horizontalOverflow = firstLineWidth >= termWidth
local finalX, finalY
if verticalOverflow then
finalX, finalY = startX, startY
elseif horizontalOverflow then
finalX, finalY = startX, startY + totalHeight
else
finalX, finalY = startX + firstLineWidth, startY
end
finalX, finalY = clampCursorPos(finalX, finalY, termWidth, termHeight)
term.setCursorPos(finalX, finalY)
return true, {
startX = startX,
startY = startY,
endX = finalX,
endY = finalY,
charCount = utf8.len(str),
fontHeight = fontManager.getFontHeight(),
overflowX = horizontalOverflow,
overflowY = verticalOverflow
}
end
function utf8display.print(raw_str, textColor, backgroundColor)
local str = tostring(raw_str)
local startX, startY = term.getCursorPos()
local width, height = term.getSize()
-- 获取颜色
local useTextColor = textColor
local useBackgroundColor = backgroundColor
if useTextColor == nil then useTextColor = term.getTextColor() end
if useBackgroundColor == nil then useBackgroundColor = term.getBackgroundColor() end
-- 生成 bimg传入宽度以启用自动换行
local bimg = utf8display.strToBimg(str, useTextColor, useBackgroundColor, width)
local frame = bimg[1]
local totalLines = #frame
local availableLines = height - startY + 1
-- 渲染
for i, rowData in ipairs(frame) do
local drawY = startY + i - 1
if drawY >= height then term.setCursorPos(1, height) else term.setCursorPos(1, drawY) end
term.blit(rowData[1], rowData[2], rowData[3])
if drawY >= height then term.scroll(1) end
end
-- 光标移到下一行开头
local finalY = startY + totalLines
local finalX = 1
finalX, finalY = clampCursorPos(finalX, finalY, width, height)
term.setCursorPos(finalX, finalY)
return true, {
startX = startX,
startY = startY,
endX = finalX,
endY = finalY,
lineCount = totalLines
}
end
-- 自动初始化(第一次使用时)
setmetatable(utf8display, {
__index = function(self, key)
if key == "write" or key == "print" or key == "blit" then
if not utf8display.isInitialized() then
local success, err = utf8display.loadFont()
if not success then
error("自动初始化失败: " .. err)
end
end
return rawget(self, key)
end
return rawget(self, key)
end
})
return utf8display

209
utf8print12px.lua Normal file
View File

@@ -0,0 +1,209 @@
--这是一个简单的打印字符的程序他使用下方url的字体进行显示
--因为字体文件超过cc存储大小所以使用网络加载字体
--通过printUtf8("字符",文字颜色,背景颜色)来达到类似 print的效果
--示例printUtf8("你好世界! Hello Word!",colors.white,colors.lightGray)
-- 从网络加载字库
local function loadRemoteFont(url)
local response = http.get(url)
if not response then
error("无法连接到字体服务器")
end
if response.getResponseCode() ~= 200 then
error("字体服务器返回错误: " .. response.getResponseCode())
end
local content = response.readAll()
response.close()
-- 使用沙箱环境安全加载字体
local sandbox = {}
local chunk, err = load(content, "=remoteFont", "t", sandbox)
if not chunk then
error("加载字体失败: " .. err)
end
local success, result = pcall(chunk)
if not success then
error("执行字体脚本失败: " .. result)
end
return sandbox.font or sandbox[1] or result
end
-- 字体URL
local fontUrl = "https://git.liulikeji.cn/xingluo/ComputerCraft-Utf8/raw/branch/main/fonts/fusion-pixel-12px-proportional-zh_hans.lua"
local font = loadRemoteFont(fontUrl)
-- 显示单个字符的函数
local function displayChar(charMap, x, y, textColor, backgroundColor)
-- 保存原始终端颜色设置
local origTextColor = term.getTextColor()
local origBackgroundColor = term.getBackgroundColor()
-- 设置新颜色
term.setTextColor(textColor)
term.setBackgroundColor(backgroundColor)
-- 遍历字符位图的每一行
for row = 1, #charMap do
term.setCursorPos(x, y + row - 1)
local line = charMap[row]
-- 遍历行中的每个像素
for col = 1, #line do
local byte = string.byte(line, col)
-- 处理像素颜色
if byte < 128 then
-- 背景色像素:反转颜色设置
term.setTextColor(backgroundColor)
term.setBackgroundColor(textColor)
term.write(string.char(byte + 128)) -- 转换为可打印字符
else
-- 前景色像素:正常颜色设置
term.setTextColor(textColor)
term.setBackgroundColor(backgroundColor)
term.write(string.char(byte))
end
end
end
-- 恢复原始颜色设置
term.setTextColor(origTextColor)
term.setBackgroundColor(origBackgroundColor)
end
-- 显示UTF-8字符串的函数
local function displayUtf8String(str, font, x, y, textColor, backgroundColor)
-- UTF-8解码器简化版
local function utf8codes(str)
local i = 1
return function()
if i > #str then return end
local b1 = string.byte(str, i)
i = i + 1
-- 单字节字符 (ASCII)
if b1 < 0x80 then
return b1
-- 双字节字符
elseif b1 >= 0xC0 and b1 < 0xE0 then
local b2 = string.byte(str, i) or 0
i = i + 1
return (b1 - 0xC0) * 64 + (b2 - 0x80)
-- 三字节字符(中文)
elseif b1 >= 0xE0 and b1 < 0xF0 then
local b2 = string.byte(str, i) or 0
i = i + 1
local b3 = string.byte(str, i) or 0
i = i + 1
return (b1 - 0xE0) * 4096 + (b2 - 0x80) * 64 + (b3 - 0x80)
else
-- 不支持的编码,返回空格
return 32
end
end
end
local cursorX = x
-- 遍历字符串中的所有字符
for code in utf8codes(str) do
-- 获取字符位图
local charMap = font[code]
if not charMap then
-- 如果字库中没有该字符,使用空格代替
charMap = font[32] or {{"\x80"}} -- 空格字符
end
-- 显示字符
displayChar(charMap, cursorX, y, textColor, backgroundColor)
-- 移动到下一个字符位置
cursorX = cursorX + #charMap[1]
end
end
local cursorX, cursorY = 1, 1
local fontHeight = #font[32] -- 获取字体高度(使用空格字符)
-- 自定义打印函数(带自动换行和滚动)
local function printUtf8(str, textColor, backgroundColor)
local width, screenHeight = term.getSize() -- 获取终端尺寸
-- UTF-8解码器
local function utf8codes(str)
local i = 1
return function()
if i > #str then return end
local b1 = string.byte(str, i)
i = i + 1
if b1 < 0x80 then
return b1
elseif b1 >= 0xC0 and b1 < 0xE0 then
local b2 = string.byte(str, i) or 0
i = i + 1
return (b1 - 0xC0) * 64 + (b2 - 0x80)
elseif b1 >= 0xE0 and b1 < 0xF0 then
local b2 = string.byte(str, i) or 0
i = i + 1
local b3 = string.byte(str, i) or 0
i = i + 1
return (b1 - 0xE0) * 4096 + (b2 - 0x80) * 64 + (b3 - 0x80)
else
return 32 -- 不支持的字符显示为空格
end
end
end
-- 处理字符串中的每个字符
for code in utf8codes(str) do
-- 处理换行符
if code == 10 then -- \n 的 ASCII
cursorX = 1
cursorY = cursorY + fontHeight
else
local charMap = font[code] or font[32]
local charWidth = #charMap[1]
-- 检查是否需要换行
if cursorX + charWidth - 1 > width then
cursorX = 1
cursorY = cursorY + fontHeight
end
-- 检查是否需要滚动屏幕
if cursorY + fontHeight - 1 > screenHeight then
term.scroll(fontHeight)
cursorY = cursorY - fontHeight
end
-- 显示字符
displayChar(charMap, cursorX, cursorY, textColor, backgroundColor)
cursorX = cursorX + charWidth
end
end
-- 自动换行(处理完字符串后)
cursorX = 1
-- 光标应该位于下一行的顶部,而不是底部
cursorY = cursorY + fontHeight
-- 检查滚动(换行后)
if cursorY > screenHeight then
term.scroll(fontHeight)
cursorY = screenHeight - fontHeight + 1
end
end
return printUtf8