Source code for formhtr.auto_align

from __future__ import annotations

import numpy as np

from .libs.pdf_to_image import convert_pdf_to_image, resize_image
from .libs.processing.align_images import get_alignment_data


def _prepare_alignment_images(
    *,
    scanned_logsheet_pdf: str,
    template_pdf: str,
    page: int,
    dpi: int = 300,
):
    """Load scan and template pages and resize them to a common pixel size.

    Args:
        scanned_logsheet_pdf: Path to the scanned multi-page PDF.
        template_pdf: Path to the template PDF for this side.
        page: Zero-based page index in the scan PDF.
        dpi: Rasterization resolution.

    Returns:
        Pair ``(logsheet_image, template_image)`` as ``numpy`` arrays (BGR).
    """
    template_image = np.array(convert_pdf_to_image(template_pdf, dpi=dpi))
    logsheet_image = np.array(convert_pdf_to_image(
        scanned_logsheet_pdf, page=page, dpi=dpi))

    height, width, _ = logsheet_image.shape

    # Keep both images in the same resolution before corner detection.
    logsheet_image = resize_image(logsheet_image, (width, height))
    template_image = resize_image(template_image, (width, height))

    return logsheet_image, template_image


[docs] def get_page_alignment_data( *, scanned_logsheet_pdf: str, template_pdf: str, page: int = 0, dpi: int = 300, ) -> dict: """Corners and image dimensions for automatic alignment of one scan page. Args: scanned_logsheet_pdf: Path to the scanned PDF. template_pdf: Path to the template PDF. page: Scan page index (``0`` = front, ``1`` = back when applicable). dpi: Rasterization resolution. Returns: Dict with ``templatePoints``, ``targetPoints``, ``imageWidth``, ``imageHeight`` (JSON-friendly point dicts and integers). """ logsheet_image, template_image = _prepare_alignment_images( scanned_logsheet_pdf=scanned_logsheet_pdf, template_pdf=template_pdf, page=page, dpi=dpi, ) alignment_data = get_alignment_data(logsheet_image, template_image) height, width, _ = logsheet_image.shape alignment_data["imageWidth"] = int(width) alignment_data["imageHeight"] = int(height) return alignment_data
[docs] def build_alignment_payload( *, scanned_logsheet_pdf: str, template_pdf: str, backside_template_pdf: str | None = None, dpi: int = 300, ) -> dict: """Build a payload with front (and optional back) alignment corner data. Args: scanned_logsheet_pdf: Path to the scanned PDF (at least two pages if back is used). template_pdf: Front template PDF path. backside_template_pdf: Optional back template PDF path. dpi: Rasterization resolution. Returns: Dict with keys ``frontside`` (dict) and ``backside`` (dict or ``None``). """ frontside_alignment_data = get_page_alignment_data( scanned_logsheet_pdf=scanned_logsheet_pdf, template_pdf=template_pdf, page=0, dpi=dpi, ) backside_alignment_data = None if backside_template_pdf: backside_alignment_data = get_page_alignment_data( scanned_logsheet_pdf=scanned_logsheet_pdf, template_pdf=backside_template_pdf, page=1, dpi=dpi, ) return { "frontside": frontside_alignment_data, "backside": backside_alignment_data, }