feat: 实现 DOCX 媒体预处理与跨端 PNG 捕获

This commit is contained in:
SkyJourney
2026-07-30 13:21:18 +08:00
parent 7831bc23f0
commit fe5d67fb6d
20 changed files with 1294 additions and 16 deletions
+69
View File
@@ -8,6 +8,14 @@ export const DOCX_FILE_EXTENSION = ".docx";
export const MAXIMUM_DOCX_MARKDOWN_LENGTH = 1_500_000;
export const MAXIMUM_DOCX_FILE_NAME_LENGTH = 500;
export const MAXIMUM_DOCX_RESOURCE_COUNT = 50;
export const DOCX_MEDIA_RASTER_DPI = 300;
export const DOCX_MEDIA_CSS_DPI = 96;
export const DOCX_MEDIA_RASTER_SCALE =
DOCX_MEDIA_RASTER_DPI / DOCX_MEDIA_CSS_DPI;
export const MAXIMUM_DOCX_MEDIA_EDGE_PIXELS = 4_096;
export const MAXIMUM_DOCX_MEDIA_PIXELS = 16_000_000;
export const MAXIMUM_DOCX_MEDIA_BYTES = 8 * 1024 * 1024;
export const MAXIMUM_DOCX_TOTAL_MEDIA_BYTES = 30 * 1024 * 1024;
export const documentExportFormatSchema = z.enum(["pdf", "docx"]);
export type DocumentExportFormat = z.infer<
@@ -79,6 +87,67 @@ export const docxCapabilitySchema = z.discriminatedUnion("status", [
export type DocxCapability = z.infer<typeof docxCapabilitySchema>;
export const docxMediaKindSchema = z.enum([
"image",
"mermaid",
"echarts"
]);
export type DocxMediaKind = z.infer<typeof docxMediaKindSchema>;
export const docxMediaCaptureTargetSchema = z.object({
id: z.string().regex(/^docx-media-\d+$/u),
kind: docxMediaKindSchema,
ordinal: z.number().int().min(1).max(MAXIMUM_DOCX_RESOURCE_COUNT),
kindOrdinal: z
.number()
.int()
.min(1)
.max(MAXIMUM_DOCX_RESOURCE_COUNT),
altText: z.string().max(1_000),
caption: z.string().max(1_000).optional(),
displayWidthPx: z.number().positive().max(10_000),
displayHeightPx: z.number().positive().max(10_000),
captureX: z.number().int().nonnegative().max(100_000),
captureY: z.number().int().nonnegative().max(100_000),
captureWidthPx: z.number().int().positive().max(10_000),
captureHeightPx: z.number().int().positive().max(10_000),
rasterScale: z.number().positive().max(DOCX_MEDIA_RASTER_SCALE)
});
export type DocxMediaCaptureTarget = z.infer<
typeof docxMediaCaptureTargetSchema
>;
export const docxMediaCapturePlanSchema = z.object({
targets: z
.array(docxMediaCaptureTargetSchema)
.max(MAXIMUM_DOCX_RESOURCE_COUNT),
echartsErrors: z.array(z.string().max(1_000)),
mermaidErrors: z.array(z.string().max(1_000))
});
export type DocxMediaCapturePlan = z.infer<
typeof docxMediaCapturePlanSchema
>;
export interface DocxPngMediaResource
extends DocxMediaCaptureTarget {
fileName: string;
contentType: "image/png";
content: Uint8Array;
pixelWidth: number;
pixelHeight: number;
}
export interface PreparedDocxMedia {
resources: DocxPngMediaResource[];
echartsErrors: string[];
mermaidErrors: string[];
warnings: string[];
totalBytes: number;
}
export const docxExportErrorCodeSchema = z.enum([
"INVALID_DOCX_REQUEST",
"INVALID_EXPORT_CONFIG",