fix: 压缩合同与报价单 PDF 并按实际内容分页,避免文件过大和空白尾页。

This commit is contained in:
wuzilong committed 2026-10-30 11:40:08 +08:00
1 parent 120b743a39
commit 0453e90000
4 files changed
+98 -44

No files matched your search

@@ -0,0 +1,40 @@
import assert from 'node:assert/strict'
import { describe, it } from 'node:test'
import { countContractPdfPages } from './contract-pdf-pages'
function pixels(width: number, height: number, marks: number[]) {
const data = new Uint8ClampedArray(width * height * 4).fill(255)
for (const row of marks) data[(row * width + 1) * 4] = 0
return { width, height, data }
}
describe('countContractPdfPages', () => {
it('ignores trailing white padding that crosses onto a second page', () => {
assert.equal(countContractPdfPages(pixels(210, 330, [20, 295])), 1)
})
it('keeps even a single visible pixel on a second page', () => {
assert.equal(countContractPdfPages(pixels(210, 330, [20, 297])), 2)
})
it('does not add a page when content ends exactly at the page boundary', () => {
assert.equal(countContractPdfPages(pixels(210, 330, [296])), 1)
})
it('removes only trailing blank pages from a multipage contract', () => {
assert.equal(countContractPdfPages(pixels(210, 900, [20, 580])), 2)
})
it('keeps one page for an empty document', () => {
assert.equal(countContractPdfPages(pixels(210, 330, [])), 1)
})
it('keeps faint content while ignoring fully transparent pixels', () => {
const image = pixels(210, 330, [20, 310])
const offset = (310 * image.width + 1) * 4
image.data[offset] = 254
assert.equal(countContractPdfPages(image), 2)
image.data[offset + 3] = 0
assert.equal(countContractPdfPages(image), 1)
})
})
@@ -0,0 +1,18 @@
/** 按不含水印的截图计算页数,仅移除没有任何可见像素的尾页。 */
export function countContractPdfPages(image: Pick<ImageData, 'width' | 'height' | 'data'>): number {
const { width, height, data } = image
const pageHeight = (width * 297) / 210
for (let y = height - 1; y >= 0; y -= 1) {
for (let x = 0; x < width; x += 1) {
const offset = (y * width + x) * 4
// 不使用深色阈值,保留浅色文字、细表格线和印章。
if (
data[offset + 3] > 0 &&
(data[offset] < 255 || data[offset + 1] < 255 || data[offset + 2] < 255)
) {
return Math.max(1, Math.ceil((y + 1) / pageHeight))
}
}
}
return 1
}