712db9c597
Add B1 directory-type seed mechanism to AGENT_WORKSPACE_SEED_FILES: - Extended agentWorkspaceFilesForRun with collectDirectorySeedFiles helper - arm2d-skill (SKILL.md + references/ + python/) auto-injected to .agents/skills/arm2d-skill/ - Enables Code Agent to follow ARM-2D constraints and call asset scripts in case Skill source: https://github.com/notLabyet/HWLabOA
812 lines
28 KiB
Python
812 lines
28 KiB
Python
#!/usr/bin/python
|
||
# -*- coding: utf-8 -*-
|
||
|
||
# *************************************************************************************************
|
||
# Arm 2D project
|
||
# @file img2c.py
|
||
# @brief image to C-array converter
|
||
#
|
||
# *************************************************************************************************
|
||
#
|
||
# * Copyright (C) 2010-2022 ARM Limited or its affiliates. All rights reserved.
|
||
# *
|
||
# * SPDX-License-Identifier: Apache-2.0
|
||
# *
|
||
# * Licensed under the Apache License, Version 2.0 (the License); you may
|
||
# * not use this file except in compliance with the License.
|
||
# * You may obtain a copy of the License at
|
||
# *
|
||
# * www.apache.org/licenses/LICENSE-2.0
|
||
# *
|
||
# * Unless required by applicable law or agreed to in writing, software
|
||
# * distributed under the License is distributed on an AS IS BASIS, WITHOUT
|
||
# * WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
|
||
# * See the License for the specific language governing permissions and
|
||
# * limitations under the License.
|
||
# */
|
||
|
||
import sys
|
||
from PIL import Image
|
||
import numpy as np
|
||
import time;
|
||
import argparse
|
||
import os
|
||
|
||
# Add current script directory to path for imports
|
||
script_dir = os.path.dirname(os.path.abspath(__file__))
|
||
if script_dir not in sys.path:
|
||
sys.path.insert(0, script_dir)
|
||
sys.path.insert(0, '.') # Also add current directory
|
||
|
||
# Import zhRGB565 compression modules
|
||
try:
|
||
from __img2c_zhRGB565 import (
|
||
encode_rgb565_rle_only,
|
||
generate_c_array as generate_rle_c_array,
|
||
encode_rgb565_rle_diff,
|
||
generate_c_array as generate_diff_c_array
|
||
)
|
||
ZHRGB565_AVAILABLE = True
|
||
except ImportError:
|
||
ZHRGB565_AVAILABLE = False
|
||
|
||
# Import LMSK compression modules
|
||
try:
|
||
from __img2c_lmsk import (
|
||
load_mask_from_image,
|
||
encode_lmsk,
|
||
)
|
||
LMSK_AVAILABLE = True
|
||
except ImportError:
|
||
LMSK_AVAILABLE = False
|
||
|
||
hdr="""
|
||
/* Generated on {0} from {1} */
|
||
/* Re-sized : {2} */
|
||
/* Rotated : {3} deg */
|
||
|
||
#include "arm_2d.h"
|
||
|
||
#if defined(__clang__)
|
||
# pragma clang diagnostic push
|
||
# pragma clang diagnostic ignored "-Wunknown-warning-option"
|
||
# pragma clang diagnostic ignored "-Wreserved-identifier"
|
||
# pragma clang diagnostic ignored "-Wmissing-variable-declarations"
|
||
# pragma clang diagnostic ignored "-Wcast-qual"
|
||
#elif defined(__IS_COMPILER_ARM_COMPILER_5__)
|
||
# pragma diag_suppress=1296
|
||
#endif
|
||
|
||
"""
|
||
|
||
tailDataGRAY8="""
|
||
|
||
extern const arm_2d_tile_t c_tile{0}GRAY8;
|
||
ARM_SECTION(\"arm2d.tile.c_tile{0}GRAY8\")
|
||
const arm_2d_tile_t c_tile{0}GRAY8 = {{
|
||
.tRegion = {{
|
||
.tSize = {{
|
||
.iWidth = {1},
|
||
.iHeight = {2},
|
||
}},
|
||
}},
|
||
.tInfo = {{
|
||
.bIsRoot = true,
|
||
.bHasEnforcedColour = true,
|
||
.tColourInfo = {{
|
||
.chScheme = ARM_2D_COLOUR_GRAY8,
|
||
}},
|
||
}},
|
||
{3}c_bmp{0}GRAY8,
|
||
}};
|
||
|
||
"""
|
||
|
||
tailDataRGB565="""
|
||
|
||
extern const arm_2d_tile_t c_tile{0}RGB565;
|
||
ARM_SECTION(\"arm2d.tile.c_tile{0}RGB565\")
|
||
const arm_2d_tile_t c_tile{0}RGB565 = {{
|
||
.tRegion = {{
|
||
.tSize = {{
|
||
.iWidth = {1},
|
||
.iHeight = {2},
|
||
}},
|
||
}},
|
||
.tInfo = {{
|
||
.bIsRoot = true,
|
||
.bHasEnforcedColour = true,
|
||
.tColourInfo = {{
|
||
.chScheme = ARM_2D_COLOUR_RGB565,
|
||
}},
|
||
}},
|
||
{3}c_bmp{0}RGB565,
|
||
}};
|
||
|
||
"""
|
||
|
||
tailDataRGB888="""
|
||
|
||
extern const arm_2d_tile_t c_tile{0}CCCN888;
|
||
|
||
ARM_SECTION(\"arm2d.tile.c_tile{0}CCCN888\")
|
||
const arm_2d_tile_t c_tile{0}CCCN888 = {{
|
||
.tRegion = {{
|
||
.tSize = {{
|
||
.iWidth = {1},
|
||
.iHeight = {2},
|
||
}},
|
||
}},
|
||
.tInfo = {{
|
||
.bIsRoot = true,
|
||
.bHasEnforcedColour = true,
|
||
.tColourInfo = {{
|
||
.chScheme = ARM_2D_COLOUR_RGB888,
|
||
}},
|
||
}},
|
||
{3}c_bmp{0}CCCN888,
|
||
}};
|
||
|
||
"""
|
||
|
||
tailDataRGBA8888="""
|
||
|
||
extern const arm_2d_tile_t c_tile{0}CCCA8888;
|
||
|
||
ARM_SECTION(\"arm2d.tile.c_tile{0}CCCA8888\")
|
||
const arm_2d_tile_t c_tile{0}CCCA8888 = {{
|
||
.tRegion = {{
|
||
.tSize = {{
|
||
.iWidth = {1},
|
||
.iHeight = {2},
|
||
}},
|
||
}},
|
||
.tInfo = {{
|
||
.bIsRoot = true,
|
||
.bHasEnforcedColour = true,
|
||
.tColourInfo = {{
|
||
.chScheme = ARM_2D_COLOUR_BGRA8888,
|
||
}},
|
||
}},
|
||
{3}c_bmp{0}CCCA8888,
|
||
}};
|
||
|
||
"""
|
||
|
||
|
||
|
||
tailAlpha="""
|
||
|
||
extern const arm_2d_tile_t c_tile{0}Mask;
|
||
|
||
ARM_SECTION(\"arm2d.tile.c_tile{0}Mask\")
|
||
const arm_2d_tile_t c_tile{0}Mask = {{
|
||
.tRegion = {{
|
||
.tSize = {{
|
||
.iWidth = {1},
|
||
.iHeight = {2},
|
||
}},
|
||
}},
|
||
.tInfo = {{
|
||
.bIsRoot = true,
|
||
.bHasEnforcedColour = true,
|
||
.tColourInfo = {{
|
||
.chScheme = ARM_2D_COLOUR_MASK_A8,
|
||
}},
|
||
}},
|
||
.pchBuffer = (uint8_t *)c_bmp{0}Alpha,
|
||
}};
|
||
"""
|
||
|
||
tail1BitAlpha="""
|
||
|
||
extern const arm_2d_tile_t c_tile{0}A1Mask;
|
||
|
||
ARM_SECTION(\"arm2d.tile.c_tile{0}A1Mask\")
|
||
const arm_2d_tile_t c_tile{0}A1Mask = {{
|
||
.tRegion = {{
|
||
.tSize = {{
|
||
.iWidth = {1},
|
||
.iHeight = {2},
|
||
}},
|
||
}},
|
||
.tInfo = {{
|
||
.bIsRoot = true,
|
||
.bHasEnforcedColour = true,
|
||
.tColourInfo = {{
|
||
.chScheme = ARM_2D_COLOUR_MASK_A1,
|
||
}},
|
||
}},
|
||
.pchBuffer = (uint8_t *)c_bmp{0}A1Alpha,
|
||
}};
|
||
"""
|
||
|
||
|
||
tail2BitAlpha="""
|
||
|
||
extern const arm_2d_tile_t c_tile{0}A2Mask;
|
||
|
||
ARM_SECTION(\"arm2d.tile.c_tile{0}A2Mask\")
|
||
const arm_2d_tile_t c_tile{0}A2Mask = {{
|
||
.tRegion = {{
|
||
.tSize = {{
|
||
.iWidth = {1},
|
||
.iHeight = {2},
|
||
}},
|
||
}},
|
||
.tInfo = {{
|
||
.bIsRoot = true,
|
||
.bHasEnforcedColour = true,
|
||
.tColourInfo = {{
|
||
.chScheme = ARM_2D_COLOUR_MASK_A2,
|
||
}},
|
||
}},
|
||
.pchBuffer = (uint8_t *)c_bmp{0}A2Alpha,
|
||
}};
|
||
"""
|
||
|
||
tail4BitAlpha="""
|
||
|
||
extern const arm_2d_tile_t c_tile{0}A4Mask;
|
||
|
||
ARM_SECTION(\"arm2d.tile.c_tile{0}A4Mask\")
|
||
const arm_2d_tile_t c_tile{0}A4Mask = {{
|
||
.tRegion = {{
|
||
.tSize = {{
|
||
.iWidth = {1},
|
||
.iHeight = {2},
|
||
}},
|
||
}},
|
||
.tInfo = {{
|
||
.bIsRoot = true,
|
||
.bHasEnforcedColour = true,
|
||
.tColourInfo = {{
|
||
.chScheme = ARM_2D_COLOUR_MASK_A4,
|
||
}},
|
||
}},
|
||
.pchBuffer = (uint8_t *)c_bmp{0}A4Alpha,
|
||
}};
|
||
"""
|
||
|
||
|
||
tailAlpha2="""
|
||
|
||
extern const arm_2d_tile_t c_tile{0}Mask2;
|
||
|
||
ARM_SECTION(\"arm2d.tile.c_tile{0}Mask2\")
|
||
const arm_2d_tile_t c_tile{0}Mask2 = {{
|
||
.tRegion = {{
|
||
.tSize = {{
|
||
.iWidth = {1},
|
||
.iHeight = {2},
|
||
}},
|
||
}},
|
||
.tInfo = {{
|
||
.bIsRoot = true,
|
||
.bHasEnforcedColour = true,
|
||
.tColourInfo = {{
|
||
.chScheme = ARM_2D_CHANNEL_8in32,
|
||
}},
|
||
}},
|
||
.nAddress = ((intptr_t)c_bmp{0}CCCA8888) + 3,
|
||
}};
|
||
"""
|
||
|
||
|
||
tail="""
|
||
|
||
#if defined(__clang__)
|
||
# pragma clang diagnostic pop
|
||
#elif defined(__IS_COMPILER_ARM_COMPILER_5__)
|
||
# pragma diag_warning=1296
|
||
#endif
|
||
|
||
"""
|
||
|
||
def main(argv):
|
||
|
||
parser = argparse.ArgumentParser(description='image to C array converter (v2.1.0)')
|
||
|
||
parser.add_argument('-i', nargs='?', type = str, required=False, help="Input file (png, bmp, etc..)")
|
||
parser.add_argument('-o', nargs='?', type = str, required=False, help="output C file containing RGB56/RGB888/Gray8 and alpha values arrays")
|
||
|
||
parser.add_argument('--name', nargs='?',type = str, required=False, help="A specified array name")
|
||
parser.add_argument('--format', nargs='?',type = str, default="all", help="RGB Format (rgb565, rgb32, gray8, mask, zhRGB565, lmsk, all)")
|
||
parser.add_argument('--dim', nargs=2,type = int, help="Resize the image with the given width and height")
|
||
parser.add_argument('--rot', nargs='?',type = float, default=0.0, help="Rotate the image with the given angle in degrees")
|
||
parser.add_argument('--a1', action='store_true', help="Generate 1bit alpha-mask")
|
||
parser.add_argument('--a2', action='store_true', help="Generate 2bit alpha-mask")
|
||
parser.add_argument('--a4', action='store_true', help="Generate 4bit alpha-mask")
|
||
parser.add_argument('--a8', action='store_true', help="Generate 8bit alpha-mask")
|
||
parser.add_argument('--border', action='store_true', help="Add a 1pix border")
|
||
parser.add_argument("--no-gradient", action="store_true", help="Disable gradient detection algorithm. (Repeat>62 still uses GRADIENT tag like C encoder.)")
|
||
parser.add_argument("--gradient-tolerant", type=int, default=2, choices=[0, 1, 2, 3], help="Gradient tolerant (0~3). Default: 2.")
|
||
parser.add_argument("--alpha-bits", type=int, default=6, choices=[1, 2, 3, 4, 5, 6, 7, 8], help="Alpha Bits (1~8). Default: 6.")
|
||
|
||
args = parser.parse_args()
|
||
|
||
if args.i == None or args.i == "" :
|
||
parser.print_help()
|
||
exit(1)
|
||
inputfile = args.i;
|
||
basename = os.path.basename(inputfile).split('.')[0];
|
||
|
||
|
||
outputfile = args.o
|
||
if outputfile == None or outputfile == "":
|
||
outputfile = basename + ".c"
|
||
|
||
arr_name = args.name
|
||
if arr_name == None or arr_name == "":
|
||
arr_name = basename
|
||
|
||
if args.format != 'rgb565' and \
|
||
args.format != 'rgb32' and \
|
||
args.format != 'gray8' and \
|
||
args.format != 'mask' and \
|
||
args.format != 'zhRGB565' and \
|
||
args.format != 'lmsk' and \
|
||
args.format != 'all':
|
||
parser.print_help()
|
||
exit(1)
|
||
|
||
if args.a1:
|
||
args.format = ''
|
||
|
||
if args.a2:
|
||
args.format = ''
|
||
|
||
if args.a4:
|
||
args.format = ''
|
||
|
||
if args.a8:
|
||
args.format = ''
|
||
|
||
try:
|
||
image = Image.open(inputfile)
|
||
except FileNotFoundError:
|
||
print("Cannot open image file %s" % (inputfile))
|
||
sys.exit(2)
|
||
|
||
|
||
# rotation
|
||
if args.rot != 0.0:
|
||
image = image.rotate(args.rot)
|
||
|
||
|
||
# resizing
|
||
resized = False
|
||
if args.dim != None:
|
||
image = image.resize((args.dim[0], args.dim[1]))
|
||
resized = True
|
||
|
||
|
||
mode = image.mode
|
||
|
||
# add 1 pixel border
|
||
if args.border:
|
||
data = np.asarray(image)
|
||
pad_val = 0
|
||
if data.ndim == 2:
|
||
padded = np.pad(data, 1, mode='constant', constant_values=pad_val)
|
||
else:
|
||
padded = np.pad(data, ((1, 1), (1, 1), (0, 0)),
|
||
mode='constant', constant_values=pad_val)
|
||
image = Image.fromarray(padded, mode=mode)
|
||
|
||
# Modes supported by Pillow
|
||
|
||
# 1 (1-bit pixels, black and white, stored with one pixel per byte), the value is in 0-1.
|
||
# L (8-bit pixels, black and white), the value is in 0-255.
|
||
# P (8-bit pixels, mapped to any other mode using a color palette), the value is in 0-255.
|
||
# RGB (3×8-bit pixels, true color), the value is in [0-255, 0-255, 0-255].
|
||
# RGBA (4×8-bit pixels, true color with transparency mask), the value is in [0-255, 0-255, 0-255, 0-255]
|
||
# CMYK (4×8-bit pixels, color separation)
|
||
# YCbCr (3×8-bit pixels, color video format)
|
||
# LAB (3×8-bit pixels, the L*a*b color space)
|
||
# HSV (3×8-bit pixels, Hue, Saturation, Value color space)
|
||
# I (32-bit signed integer pixels)
|
||
# F (32-bit floating point pixels)
|
||
# LA (L with alpha)
|
||
# PA (P with alpha)
|
||
# RGBX (true color with padding)
|
||
# RGBa (true color with premultiplied alpha)
|
||
# La (L with premultiplied alpha)
|
||
# I;16 (16-bit unsigned integer pixels)
|
||
# I;16L (16-bit little endian unsigned integer pixels)
|
||
# I;16B (16-bit big endian unsigned integer pixels)
|
||
# I;16N (16-bit native endian unsigned integer pixels)
|
||
# BGR;15 (15-bit reversed true colour)
|
||
# BGR;16 (16-bit reversed true colour)
|
||
# BGR;24 (24-bit reversed true colour)
|
||
# BGR;32 (32-bit reversed true colour)
|
||
|
||
# handle {P, LA, RGB, RGBA} for now
|
||
origin_image = image
|
||
|
||
if mode == 'P' or mode == 'LA':
|
||
image = image.convert('RGBA')
|
||
mode = 'RGBA'
|
||
if mode == 'L':
|
||
image = image.convert('RGB')
|
||
mode = 'RGB'
|
||
(row, col) = image.size
|
||
data = np.asarray(image)
|
||
|
||
# C Array format width
|
||
WIDTH_ALPHA = 16
|
||
WIDTH_GRAY8 = 32
|
||
WIDTH_RGB565 = 16
|
||
WIDTH_RGB32 = 16
|
||
|
||
with open(outputfile,"w") as o:
|
||
|
||
# insert header
|
||
print(hdr.format(time.asctime( time.localtime(time.time())), argv[0], resized, args.rot), file=o)
|
||
|
||
if mode == "RGBA":
|
||
if args.format == 'all' or args.format == 'mask':
|
||
print('ARM_ALIGN(4) ARM_SECTION(\"arm2d.asset.c_bmp%sAlpha\")' % (arr_name), file=o)
|
||
# alpha channel array available
|
||
print('static const uint8_t c_bmp%sAlpha[%d*%d] = {' % (arr_name, row, col),file=o)
|
||
cnt = 0
|
||
for eachRow in data:
|
||
lineWidth=0
|
||
print("/* -%d- */" % (cnt), file=o)
|
||
for eachPix in eachRow:
|
||
alpha = eachPix[3]
|
||
if lineWidth % WIDTH_ALPHA == (WIDTH_ALPHA - 1):
|
||
print("0x%02x," %(alpha) ,file=o)
|
||
else:
|
||
print("0x%02x" %(alpha), end =", ",file=o)
|
||
lineWidth+=1
|
||
cnt+=1
|
||
print('',file=o)
|
||
print('};\r\n', file=o)
|
||
|
||
# 1-bit Alpha channel
|
||
if args.a1 or args.format == 'all' or args.format == 'mask':
|
||
|
||
def RevBitPairPerByte(byteArr):
|
||
return ((byteArr & 0x01) << 7) | ((byteArr & 0x80) >> 7) | ((byteArr & 0x40) >> 5) | ((byteArr & 0x02) << 5) | \
|
||
((byteArr & 0x04) << 3) | ((byteArr & 0x20) >> 3) | ((byteArr & 0x10) >> 1) | ((byteArr & 0x08) << 1)
|
||
|
||
print('ARM_ALIGN(4) ARM_SECTION("arm2d.asset.c_bmp%sA1Alpha")' % (arr_name), file=o)
|
||
print('static const uint8_t c_bmp%sA1Alpha[%d*%d] = {' % (arr_name, (row+7)//8, col), file=o)
|
||
cnt = 0
|
||
alpha = data[...,3].astype(np.uint8)
|
||
for eachRow in alpha:
|
||
lineWidth=0
|
||
print("/* -%d- */" % (cnt), file=o)
|
||
|
||
bitsArr = np.unpackbits(eachRow.astype(np.uint8))
|
||
|
||
# generate indexes for MSB bit every byte
|
||
idx = np.arange(0, np.size(bitsArr), 8)
|
||
idx = np.reshape(idx, (1,-1))
|
||
|
||
# extraction + endianness conversion
|
||
msbBits = bitsArr[idx] & 0x80 >> 7
|
||
packedBytes = RevBitPairPerByte(np.packbits(msbBits))
|
||
|
||
for elt in packedBytes:
|
||
if lineWidth % WIDTH_ALPHA == (WIDTH_ALPHA-1):
|
||
print("0x%02x," %(elt) ,file=o)
|
||
else:
|
||
print("0x%02x" %(elt), end =", ",file=o)
|
||
lineWidth+=1
|
||
cnt+=1
|
||
print('',file=o)
|
||
print('};\n', file=o)
|
||
|
||
# 2-bit Alpha channel
|
||
if args.a2 or args.format == 'all' or args.format == 'mask':
|
||
|
||
def RevBitPairPerByte(byteArr):
|
||
return ((byteArr & 0x03) << 6) | ((byteArr & 0xc0) >> 6) | ((byteArr & 0x30) >> 2 ) | ((byteArr & 0x0c) << 2)
|
||
|
||
|
||
print('ARM_ALIGN(4) ARM_SECTION(\"arm2d.asset.c_bmp%sA2Alpha\")' % (arr_name), file=o)
|
||
print('static const uint8_t c_bmp%sA2Alpha[%d*%d] = {' % (arr_name, (row+3)/4, col),file=o)
|
||
cnt = 0
|
||
alpha = data[...,3].astype(np.uint8)
|
||
for eachRow in alpha:
|
||
lineWidth=0
|
||
print("/* -%d- */" % (cnt), file=o)
|
||
|
||
bitsArr = np.unpackbits(eachRow.astype(np.uint8))
|
||
|
||
# generate indexes for MSB bit pair every byte
|
||
idx = np.arange(0, np.size(bitsArr), 8)
|
||
idx=np.reshape(np.column_stack((idx+0, idx+1)), (1,-1))
|
||
|
||
# extraction + endianness conversion
|
||
packedBytes = RevBitPairPerByte(np.packbits(bitsArr[idx]))
|
||
|
||
for elt in packedBytes:
|
||
if lineWidth % WIDTH_ALPHA == (WIDTH_ALPHA-1):
|
||
print("0x%02x," %(elt) ,file=o)
|
||
else:
|
||
print("0x%02x" %(elt), end =", ",file=o)
|
||
lineWidth+=1
|
||
cnt+=1
|
||
print('',file=o)
|
||
print('};\r\n', file=o)
|
||
|
||
# 4-bit Alpha channel
|
||
if args.a4 or args.format == 'all' or args.format == 'mask':
|
||
|
||
def RevBitQuadPerByte(byteArr):
|
||
return ((byteArr & 0x0f) << 4) | ((byteArr & 0xf0) >> 4)
|
||
|
||
|
||
print('ARM_ALIGN(4) ARM_SECTION(\"arm2d.asset.c_bmp%sA4Alpha\")' % (arr_name), file=o)
|
||
print('static const uint8_t c_bmp%sA4Alpha[%d*%d] = {' % (arr_name, (row+1)/2, col),file=o)
|
||
cnt = 0
|
||
alpha = data[...,3].astype(np.uint8)
|
||
for eachRow in alpha:
|
||
lineWidth=0
|
||
print("/* -%d- */" % (cnt), file=o)
|
||
|
||
bitsArr = np.unpackbits(eachRow.astype(np.uint8))
|
||
|
||
# generate indexes for MSB bit quadruplet every byte
|
||
idx = np.arange(0, np.size(bitsArr), 8)
|
||
idx=np.reshape(np.column_stack(
|
||
(np.column_stack((idx+0, idx+1)), np.column_stack((idx+2, idx+3)))),
|
||
(1,-1)),
|
||
|
||
# extraction + endianness conversion
|
||
packedBytes = RevBitQuadPerByte(np.packbits(bitsArr[idx]))
|
||
|
||
for elt in packedBytes:
|
||
if lineWidth % WIDTH_ALPHA == (WIDTH_ALPHA - 1):
|
||
print("0x%02x," %(elt) ,file=o)
|
||
else:
|
||
print("0x%02x" %(elt), end =", ",file=o)
|
||
lineWidth+=1
|
||
cnt+=1
|
||
print('',file=o)
|
||
print('};\r\n', file=o)
|
||
|
||
|
||
# Gray8 channel array
|
||
if args.format == 'gray8' or args.format == 'all':
|
||
|
||
R = (data[...,0]).astype(np.uint16)
|
||
G = (data[...,1]).astype(np.uint16)
|
||
B = (data[...,2]).astype(np.uint16)
|
||
# merge
|
||
RGB = np.rint((R + G + B)/3).astype(np.uint8)
|
||
|
||
print('',file=o)
|
||
print('ARM_SECTION(\"arm2d.asset.c_bmp%sGRAY8\")' % (arr_name), file=o)
|
||
print('const uint8_t c_bmp%sGRAY8[%d*%d] = {' % (arr_name, row, col), file=o)
|
||
cnt = 0
|
||
for eachRow in RGB:
|
||
lineWidth=0
|
||
print("/* -%d- */" % (cnt), file=o)
|
||
for eachPix in eachRow:
|
||
if lineWidth % WIDTH_GRAY8 == (WIDTH_GRAY8 - 1):
|
||
print("0x%02x," %(eachPix) ,file=o)
|
||
else:
|
||
print("0x%02x" %(eachPix), end =", ", file=o)
|
||
lineWidth+=1
|
||
print('',file=o)
|
||
cnt+=1
|
||
print('};', file=o)
|
||
buffStr='pchBuffer'
|
||
typStr='uint8_t'
|
||
|
||
# RGB565 channel array
|
||
if args.format == 'rgb565' or args.format == 'all':
|
||
R = (data[...,0]>>3).astype(np.uint16) << 11
|
||
G = (data[...,1]>>2).astype(np.uint16) << 5
|
||
B = (data[...,2]>>3).astype(np.uint16)
|
||
# merge
|
||
RGB = R | G | B
|
||
|
||
print('',file=o)
|
||
print('ARM_SECTION(\"arm2d.asset.c_bmp%sRGB565\")' % (arr_name), file=o)
|
||
print('const uint16_t c_bmp%sRGB565[%d*%d] = {' % (arr_name, row, col), file=o)
|
||
cnt = 0
|
||
for eachRow in RGB:
|
||
lineWidth=0
|
||
print("/* -%d- */" % (cnt), file=o)
|
||
for eachPix in eachRow:
|
||
if lineWidth % WIDTH_RGB565 == (WIDTH_RGB565 - 1):
|
||
print("0x%04x," %(eachPix) ,file=o)
|
||
else:
|
||
print("0x%04x" %(eachPix), end =", ", file=o)
|
||
lineWidth+=1
|
||
print('',file=o)
|
||
cnt+=1
|
||
print('};', file=o)
|
||
buffStr='phwBuffer'
|
||
typStr='uint16_t'
|
||
|
||
# Lossless Compressed Mask (lmsk)
|
||
if (args.format == 'lmsk') or (args.format == 'all'):
|
||
if not LMSK_AVAILABLE:
|
||
print("Warning: LMSK compression library not available, skipping LMSK format", file=sys.stderr)
|
||
else:
|
||
# Detect alpha presence robustly
|
||
has_alpha = ("A" in origin_image.mode) or (origin_image.mode == "P" and "transparency" in origin_image.info)
|
||
|
||
if has_alpha:
|
||
img = origin_image.convert("RGBA")
|
||
alpha = img.getchannel("A")
|
||
mask_raw = alpha.tobytes()
|
||
else:
|
||
img = origin_image.convert("L")
|
||
mask_raw = img.tobytes()
|
||
|
||
mask_compressed = encode_lmsk(mask_raw,
|
||
width=img.width,
|
||
height=img.height,
|
||
raw=False,
|
||
no_gradient=args.no_gradient,
|
||
tolerant=args.gradient_tolerant,
|
||
alpha_bits=args.alpha_bits)
|
||
|
||
print('',file=o)
|
||
print('extern const uint8_t c_lmsk%s[%d];\n' % (arr_name, len(mask_compressed)), file=o)
|
||
print('ARM_ALIGN(4) ARM_SECTION(\"arm2d.asset.c_lmsk%s\")' % (arr_name), file=o)
|
||
print('const uint8_t c_lmsk%s[%d] = {' % (arr_name, len(mask_compressed)), file=o)
|
||
|
||
for i in range(0, len(mask_compressed), 16):
|
||
chunk = mask_compressed[i:i+16]
|
||
|
||
hex_strings = [f"0x{b:02x}" for b in chunk]
|
||
|
||
line = ", ".join(hex_strings)
|
||
|
||
o.write(" ")
|
||
o.write(line)
|
||
o.write(",\n")
|
||
|
||
print('};', file=o)
|
||
|
||
# zhRGB565 compressed format
|
||
if (args.format == 'zhRGB565') or (args.format == 'all'):
|
||
if not ZHRGB565_AVAILABLE:
|
||
print("Warning: zhRGB565 compression library not available, skipping zhRGB565 format", file=sys.stderr)
|
||
else:
|
||
# Convert to RGB565 first
|
||
R = (data[...,0]>>3).astype(np.uint16) << 11
|
||
G = (data[...,1]>>2).astype(np.uint16) << 5
|
||
B = (data[...,2]>>3).astype(np.uint16)
|
||
RGB = R | G | B
|
||
|
||
# Use RLE+DIFF compression for better gradient compression
|
||
compressed_data, compressed_size, compression_ratio = encode_rgb565_rle_diff(RGB.flatten(), row, col)
|
||
compression_method = "RLE+DIFF"
|
||
|
||
if compressed_data is not None:
|
||
print('',file=o)
|
||
print('/* ============================================ */', file=o)
|
||
print('/* zhRGB565 compressed data (%s) */' % compression_method, file=o)
|
||
print('/* Original size: %d bytes */' % (row * col * 2), file=o)
|
||
print('/* Compressed size: %d bytes */' % (compressed_size * 2), file=o)
|
||
print('/* Compression ratio: %.2f%% */' % compression_ratio, file=o)
|
||
print('/* ============================================ */', file=o)
|
||
print('',file=o)
|
||
|
||
# Generate compressed C array
|
||
c_code = generate_rle_c_array(compressed_data, compressed_size, row, col, compression_ratio, inputfile, arr_name)
|
||
|
||
# Write the compressed data (extract just the array part)
|
||
lines = c_code.split('\n')
|
||
in_array = False
|
||
for line in lines:
|
||
if 'const uint16_t' in line and '[' in line:
|
||
in_array = True
|
||
# Add ARM_SECTION directive and extern declaration for zhRGB565
|
||
# Extract the original array name and convert to ARM format
|
||
import re
|
||
match = re.search(r'const uint16_t (\w+)\[(.*?)\]', line)
|
||
|
||
if match:
|
||
original_name = match.group(1)
|
||
# Convert to ARM format: c_zhRGB565_ + name
|
||
arm_name = f'c_zhrgb{arr_name}'
|
||
array_size = match.group(2) if match.group(2) else ''
|
||
# Generate extern declaration
|
||
extern_decl = f"extern const uint16_t {arm_name}[{array_size}];"
|
||
print(extern_decl, file=o)
|
||
print('ARM_SECTION("arm2d.asset.c_zhrgb%s")' % (arr_name), file=o)
|
||
# Generate the actual array definition with modified name
|
||
modified_line = line.replace(original_name, arm_name)
|
||
print(modified_line, file=o)
|
||
|
||
continue
|
||
elif line.strip() == '};':
|
||
if in_array:
|
||
print(line, file=o)
|
||
break
|
||
elif in_array:
|
||
print(line, file=o)
|
||
else:
|
||
print("Warning: RLE compression failed for zhRGB565 format", file=sys.stderr)
|
||
|
||
|
||
|
||
if args.format == 'rgb32' or args.format == 'all':
|
||
R = data[...,0].astype(np.uint32) << 16
|
||
G = data[...,1].astype(np.uint32) << 8
|
||
B = data[...,2].astype(np.uint32)
|
||
if mode == "RGBA":
|
||
A = data[...,3].astype(np.uint32) << 24
|
||
else:
|
||
# alpha chanel forced to 0xFF
|
||
A = 0xff << 24
|
||
# merge
|
||
RGB = R | G | B | A
|
||
|
||
print('',file=o)
|
||
|
||
if mode == "RGBA":
|
||
print('ARM_SECTION(\"arm2d.asset.c_bmp%sCCCA8888\")' % (arr_name), file=o)
|
||
print('const uint32_t c_bmp%sCCCA8888[%d*%d] = {' % (arr_name, row, col), file=o)
|
||
else:
|
||
print('ARM_SECTION(\"arm2d.asset.c_bmp%sCCCN888\")' % (arr_name), file=o)
|
||
print('const uint32_t c_bmp%sCCCN888[%d*%d]= {' % (arr_name, row, col), file=o)
|
||
|
||
cnt = 0
|
||
for eachRow in RGB:
|
||
lineWidth=0
|
||
print("/* -%d- */" % (cnt), file=o)
|
||
for eachPix in eachRow:
|
||
if lineWidth % WIDTH_RGB32 == (WIDTH_RGB32 - 1):
|
||
print("0x%08x," %(eachPix) ,file=o)
|
||
else:
|
||
print("0x%08x" %(eachPix), end =", ", file=o)
|
||
lineWidth+=1
|
||
print('',file=o)
|
||
cnt+=1
|
||
print('};', file=o)
|
||
buffStr='pwBuffer'
|
||
typStr='uint32_t'
|
||
|
||
# insert tail
|
||
if args.format == 'gray8' or args.format == 'all':
|
||
buffStr='pchBuffer'
|
||
typStr='uint8_t'
|
||
print(tailDataGRAY8.format(arr_name, str(row), str(col), "."+buffStr+" = ("+typStr+"*)"), file=o)
|
||
|
||
if args.format == 'rgb565' or args.format == 'all':
|
||
buffStr='phwBuffer'
|
||
typStr='uint16_t'
|
||
print(tailDataRGB565.format(arr_name, str(row), str(col), "."+buffStr+" = ("+typStr+"*)"), file=o)
|
||
|
||
|
||
|
||
if args.format == 'rgb32' or args.format == 'all':
|
||
buffStr='pwBuffer'
|
||
typStr='uint32_t'
|
||
if mode == "RGBA":
|
||
print(tailDataRGBA8888.format(arr_name, str(row), str(col), "."+buffStr+" = ("+typStr+"*)"), file=o)
|
||
print(tailAlpha2.format(arr_name, str(row), str(col)), file=o)
|
||
else :
|
||
print(tailDataRGB888.format(arr_name, str(row), str(col), "."+buffStr+" = ("+typStr+"*)"), file=o)
|
||
|
||
|
||
if mode == "RGBA":
|
||
if args.format == 'all' or args.format == 'mask':
|
||
print(tailAlpha.format(arr_name, str(row), str(col)), file=o)
|
||
|
||
if args.a1 or args.format == 'all' or args.format == 'mask':
|
||
print(tail1BitAlpha.format(arr_name, str(row), str(col)), file=o)
|
||
|
||
if args.a2 or args.format == 'all' or args.format == 'mask':
|
||
print(tail2BitAlpha.format(arr_name, str(row), str(col)), file=o)
|
||
|
||
if args.a4 or args.format == 'all' or args.format == 'mask':
|
||
print(tail4BitAlpha.format(arr_name, str(row), str(col)), file=o)
|
||
|
||
|
||
print(tail.format(arr_name, str(row), str(col)), file=o)
|
||
|
||
if __name__ == '__main__':
|
||
main(sys.argv[1:])
|