Node.js 使用PDFKit在S3中动态存储PDF
我正在尝试创建一些图像的pdf(datauri格式)是nodejs,并将pdf存储在我的S3中。函数的返回将提供文件的S3URL 我在这里为服务器和节点画布使用parse server来创建图像的画布,然后使用PDFKit从画布元素创建pdf。(jsPdf不起作用)。现在,我希望使用AWS-SDK将此pdf发送到我的s3,并最终返回文件的URL。下面是我的代码,它一直工作到画布生成。我不知道pdf是否在第一时间创建,甚至在发送到s3之前。哦!整个事情都在heroku身上进行Node.js 使用PDFKit在S3中动态存储PDF,node.js,pdf,amazon-s3,parse-server,node-pdfkit,Node.js,Pdf,Amazon S3,Parse Server,Node Pdfkit,我正在尝试创建一些图像的pdf(datauri格式)是nodejs,并将pdf存储在我的S3中。函数的返回将提供文件的S3URL 我在这里为服务器和节点画布使用parse server来创建图像的画布,然后使用PDFKit从画布元素创建pdf。(jsPdf不起作用)。现在,我希望使用AWS-SDK将此pdf发送到我的s3,并最终返回文件的URL。下面是我的代码,它一直工作到画布生成。我不知道pdf是否在第一时间创建,甚至在发送到s3之前。哦!整个事情都在heroku身上进行 Parse.Clou
Parse.Cloud.define('getBulkMeta',async (req)=>{
const PDFDocument = require('pdfkit'),
{Canvas,loadImage} = require('canvas');
try {
let baseImg = await loadImage('data:image/png;base64,'+req.params.labels[0]);
let labels = req.params.labels,
allCanvas = [],
rowH = baseImg.naturalHeight,
rowW = baseImg.naturalWidth,
perpage = req.params.size[1],
pages = Math.ceil(labels.length/perpage),
imgInd = 0,
g = 10;
size = req.params.size[0];
for(var p=0;p<pages;p++){
let canvas = new Canvas(rowW*((size=='A4')?2:1),rowH*((size=='A4')?2:1)),
ctx = canvas.getContext("2d");
ctx.beginPath();
ctx.rect(0,0,canvas.width,canvas.height)
ctx.fillStyle = "#fff";
ctx.fill();
if(perpage == 1){
let img = await loadImage('data:image/png;base64,'+labels[imgInd++]);
ctx.drawImage(img,g,g,rowW-(2*g),rowH-(2*g));
} else {
var thisImgInd = 0;
for (var r=0;r<2;r++){
for(var c=0;c<2;c++){
let img = await loadImage('data:image/png;base64,'+labels[imgInd++]);
ctx.drawImage(img,g+(c*(rowW-g/2)),g+(r*(rowH-g/2)),rowW-(1.5*g),rowH-(1.5*g));
thisImgInd++
if(thisImgInd>=perpage||imgInd>=labels.length){break;}
}
if(thisImgInd>=perpage||imgInd>=labels.length){break;}
}
}
allCanvas.push(canvas)
}
var thisPDF = new PDFDocument({layout: 'landscape',size:size});
var bcoded;
thisPDF.pipe(()=>{bcoded = new Buffer.from(thisPDF).toString('base64')});
allCanvas.forEach((c,i)=>{
if(i){thisPDF.addPage();}
thisPDF.image(c.toDataURL(),0,0,thisPDF.page.width,thisPDF.page.width);
})
thisPDF.end();
const S3_BUCKET = process.env.S3_BUCKET;
aws.config.region = process.env.AWS_REGION;
aws.config.signatureVersion = 'v4';
let s3 = new aws.S3();
let fileName = req.params.name;
let s3Params = {
Bucket: S3_BUCKET,
Body: bcoded,
Key: fileName,
ContentType : 'application/pdf',
ACL: 'public-read'
};
s3.putObject(s3Params, (err, data) => {
if(err){
console.log('\n\n\n\n\n\n\n'+err+'\n\n\n\n\n\n\n');
throw 'Error: '+ (err);
}
let returnData = {
signedRequest: data,
url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}`
};
return (returnData);
})
} catch (e) {throw e;}
})
Parse.Cloud.define('getBulkMeta',异步(req)=>{
const PDFDocument=require('pdfkit'),
{Canvas,loadImage}=require('Canvas');
试试{
让baseImg=wait-loadImage('data:image/png;base64'+req.params.labels[0]);
让标签=请求参数标签,
allCanvas=[],
rowH=基本自然高度,
rowW=基本的自然宽度,
perpage=所需参数大小[1],
pages=Math.ceil(标签.长度/每页),
imgInd=0,
g=10;
大小=所需参数大小[0];
对于(var p=0;p=perpage | | imgInd>=labels.length){break;}
}
}
allCanvas.push(画布)
}
var thisPDF=新的PDFDocument({layout:'scape',size:size});
变异码;
thisPDF.pipe(()=>{bcoded=newbuffer.from(thisPDF.toString('base64')});
allCanvas.forEach((c,i)=>{
如果(i){thisPDF.addPage();}
thisPDF.image(c.toDataURL(),0,0,thisPDF.page.width,thisPDF.page.width);
})
thisPDF.end();
const S3_BUCKET=process.env.S3_BUCKET;
aws.config.region=process.env.aws_region;
aws.config.signatureVersion='v4';
设s3=new aws.s3();
让fileName=req.params.name;
设s3Params={
桶:S3_桶,
正文:b代码,
关键字:文件名,
ContentType:'application/pdf',
ACL:“公共读取”
};
s3.putObject(s3Params,(错误,数据)=>{
如果(错误){
console.log('\n\n\n\n\n\n\n'+err+'\n\n\n\n\n\n');
抛出“错误:”+(错误);
}
让返回数据={
signedRequest:数据,
url:`https://${S3_BUCKET}.S3.amazonaws.com/${fileName}`
};
返回(返回数据);
})
}捕捉(e){抛出e;}
})
更新。我用下面的代码将pdf文件保存在s3中:
Parse.Cloud.define('getBulkMeta',async (req)=>{
const PDFDocument = require('pdfkit'),
{Canvas,loadImage} = require('canvas');
try {
let baseImg = await loadImage('data:image/png;base64,'+req.params.labels[0]);
let labels = req.params.labels,
allCanvas = [],
rowH = baseImg.naturalHeight,
rowW = baseImg.naturalWidth,
perpage = req.params.size[1],
pages = Math.ceil(labels.length/perpage),
imgInd = 0,
g = 10;
size = req.params.size[0];
for(var p=0;p<pages;p++){
let canvas = new Canvas(),
ctx = canvas.getContext("2d");
canvas.height = rowH*((size=='A4')?2:1);
canvas.width = rowW*((size=='A4')?2:1);
ctx.beginPath();
ctx.rect(0,0,canvas.width,canvas.height)
ctx.fillStyle = "#fff";
ctx.fill();
if(perpage == 1){
let img = await loadImage('data:image/png;base64,'+labels[imgInd++]);
ctx.drawImage(img,g,g,rowW-(2*g),rowH-(2*g));
} else {
var thisImgInd = 0;
for (var r=0;r<2;r++){
for(var c=0;c<2;c++){
let img = await loadImage('data:image/png;base64,'+labels[imgInd++]);
ctx.drawImage(img,g+(c*(rowW-g/2)),g+(r*(rowH-g/2)),rowW-(1.5*g),rowH-(1.5*g));
thisImgInd++
if(thisImgInd>=perpage||imgInd>=labels.length){break;}
}
if(thisImgInd>=perpage||imgInd>=labels.length){break;}
}
}
allCanvas.push(canvas)
}
var thisPDF = new PDFDocument({layout: 'landscape',size:size});
let buffers = [],pdfData,returnData='Hi';
thisPDF.on('data', buffers.push.bind(buffers));
thisPDF.on('end',() => {
pdfData = Buffer.concat(buffers);
const S3_BUCKET = process.env.S3_BUCKET;
aws.config.region = process.env.AWS_REGION;
aws.config.signatureVersion = 'v4';
let s3 = new aws.S3();
let fileName = req.params.name;
let s3Params = {
Bucket: S3_BUCKET,
Body: pdfData,
Key: (+new Date())+'-'+fileName,
ContentType : 'application/pdf',
ACL: 'public-read'
};
s3.putObject(s3Params,(err, data) => {
delete pdfData,thisPDF;
pdfData = null;thisPDF = null;
if(err){ throw 'Error: '+ (err); }
returnData = { signedRequest: data, url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}` };
})
})
allCanvas.forEach((c,i)=>{
if(i){thisPDF.addPage();}
thisPDF.image(c.toDataURL(),0,0,{fit:[thisPDF.page.width,thisPDF.page.height]});
})
thisPDF.end();
return returnData;
} catch (e) {throw e;}
})
Parse.Cloud.define('getBulkMeta',异步(req)=>{
const PDFDocument=require('pdfkit'),
{Canvas,loadImage}=require('Canvas');
试试{
让baseImg=wait-loadImage('data:image/png;base64'+req.params.labels[0]);
让标签=请求参数标签,
allCanvas=[],
rowH=基本自然高度,
rowW=基本的自然宽度,
perpage=所需参数大小[1],
pages=Math.ceil(标签.长度/每页),
imgInd=0,
g=10;
大小=所需参数大小[0];
对于(var p=0;p=perpage | | imgInd>=labels.length){break;}
}
}
allCanvas.push(画布)
}
var thisPDF=新的PDFDocument({layout:'scape',size:size});
让缓冲区=[],pdfData,returnData='Hi';
thisPDF.on('data',buffers.push.bind(buffers));
thisPDF.on('end',()=>{
pdfData=Buffer.concat(缓冲区);
const S3_BUCKET=process.env.S3_BUCKET;
aws.config.region=process.env.aws_region;
aws.config.signatureVersion='v4';
设s3=new aws.s3();
让fileName=req.params.name;
设s3Params={
桶:S3_桶,
正文:pdfData,
键:(+新日期())+'-'+文件名,
ContentType:'application/pdf',
ACL:“公共读取”
};
s3.putObject(s3Params,(错误,数据)=>{
删除pdfData,此PDF;
pdfData=null;thisPDF=null;
如果(错误){throw'错误:'+(错误);}
returnData={signedRequest:data,url:`https://${S3_BUCKET}.S3.amazonaws.com/${fileName}`};
})
})
allCanvas.forEach((c,i)=>{
如果(i){thisPDF.addPage();}
图像(c.toDataURL(),0,0,{fit:[thisPDF.page.width,thisPDF.page.height]});
})
thisPDF.end();
返回数据;
}捕捉(e){抛出e;}
})
但是,
returnData
总是给出“Hi”作为输出,而且函数似乎没有关闭-Heroku每次都抛出内存超出错误。由于您使用异步函数创建PDF并将其发送到S3,因此您的云函数在这些操作实际完成之前返回。这就是为什么在returnData
var中总是有Hi
。您需要创建一个承诺,并等待该承诺在这两个操作结束时完成。应该是这样的:
await (new Promise((resolve, reject) => {
var thisPDF = new PDFDocument({layout: 'landscape',size:size});
let buffers = [];
thisPDF.on('data', buffers.push.bind(buffers));
thisPDF.on('end',() => {
pdfData = Buffer.concat(buffers);
const S3_BUCKET = process.env.S3_BUCKET;
aws.config.region = process.env.AWS_REGION;
aws.config.signatureVersion = 'v4';
let s3 = new aws.S3();
let fileName = req.params.name;
let s3Params = {
Bucket: S3_BUCKET,
Body: pdfData,
Key: (+new Date())+'-'+fileName,
ContentType : 'application/pdf',
ACL: 'public-read'
};
s3.putObject(s3Params,(err, data) => {
delete pdfData,thisPDF;
pdfData = null;thisPDF = null;
if(err){ reject(err); }
returnData = { signedRequest: data, url: `https://${S3_BUCKET}.s3.amazonaws.com/${fileName}` };
resolve();
})
})
});
顺便说一句,您可以使用Parse S3适配器并将PDF保存为常规解析文件,而不是使用AWS SDK。这段代码会超时。通过在wait函数中添加
thisPDF.on('end',()
),我们是否将其从正常的流程中排除?您也可以在回调中添加其他行,但我认为这不是问题所在(只是编辑了答案)。尝试添加一些控制台。记录调用,查看resolve
函数是否在某个时间点被调用。我将整个函数放在promise中,然后