backup codes
This commit is contained in:
@@ -11,12 +11,14 @@ ASSETS_DIR="$PROJECT_ROOT/utils/assets"
|
|||||||
OUTPUT_DIR="$PROJECT_ROOT/utils/output"
|
OUTPUT_DIR="$PROJECT_ROOT/utils/output"
|
||||||
|
|
||||||
# 创建输出目录
|
# 创建输出目录
|
||||||
mkdir -p "$OUTPUT_DIR"
|
mkdir -p "$OUTPUT_DIR/py"
|
||||||
|
mkdir -p "$OUTPUT_DIR/bin"
|
||||||
|
|
||||||
# 颜色输出
|
# 颜色输出
|
||||||
RED='\033[0;31m'
|
RED='\033[0;31m'
|
||||||
GREEN='\033[0;32m'
|
GREEN='\033[0;32m'
|
||||||
YELLOW='\033[1;33m'
|
YELLOW='\033[1;33m'
|
||||||
|
BLUE='\033[0;34m'
|
||||||
NC='\033[0m' # No Color
|
NC='\033[0m' # No Color
|
||||||
|
|
||||||
# 打印带颜色的信息
|
# 打印带颜色的信息
|
||||||
@@ -32,6 +34,55 @@ print_error() {
|
|||||||
echo -e "${RED}[ERROR]${NC} $1"
|
echo -e "${RED}[ERROR]${NC} $1"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
print_blue() {
|
||||||
|
echo -e "${BLUE}[CONFIG]${NC} $1"
|
||||||
|
}
|
||||||
|
|
||||||
|
# ==============================================
|
||||||
|
# 字体配置表 - 调整这里来自定义字体设置
|
||||||
|
# 格式: "字体名称|字符集|字体文件|字号|输出名称"
|
||||||
|
# ==============================================
|
||||||
|
|
||||||
|
# 小号字体配置
|
||||||
|
SMALL_FONT_CHARS="你好世界温度湿度1234567890.,?!℃°%:"
|
||||||
|
SMALL_FONT_FILE="$ASSETS_DIR/NotoSansSC-Regular.otf"
|
||||||
|
SMALL_FONT_SIZE=14
|
||||||
|
SMALL_FONT_OUTPUT="small_font"
|
||||||
|
|
||||||
|
# 中号字体配置
|
||||||
|
MEDIUM_FONT_CHARS="你好今天天气温度湿度空气质量良一般差零一二三四五六七八九十百千万亿点°%℃ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.-:"
|
||||||
|
MEDIUM_FONT_FILE="$ASSETS_DIR/NotoSansSC-Regular.otf"
|
||||||
|
MEDIUM_FONT_SIZE=18
|
||||||
|
MEDIUM_FONT_OUTPUT="medium_font"
|
||||||
|
|
||||||
|
# 大号字体配置
|
||||||
|
LARGE_FONT_CHARS="你好今天温度湿度一二三四五六七八九十°%℃:"
|
||||||
|
LARGE_FONT_FILE="$ASSETS_DIR/NotoSansSC-Regular.otf"
|
||||||
|
LARGE_FONT_SIZE=24
|
||||||
|
LARGE_FONT_OUTPUT="large_font"
|
||||||
|
|
||||||
|
# 天气字体配置
|
||||||
|
WEATHER_FONT_CHARS="晴多云阴雨雪雷风雾霾霜露冰雹"
|
||||||
|
WEATHER_FONT_FILE="$ASSETS_DIR/NotoSansSC-Regular.otf"
|
||||||
|
WEATHER_FONT_SIZE=28
|
||||||
|
WEATHER_FONT_OUTPUT="weather_font"
|
||||||
|
|
||||||
|
# ==============================================
|
||||||
|
# 图片转换配置表 - 调整这里来自定义图片设置
|
||||||
|
# ==============================================
|
||||||
|
|
||||||
|
# 默认图片颜色深度
|
||||||
|
DEFAULT_IMAGE_COLORS=8
|
||||||
|
|
||||||
|
# 支持的图片文件扩展名
|
||||||
|
IMAGE_EXTENSIONS=("png" "jpg" "jpeg" "bmp" "gif")
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
# ==============================================
|
||||||
|
# 函数定义
|
||||||
|
# ==============================================
|
||||||
|
|
||||||
# 检查依赖
|
# 检查依赖
|
||||||
check_dependencies() {
|
check_dependencies() {
|
||||||
print_info "检查依赖..."
|
print_info "检查依赖..."
|
||||||
@@ -57,28 +108,98 @@ check_dependencies() {
|
|||||||
print_info "依赖检查完成"
|
print_info "依赖检查完成"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
# 显示字体配置
|
||||||
|
show_font_configs() {
|
||||||
|
print_blue "字体配置:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
printf "%-12s %-8s %-15s %-30s %s\n" "字体名称" "字号" "输出名称" "描述" "字符集预览"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
|
||||||
|
# 小字体
|
||||||
|
local preview="${SMALL_FONT_CHARS:0:25}"
|
||||||
|
if [[ ${#SMALL_FONT_CHARS} -gt 25 ]]; then
|
||||||
|
preview="$preview..."
|
||||||
|
fi
|
||||||
|
printf "%-12s %-8s %-15s %-30s %s\n" "小字体" "$SMALL_FONT_SIZE" "$SMALL_FONT_OUTPUT" "基本UI元素" "$preview"
|
||||||
|
|
||||||
|
# 中字体
|
||||||
|
preview="${MEDIUM_FONT_CHARS:0:25}"
|
||||||
|
if [[ ${#MEDIUM_FONT_CHARS} -gt 25 ]]; then
|
||||||
|
preview="$preview..."
|
||||||
|
fi
|
||||||
|
printf "%-12s %-8s %-15s %-30s %s\n" "中字体" "$MEDIUM_FONT_SIZE" "$MEDIUM_FONT_OUTPUT" "主要文本显示" "$preview"
|
||||||
|
|
||||||
|
# 大字体
|
||||||
|
preview="${LARGE_FONT_CHARS:0:25}"
|
||||||
|
if [[ ${#LARGE_FONT_CHARS} -gt 25 ]]; then
|
||||||
|
preview="$preview..."
|
||||||
|
fi
|
||||||
|
printf "%-12s %-8s %-15s %-30s %s\n" "大字体" "$LARGE_FONT_SIZE" "$LARGE_FONT_OUTPUT" "标题和重要信息" "$preview"
|
||||||
|
|
||||||
|
# 天气字体
|
||||||
|
preview="${WEATHER_FONT_CHARS:0:25}"
|
||||||
|
if [[ ${#WEATHER_FONT_CHARS} -gt 25 ]]; then
|
||||||
|
preview="$preview..."
|
||||||
|
fi
|
||||||
|
printf "%-12s %-30s %-8s %-15s %s\n" "天气字体" "$WEATHER_FONT_SIZE" "$WEATHER_FONT_OUTPUT" "天气图标" "$preview"
|
||||||
|
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# 显示图片配置
|
||||||
|
show_image_configs() {
|
||||||
|
print_blue "图片转换:"
|
||||||
|
echo "----------------------------------------"
|
||||||
|
echo "支持格式: ${IMAGE_EXTENSIONS[*]}"
|
||||||
|
echo "默认颜色深度: $DEFAULT_IMAGE_COLORS"
|
||||||
|
echo
|
||||||
|
echo "所有图片将使用默认颜色深度: $DEFAULT_IMAGE_COLORS"
|
||||||
|
echo
|
||||||
|
}
|
||||||
|
|
||||||
|
# 检查图片文件
|
||||||
|
is_image_file() {
|
||||||
|
local file_name="$1"
|
||||||
|
local ext="${file_name##*.}"
|
||||||
|
|
||||||
|
for supported_ext in "${IMAGE_EXTENSIONS[@]}"; do
|
||||||
|
if [[ "$ext" == "$supported_ext" ]]; then
|
||||||
|
return 0
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
return 1
|
||||||
|
}
|
||||||
|
|
||||||
|
# 获取图片颜色深度
|
||||||
|
get_image_colors() {
|
||||||
|
# 统一使用默认颜色深度
|
||||||
|
echo "$DEFAULT_IMAGE_COLORS"
|
||||||
|
}
|
||||||
|
|
||||||
# 转换字体
|
# 转换字体
|
||||||
convert_font() {
|
convert_font() {
|
||||||
local font_file="$1"
|
local font_file="$1"
|
||||||
local font_size="$2"
|
local font_size="$2"
|
||||||
local characters="$3"
|
local characters="$3"
|
||||||
local output_name="$4"
|
local output_name="$4"
|
||||||
|
local output_py_dir="$5"
|
||||||
|
local output_bin_dir="$6"
|
||||||
|
|
||||||
print_info "转换字体: $font_file (大小: $font_size)"
|
print_info "转换字体: $(basename "$font_file") (字号: $font_size)"
|
||||||
|
|
||||||
local font_name=$(basename "$font_file" | cut -d'.' -f1)
|
local font_name=$(basename "$font_file" | cut -d'.' -f1)
|
||||||
local temp_py="$OUTPUT_DIR/${font_name}_${font_size}.py"
|
local temp_py="$output_py_dir/${output_name}.py"
|
||||||
local bin_file="$OUTPUT_DIR/${output_name}.bin"
|
local bin_file="$output_bin_dir/${output_name}.bin"
|
||||||
|
|
||||||
# 步骤1: 转换为Python模块
|
# 步骤1: 转换为Python模块
|
||||||
print_info "步骤1: 将字体转换为Python模块..."
|
print_info " 步骤1: 将字体转换为Python模块..."
|
||||||
python3 "$PROJECT_ROOT/utils/font2bitmap.py" "$font_file" "$font_size" -s "$characters" > "$temp_py"
|
python3 "$PROJECT_ROOT/utils/font2bitmap.py" "$font_file" "$font_size" -s "$characters" > "$temp_py"
|
||||||
|
|
||||||
# 步骤2: 转换为二进制文件
|
# 步骤2: 转换为二进制文件
|
||||||
print_info "步骤2: 将Python模块转换为二进制文件..."
|
print_info " 步骤2: 将Python模块转换为二进制文件..."
|
||||||
python3 "$PROJECT_ROOT/utils/font2bin.py" "$temp_py" "$bin_file"
|
python3 "$PROJECT_ROOT/utils/font2bin.py" "$temp_py" "$bin_file"
|
||||||
|
|
||||||
print_info "字体转换完成: $bin_file"
|
print_info " 字体转换完成: $bin_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 转换图片
|
# 转换图片
|
||||||
@@ -86,11 +207,13 @@ convert_image() {
|
|||||||
local image_file="$1"
|
local image_file="$1"
|
||||||
local colors="$2"
|
local colors="$2"
|
||||||
local output_name="$3"
|
local output_name="$3"
|
||||||
|
local output_py_dir="$4"
|
||||||
|
local output_bin_dir="$5"
|
||||||
|
|
||||||
print_info "转换图片: $image_file (颜色深度: $colors)"
|
print_info "转换图片: $(basename "$image_file") (颜色深度: $colors)"
|
||||||
|
|
||||||
local image_name=$(basename "$image_file" | cut -d'.' -f1)
|
local temp_py="$output_py_dir/${output_name}.py"
|
||||||
local temp_py="$OUTPUT_DIR/${image_name}.py"
|
local bin_file="$output_bin_dir/${output_name}.bin"
|
||||||
|
|
||||||
# 检查imgtobitmap.py是否存在
|
# 检查imgtobitmap.py是否存在
|
||||||
if [ ! -f "$PROJECT_ROOT/utils/imgtobitmap.py" ]; then
|
if [ ! -f "$PROJECT_ROOT/utils/imgtobitmap.py" ]; then
|
||||||
@@ -99,14 +222,14 @@ convert_image() {
|
|||||||
fi
|
fi
|
||||||
|
|
||||||
# 步骤1: 转换为Python模块
|
# 步骤1: 转换为Python模块
|
||||||
print_info "步骤1: 将图片转换为Python模块..."
|
print_info " 步骤1: 将图片转换为Python模块..."
|
||||||
python3 "$PROJECT_ROOT/utils/imgtobitmap.py" "$image_file" "$colors" > "$temp_py"
|
python3 "$PROJECT_ROOT/utils/imgtobitmap.py" "$image_file" "$colors" > "$temp_py"
|
||||||
|
|
||||||
# 步骤2: 转换为二进制文件
|
# 步骤2: 转换为二进制文件
|
||||||
print_info "步骤2: 将Python模块转换为二进制文件..."
|
print_info " 步骤2: 将Python模块转换为二进制文件..."
|
||||||
python3 "$PROJECT_ROOT/utils/image2bin.py" "$temp_py" "$OUTPUT_DIR/${output_name}.bin"
|
python3 "$PROJECT_ROOT/utils/image2bin.py" "$temp_py" "$bin_file"
|
||||||
|
|
||||||
print_info "图片转换完成: $OUTPUT_DIR/${output_name}.bin"
|
print_info " 图片转换完成: $bin_file"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 主转换函数
|
# 主转换函数
|
||||||
@@ -114,52 +237,101 @@ main() {
|
|||||||
print_info "开始转换资源..."
|
print_info "开始转换资源..."
|
||||||
print_info "输出目录: $OUTPUT_DIR"
|
print_info "输出目录: $OUTPUT_DIR"
|
||||||
|
|
||||||
# 定义常用字符集
|
# 显示配置
|
||||||
CHINESE_CHARS="你好世界温度湿度天气空气质量良一般差零一二三四五六七八九十百千万亿点℃°%‰"
|
show_font_configs
|
||||||
ENGLISH_CHARS="ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789.,!?-+%:="
|
show_image_configs
|
||||||
WEATHER_CHARS="晴多云阴雨雪雷风雾霾霜露冰雹"
|
|
||||||
|
|
||||||
# 转换中文字体
|
# 确认字体文件存在
|
||||||
if [ -f "$ASSETS_DIR/NotoSansSC-Regular.otf" ]; then
|
local font_files_exist=false
|
||||||
convert_font "$ASSETS_DIR/NotoSansSC-Regular.otf" "20" "$CHINESE_CHARS" "ch_font_20"
|
|
||||||
convert_font "$ASSETS_DIR/NotoSansSC-Regular.otf" "16" "$CHINESE_CHARS" "ch_font_16"
|
if [ -f "$SMALL_FONT_FILE" ]; then
|
||||||
|
font_files_exist=true
|
||||||
|
elif [ -f "$MEDIUM_FONT_FILE" ]; then
|
||||||
|
font_files_exist=true
|
||||||
|
elif [ -f "$LARGE_FONT_FILE" ]; then
|
||||||
|
font_files_exist=true
|
||||||
|
elif [ -f "$WEATHER_FONT_FILE" ]; then
|
||||||
|
font_files_exist=true
|
||||||
|
fi
|
||||||
|
|
||||||
|
if [ "$font_files_exist" = false ]; then
|
||||||
|
print_warn "没有找到任何配置的字体文件,跳过字体转换"
|
||||||
else
|
else
|
||||||
print_warn "中文字体文件不存在: $ASSETS_DIR/NotoSansSC-Regular.otf"
|
# 转换小字体
|
||||||
|
if [ -f "$SMALL_FONT_FILE" ]; then
|
||||||
|
convert_font "$SMALL_FONT_FILE" "$SMALL_FONT_SIZE" "$SMALL_FONT_CHARS" "$SMALL_FONT_OUTPUT" "$OUTPUT_DIR/py" "$OUTPUT_DIR/bin"
|
||||||
|
else
|
||||||
|
print_warn "字体文件不存在: $SMALL_FONT_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 转换中字体
|
||||||
|
if [ -f "$MEDIUM_FONT_FILE" ]; then
|
||||||
|
convert_font "$MEDIUM_FONT_FILE" "$MEDIUM_FONT_SIZE" "$MEDIUM_FONT_CHARS" "$MEDIUM_FONT_OUTPUT" "$OUTPUT_DIR/py" "$OUTPUT_DIR/bin"
|
||||||
|
else
|
||||||
|
print_warn "字体文件不存在: $MEDIUM_FONT_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 转换大字体
|
||||||
|
if [ -f "$LARGE_FONT_FILE" ]; then
|
||||||
|
convert_font "$LARGE_FONT_FILE" "$LARGE_FONT_SIZE" "$LARGE_FONT_CHARS" "$LARGE_FONT_OUTPUT" "$OUTPUT_DIR/py" "$OUTPUT_DIR/bin"
|
||||||
|
else
|
||||||
|
print_warn "字体文件不存在: $LARGE_FONT_FILE"
|
||||||
|
fi
|
||||||
|
|
||||||
|
# 转换天气字体
|
||||||
|
if [ -f "$WEATHER_FONT_FILE" ]; then
|
||||||
|
convert_font "$WEATHER_FONT_FILE" "$WEATHER_FONT_SIZE" "$WEATHER_FONT_CHARS" "$WEATHER_FONT_OUTPUT" "$OUTPUT_DIR/py" "$OUTPUT_DIR/bin"
|
||||||
|
else
|
||||||
|
print_warn "字体文件不存在: $WEATHER_FONT_FILE"
|
||||||
|
fi
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 转换英文字体
|
# 检查并转换图片
|
||||||
if [ -f "$ASSETS_DIR/NotoSansSC-Regular.otf" ]; then
|
local image_files_exist=false
|
||||||
convert_font "$ASSETS_DIR/NotoSansSC-Regular.otf" "18" "$ENGLISH_CHARS" "en_font_18"
|
|
||||||
convert_font "$ASSETS_DIR/NotoSansSC-Regular.otf" "14" "$ENGLISH_CHARS" "en_font_14"
|
|
||||||
fi
|
|
||||||
|
|
||||||
# 转换天气字体
|
# 遍历assets目录下的所有图片文件
|
||||||
if [ -f "$ASSETS_DIR/NotoSansSC-Regular.otf" ]; then
|
for image_file in "$ASSETS_DIR"/*; do
|
||||||
convert_font "$ASSETS_DIR/NotoSansSC-Regular.otf" "24" "$WEATHER_CHARS$CHINESE_CHARS$ENGLISH_CHARS" "weather_font_24"
|
if [ -f "$image_file" ]; then
|
||||||
fi
|
local file_name=$(basename "$image_file")
|
||||||
|
|
||||||
# 转换图片
|
if is_image_file "$file_name"; then
|
||||||
if [ -f "$ASSETS_DIR/python-logo.png" ]; then
|
image_files_exist=true
|
||||||
convert_image "$ASSETS_DIR/python-logo.png" "4" "python_logo"
|
break
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
|
|
||||||
|
if [ "$image_files_exist" = false ]; then
|
||||||
|
print_warn "assets目录下没有找到支持的图片文件,跳过图片转换"
|
||||||
else
|
else
|
||||||
print_warn "Python Logo图片不存在: $ASSETS_DIR/python-logo.png"
|
print_info "开始转换图片文件..."
|
||||||
fi
|
|
||||||
|
|
||||||
if [ -f "$ASSETS_DIR/boot.jpg" ]; then
|
# 遍历assets目录下的所有图片文件
|
||||||
convert_image "$ASSETS_DIR/boot.jpg" "4" "boot_image"
|
for image_file in "$ASSETS_DIR"/*; do
|
||||||
else
|
if [ -f "$image_file" ]; then
|
||||||
print_warn "启动图片不存在: $ASSETS_DIR/boot.jpg"
|
local file_name=$(basename "$image_file")
|
||||||
|
|
||||||
|
if is_image_file "$file_name"; then
|
||||||
|
local image_name="${file_name%.*}"
|
||||||
|
local colors=$(get_image_colors "$file_name")
|
||||||
|
|
||||||
|
convert_image "$image_file" "$colors" "$image_name" "$OUTPUT_DIR/py" "$OUTPUT_DIR/bin"
|
||||||
|
fi
|
||||||
|
fi
|
||||||
|
done
|
||||||
fi
|
fi
|
||||||
|
|
||||||
# 显示输出文件信息
|
# 显示输出文件信息
|
||||||
print_info "转换完成! 生成的二进制文件:"
|
print_info "转换完成! 生成的文件:"
|
||||||
ls -lh "$OUTPUT_DIR"/*.bin 2>/dev/null || print_warn "没有生成二进制文件"
|
|
||||||
|
|
||||||
print_info "信息文件:"
|
echo -e "\n${GREEN}=== 二进制文件 ===${NC}"
|
||||||
ls -lh "$OUTPUT_DIR"/*.info 2>/dev/null || print_warn "没有生成信息文件"
|
ls -lh "$OUTPUT_DIR/bin"/*.bin 2>/dev/null || print_warn "没有生成二进制文件"
|
||||||
|
|
||||||
print_info "Python模块:"
|
echo -e "\n${GREEN}=== 信息文件 ===${NC}"
|
||||||
ls -lh "$OUTPUT_DIR"/*.py 2>/dev/null || print_warn "没有生成Python模块"
|
ls -lh "$OUTPUT_DIR/bin"/*.info 2>/dev/null || print_warn "没有生成信息文件"
|
||||||
|
|
||||||
|
echo -e "\n${GREEN}=== Python模块 ===${NC}"
|
||||||
|
ls -lh "$OUTPUT_DIR/py"/*.py 2>/dev/null || print_warn "没有生成Python模块"
|
||||||
|
|
||||||
print_info "转换脚本执行完成!"
|
print_info "转换脚本执行完成!"
|
||||||
}
|
}
|
||||||
@@ -172,13 +344,15 @@ show_help() {
|
|||||||
echo " -h, --help 显示此帮助信息"
|
echo " -h, --help 显示此帮助信息"
|
||||||
echo ""
|
echo ""
|
||||||
echo "此脚本将转换以下资源:"
|
echo "此脚本将转换以下资源:"
|
||||||
echo " 1. 中文字体 - 转换为不同大小的二进制字体文件"
|
echo " 1. 字体 - 根据配置表转换为不同大小的二进制字体文件"
|
||||||
echo " 2. 英文字体 - 转换为不同大小的二进制字体文件"
|
echo " 2. 图片 - 遍历assets目录下所有支持的图片文件,转换为二进制图片文件"
|
||||||
echo " 3. 天气图标字体 - 转换为二进制字体文件"
|
|
||||||
echo " 4. 图片 - 转换为二进制图片文件"
|
|
||||||
echo ""
|
echo ""
|
||||||
echo "输入文件应位于: $ASSETS_DIR"
|
echo "输入文件应位于: $ASSETS_DIR"
|
||||||
echo "输出文件将保存到: $OUTPUT_DIR"
|
echo "输出文件将保存到:"
|
||||||
|
echo " - Python模块: $OUTPUT_DIR/py"
|
||||||
|
echo " - 二进制文件: $OUTPUT_DIR/bin"
|
||||||
|
echo ""
|
||||||
|
echo "字体和图片配置可在脚本顶部的配置表中调整"
|
||||||
}
|
}
|
||||||
|
|
||||||
# 解析命令行参数
|
# 解析命令行参数
|
||||||
|
|||||||
@@ -29,13 +29,21 @@ def read_image_module(module_path):
|
|||||||
spec.loader.exec_module(image_module)
|
spec.loader.exec_module(image_module)
|
||||||
|
|
||||||
# Extract image metadata and data
|
# Extract image metadata and data
|
||||||
|
bitmap_obj = image_module._bitmap
|
||||||
|
|
||||||
|
try:
|
||||||
|
bitmap_bytes = bytes(bitmap_obj)
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error converting bitmap to bytes: {e}", file=sys.stderr)
|
||||||
|
bitmap_bytes = b"\x00" # Fallback
|
||||||
|
|
||||||
image_data = {
|
image_data = {
|
||||||
"width": image_module.WIDTH,
|
"width": image_module.WIDTH,
|
||||||
"height": image_module.HEIGHT,
|
"height": image_module.HEIGHT,
|
||||||
"colors": image_module.COLORS,
|
"colors": image_module.COLORS,
|
||||||
"bpp": image_module.BPP,
|
"bpp": image_module.BPP,
|
||||||
"palette": getattr(image_module, "PALETTE", []),
|
"palette": getattr(image_module, "PALETTE", []),
|
||||||
"bitmap": bytes(image_module._bitmap),
|
"bitmap": bitmap_bytes,
|
||||||
}
|
}
|
||||||
|
|
||||||
return image_data
|
return image_data
|
||||||
@@ -52,14 +60,21 @@ def write_binary_file(image_data, output_path):
|
|||||||
f.write(b"IMG ") # Magic number ("IMG " with trailing space)
|
f.write(b"IMG ") # Magic number ("IMG " with trailing space)
|
||||||
f.write(struct.pack("H", image_data["width"])) # Image width
|
f.write(struct.pack("H", image_data["width"])) # Image width
|
||||||
f.write(struct.pack("H", image_data["height"])) # Image height
|
f.write(struct.pack("H", image_data["height"])) # Image height
|
||||||
f.write(struct.pack("B", image_data["colors"])) # Number of colors
|
# Limit colors to ubyte range (0-255)
|
||||||
|
colors_val = min(image_data["colors"], 255)
|
||||||
|
f.write(struct.pack("B", colors_val)) # Number of colors
|
||||||
f.write(struct.pack("B", image_data["bpp"])) # Bits per pixel
|
f.write(struct.pack("B", image_data["bpp"])) # Bits per pixel
|
||||||
|
|
||||||
# Write palette
|
# Write palette
|
||||||
if image_data["palette"]:
|
if image_data["palette"]:
|
||||||
f.write(struct.pack("B", len(image_data["palette"]))) # Palette length
|
palette_length = min(
|
||||||
for color in image_data["palette"]:
|
len(image_data["palette"]), 255
|
||||||
f.write(struct.pack("H", color)) # RGB565 color value
|
) # Limit to ubyte range
|
||||||
|
f.write(struct.pack("B", palette_length)) # Palette length
|
||||||
|
for i in range(palette_length):
|
||||||
|
f.write(
|
||||||
|
struct.pack("H", image_data["palette"][i])
|
||||||
|
) # RGB565 color value
|
||||||
else:
|
else:
|
||||||
f.write(struct.pack("B", 0)) # Zero palette length
|
f.write(struct.pack("B", 0)) # Zero palette length
|
||||||
|
|
||||||
|
|||||||
@@ -1,110 +1,156 @@
|
|||||||
#!python3
|
#!/usr/bin/env python3
|
||||||
'''
|
# -*- coding: utf-8 -*-
|
||||||
Convert image file to python module for use with blit_bitmap.
|
"""
|
||||||
|
imgtobitmap.py - Convert image files to Python bitmap modules for st7789_mpy
|
||||||
|
|
||||||
Usage imgtobitmap image_file bits_per_pixel >image.py
|
This script converts image files (PNG, JPG, etc.) to Python bitmap modules
|
||||||
'''
|
compatible with the st7789_mpy library and the image2bin.py conversion script.
|
||||||
|
The output modules can be used with st7789.bitmap() method.
|
||||||
|
|
||||||
|
Usage:
|
||||||
|
python imgtobitmap.py <image_file> <colors>
|
||||||
|
|
||||||
|
Example:
|
||||||
|
python imgtobitmap.py logo.png 4 > logo.py
|
||||||
|
"""
|
||||||
|
|
||||||
import sys
|
|
||||||
from PIL import Image
|
|
||||||
import argparse
|
import argparse
|
||||||
|
import sys
|
||||||
|
|
||||||
|
from PIL import Image
|
||||||
|
|
||||||
|
|
||||||
|
def convert_image_to_bitmap(image_path, colors):
|
||||||
|
"""
|
||||||
|
Convert an image file to a Python bitmap module
|
||||||
|
|
||||||
|
Args:
|
||||||
|
image_path (str): Path to the input image file
|
||||||
|
colors (int): Number of colors in the output (must be a power of 2, max 256)
|
||||||
|
"""
|
||||||
|
try:
|
||||||
|
# Validate colors
|
||||||
|
if colors <= 0 or (colors & (colors - 1)) != 0 or colors > 256:
|
||||||
|
print(f"Error: Colors must be a power of 2 between 1 and 256, got {colors}")
|
||||||
|
return False
|
||||||
|
|
||||||
|
# Calculate bits per pixel
|
||||||
|
bpp = 0
|
||||||
|
while (1 << bpp) < colors:
|
||||||
|
bpp += 1
|
||||||
|
|
||||||
|
# Load image
|
||||||
|
img = Image.open(image_path)
|
||||||
|
|
||||||
|
# Convert to palette image with specified number of colors
|
||||||
|
img = img.convert("P", palette=Image.Palette.ADAPTIVE, colors=colors)
|
||||||
|
palette = img.getpalette()
|
||||||
|
|
||||||
|
# Get actual number of colors
|
||||||
|
palette_colors = len(palette) // 3
|
||||||
|
bits_required = palette_colors.bit_length()
|
||||||
|
|
||||||
|
if bits_required < bpp:
|
||||||
|
print(
|
||||||
|
f"\nNOTE: Quantization reduced colors to {palette_colors} from the {colors} "
|
||||||
|
f"requested, reconverting using {bits_required} bit per pixel could save memory.\n",
|
||||||
|
file=sys.stderr,
|
||||||
|
)
|
||||||
|
|
||||||
|
# For all the colors in the palette
|
||||||
|
colors_hex = []
|
||||||
|
|
||||||
|
for color in range(palette_colors):
|
||||||
|
# Get RGB values and convert to 565
|
||||||
|
color565 = (
|
||||||
|
((palette[color * 3] & 0xF8) << 8)
|
||||||
|
| ((palette[color * 3 + 1] & 0xFC) << 3)
|
||||||
|
| (palette[color * 3 + 2] & 0xF8) >> 3
|
||||||
|
)
|
||||||
|
|
||||||
|
# Swap bytes in 565
|
||||||
|
color_val = ((color565 & 0xFF) << 8) + ((color565 & 0xFF00) >> 8)
|
||||||
|
|
||||||
|
# Append byte swapped 565 color to colors
|
||||||
|
colors_hex.append(f"{color_val:04x}")
|
||||||
|
|
||||||
|
# Generate bitmap data
|
||||||
|
image_bitstring = ""
|
||||||
|
|
||||||
|
# Run through the image and create a string with the ascii binary
|
||||||
|
# representation of the color of each pixel.
|
||||||
|
for y in range(img.height):
|
||||||
|
for x in range(img.width):
|
||||||
|
pixel = img.getpixel((x, y))
|
||||||
|
bstring = "".join(
|
||||||
|
"1" if (pixel & (1 << bit - 1)) else "0"
|
||||||
|
for bit in range(bpp, 0, -1)
|
||||||
|
)
|
||||||
|
image_bitstring += bstring
|
||||||
|
|
||||||
|
bitmap_bits = len(image_bitstring)
|
||||||
|
max_colors = 1 << bpp
|
||||||
|
|
||||||
|
# Create python source with image parameters
|
||||||
|
print(f"HEIGHT = {img.height}")
|
||||||
|
print(f"WIDTH = {img.width}")
|
||||||
|
print(f"COLORS = {max_colors}")
|
||||||
|
print(f"BPP = {bpp}")
|
||||||
|
print("PALETTE = [", sep="", end="")
|
||||||
|
|
||||||
|
for color, rgb in enumerate(colors_hex):
|
||||||
|
if color:
|
||||||
|
print(",", sep="", end="")
|
||||||
|
print(f"0x{rgb}", sep="", end="")
|
||||||
|
print("]")
|
||||||
|
|
||||||
|
# Run though image bit string 8 bits at a time
|
||||||
|
# and create python array source for memoryview
|
||||||
|
|
||||||
|
print("_bitmap =\\", sep="")
|
||||||
|
print("b'", sep="", end="")
|
||||||
|
|
||||||
|
for i in range(0, bitmap_bits, 8):
|
||||||
|
# Limit line length for readability
|
||||||
|
if i and i % (16 * 8) == 0:
|
||||||
|
print("'\\\nb'", end="", sep="")
|
||||||
|
|
||||||
|
value = image_bitstring[i : i + 8]
|
||||||
|
color = int(value, 2)
|
||||||
|
print(f"\\x{color:02x}", sep="", end="")
|
||||||
|
|
||||||
|
print("'")
|
||||||
|
|
||||||
|
return True
|
||||||
|
|
||||||
|
except Exception as e:
|
||||||
|
print(f"Error processing image: {e}", file=sys.stderr)
|
||||||
|
return False
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
|
|
||||||
parser = argparse.ArgumentParser(
|
parser = argparse.ArgumentParser(
|
||||||
prog='imgtobitmap',
|
prog="imgtobitmap",
|
||||||
description='Convert image file to python module for use with bitmap method.')
|
description="Convert image file to python module for use with bitmap method.",
|
||||||
|
)
|
||||||
|
|
||||||
|
parser.add_argument("image_file", help="Name of file containing image to convert")
|
||||||
|
|
||||||
parser.add_argument(
|
parser.add_argument(
|
||||||
'image_file',
|
"bits_per_pixel",
|
||||||
help='Name of file containing image to convert')
|
|
||||||
|
|
||||||
parser.add_argument(
|
|
||||||
'bits_per_pixel',
|
|
||||||
type=int,
|
type=int,
|
||||||
choices=range(1, 9),
|
choices=range(1, 9),
|
||||||
default=1,
|
default=1,
|
||||||
metavar='bits_per_pixel',
|
metavar="bits_per_pixel",
|
||||||
help='The number of bits to use per pixel (1..8)')
|
help="The number of bits to use per pixel (1..8)",
|
||||||
|
)
|
||||||
|
|
||||||
args = parser.parse_args()
|
args = parser.parse_args()
|
||||||
bits = args.bits_per_pixel
|
bits = args.bits_per_pixel
|
||||||
colors_requested = 1 << bits
|
colors = 1 << bits
|
||||||
img = Image.open(args.image_file)
|
|
||||||
img = img.convert("P", palette=Image.Palette.ADAPTIVE, colors=colors_requested)
|
|
||||||
palette = img.getpalette() # Make copy of palette colors
|
|
||||||
palette_colors = len(palette) // 3
|
|
||||||
bits_required = palette_colors.bit_length()
|
|
||||||
if (bits_required < bits):
|
|
||||||
print(f'\nNOTE: Quantization reduced colors to {palette_colors} from the {colors_requested} '
|
|
||||||
f'requested, reconverting using {bits_required} bit per pixel could save memory.\n''', file=sys.stderr)
|
|
||||||
|
|
||||||
# For all the colors in the palette
|
return 0 if convert_image_to_bitmap(args.image_file, colors) else 1
|
||||||
colors = []
|
|
||||||
|
|
||||||
for color in range(palette_colors):
|
|
||||||
|
|
||||||
# get rgb values and convert to 565
|
|
||||||
color565 = (
|
|
||||||
((palette[color*3] & 0xF8) << 8)
|
|
||||||
| ((palette[color*3+1] & 0xFC) << 3)
|
|
||||||
| ((palette[color*3+2] & 0xF8) >> 3))
|
|
||||||
|
|
||||||
# swap bytes in 565
|
|
||||||
color = ((color565 & 0xff) << 8) + ((color565 & 0xff00) >> 8)
|
|
||||||
|
|
||||||
# append byte swapped 565 color to colors
|
|
||||||
colors.append(f'{color:04x}')
|
|
||||||
|
|
||||||
image_bitstring = ''
|
|
||||||
max_colors = 1 << bits
|
|
||||||
|
|
||||||
# Run through the image and create a string with the ascii binary
|
|
||||||
# representation of the color of each pixel.
|
|
||||||
for y in range(img.height):
|
|
||||||
for x in range(img.width):
|
|
||||||
pixel = img.getpixel((x, y))
|
|
||||||
color = pixel
|
|
||||||
bstring = ''.join(
|
|
||||||
'1' if (color & (1 << bit - 1)) else '0'
|
|
||||||
for bit in range(bits, 0, -1)
|
|
||||||
)
|
|
||||||
|
|
||||||
image_bitstring += bstring
|
|
||||||
|
|
||||||
bitmap_bits = len(image_bitstring)
|
|
||||||
|
|
||||||
# Create python source with image parameters
|
|
||||||
print(f'HEIGHT = {img.height}')
|
|
||||||
print(f'WIDTH = {img.width}')
|
|
||||||
print(f'COLORS = {max_colors}')
|
|
||||||
print(f'BITS = {bitmap_bits}')
|
|
||||||
print(f'BPP = {bits}')
|
|
||||||
print('PALETTE = [', sep='', end='')
|
|
||||||
|
|
||||||
for color, rgb in enumerate(colors):
|
|
||||||
if color:
|
|
||||||
print(',', sep='', end='')
|
|
||||||
print(f'0x{rgb}', sep='', end='')
|
|
||||||
print("]")
|
|
||||||
|
|
||||||
# Run though image bit string 8 bits at a time
|
|
||||||
# and create python array source for memoryview
|
|
||||||
|
|
||||||
print("_bitmap =\\", sep='')
|
|
||||||
print("b'", sep='', end='')
|
|
||||||
|
|
||||||
for i in range(0, bitmap_bits, 8):
|
|
||||||
|
|
||||||
if i and i % (16*8) == 0:
|
|
||||||
print("'\\\nb'", end='', sep='')
|
|
||||||
|
|
||||||
value = image_bitstring[i:i+8]
|
|
||||||
color = int(value, 2)
|
|
||||||
print(f'\\x{color:02x}', sep='', end='')
|
|
||||||
|
|
||||||
print("'\nBITMAP = memoryview(_bitmap)")
|
|
||||||
|
|
||||||
|
|
||||||
main()
|
if __name__ == "__main__":
|
||||||
|
sys.exit(main())
|
||||||
|
|||||||
Reference in New Issue
Block a user