Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

feat: switch to new chromium headless mode refactored #118

Open
wants to merge 5 commits into
base: main
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -161,7 +161,7 @@ cython_debug/
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
# and can be added to the global gitignore or merged into this file. For a more nuclear
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
#.idea/
.idea/

### Python Patch ###
# Poetry local configuration file - https://python-poetry.org/docs/configuration/#local-configuration
Expand All @@ -173,4 +173,7 @@ poetry.toml
# LSP config files
pyrightconfig.json

# VSCode
.vscode

# End of https://www.toptal.com/developers/gitignore/api/python
24 changes: 15 additions & 9 deletions Dockerfile
Original file line number Diff line number Diff line change
@@ -1,18 +1,24 @@
FROM python:3.13.2-alpine@sha256:323a717dc4a010fee21e3f1aac738ee10bb485de4e7593ce242b36ee48d6b352
FROM python:3.13.1-slim@sha256:f41a75c9cee9391c09e0139f7b49d4b1fbb119944ec740ecce4040626dc07bed
LABEL maintainer="SBB Polarion Team <[email protected]>"

ARG APP_IMAGE_VERSION=0.0.0

# hadolint ignore=DL3018
RUN apk add --no-cache \
# hadolint ignore=DL3008
RUN apt-get update && \
apt-get --yes --no-install-recommends install \
chromium \
dbus \
font-dejavu \
font-noto \
font-liberation \
pango \
py3-brotli \
py3-cffi
upower \
fonts-dejavu \
fonts-liberation \
libpango-1.0-0 \
libpangoft2-1.0-0 \
python3-brotli \
python3-cffi \
vim && \
apt-get clean autoclean && \
apt-get --yes autoremove && \
rm -rf /var/lib/apt/lists/*

ENV WORKING_DIR="/opt/weasyprint"
ENV CHROMIUM_EXECUTABLE_PATH="/usr/bin/chromium"
Expand Down
24 changes: 21 additions & 3 deletions app/svg_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,15 +8,18 @@
from pathlib import Path
from uuid import uuid4

from PIL import Image

IMAGE_PNG = "image/png"
IMAGE_SVG = "image/svg+xml"

NON_SVG_CONTENT_TYPES = ("image/jpeg", "image/png", "image/gif")
CHROMIUM_HEIGHT_ADJUSTMENT = 100


# Process img tags, replacing base64 SVG images with PNGs
def process_svg(html: str) -> str:
pattern = re.compile(r'<img(?P<intermediate>[^>]+?src="data:)(?P<type>[^;>]+)?;base64,(?P<base64>[^"]+)?"')
pattern = re.compile(r'<img(?P<intermediate>[^>]+?src="data:)(?P<type>[^;>]+)?;base64,\s?(?P<base64>[^">]+)?"')
return re.sub(pattern, replace_img_base64, html)


Expand Down Expand Up @@ -72,16 +75,30 @@ def replace_svg_with_png(svg_content: str) -> tuple[str, str | bytes]:
if not svg_filepath or not png_filepath:
return IMAGE_SVG, svg_content

if not convert_svg_to_png(width, height, png_filepath, svg_filepath):
if not convert_svg_to_png(width, height + CHROMIUM_HEIGHT_ADJUSTMENT, png_filepath, svg_filepath): # Add 100 pixels to height to make chromium render the entire svg
return IMAGE_SVG, svg_content

crop_png(png_filepath, CHROMIUM_HEIGHT_ADJUSTMENT)

png_content = read_and_cleanup_png(png_filepath)
if not png_content:
return IMAGE_SVG, svg_content

return IMAGE_PNG, png_content


# Remove added bottom pixels from PNG after conversion
def crop_png(file_path: Path, bottom_pixels_to_crop: int) -> None:
with Image.open(file_path) as img:
img_width, img_height = img.size

if bottom_pixels_to_crop >= img_height:
raise ValueError("Not possible to crop more than the height of the picture")

cropped = img.crop((0, 0, img_width, img_height - bottom_pixels_to_crop))
cropped.save(file_path)


# Extract the width and height from the SVG tag (and convert it to px)
def extract_svg_dimensions_as_px(svg_content: str) -> tuple[int | None, int | None]:
width_match = re.search(r'<svg[^>]+?width="(?P<width>[\d.]+)(?P<unit>\w+)?', svg_content)
Expand Down Expand Up @@ -156,13 +173,14 @@ def create_chromium_command(width: int, height: int, png_filepath: Path, svg_fil

command = [
chromium_executable,
"--headless=old",
"--headless=new",
"--no-sandbox",
"--disable-gpu",
"--disable-software-rasterizer",
"--disable-dev-shm-usage",
"--default-background-color=00000000",
"--hide-scrollbars",
"--force-device-scale-factor=1",
"--enable-features=ConversionMeasurement,AttributionReportingCrossAppWeb",
f"--screenshot={png_filepath}",
f"--window-size={width},{height}",
Expand Down
2 changes: 1 addition & 1 deletion entrypoint.sh
Original file line number Diff line number Diff line change
@@ -1,4 +1,4 @@
#!/bin/sh
#!/bin/bash

BUILD_TIMESTAMP="$(cat /opt/weasyprint/.build_timestamp)"
export WEASYPRINT_SERVICE_BUILD_TIMESTAMP=${BUILD_TIMESTAMP}
Expand Down
2 changes: 1 addition & 1 deletion pyproject.toml
Original file line number Diff line number Diff line change
Expand Up @@ -11,7 +11,7 @@ requires-python=">=3.13"
dependencies = [
"flask (>=3.1.0,<4.0.0)",
"gevent (>=24.11.1,<25.0.0)",
"weasyprint (>=64.0,<65)"
"weasyprint (>=64.0,<65)",
]

[tool.poetry]
Expand Down
3 changes: 2 additions & 1 deletion tests/test_svg_utils.py
Original file line number Diff line number Diff line change
Expand Up @@ -163,13 +163,14 @@ def test_create_chromium_command():
os.environ["CHROMIUM_EXECUTABLE_PATH"] = "/"
assert create_chromium_command(1, 1, Path("/"), Path("/")) == [
"/",
"--headless=old",
"--headless=new",
"--no-sandbox",
"--disable-gpu",
"--disable-software-rasterizer",
"--disable-dev-shm-usage",
"--default-background-color=00000000",
"--hide-scrollbars",
"--force-device-scale-factor=1",
"--enable-features=ConversionMeasurement,AttributionReportingCrossAppWeb",
"--screenshot=/",
f"--window-size={1},{1}",
Expand Down
Loading