1313from esphome .const import CONF_BLUE , CONF_GREEN , CONF_RED , CONF_RESIZE , CONF_FILE , CONF_ID , CONF_BRIGHTNESS , CONF_RAW_DATA_ID , CONF_TIME , CONF_TRIGGER_ID
1414from esphome .core import CORE , HexInt
1515from esphome .cpp_generator import RawExpression
16- from esphome .components .image import CONF_ALPHA_CHANNEL , IMAGE_TYPE
16+ from esphome .components .image import CONF_CHROMA_KEY , IMAGE_TYPE
1717
1818from urllib .parse import urlparse
1919
@@ -484,7 +484,15 @@ def openImageFile(path):
484484 yaml_string += F"\" { conf [CONF_ID ]} \" ,"
485485
486486 dither = Image .Dither .NONE
487- transparency = CONF_ALPHA_CHANNEL
487+ # Use CHROMA_KEY instead of ALPHA_CHANNEL: on ESPHome 2026.4.0 the
488+ # appended-alpha layout is incompatible with Animation frame indexing
489+ # (Animation::update_data_start_ advances by w*h*2 per frame, ignoring
490+ # the alpha block). Chroma-key stores the transparent-pixel marker
491+ # inline (0x0020), so each frame is exactly w*h*2 bytes and the C++
492+ # Animation class can index into it correctly on every ESPHome
493+ # version. 8x8 pixel-art icons use binary transparency anyway —
494+ # fixes issue #331.
495+ transparency = CONF_CHROMA_KEY
488496 invert_alpha = False
489497
490498 total_rows = height * frames
@@ -495,6 +503,12 @@ def openImageFile(path):
495503 dither ,
496504 invert_alpha ,
497505 )
506+ # ESPHome 2026.4.0 flipped the default RGB565 byte order to little-
507+ # endian, but the C++ Image::get_rgb565_pixel_ decoder still reads
508+ # big-endian. set_big_endian exists on every ESPHome release that
509+ # supports EHMTXv2; no-op on <2026.4.0 where BE was already default.
510+ if hasattr (encoder , "set_big_endian" ):
511+ encoder .set_big_endian (True )
498512 for frame_index in range (frames ):
499513 image .seek (frame_index )
500514 pixels = encoder .convert (image .resize ((width , height )), path ).getdata ()
0 commit comments