[image] Replace use of cairosvg with resvg-py (#12863)

Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com>
This commit is contained in:
Clyde Stubbs
2026-01-06 09:56:59 +10:00
committed by GitHub
parent 94bedd83be
commit 21aa245cff
2 changed files with 28 additions and 62 deletions

View File

@@ -374,23 +374,6 @@ def is_svg_file(file):
return "<svg" in str(f.read(1024)) return "<svg" in str(f.read(1024))
def validate_cairosvg_installed():
try:
import cairosvg
except ImportError as err:
raise cv.Invalid(
"Please install the cairosvg python package to use this feature. "
"(pip install cairosvg)"
) from err
major, minor, _ = cairosvg.__version__.split(".")
if major < "2" or major == "2" and minor < "2":
raise cv.Invalid(
"Please update your cairosvg installation to at least 2.2.0. "
"(pip install -U cairosvg)"
)
def validate_file_shorthand(value): def validate_file_shorthand(value):
value = cv.string_strict(value) value = cv.string_strict(value)
parts = value.strip().split(":") parts = value.strip().split(":")
@@ -490,9 +473,7 @@ def validate_settings(value, path=()):
) )
if file := value.get(CONF_FILE): if file := value.get(CONF_FILE):
file = Path(file) file = Path(file)
if is_svg_file(file): if not is_svg_file(file):
validate_cairosvg_installed()
else:
try: try:
Image.open(file) Image.open(file)
except UnidentifiedImageError as exc: except UnidentifiedImageError as exc:
@@ -669,44 +650,35 @@ async def write_image(config, all_frames=False):
raise core.EsphomeError(f"Could not load image file {path}") raise core.EsphomeError(f"Could not load image file {path}")
resize = config.get(CONF_RESIZE) resize = config.get(CONF_RESIZE)
if is_svg_file(path): try:
# Local import so use of non-SVG files needn't require cairosvg installed if is_svg_file(path):
from pyexpat import ExpatError import resvg_py
from xml.etree.ElementTree import ParseError
from cairosvg import svg2png if resize:
from cairosvg.helpers import PointError width, height = resize
# resvg-py allows rendering by width/height directly
if not resize: image_data = resvg_py.svg_to_bytes(
resize = (None, None) svg_path=str(path), width=int(width), height=int(height)
try:
with open(path, "rb") as file:
image = svg2png(
file_obj=file,
output_width=resize[0],
output_height=resize[1],
) )
image = Image.open(io.BytesIO(image)) else:
# Default size
image_data = resvg_py.svg_to_bytes(svg_path=str(path))
# Convert bytes to Pillow Image
image = Image.open(io.BytesIO(image_data))
width, height = image.size width, height = image.size
except (
ValueError, else:
ParseError, image = Image.open(path)
IndexError, width, height = image.size
ExpatError, if resize:
AttributeError, # Preserve aspect ratio
TypeError, new_width_max = min(width, resize[0])
PointError, new_height_max = min(height, resize[1])
) as e: ratio = min(new_width_max / width, new_height_max / height)
raise core.EsphomeError(f"Could not load SVG image {path}: {e}") from e width, height = int(width * ratio), int(height * ratio)
else: except (OSError, UnidentifiedImageError, ValueError) as exc:
image = Image.open(path) raise core.EsphomeError(f"Could not read image file {path}: {exc}") from exc
width, height = image.size
if resize:
# Preserve aspect ratio
new_width_max = min(width, resize[0])
new_height_max = min(height, resize[1])
ratio = min(new_width_max / width, new_height_max / height)
width, height = int(width * ratio), int(height * ratio)
if not resize and (width > 500 or height > 500): if not resize and (width > 500 or height > 500):
_LOGGER.warning( _LOGGER.warning(

View File

@@ -19,13 +19,7 @@ ruamel.yaml==0.19.1 # dashboard_import
ruamel.yaml.clib==0.2.15 # dashboard_import ruamel.yaml.clib==0.2.15 # dashboard_import
esphome-glyphsets==0.2.0 esphome-glyphsets==0.2.0
pillow==11.3.0 pillow==11.3.0
resvg-py==0.2.5
# pycairo fork for Windows
cairosvg @ git+https://github.com/clydebarrow/cairosvg.git@release ; sys_platform == 'win32'
# Original for everything else
cairosvg==2.8.2 ; sys_platform != 'win32'
freetype-py==2.5.1 freetype-py==2.5.1
jinja2==3.1.6 jinja2==3.1.6
bleak==2.1.1 bleak==2.1.1