Skip to content

Commit e812e21

Browse files
committed
address comments
1 parent b4dd7fa commit e812e21

2 files changed

Lines changed: 128 additions & 9 deletions

File tree

Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
/**
2+
* @vitest-environment jsdom
3+
*/
4+
import { describe, expect, it } from 'vitest'
5+
import { parseXml } from '@/lib/pptx-renderer/parser/xml-parser'
6+
import { renderBackground } from '@/lib/pptx-renderer/renderer/background-renderer'
7+
import type { RenderContext } from '@/lib/pptx-renderer/renderer/render-context'
8+
9+
const EMPTY_NODE = parseXml(
10+
'<p:spTree xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main" />'
11+
)
12+
13+
function createContext(backgroundXml: string): RenderContext {
14+
const background = parseXml(backgroundXml)
15+
const slide = {
16+
index: 0,
17+
nodes: [],
18+
background,
19+
layoutIndex: '',
20+
rels: new Map(),
21+
slidePath: 'ppt/slides/slide1.xml',
22+
showMasterSp: true,
23+
}
24+
25+
return {
26+
presentation: {
27+
width: 960,
28+
height: 540,
29+
slides: [slide],
30+
layouts: new Map(),
31+
masters: new Map(),
32+
themes: new Map(),
33+
slideToLayout: new Map(),
34+
layoutToMaster: new Map(),
35+
masterToTheme: new Map(),
36+
media: new Map(),
37+
charts: new Map(),
38+
isWps: false,
39+
},
40+
slide,
41+
theme: {
42+
colorScheme: new Map([['bg1', '000000']]),
43+
majorFont: { latin: 'Calibri', ea: '', cs: '' },
44+
minorFont: { latin: 'Calibri', ea: '', cs: '' },
45+
fillStyles: [],
46+
lineStyles: [],
47+
effectStyles: [],
48+
},
49+
master: {
50+
colorMap: new Map(),
51+
textStyles: {},
52+
placeholders: [],
53+
spTree: EMPTY_NODE,
54+
rels: new Map(),
55+
},
56+
layout: {
57+
placeholders: [],
58+
spTree: EMPTY_NODE,
59+
rels: new Map(),
60+
showMasterSp: true,
61+
},
62+
mediaUrlCache: new Map(),
63+
colorCache: new Map(),
64+
}
65+
}
66+
67+
describe('renderBackground', () => {
68+
it('renders bgRef colors that resolve to black after modifiers', () => {
69+
const ctx = createContext(`
70+
<p:bg xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main"
71+
xmlns:a="http://schemas.openxmlformats.org/drawingml/2006/main">
72+
<p:bgRef idx="1001">
73+
<a:schemeClr val="bg1">
74+
<a:shade val="50000" />
75+
</a:schemeClr>
76+
</p:bgRef>
77+
</p:bg>
78+
`)
79+
const container = document.createElement('div')
80+
81+
renderBackground(ctx, container)
82+
83+
expect(container.style.backgroundColor).toBe('rgb(0, 0, 0)')
84+
})
85+
86+
it('keeps bgRef without a color node on the white fallback', () => {
87+
const ctx = createContext(`
88+
<p:bg xmlns:p="http://schemas.openxmlformats.org/presentationml/2006/main">
89+
<p:bgRef idx="1001" />
90+
</p:bg>
91+
`)
92+
const container = document.createElement('div')
93+
94+
renderBackground(ctx, container)
95+
96+
expect(container.style.backgroundColor).toBe('rgb(255, 255, 255)')
97+
})
98+
})

apps/sim/lib/pptx-renderer/renderer/background-renderer.ts

Lines changed: 30 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,26 @@ import { getOrCreateBlobUrl, resolveMediaPath } from '../utils/media'
99
import type { RenderContext } from './render-context'
1010
import { resolveColor, resolveFill } from './style-resolver'
1111

12+
const COLOR_NODE_NAMES = new Set([
13+
'srgbClr',
14+
'schemeClr',
15+
'sysClr',
16+
'prstClr',
17+
'hslClr',
18+
'scrgbClr',
19+
])
20+
21+
/**
22+
* Check whether a node contains a supported OOXML color node.
23+
*/
24+
function hasColorNode(node: SafeXmlNode): boolean {
25+
if (COLOR_NODE_NAMES.has(node.localName)) {
26+
return true
27+
}
28+
29+
return node.allChildren().some((child) => COLOR_NODE_NAMES.has(child.localName))
30+
}
31+
1232
/**
1333
* Composite a semi-transparent color on white so the result is always opaque.
1434
* This prevents the slide background from becoming see-through when embedded
@@ -123,17 +143,18 @@ function renderBgPr(
123143
*/
124144
function renderBgRef(bgRef: SafeXmlNode, ctx: RenderContext, container: HTMLElement): void {
125145
// bgRef may contain a color child (schemeClr, srgbClr, etc.)
146+
if (!hasColorNode(bgRef)) {
147+
container.style.backgroundColor = '#FFFFFF'
148+
return
149+
}
150+
126151
const { color, alpha } = resolveColor(bgRef, ctx)
127-
if (color && color !== '#000000') {
128-
const hex = color.startsWith('#') ? color : `#${color}`
129-
if (alpha < 1) {
130-
const { r, g, b } = hexToRgb(hex)
131-
container.style.backgroundColor = compositeOnWhite(r, g, b, alpha)
132-
} else {
133-
container.style.backgroundColor = hex
134-
}
152+
const hex = color.startsWith('#') ? color : `#${color}`
153+
if (alpha < 1) {
154+
const { r, g, b } = hexToRgb(hex)
155+
container.style.backgroundColor = compositeOnWhite(r, g, b, alpha)
135156
} else {
136-
container.style.backgroundColor = '#FFFFFF'
157+
container.style.backgroundColor = hex
137158
}
138159
}
139160

0 commit comments

Comments
 (0)