Preserve QPowerPoint slide backgrounds

This commit is contained in:
Курнат Андрей
2026-06-01 06:43:17 +03:00
parent 24206eb8bb
commit 4377e5279e
8 changed files with 119 additions and 5 deletions
+16 -1
View File
@@ -54,6 +54,7 @@ export async function importPptxFile(file: File): Promise<ImportedPowerPointDeck
const notesPath = await slideNotesPath(zip, parser, path);
const notesXml = notesPath ? await readOptionalZipText(zip, notesPath) : await readOptionalZipText(zip, `ppt/notesSlides/notesSlide${index}.xml`);
const notes = notesXml ? extractTextBlocks(parser.parse(notesXml)).join("\n") : "";
const backgroundColor = slideBackgroundColor(parsedSlide);
return {
id: `pptx-slide-${index}`,
@@ -61,6 +62,7 @@ export async function importPptxFile(file: File): Promise<ImportedPowerPointDeck
subtitle: slideTextBlocks.slice(1).join("\n"),
notes,
theme: "classic" as const,
...(backgroundColor ? { backgroundColor } : {}),
images
};
})
@@ -97,7 +99,7 @@ export async function exportPptxBlob(deck: ExportablePowerPointDeck): Promise<Bl
for (const sourceSlide of deck.slides) {
const colors = themeColors[sourceSlide.theme] ?? themeColors.classic;
const slide = pptx.addSlide();
slide.background = { color: colors.background };
slide.background = { color: normalizeHexColor(sourceSlide.backgroundColor) || colors.background };
sourceSlide.images?.forEach((image, index) => {
const data = normalizedImageData(image.src);
if (!data || !slide.addImage) {
@@ -335,6 +337,19 @@ function normalizedImageData(src: string) {
return /^data:image\/(?:png|jpe?g|gif|bmp|svg\+xml);base64,/i.test(value) ? value : "";
}
function slideBackgroundColor(slideXml: unknown) {
const background = firstRecordByKey(slideXml, "bg");
const backgroundProperties = childRecord(background, "bgPr");
const solidFill = childRecord(backgroundProperties, "solidFill");
const srgbColor = childRecord(solidFill, "srgbClr");
return normalizeHexColor(stringValue(srgbColor.val ?? srgbColor["@_val"]));
}
function normalizeHexColor(value?: string) {
const raw = value?.trim().replace(/^#/, "").toUpperCase() ?? "";
return /^[0-9A-F]{6}$/.test(raw) ? raw : "";
}
function numberAttribute(record: Record<string, unknown>, name: string) {
const value = Number.parseFloat(stringValue(record[name] ?? record[`@_${name}`]));
return Number.isFinite(value) ? value : undefined;