Files
stepanalyser/.venv/lib/python3.12/site-packages/ezdxf/addons/r12writer.py
Christian Anetzberger a197de9456 initial
2026-01-22 20:23:51 +01:00

1234 lines
25 KiB
Python

# Copyright (c) 2016-2022, Manfred Moitzi
# License: MIT License
# Purpose: fast & simple but restricted DXF R12 writer, with no in-memory
# drawing, and without dependencies to other ezdxf modules.
# The created DXF file contains no HEADER, TABLES or BLOCKS section only the
# ENTITIES section is present.
from __future__ import annotations
from typing import (
TextIO,
BinaryIO,
Union,
Sequence,
Iterable,
cast,
Iterator,
Optional,
)
from contextlib import contextmanager
from functools import partial
from io import StringIO
from pathlib import Path
from ezdxf.lldxf.tagwriter import BinaryTagWriter
Vertex = Sequence[float]
rnd = partial(round, ndigits=6)
TEXT_ALIGN_FLAGS = {
"LEFT": (0, 0),
"CENTER": (1, 0),
"RIGHT": (2, 0),
"BOTTOM_LEFT": (0, 1),
"BOTTOM_CENTER": (1, 1),
"BOTTOM_RIGHT": (2, 1),
"MIDDLE_LEFT": (0, 2),
"MIDDLE_CENTER": (1, 2),
"MIDDLE_RIGHT": (2, 2),
"TOP_LEFT": (0, 3),
"TOP_CENTER": (1, 3),
"TOP_RIGHT": (2, 3),
}
VERTEX_GROUP_CODES = {"x": 10, "y": 20, "s": 40, "e": 41, "b": 42}
class BinaryDXFWriter:
def __init__(self, stream: BinaryIO):
self._stream = stream
self._tagwriter = BinaryTagWriter(
self._stream,
dxfversion="AC1009",
write_handles=False,
encoding="cp1252",
)
self._tagwriter.write_signature()
def write(self, s: str) -> None:
self._tagwriter.write_str(s)
@contextmanager
def r12writer(
stream: Union[TextIO, BinaryIO, str, Path],
fixed_tables: bool = False,
fmt: str = "asc",
) -> Iterator[R12FastStreamWriter]:
"""Context manager for writing DXF entities to a stream/file. `stream` can
be any file like object with a :func:`write` method or just a string for
writing DXF entities to the file system. If `fixed_tables` is ``True``, a
standard TABLES section is written in front of the ENTITIES
section and some predefined text styles and line types can be used.
Set argument `fmt` to "asc" to write ASCII DXF file (default) or "bin" to
write Binary DXF files. ASCII DXF require a :class:`TextIO` stream and
Binary DXF require a :class:`BinaryIO` stream.
"""
_stream: Union[TextIO, BinaryIO, None] = None
if fmt.startswith("asc"):
if isinstance(stream, (str, Path)):
_stream = open(stream, "wt", encoding="cp1252")
stream = _stream
elif fmt.startswith("bin"):
if isinstance(stream, (str, Path)):
_stream = open(stream, "wb")
stream = cast(TextIO, BinaryDXFWriter(_stream))
else:
stream = cast(TextIO, BinaryDXFWriter(cast(BinaryIO, stream)))
else:
raise ValueError(f"Unknown format '{fmt}'.")
writer = R12FastStreamWriter(cast(TextIO, stream), fixed_tables)
try:
yield writer
finally:
writer.close()
if _stream:
_stream.close()
class R12FastStreamWriter:
"""Fast stream writer to create simple DXF R12 drawings.
Args:
stream: a file like object with a :func:`write` method.
fixed_tables: if `fixed_tables` is ``True``, a standard TABLES section
is written in front of the ENTITIES section and some predefined text
styles and line types can be used.
"""
def __init__(self, stream: TextIO, fixed_tables=False):
self.stream = stream
if fixed_tables:
stream.write(PREFACE)
stream.write("0\nSECTION\n2\nENTITIES\n") # write header
def close(self) -> None:
"""Writes the DXF tail. Call is not necessary when using the context
manager :func:`r12writer`.
"""
self.stream.write("0\nENDSEC\n0\nEOF\n") # write tail
def add_line(
self,
start: Vertex,
end: Vertex,
layer: str = "0",
color: Optional[int] = None,
linetype: Optional[str] = None,
) -> None:
"""Add a LINE entity from `start` to `end`.
Args:
start: start vertex as ``(x, y[, z])`` tuple
end: end vertex as as ``(x, y[, z])`` tuple
layer: layer name as string, without a layer definition the assigned
color = ``7`` (black/white) and line type is ``'Continuous'``.
color: color as :ref:`ACI` in the range from ``0`` to ``256``,
``0`` is `ByBlock` and ``256`` is `ByLayer`, default is `ByLayer`
which is always color = ``7`` (black/white) without a layer
definition.
linetype: line type as string, if FIXED-TABLES are written some
predefined line types are available, else line type is always
`ByLayer`, which is always ``'Continuous'`` without a LAYERS
table.
"""
dxf = ["0\nLINE\n"]
dxf.append(dxf_attribs(layer, color, linetype))
dxf.append(dxf_vertex(start, code=10))
dxf.append(dxf_vertex(end, code=11))
self.stream.write("".join(dxf))
def add_circle(
self,
center: Vertex,
radius: float,
layer: str = "0",
color: Optional[int] = None,
linetype: Optional[str] = None,
) -> None:
"""Add a CIRCLE entity.
Args:
center: circle center point as ``(x, y)`` tuple
radius: circle radius as float
layer: layer name as string see :meth:`add_line`
color: color as :ref:`ACI` see :meth:`add_line`
linetype: line type as string see :meth:`add_line`
"""
dxf = ["0\nCIRCLE\n"]
dxf.append(dxf_attribs(layer, color, linetype))
dxf.append(dxf_vertex(center))
dxf.append(dxf_tag(40, str(rnd(radius))))
self.stream.write("".join(dxf))
def add_arc(
self,
center: Vertex,
radius: float,
start: float = 0,
end: float = 360,
layer: str = "0",
color: Optional[int] = None,
linetype: Optional[str] = None,
) -> None:
"""Add an ARC entity. The arc goes counter-clockwise from `start` angle
to `end` angle.
Args:
center: arc center point as ``(x, y)`` tuple
radius: arc radius as float
start: arc start angle in degrees as float
end: arc end angle in degrees as float
layer: layer name as string see :meth:`add_line`
color: color as :ref:`ACI` see :meth:`add_line`
linetype: line type as string see :meth:`add_line`
"""
dxf = ["0\nARC\n"]
dxf.append(dxf_attribs(layer, color, linetype))
dxf.append(dxf_vertex(center))
dxf.append(dxf_tag(40, str(rnd(radius))))
dxf.append(dxf_tag(50, str(rnd(start))))
dxf.append(dxf_tag(51, str(rnd(end))))
self.stream.write("".join(dxf))
def add_point(
self,
location: Vertex,
layer: str = "0",
color: Optional[int] = None,
linetype: Optional[str] = None,
) -> None:
"""
Add a POINT entity.
Args:
location: point location as ``(x, y [,z])`` tuple
layer: layer name as string see :meth:`add_line`
color: color as :ref:`ACI` see :meth:`add_line`
linetype: line type as string see :meth:`add_line`
"""
dxf = ["0\nPOINT\n"]
dxf.append(dxf_attribs(layer, color, linetype))
dxf.append(dxf_vertex(location))
self.stream.write("".join(dxf))
def add_3dface(
self,
vertices: Iterable[Vertex],
invisible: int = 0,
layer: str = "0",
color: Optional[int] = None,
linetype: Optional[str] = None,
) -> None:
"""Add a 3DFACE entity. 3DFACE is a spatial area with 3 or 4 vertices,
all vertices have to be in the same plane.
Args:
vertices: iterable of 3 or 4 ``(x, y, z)`` vertices.
invisible: bit coded flag to define the invisible edges,
1. edge = 1
2. edge = 2
3. edge = 4
4. edge = 8
Add edge values to set multiple edges invisible,
1. edge + 3. edge = 1 + 4 = 5, all edges = 15
layer: layer name as string see :meth:`add_line`
color: color as :ref:`ACI` see :meth:`add_line`
linetype: line type as string see :meth:`add_line`
"""
self._add_quadrilateral(
"3DFACE", vertices, invisible, layer, color, linetype
)
def add_solid(
self,
vertices: Iterable[Vertex],
layer: str = "0",
color: Optional[int] = None,
linetype: Optional[str] = None,
) -> None:
"""Add a SOLID entity. SOLID is a solid filled area with 3 or 4 edges
and SOLID is a 2D entity.
Args:
vertices: iterable of 3 or 4 ``(x, y[, z])`` tuples, z-axis will be
ignored.
layer: layer name as string see :meth:`add_line`
color: color as :ref:`ACI` see :meth:`add_line`
linetype: line type as string see :meth:`add_line`
"""
self._add_quadrilateral("SOLID", vertices, 0, layer, color, linetype)
def _add_quadrilateral(
self,
dxftype: str,
vertices: Iterable[Vertex],
flags: int,
layer: str,
color: Optional[int],
linetype: Optional[str],
) -> None:
dxf = ["0\n%s\n" % dxftype]
dxf.append(dxf_attribs(layer, color, linetype))
vertices = list(vertices)
if len(vertices) < 3:
raise ValueError("%s needs 3 or 4 vertices." % dxftype)
elif len(vertices) == 3:
vertices.append(vertices[-1]) # double last vertex
dxf.extend(
dxf_vertex(vertex, code)
for code, vertex in enumerate(vertices, start=10)
)
if flags:
dxf.append(dxf_tag(70, str(flags)))
self.stream.write("".join(dxf))
def add_polyline(
self,
vertices: Iterable[Vertex],
closed: bool = False,
layer: str = "0",
color: Optional[int] = None,
linetype: Optional[str] = None,
) -> None:
"""Add a 3D POLYLINE entity.
Args:
vertices: iterable of ``(x, y[, z])`` tuples, z-axis is ``0`` by
default
closed: ``True`` creates a closed polyline
layer: layer name as string see :meth:`add_line`
color: color as :ref:`ACI` see :meth:`add_line`
linetype: line type as string see :meth:`add_line`
"""
dxf = ["0\nPOLYLINE\n"]
dxf.append(dxf_attribs(layer, color, linetype))
dxf.append(dxf_tag(66, 1)) # entities follow
dxf.append(dxf_tag(70, 8 + int(closed))) # bit 1 is the closed state
self.stream.write("".join(dxf))
vertex_template = "0\nVERTEX\n" + dxf_attribs(layer) + dxf_tag(70, 32)
for vertex in vertices:
self.stream.write(vertex_template)
vertex = tuple(vertex)
len_vertex = len(vertex)
if len_vertex < 2:
raise ValueError("Vertices require at least a x- and a y-axis.")
elif len_vertex == 2:
vertex = (vertex[0], vertex[1], 0)
self.stream.write(dxf_vertex(vertex[:3]))
self.stream.write("0\nSEQEND\n")
def add_polyline_2d(
self,
points: Iterable[Sequence],
format: str = "xy",
closed: bool = False,
start_width: float = 0,
end_width: float = 0,
layer: str = "0",
color: Optional[int] = None,
linetype: Optional[str] = None,
) -> None:
"""Add a 2D POLYLINE entity with start width, end width and bulge value
support.
Format codes:
=== =================================
x x-coordinate
y y-coordinate
s start width
e end width
b bulge value
v (x, y) tuple (z-axis is ignored)
=== =================================
Args:
points: iterable of (x, y, [start_width, [end_width, [bulge]]])
tuple, value order according to the `format` string, unset
values default to ``0``
format: format: format string, default is ``'xy'``
closed: ``True`` creates a closed polyline
start_width: default start width, default is ``0``
end_width: default end width, default is ``0``
layer: layer name as string see :meth:`add_line`
color: color as :ref:`ACI` see :meth:`add_line`
linetype: line type as string see :meth:`add_line`
"""
def vertex_attribs(data: Sequence) -> dict:
attribs = dict()
for code, value in zip(format, data):
if code == "v":
location = tuple(value)
attribs["x"] = location[0]
attribs["y"] = location[1]
else:
attribs[code] = value
return attribs
dxf = ["0\nPOLYLINE\n"]
dxf.append(dxf_attribs(layer, color, linetype))
dxf.append(dxf_tag(66, 1)) # entities follow
dxf.append(dxf_tag(70, int(closed))) # bit 1 is the closed state
if start_width: # default start width
dxf.append(dxf_tag(40, start_width))
if end_width: # default end width
dxf.append(dxf_tag(41, end_width))
self.stream.write("".join(dxf))
vertex_template = "0\nVERTEX\n" + dxf_attribs(layer) + dxf_tag(70, 0)
for point in points:
self.stream.write(vertex_template)
attribs = vertex_attribs(point)
for format_code in format:
value = attribs.get(format_code, 0)
if value == 0 and format_code in "seb":
continue # do not write default values
self.stream.write(
dxf_tag(VERTEX_GROUP_CODES[format_code], value)
)
self.stream.write("0\nSEQEND\n")
def add_polyface(
self,
vertices: Iterable[Vertex],
faces: Iterable[Sequence[int]],
layer: str = "0",
color: Optional[int] = None,
linetype: Optional[str] = None,
) -> None:
"""Add a POLYFACE entity. The POLYFACE entity supports only faces of
maximum 4 vertices, more indices will be ignored. A simple square would
be::
v0 = (0, 0, 0)
v1 = (1, 0, 0)
v2 = (1, 1, 0)
v3 = (0, 1, 0)
dxf.add_polyface(vertices=[v0, v1, v2, v3], faces=[(0, 1, 2, 3)])
All 3D form functions of the :mod:`ezdxf.render.forms` module return
:class:`~ezdxf.render.MeshBuilder` objects, which provide the required
vertex and face lists.
See sphere example: https://github.com/mozman/ezdxf/blob/master/examples/r12writer.py
Args:
vertices: iterable of ``(x, y, z)`` tuples
faces: iterable of 3 or 4 vertex indices, indices have to be 0-based
layer: layer name as string see :meth:`add_line`
color: color as :ref:`ACI` see :meth:`add_line`
linetype: line type as string see :meth:`add_line`
"""
def write_polyline(flags: int = 64) -> None:
dxf = ["0\nPOLYLINE\n"]
dxf.append(dxf_attribs(layer, color, linetype))
dxf.append(dxf_tag(66, 1)) # entities follow
dxf.append(dxf_tag(70, flags))
dxf.append(dxf_tag(71, vertex_count))
dxf.append(dxf_tag(72, face_count))
self.stream.write("".join(dxf))
def write_vertices(flags: int = 64 + 128):
buf = StringIO()
count = 0
s = "0\nVERTEX\n" + dxf_attribs(layer) + dxf_tag(70, flags)
for vertex in vertices:
count += 1
buf.write(s)
buf.write(dxf_vertex(vertex))
s = buf.getvalue()
buf.close()
return count, s
def write_faces(flags: int = 128):
buf = StringIO()
count = 0
s = (
"0\nVERTEX\n"
+ dxf_attribs(layer, color)
+ dxf_tag(70, flags)
+ dxf_vertex((0, 0, 0))
)
for face in faces:
count += 1
buf.write(s)
for code, index in zip((71, 72, 73, 74), face):
buf.write(dxf_tag(code, index + 1))
s = buf.getvalue()
buf.close()
return count, s
vertex_count, vertex_str = write_vertices()
face_count, face_str = write_faces()
write_polyline()
self.stream.write(vertex_str)
self.stream.write(face_str)
self.stream.write("0\nSEQEND\n")
def add_polymesh(
self,
vertices: Iterable[Vertex],
size: tuple[int, int],
closed=(False, False),
layer: str = "0",
color: Optional[int] = None,
linetype: Optional[str] = None,
) -> None:
"""Add a POLYMESH entity. A POLYMESH is a mesh of m rows and n columns,
each mesh vertex has its own x-, y- and z coordinates. The mesh can be
closed in m- and/or n-direction. The vertices have to be in column
order: (m0, n0), (m0, n1), (m0, n2), (m1, n0), (m1, n1), (m1, n2), ...
See example: https://github.com/mozman/ezdxf/blob/master/examples/r12writer.py
Args:
vertices: iterable of ``(x, y, z)`` tuples, in column order
size: mesh dimension as (m, n)-tuple, requirement:
``len(vertices) == m*n``
closed: (m_closed, n_closed) tuple, for closed mesh in m and/or n
direction
layer: layer name as string see :meth:`add_line`
color: color as :ref:`ACI` see :meth:`add_line`
linetype: line type as string see :meth:`add_line`
"""
m, n = size
m_closed, n_closed = closed
def write_polyline(flags: int = 16) -> None:
if m_closed:
flags += 1
if n_closed:
flags += 32
dxf = ["0\nPOLYLINE\n"]
dxf.append(dxf_attribs(layer, color, linetype))
dxf.append(dxf_tag(66, 1)) # entities follow
dxf.append(dxf_tag(70, flags))
dxf.append(dxf_tag(71, m))
dxf.append(dxf_tag(72, n))
self.stream.write("".join(dxf))
def write_vertices(flags: int = 64) -> int:
count = 0
s = "0\nVERTEX\n" + dxf_attribs(layer) + dxf_tag(70, flags)
for vertex in vertices:
count += 1
self.stream.write(s)
self.stream.write(dxf_vertex(vertex))
return count
write_polyline()
count = write_vertices()
if m * n != count:
raise ValueError("Invalid mesh dimensions.")
self.stream.write("0\nSEQEND\n")
def add_text(
self,
text: str,
insert: Vertex = (0, 0),
height: float = 1.0,
width: float = 1.0,
align: str = "LEFT",
rotation: float = 0.0,
oblique: float = 0.0,
style: str = "STANDARD",
layer: str = "0",
color: Optional[int] = None,
) -> None:
"""Add a one line TEXT entity.
Args:
text: the text as string
insert: insert location as ``(x, y)`` tuple
height: text height in drawing units
width: text width as factor
align: text alignment, see table below
rotation: text rotation in degrees as float
oblique: oblique in degrees as float, vertical = ``0`` (default)
style: text style name as string, if FIXED-TABLES are written some
predefined text styles are available, else text style is
always ``'STANDARD'``.
layer: layer name as string see :meth:`add_line`
color: color as :ref:`ACI` see :meth:`add_line`
============ =============== ================= =====
Vert/Horiz Left Center Right
============ =============== ================= =====
Top ``TOP_LEFT`` ``TOP_CENTER`` ``TOP_RIGHT``
Middle ``MIDDLE_LEFT`` ``MIDDLE_CENTER`` ``MIDDLE_RIGHT``
Bottom ``BOTTOM_LEFT`` ``BOTTOM_CENTER`` ``BOTTOM_RIGHT``
Baseline ``LEFT`` ``CENTER`` ``RIGHT``
============ =============== ================= =====
The special alignments ``ALIGNED`` and ``FIT`` are not available.
"""
# text style is always STANDARD without a TABLES section
dxf = ["0\nTEXT\n"]
dxf.append(dxf_attribs(layer, color))
dxf.append(dxf_vertex(insert, code=10))
dxf.append(dxf_tag(1, str(text)))
dxf.append(dxf_tag(40, str(rnd(height))))
if width != 1.0:
dxf.append(dxf_tag(41, str(rnd(width))))
if rotation != 0.0:
dxf.append(dxf_tag(50, str(rnd(rotation))))
if oblique != 0.0:
dxf.append(dxf_tag(51, str(rnd(oblique))))
if style != "STANDARD":
dxf.append(dxf_tag(7, str(style)))
halign, valign = TEXT_ALIGN_FLAGS[align.upper()]
dxf.append(dxf_tag(72, str(halign)))
dxf.append(dxf_tag(73, str(valign)))
dxf.append(dxf_vertex(insert, code=11)) # align point
self.stream.write("".join(dxf))
def dxf_attribs(
layer: str, color: Optional[int] = None, linetype: Optional[str] = None
) -> str:
dxf = ["8\n%s\n" % layer] # layer is required
if linetype is not None:
dxf.append("6\n%s\n" % linetype)
if color is not None:
if 0 <= int(color) < 257:
dxf.append("62\n%d\n" % color)
else:
raise ValueError(
"color has to be an integer in the range from 0 to 256."
)
return "".join(dxf)
def dxf_vertex(vertex: Vertex, code=10) -> str:
dxf = []
for c in vertex:
dxf.append("%d\n%s\n" % (code, str(rnd(c))))
code += 10
return "".join(dxf)
def dxf_tag(code: int, value) -> str:
return "%d\n%s\n" % (code, value)
FORMAT_CODES = frozenset("xysebv")
PREFACE = """ 0
SECTION
2
HEADER
9
$ACADVER
1
AC1009
9
$DWGCODEPAGE
3
ANSI_1252
0
ENDSEC
0
SECTION
2
TABLES
0
TABLE
2
LTYPE
5
431
70
20
0
LTYPE
5
40F
2
CONTINUOUS
70
0
3
Solid line
72
65
73
0
40
0.0
0
LTYPE
5
410
2
CENTER
70
0
3
Center ____ _ ____ _ ____ _ ____ _ ____ _ ____
72
65
73
4
40
2.0
49
1.25
49
-0.25
49
0.25
49
-0.25
0
LTYPE
5
411
2
DASHED
70
0
3
Dashed __ __ __ __ __ __ __ __ __ __ __ __ __ _
72
65
73
2
40
0.75
49
0.5
49
-0.25
0
LTYPE
5
412
2
PHANTOM
70
0
3
Phantom ______ __ __ ______ __ __ ______
72
65
73
6
40
2.5
49
1.25
49
-0.25
49
0.25
49
-0.25
49
0.25
49
-0.25
0
LTYPE
5
413
2
HIDDEN
70
0
3
Hidden __ __ __ __ __ __ __ __ __ __ __ __ __ __
72
65
73
2
40
9.525
49
6.345
49
-3.175
0
LTYPE
5
43B
2
CENTERX2
70
0
3
Center (2x) ________ __ ________ __ ________
72
65
73
4
40
3.5
49
2.5
49
-0.25
49
0.5
49
-0.25
0
LTYPE
5
43C
2
CENTER2
70
0
3
Center (.5x) ____ _ ____ _ ____ _ ____ _ ____
72
65
73
4
40
1.0
49
0.625
49
-0.125
49
0.125
49
-0.125
0
LTYPE
5
43D
2
DASHEDX2
70
0
3
Dashed (2x) ____ ____ ____ ____ ____ ____
72
65
73
2
40
1.2
49
1.0
49
-0.2
0
LTYPE
5
43E
2
DASHED2
70
0
3
Dashed (.5x) _ _ _ _ _ _ _ _ _ _ _ _ _ _
72
65
73
2
40
0.3
49
0.25
49
-0.05
0
LTYPE
5
43F
2
PHANTOMX2
70
0
3
Phantom (2x)____________ ____ ____ ____________
72
65
73
6
40
4.25
49
2.5
49
-0.25
49
0.5
49
-0.25
49
0.5
49
-0.25
0
LTYPE
5
440
2
PHANTOM2
70
0
3
Phantom (.5x) ___ _ _ ___ _ _ ___ _ _ ___ _ _ ___
72
65
73
6
40
1.25
49
0.625
49
-0.125
49
0.125
49
-0.125
49
0.125
49
-0.125
0
LTYPE
5
441
2
DASHDOT
70
0
3
Dash dot __ . __ . __ . __ . __ . __ . __ . __
72
65
73
4
40
1.4
49
1.0
49
-0.2
49
0.0
49
-0.2
0
LTYPE
5
442
2
DASHDOTX2
70
0
3
Dash dot (2x) ____ . ____ . ____ . ____
72
65
73
4
40
2.4
49
2.0
49
-0.2
49
0.0
49
-0.2
0
LTYPE
5
443
2
DASHDOT2
70
0
3
Dash dot (.5x) _ . _ . _ . _ . _ . _ . _ . _
72
65
73
4
40
0.7
49
0.5
49
-0.1
49
0.0
49
-0.1
0
LTYPE
5
444
2
DOT
70
0
3
Dot . . . . . . . . . . . . . . . .
72
65
73
2
40
0.2
49
0.0
49
-0.2
0
LTYPE
5
445
2
DOTX2
70
0
3
Dot (2x) . . . . . . . .
72
65
73
2
40
0.4
49
0.0
49
-0.4
0
LTYPE
5
446
2
DOT2
70
0
3
Dot (.5) . . . . . . . . . . . . . . . . . . .
72
65
73
2
40
0.1
49
0.0
49
-0.1
0
LTYPE
5
447
2
DIVIDE
70
0
3
Divide __ . . __ . . __ . . __ . . __ . . __
72
65
73
6
40
1.6
49
1.0
49
-0.2
49
0.0
49
-0.2
49
0.0
49
-0.2
0
LTYPE
5
448
2
DIVIDEX2
70
0
3
Divide (2x) ____ . . ____ . . ____ . . ____
72
65
73
6
40
2.6
49
2.0
49
-0.2
49
0.0
49
-0.2
49
0.0
49
-0.2
0
LTYPE
5
449
2
DIVIDE2
70
0
3
Divide(.5x) _ . _ . _ . _ . _ . _ . _ . _
72
65
73
6
40
0.8
49
0.5
49
-0.1
49
0.0
49
-0.1
49
0.0
49
-0.1
0
ENDTAB
0
TABLE
2
STYLE
5
433
70
18
0
STYLE
5
417
2
STANDARD
70
0
40
0.0
41
1.0
50
0.0
71
0
42
0.2
3
txt
4
0
STYLE
5
44A
2
OpenSans
70
0
40
0.0
41
1.0
50
0.0
71
0
42
1.0
3
OpenSans-Regular.ttf
4
0
STYLE
5
44F
2
OpenSansCondensed-Light
70
0
40
0.0
41
1.0
50
0.0
71
0
42
1.0
3
OpenSansCondensed-Light.ttf
4
0
ENDTAB
0
TABLE
2
VIEW
5
434
70
0
0
ENDTAB
0
ENDSEC
"""