fix: 压缩合同与报价单 PDF 并按实际内容分页,避免文件过大和空白尾页。
This commit is contained in:
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
|
||||
}
|
||||
Reference in new issue
Block a user