From 239bb3c465a0d3bbcc91b61233919d0e40fce602 Mon Sep 17 00:00:00 2001 From: Albrecht Degering Date: Wed, 22 Jul 2026 19:46:40 +0200 Subject: [PATCH] fix: map ink transparency to SVG opacity --- src/components/PageReader.test.tsx | 5 +++++ src/components/PageReader.tsx | 2 +- src/onenote/export/export.test.ts | 26 +++++++++++++++++++++++++- src/onenote/export/serializers.ts | 2 +- 4 files changed, 32 insertions(+), 3 deletions(-) diff --git a/src/components/PageReader.test.tsx b/src/components/PageReader.test.tsx index 63ec432..ce048a8 100644 --- a/src/components/PageReader.test.tsx +++ b/src/components/PageReader.test.tsx @@ -82,6 +82,7 @@ const page: OneNotePageDto = { ], width: 2, color: 0xff0000, + transparency: 255, }, ], children: [], @@ -127,6 +128,10 @@ describe('PageReader structured content', () => { 'd', 'M 10 20 L 15 25 30 40' ); + expect(document.querySelector('.onenote-ink path')).toHaveAttribute( + 'stroke-opacity', + '0' + ); await waitFor(() => expect( screen.getByRole('img', { name: 'Embedded diagram' }) diff --git a/src/components/PageReader.tsx b/src/components/PageReader.tsx index a7894d4..005e56b 100644 --- a/src/components/PageReader.tsx +++ b/src/components/PageReader.tsx @@ -464,7 +464,7 @@ function InkView({ ink }: { ink: OneNoteInkBlock }) { strokeOpacity={ stroke.transparency === undefined ? undefined - : Math.max(0, Math.min(1, (255 - stroke.transparency) / 256)) + : Math.max(0, Math.min(1, 1 - stroke.transparency / 255)) } strokeLinecap={stroke.penTip === 0 ? 'round' : 'square'} strokeLinejoin={stroke.penTip === 0 ? 'round' : 'bevel'} diff --git a/src/onenote/export/export.test.ts b/src/onenote/export/export.test.ts index 7a89415..5964694 100644 --- a/src/onenote/export/export.test.ts +++ b/src/onenote/export/export.test.ts @@ -103,7 +103,7 @@ describe('OneNote export serializers', () => { expect(document.querySelectorAll('svg.ink')).toHaveLength(1); expect( document.querySelector('polyline')?.getAttribute('stroke-opacity') - ).toBe('0.496'); + ).toBe('0.498'); expect( document .querySelector('meta[http-equiv="Content-Security-Policy"]') @@ -111,6 +111,30 @@ describe('OneNote export serializers', () => { ).toContain("default-src 'none'"); }); + it('maps the full ink transparency byte range to SVG opacity', () => { + const snapshot = fixtureSnapshot(); + const ink = snapshot.sections[0]!.pages[0]!.blocks.find( + (block) => block.kind === 'ink' + ); + if (!ink || ink.kind !== 'ink') throw new Error('Ink fixture is missing'); + ink.strokes[0]!.transparency = 0; + ink.strokes.push({ + ...ink.strokes[0]!, + points: ink.strokes[0]!.points.map((point) => ({ ...point })), + transparency: 255, + }); + + const document = new DOMParser().parseFromString( + serializeOneNoteSemanticHtml(snapshot), + 'text/html' + ); + expect( + [...document.querySelectorAll('polyline')].map((stroke) => + stroke.getAttribute('stroke-opacity') + ) + ).toEqual(['1', '0']); + }); + it('creates a deterministic, path-safe static notebook ZIP', () => { const snapshot = fixtureSnapshot(); const first = createOneNoteStaticNotebookZip(snapshot); diff --git a/src/onenote/export/serializers.ts b/src/onenote/export/serializers.ts index 361db77..69967f4 100644 --- a/src/onenote/export/serializers.ts +++ b/src/onenote/export/serializers.ts @@ -573,7 +573,7 @@ function svgStroke(stroke: OneNoteInkBlock['strokes'][number]): string { stroke.transparency !== undefined && Number.isFinite(stroke.transparency) ? Math.max(0, Math.min(255, stroke.transparency)) : undefined; - const opacity = transparency === undefined ? 1 : (255 - transparency) / 256; + const opacity = transparency === undefined ? 1 : 1 - transparency / 255; if (points.length === 1) { return ``; }