[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))
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):
value = cv.string_strict(value)
parts = value.strip().split(":")
@@ -490,9 +473,7 @@ def validate_settings(value, path=()):
)
if file := value.get(CONF_FILE):
file = Path(file)
if is_svg_file(file):
validate_cairosvg_installed()
else:
if not is_svg_file(file):
try:
Image.open(file)
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}")
resize = config.get(CONF_RESIZE)
if is_svg_file(path):
# Local import so use of non-SVG files needn't require cairosvg installed
from pyexpat import ExpatError
from xml.etree.ElementTree import ParseError
try:
if is_svg_file(path):
import resvg_py
from cairosvg import svg2png
from cairosvg.helpers import PointError
if not resize:
resize = (None, None)
try:
with open(path, "rb") as file:
image = svg2png(
file_obj=file,
output_width=resize[0],
output_height=resize[1],
if resize:
width, height = resize
# resvg-py allows rendering by width/height directly
image_data = resvg_py.svg_to_bytes(
svg_path=str(path), width=int(width), height=int(height)
)
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
except (
ValueError,
ParseError,
IndexError,
ExpatError,
AttributeError,
TypeError,
PointError,
) as e:
raise core.EsphomeError(f"Could not load SVG image {path}: {e}") from e
else:
image = Image.open(path)
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)
else:
image = Image.open(path)
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)
except (OSError, UnidentifiedImageError, ValueError) as exc:
raise core.EsphomeError(f"Could not read image file {path}: {exc}") from exc
if not resize and (width > 500 or height > 500):
_LOGGER.warning(

View File

@@ -19,13 +19,7 @@ ruamel.yaml==0.19.1 # dashboard_import
ruamel.yaml.clib==0.2.15 # dashboard_import
esphome-glyphsets==0.2.0
pillow==11.3.0
# 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'
resvg-py==0.2.5
freetype-py==2.5.1
jinja2==3.1.6
bleak==2.1.1