Decomate / utils.py
Milhaud's picture
feat: add HTML normalization and style fixing functions for improved preview rendering
539cbd4
Raw
History Blame Contribute Delete
3.21 kB
import cairosvg
import io
import base64
import re
from PIL import Image
def svg_to_png_base64(svg_content: str, width=800, height=800) -> tuple[str, str]:
"""Convert SVG to PNG and return as base64 encoded string with media type.
Args:
svg_content: SVG markup string
width: Desired PNG width
height: Desired PNG height
Returns:
Tuple of (media_type, base64_string)
"""
try:
# Convert SVG to PNG using cairosvg
png_data = cairosvg.svg2png(
bytestring=svg_content.encode("utf-8"),
output_width=width,
output_height=height,
)
# Open PNG with Pillow to ensure correct format
img = Image.open(io.BytesIO(png_data))
# Convert to RGB if needed
if img.mode != "RGB":
img = img.convert("RGB")
# Save as PNG to bytes
img_byte_arr = io.BytesIO()
img.save(img_byte_arr, format="PNG")
img_byte_arr = img_byte_arr.getvalue()
# Encode to base64
base64_str = base64.b64encode(img_byte_arr).decode("utf-8")
return "image/png", base64_str
except Exception as e:
print(f"Error converting SVG to PNG: {e}")
return "", ""
def normalize_html_content(html_content: str) -> str:
"""
Normalizes the body and svg styles in the HTML content to fixed values.
"""
fixed_body_style = """body {
margin: 0;
padding: 20px;
display: flex;
justify-content: center;
align-items: center;
min-height: 100%;
overflow: hidden;
}"""
fixed_svg_style = """svg {
max-width: 400px;
height: auto;
border-radius: 10px;
}"""
if '<meta name="viewport"' not in html_content:
html_content = html_content.replace(
"<head>",
'<head>\n<meta name="viewport" content="width=device-width, initial-scale=1.0">',
)
body_pattern = r"body\s*\{[^}]*\}"
html_content = re.sub(
body_pattern,
fixed_body_style,
html_content,
flags=re.MULTILINE | re.DOTALL | re.IGNORECASE,
)
# Match and replace svg style pattern
svg_pattern = r"svg\s*\{[^}]*\}"
html_content = re.sub(
svg_pattern,
fixed_svg_style,
html_content,
flags=re.MULTILINE | re.DOTALL | re.IGNORECASE,
)
return html_content
def fix_html_styles_for_preview(html_content: str) -> str:
"""
Main function to modify HTML styles for preview purposes.
"""
if not html_content or not html_content.strip():
return html_content
try:
normalized_html = normalize_html_content(html_content)
if "<!DOCTYPE html>" not in normalized_html:
normalized_html = "<!DOCTYPE html>\n" + normalized_html
if "<meta charset=" not in normalized_html:
normalized_html = normalized_html.replace(
"<head>", '<head>\n<meta charset="utf-8">'
)
return normalized_html
except Exception as e:
print(f"Error occurred while modifying HTML styles: {e}")
return html_content