Skip to content

DWG reader: fix PSTYLEMODE, hatch spline edges, proxy colors, MText and table robustness - #1271

Open
jarrett-meyer wants to merge 6 commits into
DomCR:masterfrom
jarrett-meyer:fix/dwg-reader-robustness
Open

jarrett-meyer wants to merge 6 commits into
DomCR:masterfrom
jarrett-meyer:fix/dwg-reader-robustness

Conversation

@jarrett-meyer

Copy link
Copy Markdown

This PR fixes several issues found while reading real-world DWG files. Each fix is in its own commit.

PSTYLEMODE read as 8192

DwgHeaderReader assigned flags & 0x2000 directly to CadHeader.PlotStyleMode, so a drawing that uses color-dependent plot styles reported 8192 instead of 1. The DXF reader and the DWG writer both use 1/0, so the value is now mapped to 1/0.

Reproduce: create a CadDocument with PlotStyleMode = 1, write it as DWG (R2000 or later) and read the header back. Before this change the value read is 8192.

Hatch spline edges converted to closed splines with zero weights

Hatch.BoundaryPath.Spline.ToEntity():

  • set IsClosed = true, but a spline edge is one open piece of the boundary loop;
  • copied the Z of every control point as the weight. Non-rational edges can store 0 there, which gives a spline with all weights 0 that cannot be evaluated. Weights are now 1 for non-rational edges (and for non-positive values).

Proxy graphics true color and truncated proxy graphics

  • In ProxyGeometryReader, the true color value is 0xmmRRGGBB stored little-endian, so the bytes come in blue, green, red order. Red and blue were swapped.
  • A truncated or unexpected record in the proxy graphics threw and lost every geometry already read. Reading now stops at the bad record and keeps the geometries read so far.

MText dropped because of its background transparency

The MText background transparency (BL 441) is stored like an entity transparency: the type in the high byte and the alpha in the low byte. AutoCAD can leave stale bits in this field when the type is ByLayer. The raw value was passed to new Transparency(short), which throws for values outside 0-90, so the whole MText was dropped. Values from 0 to 90 are still used as before. Values with a type byte are decoded with Transparency.FromAlphaValue. Anything else falls back to ByLayer.

ACAD_TABLE dropped when its cell data cannot be parsed

The insert part of a table (position, scale and the anonymous block with its graphics) is read before the cell data. If the cell data could not be parsed, the whole entity was lost. The cell data is now read in a separate method. A failure there reports a warning and keeps the table with its graphics. CadTableComponentTemplate.Build now tolerates a missing cell style template from a partly read table.

Tests

  • HatchTests.BoundaryPathSplineToEntityTest: checks the closed flag and the weights for non-rational and rational edges.
  • DwgWriterTests.WriteHeaderPlotStyleModeTest: round-trips PlotStyleMode 0 and 1 through DWG for every supported version from R2000.

Both tests fail before these changes. The full ACadSharp.Tests suite passes on net9.0 (2408 passed, 2 skipped).

The proxy color, MText transparency and table changes have no synthetic test. Reproducing them needs DWG content that the writer cannot produce (AutoCAD proxy graphics, stale transparency bits, and table cell data the reader fails on). They were checked against real drawings that I cannot share.

🤖 Generated with Claude Code

jarrett-meyer and others added 6 commits October 6, 2026 15:26
The header flags store PSTYLEMODE in bit 0x2000, but the reader assigned
the masked value directly, so a color-dependent drawing reported
PlotStyleMode = 8192 instead of 1. Map the bit to 1/0 as the DXF reader
and the DWG writer do.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
A spline boundary edge is one open piece of the loop, so the converted
Spline must not be flagged as closed. Non-rational edges may store 0 as
the weight of every control point; use 1 in that case so the resulting
Spline evaluates correctly.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The true color value is 0xmmRRGGBB stored little-endian, so the bytes
come in blue, green, red order; red and blue were swapped.

A truncated or unexpected record in the proxy graphics threw and lost
every geometry already read. Stop at the bad record and keep what was
read so far.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The MText background transparency (BL 441) is stored like an entity
transparency, with the type in the high byte and the alpha in the low
byte. AutoCAD can leave stale bits in it when the type is ByLayer, and
passing the raw value to the Transparency constructor threw, so the
whole MText was lost. Accept plain 0-90 values as before, decode values
with a type byte as an alpha value and fall back to ByLayer otherwise.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
The insert data of a table (position, scale and the anonymous block with
its graphics) is read before the cell data. If parsing the cell data
fails, the whole entity was dropped. Read the cell data in a separate
method, report a warning on failure and keep the table with its
graphics. A partly read cell may have no cell style template, so guard
the build against it.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>

This branch has not been deployed

No deployments
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant