修复(08-28-reimbursement-detail-material-preview-fixes): 收紧撤回展示并校正材料图片尺寸

这个提交包含在:
2026-08-28 21:53:26 +08:00
父节点 f178aa0de3
当前提交 46bfa7e00f
共修改 14 个文件,包含 342 行新增和 13 行删除
@@ -1,7 +1,12 @@
const { PDFDocument } = require("pdf-lib");
const sharp = require("sharp");
const { mergeMaterialsToPdf } = require("../../../src/services/reimbursementMaterialPdf");
const { MaterialPreviewError, createReimbursementMaterialPreviewStore, runMergeWorker } = require("../../../src/services/reimbursementMaterialPreview");
const {
MATERIAL_PREVIEW_MERGER_VERSION,
MaterialPreviewError,
createReimbursementMaterialPreviewStore,
runMergeWorker,
} = require("../../../src/services/reimbursementMaterialPreview");
const limits = { maxPages: 40, maxImagePixels: 40_000_000, maxOutputBytes: 10 * 1024 * 1024 };
const ENCRYPTED_PDF = Buffer.from("JVBERi0xLjMKJeLjz9MKMSAwIG9iago8PAovUHJvZHVjZXIgPGQ1MTZlOTU0YzA+Cj4+CmVuZG9iagoyIDAgb2JqCjw8Ci9UeXBlIC9QYWdlcwovQ291bnQgMQovS2lkcyBbIDQgMCBSIF0KPj4KZW5kb2JqCjMgMCBvYmoKPDwKL1R5cGUgL0NhdGFsb2cKL1BhZ2VzIDIgMCBSCj4+CmVuZG9iago0IDAgb2JqCjw8Ci9UeXBlIC9QYWdlCi9SZXNvdXJjZXMgPDwKPj4KL01lZGlhQm94IFsgMC4wIDAuMCAyMDAgMjAwIF0KL1BhcmVudCAyIDAgUgo+PgplbmRvYmoKNSAwIG9iago8PAovViAyCi9SIDMKL0xlbmd0aCAxMjgKL1AgNDI5NDk2NzI5MgovRmlsdGVyIC9TdGFuZGFyZAovTyA8YTgxN2MwMzIxY2ViOTJjMDQ3MDkyMDc2MTA0NjJkZjViZWIwMzJjYzBhYTQ4YTY3MGY5YWVmNTM3NTk2MzdkNj4KL1UgPDIyOWI4ZWJjYTUzMTFkZWYzZjhiNzM4MzQ1MzExZTdmMjhiZjRlNWU0ZTc1OGE0MTY0MDA0ZTU2ZmZmYTAxMDg+Cj4+CmVuZG9iagp4cmVmCjAgNgowMDAwMDAwMDAwIDY1NTM1IGYgCjAwMDAwMDAwMTUgMDAwMDAgbiAKMDAwMDAwMDA1OSAwMDAwMCBuIAowMDAwMDAwMTE4IDAwMDAwIG4gCjAwMDAwMDAxNjcgMDAwMDAgbiAKMDAwMDAwMDI2MSAwMDAwMCBuIAp0cmFpbGVyCjw8Ci9TaXplIDYKL1Jvb3QgMyAwIFIKL0luZm8gMSAwIFIKL0lEIFsgPDM1Mzk2MzMyMzA2MjYyNjE2NTYzMzgzMjY1MzE2MjM1NjMzNjMzNjM2MTYyNjU2NjM1NjE2NjYxNjU2NjMxMzE+IDwzNTM5NjMzMjMwNjI2MjYxNjU2MzM4MzI2NTMxNjIzNTYzMzYzMzYzNjE2MjY1NjYzNTYxNjY2MTY1NjYzMTMxPiBdCi9FbmNyeXB0IDUgMCBSCj4+CnN0YXJ0eHJlZgo0NzYKJSVFT0YK", "base64");
@@ -13,6 +18,39 @@ async function samplePdf(pageCount = 2) {
}
describe("reimbursement material PDF preview", () => {
it("uses normalized output dimensions for EXIF-rotated and ordinary images", async () => {
const oriented6 = await sharp({ create: { width: 400, height: 200, channels: 3, background: "white" } })
.jpeg()
.withMetadata({ orientation: 6 })
.toBuffer();
const oriented8 = await sharp({ create: { width: 600, height: 300, channels: 3, background: "white" } })
.jpeg()
.withMetadata({ orientation: 8 })
.toBuffer();
const verticalJpeg = await sharp({ create: { width: 120, height: 240, channels: 3, background: "white" } })
.jpeg()
.toBuffer();
const horizontalWebp = await sharp({ create: { width: 160, height: 80, channels: 3, background: "white" } })
.webp()
.toBuffer();
const result = await mergeMaterialsToPdf([
{ id: "orientation-6", materialType: "attachment", mimeType: "image/jpeg", source: oriented6 },
{ id: "orientation-8", materialType: "attachment", mimeType: "image/jpeg", source: oriented8 },
{ id: "vertical-jpeg", materialType: "attachment", mimeType: "image/jpeg", source: verticalJpeg },
{ id: "horizontal-webp", materialType: "attachment", mimeType: "image/webp", source: horizontalWebp },
], limits);
const pages = (await PDFDocument.load(result.buffer)).getPages();
expect(pages.map((page) => [page.getWidth(), page.getHeight()])).toEqual([
[200, 400],
[300, 600],
[120, 240],
[160, 80],
]);
expect(MATERIAL_PREVIEW_MERGER_VERSION).toBe("pdf-v2");
});
it("copies every PDF page, embeds images, and produces deterministic bytes", async () => {
const pdf = await samplePdf(2);
const png = await sharp({ create: { width: 80, height: 40, channels: 3, background: "white" } }).png().toBuffer();