File: render_parts_via_recorder_backend.py

package info (click to toggle)
ezdxf 1.4.1-1
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 104,528 kB
  • sloc: python: 182,341; makefile: 116; lisp: 20; ansic: 4
file content (126 lines) | stat: -rw-r--r-- 4,337 bytes parent folder | download
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
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
#  Copyright (c) 2023, Manfred Moitzi
#  License: MIT License
from typing import Iterator
import pathlib
import random

import ezdxf
from ezdxf.addons.drawing import (
    RenderContext,
    Frontend,
    recorder,
    config,
    layout,
    pymupdf,
)
from ezdxf.math import BoundingBox2d

# ------------------------------------------------------------------------------
# This example renders the DXF file in rows by cols tiles including filtering
# the DXF entities outside the rendering area.
#
# This example is a reimplementation of the "render_model_space_as_tiles.py" example
# nut uses the new RecorderBackend introduced in ezdxf v1.1.
# The RecorderBackend stores the output of the Frontend as compact objects based on
# numpy arrays.  The recordings can be replayed on any other backend, including the
# older Matplotlib- and PyQt backends.  The player class provides fast bounding box
# detection, inplace transformation and rectangular content cropping.
#
# docs: https://ezdxf.mozman.at/docs/addons/drawing.html
# ------------------------------------------------------------------------------

CWD = pathlib.Path("~/Desktop/Outbox").expanduser()
if not CWD.exists():
    CWD = pathlib.Path(".")

COLORS = list(range(1, 7))
WIDTH = 400
HEIGHT = 400


def random_points(count: int, width: float, height: float):
    for _ in range(count):
        yield width * random.random(), height * random.random()


def create_content(msp):
    for s, e in zip(
        random_points(100, WIDTH, HEIGHT), random_points(100, WIDTH, HEIGHT)
    ):
        msp.add_line(s, e, dxfattribs={"color": random.choice(COLORS)})


def render_areas(extents, grid=(2, 2)) -> Iterator[BoundingBox2d]:
    """Returns a bounding box for each tile to render."""
    rows, cols = grid
    tile_width = extents.size.x / cols
    tile_height = extents.size.y / rows
    for row in range(rows):
        for col in range(cols):
            x_min = extents.extmin.x + col * tile_width
            y_min = extents.extmin.y + row * tile_height
            # BoundingBox2d ignores the z-axis!
            yield BoundingBox2d(
                [(x_min, y_min), (x_min + tile_width, y_min + tile_height)]
            )


def main(rows: int, cols: int):
    doc = ezdxf.new()
    msp = doc.modelspace()
    create_content(msp)

    ctx = RenderContext(doc)
    # record the output of the Frontend class
    recorder_backend = recorder.Recorder()
    Frontend(
        ctx,
        recorder_backend,
        config=config.Configuration(background_policy=config.BackgroundPolicy.WHITE),
    ).draw_layout(msp)

    # the main player has access to the original recordings
    main_player = recorder_backend.player()
    # basic layout settings for full image and all tiles
    settings = layout.Settings(fit_page=False)

    # export full image
    # always copy the main player when the content is rendered multiple times!
    full_player = main_player.copy()
    # create the output backend
    png_backend = pymupdf.PyMuPdfBackend()
    full_player.replay(png_backend)
    # export full image as png file, auto-detect image size
    page = layout.Page(0, 0, layout.Units.mm)
    (CWD / "full_image.png").write_bytes(
        png_backend.get_pixmap_bytes(page, settings=settings)
    )
    # calculating tile size:
    extents = full_player.bbox()
    image_size = extents.size
    tile_size_x = image_size.x / cols
    tile_size_y = image_size.y / rows

    # export image as tiles
    for tile, render_area in enumerate(render_areas(extents, (rows, cols))):
        # copy the content of the main player!!!
        tile_player = main_player.copy()
        # crop content to the size of the tile
        tile_player.crop_rect(render_area.extmin, render_area.extmax, distance=0.1)
        # create a new output backend for each tile
        png_backend = pymupdf.PyMuPdfBackend()
        tile_player.replay(png_backend)
        filename = f"tile-{tile:02d}.png"
        print(f'saving tile #{tile} to "{filename}"')
        # export tile as png file
        page = layout.Page(tile_size_x, tile_size_y, layout.Units.mm)
        (CWD / filename).write_bytes(
            png_backend.get_pixmap_bytes(
                page, fmt="png", settings=settings, render_box=render_area
            )
        )


if __name__ == "__main__":
    # create 3x3 tiles
    main(3, 3)