最近在做项目的时候,碰到一个功能需要多张图片转成pdf的功能,首先,在网上找了很多资料,都没有一个合适的。
后来,就自己动手使用云函数写了一个处理图片转成pdf的云函数,而且需带水印。
直奔主题,使用的是微信小程序云开发里面的云函数,是基于node.js写的
先看效果:
看完整代码,都有详细注释!!!
// 云函数多张图片 转成 pdf
//引入模块之前,记得先install安装模块哈,熟悉nodejs的安装模块不难,不懂的百度一下
const cloud = require('wx-server-sdk');
const { PDFDocument, StandardFonts, rgb } = require('pdf-lib'); //引入pdf-lib模块,转成pdf的时候用到
const {fontkit} = require('@pdf-lib/fontkit') //引入@pdf-lib/fontkit模块,水印的时候用到
cloud.init({
env:'你的环境id' //填入你的环境id
});
// 云函数入口函数
exports.main = async (event, context) => {
//接收小程序端传来的图片数组
let img_arr =event.img_arr;
//arr是用来存储fileContent的数组
let arr = []
//pdf的总高度,是等于数组里面的所有图片的高度之和
let zheight = 0
//用来存储处理过后的各个图片信息的数组
let content_arr = []
const doc = await PDFDocument.create();
let page = doc.addPage();
doc.registerFontkit(fontkit)
//下载图片 获取fileContent,并且存入arr数组
for (let i = 0; i < img_arr.length; i++) {
let lian = img_arr[i]
let lenderSignSign = await cloud.downloadFile({
fileID:lian
});
//concat是数组直接的拼接,这里需要使用push,这是个开发习惯导致的坑
arr.push(lenderSignSign.fileContent)
}
//获取所有照片组成的高度和宽度
for (let j = 0; j < arr.length; j++) {
//判断图片是png
if(img_arr[j].match(/.png/g)){
let img = await doc.embedPng(arr[j]);
//计算图片展示的宽高,根据原有的比例和pdf的宽度来算
let h = (img.height*700)/img.width
let obj ={
img:img,
width:700,
height:h,
}
content_arr.push(obj)
zheight =parseInt(zheight + h)
}
//判断图片是jpg
if(img_arr[j].match(/.jpg/g)){
let img = await doc.embedJpg(arr[j]);
//计算图片展示的宽高,根据原有的比例和pdf的宽度来算
let h = (img.height*700)/img.width
let obj ={
img:img,
width:700,
height:h,
}
content_arr.push(obj)
zheight =parseInt(zheight + h)
}
//判断如果图片不是png或者jpg。则返回提示
if(!img_arr[j].match(/.jpg/g)&&!img_arr[j].match(/.png/g)){
let str = '图片只支持jpg和png格式'
return str
}
}
//开始设置pdf的高度和宽度
page.setWidth(800);
page.setHeight(zheight);
//guodu_height用来存储排在前面的高度
let guodu_height = 0
//开始绘制
for (let i = 0; i < content_arr.length; i++) {
guodu_height = guodu_height + content_arr[i].height
let height = zheight - guodu_height
page.drawImage(content_arr[i].img,{
x: 50, //左右各间隔50
y: height
,width:content_arr[i].width
,height:content_arr[i].height,
});
}
// 定义水印的字体
const customFont = await doc.embedFont(StandardFonts.Helvetica)
// 定义水印,水印不能中文,不然会报错
const text = 'this is ziwenlu'
const textSize = 20
// 嵌入水印
page.drawText(text, {
x: 0,
y: 0,
size: textSize,
font:customFont,
opacity: 0.5,
color: rgb(0, 0.53, 0.71),
})
const docBase64 = await doc.saveAsBase64()
const docBuffer = Buffer.from(docBase64, 'base64');
//表明这个pdf是存放在云存储里面带的tmp文件夹,后面是给pdf取名称
let fileName = 'tmp/' + parseInt(new Date().getTime() / 1000) + '.pdf';
//开始上传到云存储
let result = await cloud.uploadFile({ cloudPath: fileName, fileContent: docBuffer });
let fileID = result.fileID;
//转http访问
const fileList = await cloud.getTempFileURL({
fileList: [fileID],
});
let pdf = fileList.fileList[0].tempFileURL;
return { code: 1, msg: '', data: { fileID: fileID, pdf: pdf } }
}
这就是完整的云函数代码。不过这个处理有点点耗时,再加上云函数的冷启动缺点,云函数的请求超时时间默认是3秒,所以建议把云函数的请求超时时间改为10秒,这样就不会请求超时了,测试过还是挺快的。
end