A media named wider than tall is stored two ways: AutoCAD writes a portrait size
and a quarter turn (ISO_A4_(297.00_x_210.00_MM) as 210 x 297, 73 = 1), ZWCAD the
media's own size and no turn (420 x 297, 73 = 0). Deriving the groups from the
name alone turned the AutoCAD form into the ZWCAD one. The reader now keeps
groups 44, 45 and 73 as read (PageSetup::file_paper, not serialized), and the
writer puts them back while they still describe the page setup's size and
orientation; page setups made or changed in CADCraft are derived from the media
name as before.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
LAYOUT writing moved into layout_obj (2721aa8): the groups 44/45/73 change and
plot_paper/media_is_landscape follow it in dxf_write/sections.rs. No logic change.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
The pre-signing check matched any folder named Program Files, so it rejected
a valid MSI when Windows resolves Program Files elsewhere, accepted the 64-bit
root for an x86 package and accepted a different app name. Build the expected
folder from the package architecture's resolved root and the policy name.
Real msiexec runs (per-user and all-users, silent and wizard) found two defects
that the metadata fixtures cannot see:
- "Only for me" published ALLUSERS=2, so FindRelatedProducts treated the run as
per-machine and skipped the existing per-user copy. An interactive upgrade
left two registered products and uninstall left files behind. The page now
leaves ALLUSERS unset for a per-user choice.
- Windows Installer resolves Program Files once, for the context it started in,
so choosing "Everyone" in the wizard installed into the user profile with a
machine-wide registration. The wizard now sets the new-install folder itself
after the choice (Program Files, Program Files (x86) for 32-bit, or the
per-user Programs folder). Silent installs are unchanged.
check-install-policy.ps1 now fails if either regresses.
PNG export (and everything else drawn by raster::render) stroked every
polyline primitive with its own tiny-skia stroke_path call: a new path
and a newly built paint pipeline per primitive. Hatch patterns, linetype
dashes and text strokes produce long runs of short polylines in one
colour, so that per-call setup dominated the render.
Consecutive hairline polylines (zero width, or at most one pixel when
anti-aliased; the default for PNG export) with the same colour, alpha
and width are now collected into one path and stroked once. tiny-skia
draws hairlines segment by segment straight onto the pixmap with the
same per-contour round caps, so the pixels and their blending order are
unchanged. Thicker strokes (filled outlines), fills, points, infinite
lines and polylines with non-finite or far-out screen coordinates break
the run and are drawn exactly as before.
Adds crates/io/examples/export_bench.rs, which exports examples/
apartment.dxf repeated on a grid (10x10: 5,800 entities) and reports
median/min wall time per format.
PNG export, 10x10 grid, 11 interleaved runs (Ryzen, 16 threads, Linux):
before: median 1790.7 ms, min 1703.3 ms
after: median 1037.6 ms, min 926.0 ms (-42.1 %)
A/A noise on the same setup: 1.1 %. Output PNGs are byte-identical
(bench at 10x10 and 20x20, CLI export of apartment.dxf and a 23,200-
entity drawing). New tests compare render() against stroking each
primitive on its own.
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
main split dxf_write.rs into dxf_write/ (736a834): plot_paper, media_is_landscape
and the LAYOUT groups 44/45/73 change move to dxf_write/sections.rs. No logic
change.
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>