Drawing / Export Addon¶
This add-on provides the functionality to render a DXF document to produce a rasterized or vector-graphic image which can be saved to a file or viewed interactively depending on the backend being used.
The module provides two example scripts in the folder examples/addons/drawing
which can be run to save rendered images to files or view an interactive
visualisation.
$ ./draw_cad.py --supported_formats
# will list the file formats supported by the matplotlib backend.
# Many formats are supported including vector graphics formats
# such as pdf and svg
$ ./draw_cad.py <my_file.dxf> --out image.png
# draw a layout other than the model space
$ ./draw_cad.py <my_file.dxf> --layout Layout1 --out image.png
# opens a GUI application to view CAD files
$ ./cad_viewer.py
See also
How-to section for the FAQ about the Drawing Add-on.
Design¶
The implementation of the drawing
add-on is divided into a frontend and
multiple backends. The frontend handles the translation of DXF features and
properties into simplified structures, which are then processed by the backends.
Common Limitations to all Backends¶
rich text formatting of the MTEXT entity is close to AutoCAD but not pixel perfect
relative size of POINT entities cannot be replicated exactly
rendering of ACIS entities is not supported
no 3D rendering engine, therefore:
3D entities are projected into the xy-plane and 3D text is not supported
only top view rendering of the modelspace
VIEWPORTS are always rendered as top view
no visual style support
only basic support for:
infinite lines (rendered as lines with a finite length)
OLE2FRAME entities (rendered as rectangles)
vertical text (will render as horizontal text)
rendering of additional MTEXT columns may be incorrect
MatplotlibBackend¶
- class ezdxf.addons.drawing.matplotlib.MatplotlibBackend(ax, *, adjust_figure=True, font=FontProperties(), use_text_cache=True)¶
Backend which uses the
Matplotlib
package for image export.- Parameters
ax – drawing canvas as
matplotlib.pyplot.Axes
objectadjust_figure – automatically adjust the size of the parent
matplotlib.pyplot.Figure
to display all contentfont – default font properties
use_text_cache – use caching for text path rendering
The MatplotlibBackend
is used by the Draw command of the
ezdxf launcher.
Limitations¶
the text path rendering is different to AutoCAD, therefore text placement and wrapping may appear slightly different
the SVG export of dimensionless POINT entities is rendered as circles
has no VIEWPORT clipping support (yet?) and is therefore not very suitable for exporting paperspace layouts
Example for the usage of the Matplotlib
backend:
import sys
import matplotlib.pyplot as plt
from ezdxf import recover
from ezdxf.addons.drawing import RenderContext, Frontend
from ezdxf.addons.drawing.matplotlib import MatplotlibBackend
# Safe loading procedure (requires ezdxf v0.14):
try:
doc, auditor = recover.readfile('your.dxf')
except IOError:
print(f'Not a DXF file or a generic I/O error.')
sys.exit(1)
except ezdxf.DXFStructureError:
print(f'Invalid or corrupted DXF file.')
sys.exit(2)
# The auditor.errors attribute stores severe errors,
# which may raise exceptions when rendering.
if not auditor.has_errors:
fig = plt.figure()
ax = fig.add_axes([0, 0, 1, 1])
ctx = RenderContext(doc)
out = MatplotlibBackend(ax)
Frontend(ctx, out).draw_layout(doc.modelspace(), finalize=True)
fig.savefig('your.png', dpi=300)
Simplified render workflow but with less control:
from ezdxf import recover
from ezdxf.addons.drawing import matplotlib
# Exception handling left out for compactness:
doc, auditor = recover.readfile('your.dxf')
if not auditor.has_errors:
matplotlib.qsave(doc.modelspace(), 'your.png')
- ezdxf.addons.drawing.matplotlib.qsave(layout: Layout, filename: Union[str, PathLike], *, bg: Optional[str] = None, fg: Optional[str] = None, dpi: int = 300, backend: str = 'agg', config: Optional[Configuration] = None, filter_func: Optional[Callable[[DXFGraphic], bool]] = None, size_inches: Optional[tuple[float, float]] = None) None ¶
Quick and simplified render export by matplotlib.
- Parameters
layout – modelspace or paperspace layout to export
filename – export filename, file extension determines the format e.g. “image.png” to save in PNG format.
bg – override default background color in hex format #RRGGBB or #RRGGBBAA, e.g. use bg=”#FFFFFF00” to get a transparent background and a black foreground color (ACI=7), because a white background #FFFFFF gets a black foreground color or vice versa bg=”#00000000” for a transparent (black) background and a white foreground color.
fg – override default foreground color in hex format #RRGGBB or #RRGGBBAA, requires also bg argument. There is no explicit foreground color in DXF defined (also not a background color), but the ACI color 7 has already a variable color value, black on a light background and white on a dark background, this argument overrides this (ACI=7) default color value.
dpi – image resolution (dots per inches).
size_inches – paper size in inch as (width, height) tuple, which also defines the size in pixels = (width * dpi) x (height * dpi). If width or height is 0.0 the value is calculated by the aspect ratio of the drawing.
backend – the matplotlib rendering backend to use (agg, cairo, svg etc) (see documentation for matplotlib.use() for a complete list of backends)
config – drawing parameters
filter_func – filter function which takes a DXFGraphic object as input and returns
True
if the entity should be drawn orFalse
if the entity should be ignored
PyQtBackend¶
- class ezdxf.addons.drawing.pyqt.PyQtBackend(scene=None, *, extra_lineweight_scaling=2.0, use_text_cache=True)¶
Backend which uses the
PySide6
package to implement an interactive viewer. ThePyQt5
package can be used as fallback if thePySide6
package is not available.- Parameters
scene – drawing canvas of type
QtWidgets.QGraphicsScene
, ifNone
a new canvas will be createdextra_lineweight_scaling – compared to other backends, PyQt draws lines which appear thinner
use_text_cache – use caching for text path rendering
The PyQtBackend
is used by the View command of the
ezdxf launcher.
Limitations¶
the text path rendering is different to AutoCAD, therefore text placement and wrapping may appear slightly different
See also
The qtviewer.py module implements the core of a simple DXF viewer and the
cad_viewer.py example is a skeleton to show how to launch the
CADViewer
class.
PillowBackend¶
- class ezdxf.addons.drawing.pillow.PillowBackend(region: AbstractBoundingBox, image_size: Optional[tuple[int, int]] = None, resolution: float = 1.0, margin: int = 10, dpi: int = 300, oversampling: int = 1, text_mode=TextMode.OUTLINE)¶
Backend which uses the
Pillow
package for image export.For linetype support configure the line_policy in the frontend as ACCURATE.
- Parameters
region – output region of the layout in DXF drawing units
image_size – image output size in pixels or
None
to be calculated by the region size and the resolutionmargin – image margin in pixels, same margin for all four borders
resolution – pixels per DXF drawing unit, e.g. a resolution of 100 for the drawing unit “meter” means, each pixel represents an area of 1cm x 1cm (1m is 100cm). If the image_size is given the resolution is calculated automatically
dpi – output image resolution in dots per inch. The pixel width of lines is determined by the DXF lineweight (in mm) and this image resolution (dots/pixels per inch). The line width is independent of the drawing scale!
oversampling – multiplier of the final image size to define the render canvas size (e.g. 1, 2, 3, …), the final image will be scaled down by the LANCZOS method
text_mode –
text rendering mode
IGNORE: do not draw text
PLACEHOLDER: draw text as filled rectangles
OUTLINE: draw text as outlines (recommended)
FILLED: simulate text filling by hatching the text outline with dense lines - has some issues
The PillowBackend
is used by the Pillow command of the
ezdxf launcher. The pillow.py example script is the development prototype
for the Pillow command.
Limitations¶
text paths are generated by
matplotlib
the text path rendering is different to AutoCAD, therefore text placement and wrapping may appear slightly different
no real solid fill for HATCH entities and text glyphs; simulated by a dense line pattern filling, to improve this, a triangulation algorithm with support for nested holes (hole in hole in hole …) is required
Configuration¶
Additional options for the drawing add-on can be passed by the config
argument of the Frontend
constructor __init__()
. Not every
option will be supported by all backends.
- class ezdxf.addons.drawing.config.Configuration(pdsize: Optional[int], pdmode: Optional[int], measurement: Optional[Measurement], show_defpoints: bool, proxy_graphic_policy: ProxyGraphicPolicy, line_policy: LinePolicy, hatch_policy: HatchPolicy, infinite_line_length: float, lineweight_scaling: float, min_lineweight: Optional[float], min_dash_length: float, max_flattening_distance: float, circle_approximation_count: int, hatching_timeout: float)¶
Configuration options for the
drawing
add-on.- pdsize¶
the size to draw POINT entities (in drawing units) set to None to use the $PDSIZE value from the dxf document header
0
5% of draw area height
<0
Specifies a percentage of the viewport size
>0
Specifies an absolute size
None
use the $PDMODE value from the dxf document header
- Type
Optional[int]
- pdmode¶
point styling mode (see POINT documentation)
see
Point
class documentation- Type
Optional[int]
- measurement¶
whether to use metric or imperial units as enum
ezdxf.enums.Measurement
0
use imperial units (in, ft, yd, …)
1
use metric units (ISO meters)
None
use the $MEASUREMENT value from the dxf document header
- Type
Optional[ezdxf.enums.Measurement]
- show_defpoints¶
whether to show or filter out POINT entities on the defpoints layer
- Type
bool
- proxy_graphic_policy¶
the action to take when a proxy graphic is encountered
- line_policy¶
the method to use when drawing styled lines (eg dashed, dotted etc)
- hatch_policy¶
the method to use when drawing HATCH entities
- infinite_line_length¶
the length to use when drawing infinite lines
- Type
float
- lineweight_scaling¶
multiplies every lineweight by this factor; set this factor to 0.0 for a constant minimum line width defined by the
min_lineweight
setting for all lineweights; the correct DXF lineweight often looks too thick in SVG, so setting a factor < 1 can improve the visual appearance- Type
float
- min_lineweight¶
the minimum line width in 1/300 inch; set to
None
for let the backend choose.- Type
Optional[float]
- min_dash_length¶
the minimum length for a dash when drawing a styled line (default value is arbitrary)
- Type
float
- max_flattening_distance¶
Max flattening distance in drawing units see Path.flattening documentation. The backend implementation should calculate an appropriate value, like 1 screen- or paper pixel on the output medium, but converted into drawing units. Sets Path() approximation accuracy
- Type
float
- circle_approximation_count¶
Approximate a full circle by n segments, arcs have proportional less segments. Only used for approximation of arcs in banded polylines.
- Type
int
- hatching_timeout¶
hatching timeout for a single entity, very dense hatching patterns can cause a very long execution time, the default timeout for a single entity is 30 seconds.
- Type
float
- defaults()¶
Returns a frozen
Configuration
object with default values.
- with_changes()¶
Returns a new frozen
Configuration
object with modified values.Usage:
my_config = Configuration.defaults() my_config = my_config.with_changes(lineweight_scaling=2)
LinePolicy¶
- class ezdxf.addons.drawing.config.LinePolicy(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)¶
- SOLID¶
draw all lines as solid regardless of the linetype style
- APPROXIMATE¶
use the closest approximation available to the backend for rendering styled lines
- ACCURATE¶
analyse and render styled lines as accurately as possible. This approach is slower and is not well suited to interactive applications.
HatchPolicy¶
- class ezdxf.addons.drawing.config.HatchPolicy(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)¶
The action to take when a HATCH entity is encountered
- IGNORE¶
do not show HATCH entities at all
- SHOW_OUTLINE¶
show only the outline of HATCH entities
- SHOW_SOLID¶
show HATCH entities but draw with solid fill regardless of the pattern
ProxyGraphicPolicy¶
- class ezdxf.addons.drawing.config.ProxyGraphicPolicy(value, names=None, *, module=None, qualname=None, type=None, start=1, boundary=None)¶
The action to take when an entity with a proxy graphic is encountered
Note
To get proxy graphics support proxy graphics have to be loaded: Set the global option
ezdxf.options.load_proxy_graphics
toTrue
, which is the default value.This can not prevent drawing proxy graphic inside of blocks, because this is outside of the domain of the drawing add-on!
- IGNORE¶
do not display proxy graphics (skip_entity will be called instead)
- SHOW¶
if the entity cannot be rendered directly (eg if not implemented) but a proxy is present: display the proxy
- PREFER¶
display proxy graphics even for entities where direct rendering is available
Properties¶
- class ezdxf.addons.drawing.properties.Properties¶
An implementation agnostic representation of DXF entity properties like color and linetype. These properties represent the actual values after resolving all DXF specific rules like “by layer”, “by block” and so on.
- color¶
The actual color value of the DXF entity as “#RRGGBB” or “#RRGGBBAA” string. An alpha value of “00” is opaque and “ff” is fully transparent.
- linetype_name¶
The actual linetype name as string like “CONTINUOUS”
- linetype_pattern¶
The simplified DXF linetype pattern as tuple of floats, all line elements and gaps are values greater than 0.0 and 0.0 represents a point. Line or point elements do always alternate with gap elements: line-gap-line-gap-point-gap and the pattern always ends with a gap. The continuous line is an empty tuple.
- linetype_scale¶
The scaling factor as float to apply to the
linetype_pattern
.
- lineweight¶
The absolute lineweight to render in mm as float.
- is_visible¶
Visibility flag as bool.
- layer¶
The actual layer name the entity resides on as UPPERCASE string.
- font¶
The
FontFace
used for text rendering orNone
.
- filling¶
The actual
Filling
properties of the entity orNone
.
- units¶
The actual drawing units as
InsertUnits
enum.
LayerProperties¶
LayoutProperties¶
- class ezdxf.addons.drawing.properties.LayoutProperties¶
Actual layout properties.
- name¶
Layout name as string
- units¶
Layout units as
InsertUnits
enum.
- property LayoutProperties.background_color: str¶
Returns the default layout background color.
- property LayoutProperties.default_color: str¶
Returns the default layout foreground color.
- property LayoutProperties.has_dark_background: bool¶
Returns
True
if the actual background-color is “dark”.
- LayoutProperties.set_colors(bg: str, fg: Optional[str] = None) None ¶
Setup default layout colors.
Required color format “#RRGGBB” or including alpha transparency “#RRGGBBAA”.
RenderContext¶
- class ezdxf.addons.drawing.properties.RenderContext(doc: Optional[Drawing] = None, *, ctb: str = '', export_mode: bool = False)¶
The render context for the given DXF document. The
RenderContext
resolves the properties of DXF entities from the context they reside in to actual values like RGB colors, transparency, linewidth and so on.A given ctb file (plot style file) overrides the default properties for all layouts, which means the plot style table stored in the layout is always ignored.
- Parameters
doc – DXF document
ctb – path to a plot style table
export_mode – Whether to render the document as it would look when exported (plotted) by a CAD application to a file such as pdf, or whether to render the document as it would appear inside a CAD application.
- resolve_aci_color(aci: int, resolved_layer: str) str ¶
Resolve the aci color as hex color string: “#RRGGBB”
- resolve_all(entity: DXFGraphic) Properties ¶
Resolve all properties of entity.
- resolve_color(entity: DXFGraphic, *, resolved_layer: Optional[str] = None) str ¶
Resolve the rgb-color of entity as hex color string: “#RRGGBB” or “#RRGGBBAA”.
- resolve_filling(entity: DXFGraphic) Optional[Filling] ¶
Resolve filling properties (SOLID, GRADIENT, PATTERN) of entity.
- resolve_font(entity: DXFGraphic) Optional[FontFace] ¶
Resolve the text style of entity to a font name. Returns
None
for the default font.
- resolve_layer(entity: DXFGraphic) str ¶
Resolve the layer of entity, this is only relevant for entities inside of block references.
- resolve_layer_properties(layer: Layer) LayerProperties ¶
Resolve layer properties.
- resolve_linetype(entity: DXFGraphic, *, resolved_layer: Optional[str] = None) tuple[str, Sequence[float]] ¶
Resolve the linetype of entity. Returns a tuple of the linetype name as upper-case string and the simplified linetype pattern as tuple of floats.
- resolve_lineweight(entity: DXFGraphic, *, resolved_layer: Optional[str] = None) float ¶
Resolve the lineweight of entity in mm.
DXF stores the lineweight in mm times 100 (e.g. 0.13mm = 13). The smallest line weight is 0 and the biggest line weight is 211. The DXF/DWG format is limited to a fixed value table, see:
ezdxf.lldxf.const.VALID_DXF_LINEWEIGHTS
CAD applications draw lineweight 0mm as an undefined small value, to prevent backends to draw nothing for lineweight 0mm the smallest return value is 0.01mm.
- resolve_units() InsertUnits ¶
- resolve_visible(entity: DXFGraphic, *, resolved_layer: Optional[str] = None) bool ¶
Resolve the visibility state of entity. Returns
True
if entity is visible.
- set_current_layout(layout: Layout, ctb: str = '')¶
Set the current layout and update layout specific properties.
- set_layer_properties_override(func: Optional[Callable[[Sequence[LayerProperties]], None]] = None)¶
The function func is called with the current layer properties as argument after resetting them, so the function can override the layer properties.
The RenderContext
class can be used isolated from the drawing
add-on to resolve DXF properties.
Frontend¶
- class ezdxf.addons.drawing.frontend.Frontend(ctx: RenderContext, out: BackendInterface, config: Configuration = Configuration.defaults(), bbox_cache: ezdxf.bbox.Cache = None)¶
Drawing frontend, responsible for decomposing entities into graphic primitives and resolving entity properties.
By passing the bounding box cache of the modelspace entities can speed up paperspace rendering, because the frontend can filter entities which are not visible in the VIEWPORT. Even passing in an empty cache can speed up rendering time when multiple viewports need to be processed.
- Parameters
ctx – the properties relevant to rendering derived from a DXF document
out – the backend to draw to
config – settings to configure the drawing frontend and backend
bbox_cache – bounding box cache of the modelspace entities or an empty cache which will be filled dynamically when rendering multiple viewports or
None
to disable bounding box caching at all
- log_message(message: str)¶
Log given message - override to alter behavior.
- skip_entity(entity: DXFEntity, msg: str) None ¶
Called for skipped entities - override to alter behavior.
- override_properties(entity: DXFGraphic, properties: Properties) None ¶
The
override_properties()
filter can change the properties of an entity independent of the DXF attributes.This filter has access to the DXF attributes by the entity object, the current render context, and the resolved properties by the properties object. It is recommended to modify only the properties object in this filter.
- draw_layout(layout: Layout, finalize: bool = True, *, filter_func: Optional[Callable[[DXFGraphic], bool]] = None, layout_properties: Optional[LayoutProperties] = None) None ¶
Draw all entities of the given layout.
Draws the entities of the layout in the default or redefined redraw-order and calls the
finalize()
method of the backend if requested. The default redraw order is the ascending handle order not the order the entities are stored in the layout.The method skips invisible entities and entities for which the given filter function returns
False
.- Parameters
layout – layout to draw of type
Layout
finalize –
True
if thefinalize()
method of the backend should be called automaticallyfilter_func – function to filter DXf entities, the function should return
False
if a given entity should be ignoredlayout_properties – override the default layout properties
BackendInterface¶
- class ezdxf.addons.drawing.backend.BackendInterface¶
The public interface definition for the rendering backend.
For more information read the source code: backend.py
Backend¶
- class ezdxf.addons.drawing.backend.Backend¶
Abstract base class for concrete backend implementations and implements some default features.
For more information read the source code: backend.py
Details¶
The rendering is performed in two stages. The frontend traverses the DXF document
structure, converting each encountered entity into primitive drawing commands.
These commands are fed to a backend which implements the interface:
Backend
.
Although the resulting images will not be pixel-perfect with AutoCAD (which was taken as the ground truth when developing this add-on) great care has been taken to achieve similar behavior in some areas:
The algorithm for determining color should match AutoCAD. However, the color palette is not stored in the DXF file, so the chosen colors may be different to what is expected. The
RenderContext
class supports passing a plot style table (CTB-file) as custom color palette but uses the same palette as AutoCAD by default.Text rendering is quite accurate, text positioning, alignment and word wrapping are very faithful. Differences may occur if a different font from what was used by the CAD application but even in that case, for supported backends, measurements are taken of the font being used to match text as closely as possible.
Visibility determination (based on which layers are visible) should match AutoCAD
See also
draw_cad.py for a simple use of this module
cad_viewer.py for an advanced use of this module
Notes on Rendering DXF Content for additional behaviours documented during the development of this add-on.