Images on a page

Images placed on a page.

Python write_image.py 106 lines
  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
"""Places images on a page, and writes the result to disk.

The Python twin of the `write_image` example in Rust.

Each image named on the command line gets a page of its own, exactly as big as the
image is: at 72 dots to the inch one pixel is one point, so the page that comes back
out of a renderer is the image that went in.

Named nothing, the example places the two committed fixtures — a JPEG, whose bytes go
into the file undecoded, and a PNG whose transparency becomes a soft mask — and adds a
page that lays them out the way a document would.

Usage: python examples/write_image.py [out.pdf] [image...]
"""

from __future__ import annotations

import sys
from pathlib import Path

import _licence
import _out

import hqf_pdf

# The images the example places when the caller names none: the ones committed for the
# tests, so that it runs on any machine.
IMAGES = Path(__file__).resolve().parents[2] / "hqf-pdf" / "tests" / "images"
DEFAULT_IMAGES = [IMAGES / "photo.jpg", IMAGES / "logo.png"]

A4_WIDTH = 595.276


def main() -> None:
    out = _out.output_path("image")

    named = [Path(argument) for argument in sys.argv[2:]]
    showcase = not named
    paths = DEFAULT_IMAGES if showcase else named

    doc = hqf_pdf.Document()
    doc.set_license(_licence.licensed())
    doc.set_info("Title", "hqf-pdf image sample")

    handles = []
    for path in paths:
        image = hqf_pdf.Image.from_path(path)
        resolution = image.resolution
        declared = (
            f"{resolution.x} by {resolution.y} dots to the inch"
            if resolution is not None
            else "stating no resolution of its own"
        )
        orientation = image.orientation
        way_up = f"seen {orientation!r}" if orientation is not None else "and no way up"
        print(
            f"{path}: {image.width}x{image.height}"
            f"{', with a soft mask' if image.has_alpha else ''}, {declared}, {way_up}"
        )

        handle = doc.add_image(image)

        # A page the size of the image, with the image filling it. The size is the one
        # the file itself asks for; a file asking for none is laid down one pixel to the
        # point.
        width, height = handle.size
        content = hqf_pdf.Content()
        content.draw_image(handle, 0.0, 0.0, width, height)

        page = hqf_pdf.Page(width, height)
        page.set_content(content)
        doc.add_page(page)

        handles.append(handle)

    if showcase:
        # One more page, laid out the way a document would lay it out: the photo fitted
        # into a box without being stretched, and the logo, whose transparency lets what
        # is under it show through.
        content = hqf_pdf.Content()

        content.set_fill(hqf_pdf.Rgb(0.93, 0.94, 0.96))
        content.rect(0.0, 700.0, A4_WIDTH, 142.0)
        content.fill()

        photo, logo = handles[0], handles[1]

        width, height = photo.fit_within(240.0, 160.0)
        content.draw_image(photo, 60.0, 500.0, width, height)

        width, height = logo.fit_within(90.0, 90.0)
        content.draw_image(logo, 380.0, 730.0, width, height)

        page = hqf_pdf.Page.a4()
        page.set_content(content)
        doc.add_page(page)

    pdf = doc.to_bytes()
    Path(out).parent.mkdir(parents=True, exist_ok=True)
    Path(out).write_bytes(pdf)

    print(f"wrote {out}: {len(pdf)} bytes, {doc.page_count} page(s)")


if __name__ == "__main__":
    main()