Skip to content

fix: avoid mutating shared shadow options during serialization - #1538

Open
vhinayindia wants to merge 1 commit into
gitbrent:masterfrom
vhinayindia:fix/shared-shadow-serialization
Open

vhinayindia wants to merge 1 commit into
gitbrent:masterfrom
vhinayindia:fix/shared-shadow-serialization

Conversation

@vhinayindia

@vhinayindia vhinayindia commented Oct 6, 2026 •

Copy link
Copy Markdown

Change Summary

Fix shared shadow options being converted repeatedly during slide XML generation. Four shapes sharing one shadow currently emit blurRad values of 76200, 967740000, 12290298000000, and 156086784600000000. This change emits 76200 for each and keeps subsequent writes stable.

Change Description

Copy shadow options locally in the image and shape XML paths before converting to OOXML units. Preserve explicit zero blur, offset, angle, and opacity rather than replacing them with defaults. Only src/gen-xml.ts is changed; no generated bundles or dependencies are submitted.

Change Type

  • Bug fix
  • New feature
  • Documentation update

Related Issue

Fixes #1527.

Motivation and Context

Reusing a shadow style across shapes or images, or writing the same presentation twice, should not multiply already-converted values. The existing mutation corrupts shadow XML and changes the options object supplied by the caller.

Checklist before requesting a review

  • If it is a core feature, I have added new code under /demos/modules/ (not applicable: bug fix)
  • My code follows the style guidelines of this project
  • My changes generate no new eslint warnings
  • I have performed a self-review of my code
  • I have commented my code, particularly in hard-to-understand areas (straightforward local copy)
  • I have included code/tests that prove my fix is effective or that my feature works (runnable sample below)
  • I have used the Run All Demos feature on the browser demo and no errors were found

Validation

Reproduced the issue on upstream 3c9ec1b before changing the source. After the change, npm run build, npx eslint src/gen-xml.ts, npx tsc --noEmit, and git diff --check passed. A separate local regression harness checks shared shapes, shared images, mixed shape/image use, repeated writes, unchanged caller options, exact blur/dist/dir/alpha values, and explicit zero values.

Validation inspects XML extracted from generated PPTX archives. PowerPoint/LibreOffice visual rendering and browser Run All Demos have not been performed.

Sample Code

Run from the repository after npm run build:

const assert = require('node:assert/strict');
const PptxGenJS = require('./src/bld/pptxgen.cjs.js');
const JSZip = require('jszip');

(async () => {
  const pres = new PptxGenJS();
  const slide = pres.addSlide();
  const shadow = { type: 'outer', blur: 6, offset: 3, angle: 90, color: '000000', opacity: 0.18 };
  const original = { ...shadow };
  for (let i = 0; i < 4; i++) {
    slide.addShape(pres.ShapeType.rect, { x: i * 2, y: 1, w: 1, h: 1, shadow });
  }
  async function xml() {
    const zip = await JSZip.loadAsync(await pres.write({ outputType: 'nodebuffer' }));
    return zip.file('ppt/slides/slide1.xml').async('string');
  }
  const first = await xml();
  assert.deepEqual([...first.matchAll(/blurRad="([^"]*)"/g)].map(m => m[1]), Array(4).fill('76200'));
  assert.deepEqual(shadow, original);
  assert.equal(await xml(), first);
  assert.deepEqual(shadow, original);
  console.log('PASS');
})().catch(error => { console.error(error); process.exitCode = 1; });

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

1 participant