返回 oh-my-ppt
static-background.ts
根目录 / src / main / io / html-pptx / static-background.ts
1 import type { SlideSizePreset } from '@shared/slide-size'
2
3 export interface PptxExportLayout {
4 captureWidthPx: number
5 captureHeightPx: number
6 slideWidthIn: number
7 slideHeightIn: number
8 }
9
10 export interface PptxCaptureRect {
11 x: number
12 y: number
13 width: number
14 height: number
15 }
16
17 export const PPTX_WIDE_LAYOUT: Omit<PptxExportLayout, 'captureWidthPx' | 'captureHeightPx'> = {
18 slideWidthIn: 13.333333333,
19 slideHeightIn: 7.5
20 }
21
22 export const PPTX_STANDARD_LAYOUT: Omit<PptxExportLayout, 'captureWidthPx' | 'captureHeightPx'> = {
23 slideWidthIn: 10,
24 slideHeightIn: 7.5
25 }
26
27 export const resolvePptxExportLayout = (slideSize: SlideSizePreset): PptxExportLayout => {
28 const physicalSize =
29 slideSize.id === 'wide-16-9'
30 ? PPTX_WIDE_LAYOUT
31 : slideSize.id === 'standard-4-3'
32 ? PPTX_STANDARD_LAYOUT
33 : null
34 if (!physicalSize) {
35 throw new Error(`Unsupported PPTX slide size: ${slideSize.id}`)
36 }
37
38 return {
39 captureWidthPx: slideSize.width,
40 captureHeightPx: slideSize.height,
41 ...physicalSize
42 }
43 }
44
45 export const resolvePptxCaptureRect = (
46 rect: { x: number; y: number; w: number; h: number },
47 layout: Pick<PptxExportLayout, 'captureWidthPx' | 'captureHeightPx'>,
48 paddingPx = 0
49 ): PptxCaptureRect | null => {
50 const x = Math.min(layout.captureWidthPx, Math.max(0, rect.x - paddingPx))
51 const y = Math.min(layout.captureHeightPx, Math.max(0, rect.y - paddingPx))
52 const width = Math.max(0, Math.min(layout.captureWidthPx - x, rect.w + paddingPx * 2))
53 const height = Math.max(0, Math.min(layout.captureHeightPx - y, rect.h + paddingPx * 2))
54 return width > 0 && height > 0 ? { x, y, width, height } : null
55 }
56
57 const STATIC_BACKGROUND_MIN_AREA_RATIO = 0.2
58 const STATIC_BACKGROUND_EDGE_TOLERANCE_PX = 2
59
60 type PptxShapeBox = {
61 x: number
62 y: number
63 w: number
64 h: number
65 }
66
67 // Large edge-anchored fills are structural slide backgrounds. Keeping them in
68 // the raster base avoids both z-order coverage and accidental animation matches.
69 export const isPptxStaticBackgroundShape = (
70 shape: PptxShapeBox,
71 layout: PptxExportLayout = {
72 captureWidthPx: 1600,
73 captureHeightPx: 900,
74 ...PPTX_WIDE_LAYOUT
75 }
76 ): boolean => {
77 const horizontalToleranceIn =
78 (layout.slideWidthIn / layout.captureWidthPx) * STATIC_BACKGROUND_EDGE_TOLERANCE_PX
79 const verticalToleranceIn =
80 (layout.slideHeightIn / layout.captureHeightPx) * STATIC_BACKGROUND_EDGE_TOLERANCE_PX
81 const area = Math.max(0, shape.w) * Math.max(0, shape.h)
82 const slideArea = layout.slideWidthIn * layout.slideHeightIn
83 if (area < slideArea * STATIC_BACKGROUND_MIN_AREA_RATIO) return false
84
85 const spansHeight = shape.h >= layout.slideHeightIn - verticalToleranceIn
86 // Only full-height columns and full-page fills belong in the raster base.
87 // Full-width header or footer bands should remain editable shapes.
88 if (!spansHeight) return false
89
90 const touchesHorizontalEdge =
91 shape.x <= horizontalToleranceIn ||
92 shape.x + shape.w >= layout.slideWidthIn - horizontalToleranceIn
93 const touchesVerticalEdge =
94 shape.y <= verticalToleranceIn ||
95 shape.y + shape.h >= layout.slideHeightIn - verticalToleranceIn
96
97 return touchesHorizontalEdge && touchesVerticalEdge
98 }
99
99 lines TYPESCRIPT