为何readAsDataURL对PDF不同页面返回相同DataURL字符串?
PDF转PNG时页面DataURL重复的问题分析
转换代码
export async function convertFromPdf(f: any) { const pdfjsLib = require("pdfjs-dist/webpack"); const pdf = await pdfjsLib.getDocument(f).promise; const pdfPages = await toImageData(pdf); const pages = await Promise.all( pdfPages.map(async (x) => { if (!x) return null; const canvas = document.createElement("canvas"); canvas.width = x.width; canvas.height = x.height; const ctx = canvas.getContext("2d"); ctx?.putImageData(x, 0, 0); const blob = await new Promise<Blob | null>((resolve) => { canvas.toBlob((blob) => resolve(blob)); }); if (!blob) return null; const reader = new FileReader(); reader.readAsDataURL(blob); return await new Promise<string>((resolve) => { reader.onloadend = () => resolve(reader.result as string); }); }) ); return pages.filter((x) => x !== null) as string[]; } async function toImageData(pdf: any) { const pdfPages = []; for (let i = 1; i <= pdf.numPages; i++) { const page = await pdf.getPage(i); const viewport = page.getViewport({ scale: 1.5 }); const canvas = document.createElement("canvas"); canvas.width = viewport.width; canvas.height = viewport.height; const ctx = canvas.getContext("2d"); const renderContext = { canvasContext: ctx, viewport: viewport }; await page.render(renderContext).promise; pdfPages.push(ctx?.getImageData(0, 0, canvas.width, canvas.height)); } return pdfPages; }
问题描述
我使用上述函数将PDF转换为PNG图片,但在某些情况下,
reader.readAsDataURL(blob)会对PDF的两个不同页面返回完全相同的字符串。这会导致后续UI交互出现问题,比如选择操作会同时选中两个页面,因为它们的URL一致,请问该问题的成因是什么?
成因分析
- 页面渲染异常导致ImageData重复:在
toImageData的循环渲染过程中,若某一页渲染失败(比如PDF页面损坏、资源加载异常),或者viewport计算错误,会生成空白或重复的ImageData。这些重复的ImageData转成Blob后,对应的DataURL自然完全一致。 - 空白页面或内容完全重合:如果PDF本身存在两个空白页面,或者渲染后的页面内容完全相同(比如模板页、重复的占位页),
canvas.toBlob()生成的Blob内容毫无差异,readAsDataURL输出的Base64字符串也会一模一样。 - PDF.js渲染的缓存或竞态问题:PDF.js内部可能存在渲染缓存,当连续渲染结构相似的页面时,可能复用了之前的渲染结果;或者循环中异步渲染的时序出现问题,导致后一页覆盖了前一页的canvas内容,最终生成重复的ImageData。
- FileReader无差异化处理:
readAsDataURL的输出完全依赖输入Blob的内容,只要Blob的二进制数据一致,不管来源是哪个页面,生成的DataURL必然相同。这是该API的特性,不是bug,但会暴露上游渲染环节的问题。
内容的提问来源于stack exchange,提问作者Owenn
相关产品推荐
相关产品推荐

