Drawing / Export Add-on¶
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 VISUALSTYLE 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¶
The MatplotlibBackend
is used by the Draw command of the
ezdxf launcher.
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')
PyQtBackend¶
The PyQtBackend
is used by the View command of the
ezdxf launcher.
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.
Recorder¶
Added in version 1.1.
This is a special backend which records the output of the Frontend
class in compact numpy arrays and these recordings and can be played by a Player
instance on one or more backends.
The recorded numpy arrays support measurement of bounding boxes and transformations
which is for some backends a requirement to place the DXF content on size limited pages.
Layout¶
Added in version 1.1.
The Layout
class builds the page layout and the matrix to transform the DXF
content to page coordinates according to the layout Settings
.
The DXF coordinate transformation is required for PDF and HPGL/2 which expects the
output coordinates in the first quadrant and SVG which has an inverted y-axis.
The Layout
class uses following classes and enums for configuration:
Page
- page definitionMargins
- page margins definitionSettings
- configuration settingsUnits
- enum for page units
SVGBackend¶
Added in version 1.1.
Usage:
from ezdxf.addons.drawing import Frontend, RenderContext
from ezdxf.addons.drawing import layout, svg
doc = ezdxf.readfile("your.dxf")
msp = doc.modelspace()
backend = svg.SVGBackend()
Frontend(RenderContext(doc), backend).draw_layout(msp)
with open("your.svg", "wt") as fp:
fp.write(backend.get_string(layout.Page(0, 0))
PyMuPdfBackend¶
Added in version 1.1.
Usage:
import ezdxf
from ezdxf.addons.drawing import Frontend, RenderContext
from ezdxf.addons.drawing import layout, pymupdf
doc = ezdxf.readfile("your.dxf")
msp = doc.modelspace()
backend = pymupdf.PyMuPdfBackend()
Frontend(RenderContext(doc), backend).draw_layout(msp)
with open("your.pdf", "wb") as fp:
fp.write(backend.get_pdf_bytes(layout.Page(0, 0))
Load the output of the PyMuPdfBackend
into the Image
class of the Pillow
package for further processing or to output additional image formats:
import io
from PIL import Image
... # see above
# the ppm format is faster to process than png
fp = io.BytesIO(backend.get_pixmap_bytes(layout.Page(0, 0), fmt="ppm", dpi=300))
image = Image.open(fp, formats=["ppm"])
PlotterBackend¶
Added in version 1.1.
Usage:
import ezdxf
from ezdxf.addons.drawing import Frontend, RenderContext
from ezdxf.addons.drawing import layout, hpgl2
doc = ezdxf.readfile("your.dxf")
psp = doc.paperspace("Layout1")
backend = hpgl2.PlotterBackend()
Frontend(RenderContext(doc), backend).draw_layout(psp)
page = layout.Page.from_dxf_layout(psp)
with open("your.plt", "wb") as fp:
fp.write(backend.normal_quality(page)
You can check the output by the HPGL/2 viewer:
ezdxf hpgl your.plt
DXFBackend¶
Added in version 1.1.
Render a paperspace layout into modelspace:
import ezdxf
from ezdxf.addons.drawing import Frontend, RenderContext
from ezdxf.addons.drawing import layout, dxf
doc = ezdxf.readfile("your.dxf")
layout1 = doc.paperspace("Layout1")
output_doc = ezdxf.new()
output_msp = output_doc.modelspace()
backend = dxf.DXFBackend(output_msp)
Frontend(RenderContext(doc), backend).draw_layout(layout1)
output_doc.saveas("layout1_in_modelspace.dxf")
GeoJSONBackend¶
Added in version 1.3.0.
CustomJSONBackend¶
Added in version 1.3.0.
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.
Usage:
my_config = Configuration(lineweight_scaling=2)
BackgroundPolicy¶
ColorPolicy¶
HatchPolicy¶
ImagePolicy¶
LinePolicy¶
LineweightPolicy¶
ProxyGraphicPolicy¶
TextPolicy¶
Properties¶
LayerProperties¶
LayoutProperties¶
- class ezdxf.addons.drawing.properties.LayoutProperties¶
Actual layout properties.
- name¶
Layout name as string
- units¶
Layout units as
InsertUnits
enum.
RenderContext¶
The RenderContext
class can be used isolated from the drawing
add-on to resolve DXF properties.
Frontend¶
BackendInterface¶
- class ezdxf.addons.drawing.backend.BackendInterface¶
Public interface definition for 2D rendering backends.
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.