chore(image_converter): add AL88 color format support (#9453)

Signed-off-by: Neo Xu <neo.xu1990@gmail.com>
This commit is contained in:
Neo Xu
2025-12-23 14:28:22 +08:00
committed by GitHub
parent 7a7ca5bbc2
commit b78aa6afc7
2 changed files with 48 additions and 3 deletions
+47 -2
View File
@@ -117,6 +117,7 @@ class ColorFormat(Enum):
A2 = 0x0C
A4 = 0x0D
A8 = 0x0E
AL88 = 0x15
ARGB8888 = 0x10
XRGB8888 = 0x11
RGB565 = 0x12
@@ -141,6 +142,7 @@ class ColorFormat(Enum):
ColorFormat.A2: 2,
ColorFormat.A4: 4,
ColorFormat.A8: 8,
ColorFormat.AL88: 16,
ColorFormat.ARGB8888: 32,
ColorFormat.XRGB8888: 32,
ColorFormat.RGB565: 16,
@@ -182,6 +184,7 @@ class ColorFormat(Enum):
@property
def has_alpha(self) -> bool:
return self.is_alpha_only or self.is_indexed or self in (
ColorFormat.AL88,
ColorFormat.ARGB8888,
ColorFormat.XRGB8888, # const alpha: 0xff
ColorFormat.ARGB8565,
@@ -276,7 +279,14 @@ def unpack_colors(data: bytes, cf: ColorFormat, w) -> List:
ret.append(bit_extend((p >> 11) & 0x1f, 5)) # R
ret.append(bit_extend((p >> 5) & 0x3f, 6)) # G
ret.append(bit_extend((p >> 0) & 0x1f, 5)) # B
elif cf == ColorFormat.AL88:
# AL88: low 8bit = Luminance, high 8bit = Alpha
L = data[0::2] # low byte: luminance
A = data[1::2] # high byte: alpha
for luma, alpha in zip(L, A):
ret.append(luma) # L
ret.append(alpha) # A
elif bpp == 24:
if cf == ColorFormat.RGB888:
B = data[0::3]
@@ -854,6 +864,14 @@ class LVGLImage:
greyscale=True,
alpha=False)
data = self.data
elif self.cf == ColorFormat.AL88:
# to grayscale with alpha
encoder = png.Writer(self.w,
self.h,
bitdepth=8,
greyscale=True,
alpha=True)
data = unpack_colors(self.data, self.cf, self.w)
elif self.cf.is_colormap:
encoder = png.Writer(self.w,
self.h,
@@ -897,6 +915,8 @@ class LVGLImage:
self._png_to_indexed(cf, filename)
elif cf.is_alpha_only:
self._png_to_alpha_only(cf, filename)
elif cf == ColorFormat.AL88:
self._png_to_al88(cf, filename)
elif cf.is_luma_only:
self._png_to_luma_only(cf, filename)
elif cf.is_colormap:
@@ -993,6 +1013,31 @@ class LVGLImage:
return 12.92 * y
return 1.055 * pow(y, 1 / 2.4) - 0.055
def _png_to_al88(self, cf: ColorFormat, filename: str):
reader = png.Reader(str(filename))
w, h, rows, info = reader.asRGBA8()
if not info['alpha']:
raise FormatError(f"{filename} has no alpha channel")
rawdata = bytearray()
for row in rows:
R = row[0::4]
G = row[1::4]
B = row[2::4]
A = row[3::4]
for r, g, b, a in zip(R, G, B, A):
# Calculate luminance using ITU-R BT.709 coefficients
r_linear = self.sRGB_to_linear(r / 255.0)
g_linear = self.sRGB_to_linear(g / 255.0)
b_linear = self.sRGB_to_linear(b / 255.0)
luma = 0.2126 * r_linear + 0.7152 * g_linear + 0.0722 * b_linear
luma_byte = int(self.linear_to_sRGB(luma) * 255)
# AL88: low byte = luminance, high byte = alpha
rawdata += uint8_t(luma_byte) # L
rawdata += uint8_t(a) # A
self.set_data(ColorFormat.AL88, w, h, rawdata)
def _png_to_luma_only(self, cf: ColorFormat, filename: str):
reader = png.Reader(str(filename))
w, h, rows, info = reader.asRGBA8()
@@ -1389,7 +1434,7 @@ def main():
"choose from I1/2/4/8"),
default="I8",
choices=[
"L8", "I1", "I2", "I4", "I8", "A1", "A2", "A4", "A8", "ARGB8888",
"L8", "I1", "I2", "I4", "I8", "A1", "A2", "A4", "A8", "AL88", "ARGB8888",
"XRGB8888", "RGB565", "RGB565_SWAPPED", "RGB565A8", "ARGB8565", "RGB888", "AUTO",
"RAW", "RAW_ALPHA", "ARGB8888_PREMULTIPLIED"
])