对pdf修改主要使用pdf.js和pdf-lib这两个库
首先使用pdf.js对文件进行预览
<iframe ref="iframe" style="width: 100%; height: 99.4%"
:src="'/pdf/web/viewer.html'" class="iframeClass" frameborder="0"
seamless allowfullscreen="false">
</iframe>
然后再引入自己封装的对pdf操作的文件
import { PDFLibEditor } from "./../../../public/plugins/web/pdflib-editor";
pdflib-editor文件内容如下
import { PDFDocument, rgb, degrees } from 'pdf-lib'
// import html2pdf from "html2pdf.js"
// console.log(html2pdf)
/**
* 根据字符串生成页面数组
* @param pageNumStr
* @returns {*[]}
*/
function getPages(pageNumStr) {
if (!pageNumStr) {
console.error("page number string: ", pageNumStr)
return []
}
const srcPageNum = pageNumStr.split(',')
const resultPageNum = []
const reg = /[\t\r\f\n\s]*/g
srcPageNum.forEach(num => {
if (/^[1-9]\d*$/g.test(num)) {
resultPageNum.push(parseInt(num.replace(reg, '')))
} else if (/^([1-9]\d*\s*-\s*[1-9]\d*)*$/g.test(num)) {
const tmpArray = num.split('-')
const a = tmpArray[0].replace(reg, '')
const b = tmpArray[1].replace(reg, '')
const start = Math.min(a, b)
const end = Math.max(a, b)
for (let i = start; i <= end; i++) {
resultPageNum.push(i)
}
} else {
console.error("page number format error:", num)
}
})
resultPageNum.sort((a, b) => b - a)
return resultPageNum
}
/**
* 计算页码开始坐标
* @param position 页码位置
* @param width pdf page 宽度
* @param height pdf page 高度
* @param charNum 字符数个数
*/
function computePosition(position, width, height, charNum) {
let x, y
if (position == 1) {
x = 20
y = height - 22
return { x, y }
} else if (position == 2) {
x = (width - charNum * 12) / 2
y = height - 22
return { x, y }
} else if (position == 3) {
x = width - charNum * 12 - 10
y = height - 22
return { x, y }
} else if (position == 4) {
x = 20
y = 10
return { x, y }
} else if (position == 5) {
x = (width - charNum * 12) / 2
y = 10
return { x, y }
} else if (position == 6) {
x = width - charNum * 12 - 10
y = 10
return { x, y }
}
}
/**
* 处理拆分页数
*/
function splitList(a, b) {
var d = []
if (a[0] != 1 && (a[1] != ',' || a[1] != '-')) {
a = "1-" + String(Number(a.split(',')[0].split('-')[0]) - 1) + "," + a
}
if (a.indexOf(String(b)) == -1) {
if (a.split(',')[a.split(',').length - 1].indexOf('-') > -1) {
a = a + ',' + String(Number(a.split(',')[a.split(',').length - 1].split("-")[1]) + 1) + '-' + String(b)
} else {
a = a + ',' + String(Number(a.split(',')[a.split(',').length - 1]) + 1) + '-' + String(b)
}
}
var c = a.split(',')
console.log(a)
c.map((item, index) => {
if (item.indexOf('-') > -1) {
let e = []
let f = []
if (c[index - 1]) {
if (c[index - 1].indexOf('-') > -1) {
if (Number(c[index - 1].split('-')[1]) + 1 != Number(item.split('-')[0])) {
for (let x = Number(c[index - 1].split('-')[1]) + 1; x < Number(item.split('-')[0]); x++) {
e.push(x)
}
d.push(e)
}
} else {
if (Number(item.split('-')[0]) > Number(c[index - 1]) + 1) {
for (let x = Number(c[index - 1]) + 1; x < Number(item.split('-')[0]); x++) {
e.push(x)
}
d.push(e)
}
}
for (let x = Number(item.split('-')[0]); x <= Number(item.split('-')[1]); x++) {
f.push(x)
}
} else {
for (let x = Number(item.split('-')[0]); x <= Number(item.split('-')[1]); x++) {
f.push(x)
}
}
d.push(f)
} else {
if (c[index - 1] && c[index - 1].indexOf('-') > -1) {
let e = []
if (Number(item) > Number(c[index - 1].split('-')[1]) + 1) {
for (let x = Number(c[index - 1].split('-')[1]) + 1; x < Number(item); x++) {
e.push(x)
}
d.push(e)
}
} else {
if (c[index - 1] && Number(item) - Number(c[index - 1]) > 1) {
let e = []
if (c[index - 1].indexOf('-') > -1) {
for (let x = Number(c[index - 1].split('-')[1]) + 1; x < Number(item) - 1; x++) {
e.push(x)
}
} else {
for (let x = Number(c[index - 1]) + 1; x <= Number(item) - 1; x++) {
e.push(x)
}
}
d.push(e)
}
}
d.push([Number(item)])
}
}
)
return d;
}
function tgbTo(hex) {
let rgb = ''
hex = hex.replace('#', '')
for (let i = 0; i < hex.length; i += 2) {
rgb += parseInt(hex.slice(i, i + 2), 16) + (i < 4 ? ',' : '')
}
rgb += ''
return rgb
}
/**
* 加载 pdf js 库的 pdf文档
* @param pdfJsApp
* @returns {Promise<PDFDocument>}
*/
async function loadPdfJsDoc(pdfJsApp) {
const pageNum = pdfJsApp.pdfDocument.numPages
const result = await pdfJsApp.pdfDocument.getData()
// pdfJsApp.pdfDocument.getData().then(res => {
// console.log(new Uint8Array(res), 22222)
// })
// const data = await pdfJsApp.pdfDocument.saveDocument()
return await PDFDocument.load(new Uint8Array(result.buffer))
// return await PDFDocument.load(data)
}
/**
* 加载pdf文件
* @param file
* @returns {Promise<unknown>}
*/
function loadPdfFile(file) {
return new Promise(function (resolve, reject) {
let reader = new FileReader();
reader.onload = function (progressEvent) {
resolve(reader.result);
}
reader.onerror = function (error) {
reject(error);
}
reader.readAsArrayBuffer(file);
});
}
/**
* 基于pdf-lib的pdf编辑工具
* @type {{merge(*): Promise<void>, insert(*, *, *): Promise<*>, remove(*, *): Promise<*>, rebuildPageNum(*, *): Promise<void>}}
*/
const PDFLibEditor = {
/**
* 保存PDF
*/
// savePdf(pdfJsApp){
// var opt = {
// margin: 0.3,
// filename: "name.pdf",
// image: { type: "jpeg", quality: 1 },
// html2canvas: { scale: 2 },
// jsPDF: { unit: "in", format: "letter", orientation: "portrait" },
// };
// html2pdf().set(opt).from(pdfJsApp).save()
// },
/**
* 旋转pdf
*/
async degreesPdf(pdfJsApp,nums){
let pdfDoc = await loadPdfJsDoc(pdfJsApp)
const pageCount = pdfDoc.getPageCount()
for (let i = 0; i < pageCount; i++) {
const page = pdfDoc.getPage(i)
page.setRotation(degrees(nums*90));
}
await pdfJsApp.open({ data: await pdfDoc.save() })
},
/**
* 画横线
* @param pdfJsApp
* @param color
* @param size
* @param start
* @param end
*
*/
async drawLine(pdfJsApp, color = "#000000", size = 1, start, end, IEwidth, IEheight) {
const startX = start.x
const startY = start.y
const endX = end.x
const endY = end.y
let pdfDoc = await loadPdfJsDoc(pdfJsApp)
const page = pdfDoc.getPage(pdfJsApp.page - 1)
let rgbs = tgbTo(color)
console.log({ x: startX / (992 / 595.32), y: page.getHeight() - startY / (992 / 595.32) },
{ x: endX / (992 / 595.32), y: page.getHeight() - startY / (992 / 595.32) },
"开始坐标与结束坐标",
page.getWidth(),
page.getHeight(),
IEwidth,
IEheight,
)
// 992 / 595.32
page.drawLine({
start: { x: startX / (IEwidth / page.getWidth()), y: page.getHeight() - startY / (IEheight / page.getHeight()) },
end: { x: endX / (IEwidth / page.getWidth()), y: page.getHeight() - startY / (IEheight / page.getHeight()) },
color: rgb(Number(rgbs.split(",")[0]) / 255, Number(rgbs.split(",")[1]) / 255, Number(rgbs.split(",")[2]) / 255),
thickness: size,
});
await pdfJsApp.open({ data: await pdfDoc.save() })
},
/**
* 重新生成页码
* @param pdfJsApp
* @param position 1- 左上,2-上中,3-右上,4-左下,5-下中,6-右下
* @returns {Promise<void>}
*/
async rebuildPageNum(pdfJsApp, position, startPageNum, mergeAdd = false) {
if (!pdfJsApp) {
console.error("pdf js application:", pdfJsApp)
return
}
// if (!position) {
// position = 3
// }
let pdfDoc
if (mergeAdd) {
pdfDoc = pdfJsApp
} else {
pdfDoc = await loadPdfJsDoc(pdfJsApp)
}
const pageCount = pdfDoc.getPageCount()
for (let i = 0; i < pageCount; i++) {
const num = Number(startPageNum) + i + ''
const page = pdfDoc.getPage(i)
page.drawText(num, {
...computePosition(position, page.getWidth(), page.getHeight(), num.length),
size: 12
})
}
if (mergeAdd) {
return pdfDoc
} else {
await pdfJsApp.open({ data: await pdfDoc.save() })
}
},
/**
* 合并pdf
* @param pdfJsApp pdfjs application
* @param pdfFiles
* @param path
* @param isAppend
* @returns {Promise<void>}
*/
async mergePages(pdfJsApp, pdfFiles, path, mergeAdd, radio2, startPageNum) {
if (!pdfJsApp) {
console.error("pdf js application:", pdfJsApp)
return
}
if (!pdfFiles) {
console.error("merge pdf file:", pdfFiles)
return
}
let pdfDoc;
// if (isAppend) {
// pdfDoc = loadPdfJsDoc(pdfJsApp)
// } else {
pdfDoc = await PDFDocument.create()
// }
for (let i = 0; i < pdfFiles.length; i++) {
const data = await loadPdfFile(pdfFiles[i].raw)
const mergeDoc = await PDFDocument.load(new Uint8Array(data))
const mergePageCount = Array.from(new Array(mergeDoc.getPageCount()).keys())
const copiedPages = await pdfDoc.copyPages(mergeDoc, mergePageCount)
for (let i = 0; i < copiedPages.length; i++) {
await pdfDoc.addPage(copiedPages[i])
}
}
if (mergeAdd) {
const page = await this.rebuildPageNum(pdfDoc, radio2, startPageNum, true)
window.ipcRenderer.send('saveFile', { FileList: [await page.save()], path: path })
} else {
window.ipcRenderer.send('saveFile', { FileList: [await pdfDoc.save()], path: path })
}
// window.ipcRenderer.send('saveFile', { FileList: [await pdfDoc.save()], path: path })
},
/**
* 在指定位置之后插入pdf page
* @param pdfJsApp pdfjs application
* @param insertPdfFile
* @param pageNum
* @returns {Promise<*>}
*/
async insertPages(pdfJsApp, insertPdfFile, pageNum) {
if (!pdfJsApp) {
console.error("pdf js application:", pdfJsApp)
return
}
if (!insertPdfFile) {
console.error("insert pdf file:", insertPdfFile)
return
}
// if (!pageNum) {
// console.error("insert pdf pageNum:", pageNum)
// return
// }
// const render = new FileReader()
// render.readAsArrayBuffer(insertPdfFile)
// render.onload = async function () {
const pdfDoc = await loadPdfJsDoc(pdfJsApp)
const insertDoc = await PDFDocument.load(insertPdfFile)
const insertPageCount = Array.from(new Array(insertDoc.getPageCount()).keys())
const copiedPages = await pdfDoc.copyPages(insertDoc, insertPageCount)
for (let i = copiedPages.length - 1; i >= 0; i--) {
await pdfDoc.insertPage(pageNum, copiedPages[i])
}
// const mergedPdfBytes = await pdfDoc.save();
// var downloadLink = document.createElement('a');
// downloadLink.href = URL.createObjectURL(new Blob([mergedPdfBytes]));
// downloadLink.download = 'merged_pdf.pdf';
// document.body.appendChild(downloadLink);
// downloadLink.click();
// document.body.removeChild(downloadLink);
await pdfJsApp.open({ data: await pdfDoc.save() })
// }
}
,
/**
* 删除指定的pdf页面
* @param pdfJsApp pdfjs application
* @param pagesStr
* @returns {Promise<*>}
*/
async removePages(pdfJsApp, pagesStr) {
if (!pdfJsApp) {
console.error("pdf js application:", pdfJsApp)
return
}
const pdfDoc = await loadPdfJsDoc(pdfJsApp)
getPages(pagesStr).forEach(num => {
pdfDoc.removePage(num - 1)
})
const data = await pdfDoc.save()
await pdfJsApp.open({ data: data })
}
,
// 拆分pdf
async splitPages(pdfJsApp, pagesStr, pageNum, path) {
let list = splitList(pagesStr, pageNum)
const pastPdfDoc = await loadPdfJsDoc(pdfJsApp)
let FileList = []
for (let z = 0; z < list.length; z++) {
let pdfDoc = await PDFDocument.create()
let list_1 = []
for (let y = 0; y < list[z].length; y++) {
list_1.push(list[z][y] - 1)
}
console.log(list, "zzzzzzzz")
let copiedPages = await pdfDoc.copyPages(pastPdfDoc, list_1)
for (let i = 0; i < copiedPages.length; i++) {
await pdfDoc.addPage(copiedPages[i])
}
FileList.push(await pdfDoc.save())
// window.ipcRenderer.send('saveFile', { FileList: [await pdfDoc.save()], path: path })
}
window.ipcRenderer.send('saveFile', { FileList: FileList, path: path })
}
}
export {
PDFLibEditor
}
在vue中文件使用,以删除pdf为例:
// 删除pdf
async removePdfPages(){
if(this.pageSize1.indexOf(",")>-1){
window.$messageInfo.warning('请使用英文逗号!')
return
}
const pdfApp = this.$refs.iframe.contentWindow.PDFViewerApplication
await PDFLibEditor.removePages(pdfApp, this.radio3==1?String(pdfApp.page):this.pageSize1)
this.dialogVisible2 = false
this.pageSize1 = ''
this.radio3 = '1'
},