PDFJS 解析pdf
文本复制有个问题:当pdf缩小时scale < 1,显示的textLayer 不会进行缩小、回导致文本超出canvas显示的宽度。注:若针对pdf还有个性化的功能,不建议直接引入pdf.js 方法,里面的事件都是原生js的写法,而且有关pdf的配置也很多。有对应的示例git clone后,将viewer.htmlopen whith live server。(1)安装 pdfjs-dist (版本
文章共1,305字 · 阅读需要大约5分钟
一键AI生成摘要,助你高效阅读
问答
·
1.引入pdf.js文件
官网地址:PDF.js
有对应的示例git clone后,将viewer.html open whith live server
注:若针对pdf还有个性化的功能,不建议直接引入pdf.js 方法,里面的事件都是原生js的写法,而且有关pdf的配置也很多
2. pdfjs-dist
(1)安装 pdfjs-dist (版本2.0.943,其余版本都出现过问题)
npm i pdfjs-dist@2.0.943
(2)引用 pdfjs-dist
import * as pdfjsLib from 'pdfjs-dist';
const workerSrc = import('pdfjs-dist/build/pdf.worker.entry');
export default () => {
pdfjsLib.GlobalWorkerOptions.workerSrc = workerSrc;
// pdf 资源
const [pdfRefList, setPdfRefList] = useState([]);
// 当前页码
const [currentPage, setCurrentPage] = useState(1);
const getDetail = (pageNum, href) => {
const loadingTask = pdfjsLib.getDocument({
url: href, // pdf文件地址 或者 请求资源地址
cMapUrl: 'https://unpkg.com/pdfjs-dist@2.0.943/cmaps/', // 使用cdn加载pdf.js提供的字体文件。
cMapPacked: true, // 此参数需要设为true
});
loadingTask.promise.then((loadedPdf) => {
const pdf = [{ id: pageNum, detail: loadedPdf }];
setPdfRefList(pdf);
setCurrentPage(pageNum);
}, function (reason) {
console.log(reason);
});
}
useEffect(() => {
pdfRefList&& pdfRefList.map((pdf) => {
pdf.detail && pdf.detail.getPage(pageNum).then(function (page) {
const viewport = page.getViewport(1.5);
const canvas = document.getElementById('canvas' + pdf.id);
canvas.height = viewport.height;
canvas.width = viewport.width;
const canvasContext = canvas.getContext('2d')
const renderContext = {
canvasContext: canvasContext,
viewport: viewport,
background: background === '#303033' ? '#999999' : background,
};
// background 可修改canvas背景色
page.render(renderContext);
// 显示文本可进行复制
// page.render(renderContext).then(() => {
// return page.getTextContent()
// }).then((textContent) => {
// // console.log(textContent) 解析出dom元素
// const pageDiv = document.getElementById('canvas')
// console.log(viewport)
// // 创建文本图层div
// const textLayerDiv = document.createElement('div')
// textLayerDiv.setAttribute('class', 'textLayer');
// textLayerDiv.id = 'textLayer' + pageNum
// textLayerDiv.style.height = viewport.height + 'px';
// textLayerDiv.style.width = viewport.width + 'px';
// // 将文本图层div添加至每页pdf的div中
// pageDiv.appendChild(textLayerDiv)
// // 创建新的TextLayerBuilder实例
// let textLayer = new TextLayerBuilder({
// textLayerDiv: textLayerDiv,
// pageIndex: 1,
// viewport: viewport
// })
// textLayer.setTextContent(textContent)
// textLayer.render()
// });
});
})
}, [pdfRefList])
return (<div class="pdfViewer">
<div class="viewer">
{pdfRefList && pdfRefList.map((pdf) => {
const markIndex = bookMarkList.findIndex((book) => (book.chapterId === pdf.id));
return (
<div class="page"
key={pdf.id}>
<div class="canvasWrapper">
<canvas id={"canvas" + pdf.id}></canvas>
</div>
</div>
)
})}
</div>)
}
文本复制有个问题:当pdf缩小时 scale < 1,显示的textLayer 不会进行缩小、回导致文本超出canvas显示的宽度
3.移动端 引用 pdfjs-dist 分辨率问题
getViewport(1) 获取到的是原pdf大小,原pdf宽度小于移动端h5宽度,也就是scale<1时,加载出来的pdf 分辨率很低,是模糊的
解决不降低pdf分辨率,按照手机屏幕展示
AbortController
是一个用于在 JavaScript 中处理异步操作的控制器,可以用于取消异步任务,当pdf列表 pdfRefList 更新时,canvas渲染绘制可能还没有结束,这时候需要取消当前绘制的canvas,重新根据pdfRefList加载渲染
useEffect(() => {
if (!utils.helper.isEmptyObj(pdfRefList)){
const abortController = new AbortController();
abortControllerRef.current = abortController;
renderPage(pdfRefList, pdfRefList[0], window.previousBackgroundColor, settings.theme, settings.type, abortController);
}
return () => {
abortControllerRef.current.abort(); // Abort the current rendering
abortControllerRef.current = new AbortController(); // Create a new AbortController for future rendering
};
}, [pdfRefList, settings.theme, window.previousBackgroundColor, settings.type]);
const isCanvasEmpty = (canvas) => {
const ctx = canvas.getContext('2d');
if (canvas.width) {
const imageData = ctx.getImageData(0, 0, canvas.width, canvas.height);
const data = imageData.data;
for (let i = 0; i < data.length; i += 4) {
// 检查每个像素的透明度
if (data[i + 3] !== 0) {
return false; // 如果有非透明像素,则 Canvas 不为空
}
}
}
return true; // 所有像素都是透明的,Canvas 为空
}
const renderPage = (pdfList, pdf, previousBackgroundColor, background, type, abortController) => {
return new Promise((resolve, reject) => {
const pageId = pdf.id % bookInfo.splitSize === 0 ? bookInfo.splitSize : pdf.id % bookInfo.splitSize;
pdf.detail && pdf.detail.getPage(pageId).then(function (page) {
const canvas = document.getElementById(`canvas_${copyRightId}_${pdf.id}_${type}`);
if (canvas && !isCanvasEmpty(canvas) && previousBackgroundColor == background) {
const index = pdfList.findIndex((v) => (v.id == pdf.id));
if (index < pdfList.length - 1) {
renderPage(pdfList, pdfList[index + 1], previousBackgroundColor, background, type, abortController)
} else {
window.previousBackgroundColor = settings.theme;
resolve()
}
} else if (canvas) {
const vp = page.getViewport(1);
if (!vp.width) {
vp.width = vp.viewBox[2];
vp.height = vp.viewBox[3];
vp.scale = 1;
vp.transform = [1, 0, 0, -1, 0, vp.viewBox[3]]
}
let ctx = canvas.getContext("2d");
let dpr = window.devicePixelRatio || 1;
let bsr =
ctx.webkitBackingStorePixelRatio ||
ctx.mozBackingStorePixelRatio ||
ctx.msBackingStorePixelRatio ||
ctx.oBackingStorePixelRatio ||
ctx.backingStorePixelRatio ||
1;
let ratio = Number(utils.caculate.accDiv(dpr, bsr));
const scale = Number(utils.caculate.accDiv(window.innerWidth, vp.width))
let viewport = page.getViewport(scale);
if (!viewport.width) {
viewport.width = utils.caculate.accMul(viewport.viewBox[2], scale);
viewport.height = utils.caculate.accMul(viewport.viewBox[3], scale);
viewport.scale = scale;
viewport.transform = [scale, 0, 0, -scale, 0, utils.caculate.accMul(viewport.viewBox[3], scale)]
}
canvas.width = viewport.width * ratio;
canvas.height = viewport.height * ratio;
canvas.style.width = viewport.width + "px";
ctx.setTransform(ratio, 0, 0, ratio, 0, 0);
let renderContext = {
canvasContext: ctx,
viewport: viewport,
background: background === '#000000' ? 'rgb(255,255,255,0.9)' : background,
};
const renderTask = page.render(renderContext);
const abortFn = () => {
ctx.clearRect(0, 0, canvas.width, canvas.height);
canvas.width = 0;
canvas.height = 0;
canvas.style.width = 0;
renderTask.cancel();
reject('cancel');
}
abortController.signal.addEventListener('abort', abortFn);
renderTask.promise.then(() => {
abortController.signal.removeEventListener('abort', abortFn)
const index = pdfList.findIndex((v) => (v.id == pdf.id));
if (index < pdfList.length - 1) {
renderPage(pdfList, pdfList[index + 1], previousBackgroundColor, background, type, abortController)
} else {
window.previousBackgroundColor = settings.theme;
resolve()
}
}).catch((error) => {
reject(error);
});
}
})
})
};
更多推荐
已为社区贡献1条内容
所有评论(0)