write_image.py

Le fichier Python de l'exemple « Des images sur une page ». Une photo qui entre exactement comme elle est sortie de l'appareil, et une image à parties transparentes qui les garde, chacune sur une page taillée à sa mesure.

Python 106 lignes

À quoi sert cet exemple

Une photo compressée une fois, puis compressée une seconde fois par ce qui l'a mise dans le document, ressort molle, tachée sur les bords, et plus lourde que l'originale. C'est la façon la plus courante d'abîmer une bonne image entre l'appareil photo et l'imprimeur, et rien dans le fichier fini n'avoue que c'est arrivé.

Ce que montre cet exemple

  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()