PPTX import: derive line stroke width from a:ln@w

Imported lines were rendering ~25x thicker than their PowerPoint
source because shape.strokeWidth was left at the _LINE_DEFAULTS
value of 6 viewBox units. The Artstr line renderer treats that
viewBox stroke as 6% of the layer's width, so a 4.58"-wide line
shape produced a 0.27" tall "bar" instead of a hairline. The
shapes were correctly positioned — they just looked like big
filled bars because the strokes were huge.

Fix: derive shape.strokeWidth from the source a:ln@w. Math:
the renderer sets vbH = 100·lh/lw so both viewBox axes share a
uniform scale of (lw_inches / 100) inches per viewBox unit. So
to target an on-screen stroke equal to the source thickness in
inches, set:
    shape.strokeWidth = (stroke.width_in_inches / lw_inches) · 100

The renderer's internal clamp to [0.5, 50] viewBox units acts as
a soft floor / ceiling for very wide or narrow lines (a 0.011"
hairline on a 5"-wide horizontal line bottoms out at ~0.5px
thick — visibly a line, just slightly thicker than source).

User-visible: re-importing gallery_template_layout_set.pptx now
yields lines at roughly their source thickness — the bottom-of-
slide #69746C hairlines look like hairlines, not bars.
This commit is contained in:
thePR0M3TH3AN committed 2026-05-30 08:32:13 -04:00
1 parent 29e731075e
commit 9a7a0841df
1 file changed
+12 -6
+12 -6
View File
@@ -1096,14 +1096,20 @@ window.ArtstrPptxImporter = (function () {
// Quirk of the renderer: for shape.kind === 'line' the inner SVG
// <line> uses the layer's *fill* paint as the stroke colour, not
// the layer's `stroke` field. PPTX puts the line's colour on
// a:ln, so for lines we copy the stroke colour over to fill. The
// shape.strokeWidth from _LINE_DEFAULTS (6 viewBox units) drives
// the on-screen thickness; deriving from a:ln@w would need to
// account for preserveAspectRatio="none" distortion which is
// out of scope here. If lines come out too thick / thin the user
// can adjust strokeWidth on the layer.
// a:ln, so for lines we copy the stroke colour over to fill.
//
// Thickness: the renderer's viewBox is 0..100 (x) × 0..vbH (y)
// where vbH = 100·lh/lw, deliberately picking vbH so both axes
// share the same in/unit scale (lw/100 in per viewBox unit). So
// shape.strokeWidth = (stroke.width_inches / lw_inches) · 100
// gives an on-screen stroke that matches the source PPTX a:ln@w.
// The renderer's hard clamp to [0.5, 50] viewBox units becomes
// the effective floor / ceiling for very wide or very narrow
// layers (a hairline on a 5"-wide line floors at ~0.5px thick).
if (shape.kind === 'line' && stroke.type === 'solid') {
fill = { type: 'solid', color: stroke.color };
const refW = bounds.w || bounds.h || 1;
shape.strokeWidth = (stroke.width / refW) * 100;
}
return {