Decomate / utils.py
Milhaud's picture
feat: add HTML normalization and style fixing functions for improved preview rendering
539cbd4
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