Source code for faker_file.providers.image.weasyprint_generator

import io
import logging
from typing import Any, Dict, Union

from faker import Faker
from faker.generator import Generator
from faker.providers.python import Provider
from pdf2image import convert_from_bytes
from PIL import Image
from weasyprint import HTML

from ...base import DynamicTemplate, StringList
from ...constants import DEFAULT_FILE_ENCODING
from ..base.image_generator import BaseImageGenerator

__author__ = "Artur Barseghyan <artur.barseghyan@gmail.com>"
__copyright__ = "2022-2023 Artur Barseghyan"
__license__ = "MIT"
__all__ = ("WeasyPrintImageGenerator",)

LOGGER = logging.getLogger(__name__)


[docs]class WeasyPrintImageGenerator(BaseImageGenerator): """WeasyPrint and Pdf2Image ImageGenerator image generator. Usage example: .. code-block:: python from faker import Faker from faker_file.providers.png_file import PngFileProvider from faker_file.providers.image.weasyprint_generator import ( WeasyPrintImageGenerator ) FAKER = Faker() FAKER.add_provider(PngFileProvider) file = FAKER.png_file( img_generator_cls=WeasyPrintImageGenerator ) With dynamic content: .. code-block:: python from faker import Faker from faker_file.base import DynamicTemplate from faker_file.contrib.image.weasyprint_snippets import * from faker_file.providers.image.weasyprint_generator import ( WeasyPrintImageGenerator ) from faker_file.providers.png_file import PngFileProvider FAKER = Faker() FAKER.add_provider(PngFileProvider) file = FAKER.png_file( image_generator_cls=WeasyPrintImageGenerator, content=DynamicTemplate( [ (add_h1_heading, {}), (add_paragraph, {"max_nb_chars": 500}), (add_paragraph, {"max_nb_chars": 500}), (add_paragraph, {"max_nb_chars": 500}), (add_paragraph, {"max_nb_chars": 500}), ] ) ) file = FAKER.png_file( image_generator_cls=WeasyPrintImageGenerator, content=DynamicTemplate( [ (add_h1_heading, {}), (add_paragraph, {}), (add_picture, {}), (add_paragraph, {}), (add_picture, {}), (add_paragraph, {}), (add_picture, {}), (add_paragraph, {}), ] ) ) file = FAKER.png_file( image_generator_cls=WeasyPrintImageGenerator, content=DynamicTemplate( [ (add_h1_heading, {}), (add_picture, {}), (add_paragraph, {"max_nb_chars": 500}), (add_picture, {}), (add_paragraph, {"max_nb_chars": 500}), (add_picture, {}), (add_paragraph, {"max_nb_chars": 500}), (add_picture, {}), (add_paragraph, {"max_nb_chars": 500}), ] ) ) file = FAKER.png_file( image_generator_cls=WeasyPrintImageGenerator, content=DynamicTemplate( [ (add_h1_heading, {}), (add_picture, {}), (add_paragraph, {"max_nb_chars": 500}), (add_table, {"rows": 5, "cols": 4}), ] ) ) file = FAKER.png_file( image_generator_cls=WeasyPrintImageGenerator, content=DynamicTemplate( [ (add_h1_heading, {"margin": (2, 2)}), (add_picture, {"margin": (2, 2)}), (add_paragraph, {"max_nb_chars": 500, "margin": (2, 2)}), (add_picture, {"margin": (2, 2)}), (add_paragraph, {"max_nb_chars": 500, "margin": (2, 2)}), (add_picture, {"margin": (2, 2)}), (add_paragraph, {"max_nb_chars": 500, "margin": (2, 2)}), (add_picture, {"margin": (2, 2)}), (add_paragraph, {"max_nb_chars": 500, "margin": (2, 2)}), ] ) ) """ encoding: str = DEFAULT_FILE_ENCODING page_width: int = 794 # A4 size at 96 DPI page_height: int = 1123 # A4 size at 96 DPI wrapper_tag: str = "div" def __init__(self: "WeasyPrintImageGenerator", **kwargs): super().__init__(**kwargs) self.pages = [] self.image_mode = "RGB"
[docs] def handle_kwargs(self: "WeasyPrintImageGenerator", **kwargs) -> None: """Handle kwargs.""" if "page_width" in kwargs: self.page_width = kwargs["page_width"] if "page_height" in kwargs: self.page_height = kwargs["page_height"] if "image_mode" in kwargs: self.image_mode = kwargs["image_mode"] if "wrapper_tag" in kwargs: self.wrapper_tag = kwargs["wrapper_tag"]
[docs] def create_image_instance( self: "WeasyPrintImageGenerator", width: Union[int, None] = None, height: Union[int, None] = None, ) -> Image: return Image.new( self.image_mode, (width or self.page_width, height or self.page_height), # (width, height), (255, 255, 255), )
[docs] def wrap(self: "WeasyPrintImageGenerator", content: str) -> str: return f"<{self.wrapper_tag}>" f"{content}" f"</{self.wrapper_tag}>"
[docs] def generate( self: "WeasyPrintImageGenerator", content: str, data: Dict[str, Any], provider: Union[Faker, Generator, Provider], **kwargs, ) -> bytes: """Generate image.""" if isinstance(content, DynamicTemplate): _content = StringList() for counter, (ct_modifier, ct_modifier_kwargs) in enumerate( content.content_modifiers ): ct_modifier( provider, self, _content, data, counter, **ct_modifier_kwargs, ) else: # Convert the HTML to a PDF and store in memory pdf_bytes = HTML( string=f"<{self.wrapper_tag}>{content}</{self.wrapper_tag}>" ).write_pdf() # Convert the in-memory PDF to images self.pages = convert_from_bytes(pdf_bytes) # If the PDF has multiple pages, stitch them together if len(self.pages) > 1: # Get dimensions of combined image width, height = self.pages[0].size[0], sum( [img.size[1] for img in self.pages] ) # Create a new image with white background result = self.create_image_instance(width, height) # Iterate over images and paste them onto the new image y_offset = 0 for img in self.pages: result.paste(img, (0, y_offset)) y_offset += img.size[1] else: # If there's only one page, use it directly result = self.pages[0] # Save the result to a BytesIO object output = io.BytesIO() result.save(output, format=provider.image_format) image_bytes = output.getvalue() # Image, stored in memory return image_bytes