Can pdf kit save images from a url? - node.js

I have a node.js application in which I'm using pdfkit to generate pdf documents. I want to be able to include images from a url in the pdf. I cant save the image to the file system because my runtime environment is read only and pdf kit seems to find the images to embed from a file system directory. Is there a way I can use an url in pdf kit to embed an image?
Here. This guy modified the pdfkit to include that functionality.

PDFKit now supports passing buffers to the doc.image method instead of a filename. See this commit. So you could do as the other answer suggests, and download the image from the URL yourself, and then pass the buffer directly to PDFKit instead of saving it to a file first.

you can use http.get:
http.get('YOUR URL TO GET THE IMAGE').on('response', function(res)
res.setEncoding('binary');
res.on('data', function(chunk){
buffer += chunk;
});
res.on('end', function(){
fs.writeFile('PATH TO SAVE IMAGE', buffer, 'binary', function (err) {
if (err){
throw err;
}
doc = new PDFDocument({ size: 'LETTER or any other size pdfkit offer' });
doc.image('PATH TO SAVE IMAGE', 0, 0, { fit: [WIDTH, HEIGHT] })
.fontSize(10).text('text 1', 100, 170)
.fontSize(16).text('text 2', 60, 120)
}); //After file is download and was write into the HD will use it
}).end(); //EO Downloading the file

Related

Saving image in local file system using node.js

I was working on a simple code to download missing images from a site and save it in the local system, given its complete URL. I am able to get the data in binary format as response and also I am able to save it properly. But when I try to open the image it shows the format is not supported by the system. I tried to save some js and css file and they are being saved properly and I am able to view them as well. But I am having problem with all the image formats.
Here is the code I wrote:
try {
response = await axios.get(domain + pathOfFile);
console.log(response);
fs.writeFile(localBasePath + pathOfFile, response.data, "binary", (error) => {
if (error) console.log("error while writting file", error.message);
});
} catch (error) {
console.log("error in getting response", error.message);
}
domian: contains the base domain of the site
pathOfFile: contains the path of file on that domain
localBasePath: the base folder where I need to store the image
I even tried to store the response in a buffer and then tried to save the image, but still I am facing the same problem.
Any suggestions would be appreciated.
You need to define responseEncoding while calling axios.get method.
Change your line to:
response = await axios.get(domain + pathOfFile, {responseEncoding: "binary"});

Node + Express + PDF getting downloaded instead of opening

Although it may be a duplicate question but I have done everything I can without getting the solution.
I'm using Node + Express.
We use to send link of PDF file as CDN url in SMS
The link looks like this:
/api/v1/cdn/pdf/24
To get PDf and return, I have this code:
let parameter = await this.parameterDB.readRecord(where);
if (parameter) {
let fileName = parameter.id + '_' + parameter.patient_id + '.pdf';
// METHOD 1
let data = fs.readFileSync(constants.PATH.PDFS + fileName);
res.setHeader('Content-disposition', 'inline; filename="' + fileName + '"');
res.contentType('application/pdf');
res.send(data);
// METHOD 2
res.writeHead(200, {
'Content-Type': 'application/pdf',
'Content-Disposition': 'inline; filename=report_' + fileName,
'Content-Length': data.length
});
res.end(data, 'binary');
// METHOD 3
let file = fs.createReadStream(constants.PATH.PDFS + fileName);
var stat = fs.statSync(constants.PATH.PDFS + fileName);
res.setHeader('Content-Length', stat.size);
res.setHeader('Content-Type', 'application/pdf');
res.setHeader('Content-Disposition', 'inline; filename=' + fileName);
file.pipe(res);
} else {
return this.responseUtil.sendReadResponse(req, res, {
message: 'not found'
}, 200);
}
I all of the above 3 methods, when I click on the link in SMS, it downloads the PDF file instead of opening in web browser (which is annoying for the customers).
File is returned properly.
What can I do here?
I assume, by sending the API link in SMS means you want your customers to view the PDF in mobile browser.
Browsers can view the PDF file due to the plugins they support or have installed by default, but this is not the case with phone browsers, atleast
not all browsers on smartphones support PDF viewer, especially android. I can view PDF files in safari and chrome browser on iPhone though, because they have support for PDF view.
source: https://www.quora.com/Why-does-Chrome-on-Android-not-open-PDF-files-like-Chrome-on-Windows-Linux-can
Any one of the method in your code can show the PDF file on desktop browser with no modification, however when you try to call the API URI on phone browser,
you'll see the PDF file getting downloaded as there is no support for that in the browser, instead browser looks for the native application on phone,
downloads the file and opens in it.
Although there is a way/work-around for this if you want to see the PDF files in the browser using google docs.
You can simply embed your URL location of the PDF in the google docs link itself and redirect to it when customer hits your API URI.
source: How to display a PDF via Android web browser without "downloading" first
So you can modify your code something like this:
let parameter = await this.parameterDB.readRecord(where);
if (parameter) {
res.redirect("https://docs.google.com/gview?embedded=true&url=http://host...your-pdf-path.pdf")
} else {
return this.responseUtil.sendReadResponse(req, res, {
message: 'not found'
}, 200);
}
There is an another alternative for this, although it would require more efforts, but it is worth if you have lots of documents in your application that need to be seen on phone browser.
You can make use of PDF.js by Mozilla and create your own custom pdf viewer, this viewer is completely created in vanilla JavaScript and thus, it is supported by almost all browsers.
Once you have your own viewer implemented, all you have to do is :
res.sendfFile('show an html file eg index.html', { pdfURL: <path of the pdf file> });
and inside this index.html file you need to pass the path of the pdf file, make use of PDF.js functions to get the document data and create custom viewer.
You can use ejs to achieve this in Express JS.

Converting adobe inDesign to pptx (is it even possible?)

I'm struggling to find a solution. I have a bulk of Adobe inDesign files I'm trying to convert over as PDFs
I know you can export to inDesign -> PDF then from Acrobat PDF -> PPTX. This would work well if it was just one or two files. I don't want to keep doing this over and over. I've tried using pdf-powerpoint the only issue with that is it exports each slide as a PNG. I would still like to be able to edit them afterward. I've seen that it is possible to use javascript to automate Adobe products but, after combing through their documentation I'm not sure if it's possible to pipe data into other Adobe products. Any suggestions?
You want to convert a PDF file to a Microsoft Powerpoint file (pptx).
You want to achieve this using Node.js.
If my understanding is correct, how about this workaround? In this workaround, it uses an external API which is ConvertAPI. The pptx file converted by this API can be edited by Microsoft Powerpoint. When you try this, for example, you can also test this using "Free Package". When you try using "Free Package", please Sign Up at "Free Package" and retrieve your Secret key.
Sample script:
const fs = require('fs');
const request = require('request');
const pdfFile = "### PDF file ###"; // Please set PDF filename including the path.
const url = "https://v2.convertapi.com/convert/pdf/to/pptx?Secret=#####"; // Please set your Secret key.
const options = {
url: url,
method: 'POST',
formData: {File: fs.createReadStream(pdfFile)},
};
request(options, function(err, res, body) {
if (err) {
console.log(err);
return;
}
const obj = JSON.parse(body);
obj.Files.forEach(function(e) {
const file = new Buffer(e.FileData, "base64");
fs.writeFile(e.FileName, file, function(err) {
if (err) {
console.log(err);
return;
}
console.log("Done.");
});
});
});
Note:
Before you run ths script, please retrieve your secret key.
In this script, a PDF file is uploaded and converted to pptx file, and download it. Then, it is saved as a pptx file.
This is a simple sample script. So please modify it for your situation.
Reference:
PDF to PPTX API of ConvertAPI
If this workaround was not what you want, I'm sorry.

Node buffer doesn't properly download file?

I'm successfully sending a get request that generates a pdf on the server, which I now want to send back to client and download it on their browser. The npm pdf generating library I'm using is called html-pdf and has the following options:
pdf.create(html).toFile([filepath, ]function(err, res){
console.log(res.filename);
});
pdf.create('<h1>Hi</h1>').toBuffer(function(err, buffer){
console.log('This is a buffer:', Buffer.isBuffer(buffer));
});
When I use the toFile option, the file gets correctly generated, however, when I use the toBuffer option and send that back to the user, the resulting pdf is blank.
I send the buffer to the user from my ajax handler like this:
module.exports = function(req, res) {
pdf.create(html).toBuffer(function(err, buffer){
res.setHeader('Content-Disposition', 'attachment; filename=panda.pdf');
res.setHeader('Content-Type', 'application/pdf');
res.send(buffer)
});
};
which gets received on the client here:
$.get('generatePdf', function(data, status) {
const url = window.URL.createObjectURL(new Blob([data]));
const link = document.createElement('a');
link.href = url;
link.setAttribute('download', 'file.pdf');
document.body.appendChild(link);
link.click();
})
For some reason though the pdf that is downloaded is blank. Does anyone know what I might be doing wrong?
My downloaded file is corrupt according to this online pdf validator with the following errors:
Result Document does not conform to PDF/A. Details Validating file
"file (8).pdf" for conformance level pdf1.4
The 'xref' keyword was not found or the xref table is malformed. The
file trailer dictionary is missing or invalid. The "Length" key of the
stream object is wrong. Error in Flate stream: data error. The
document does not conform to the requested standard. The file format
(header, trailer, objects, xref, streams) is corrupted. The document
does not conform to the PDF 1.4 standard.

Resize Image From S3 with Javascript

I am using the knox package to connect my S3 account and pull an image, like this:
var picturestring;
knoxclient.get(key).on('response', function(res){
console.log(res.statusCode);
console.log(res.headers);
res.setEncoding('base64');
res.on('data', function(chunk){
picturestring += chunk;
});
res.on('end', function () {
console.log(picturestring);
resizeimage(picturestring, done); // use the resize library in this function
});
}).end();
After that, I want to use a library that can take in that string (picturestring), resize the image, and return a new base64 string that represents the resized image. At this point, I plan on uploaded the resized image to S3.
I wrote a similar script in Golang that let me resize images like this, but every JS resizing library I've reviewed only give examples on resizing images from the local file system.
Is there any way that I can avoid reading the image from S3 into the file system, and focus on dealing with the returned string exclusively??
***************UPDATE***********************
function pullFromS3 (key, done) {
console.log("This is the key being pulled from Amazon: ", key);
var originalstream = new MemoryStream(null, {readable: false});
var picturefile;
client.get(key).on('response', function(res){
console.log("This is the res status code: ", res.statusCode);
res.setEncoding('base64');
res.pipe(originalstream);
res.on('end', function () {
resizeImage(originalstream, key, done);
});
}).end();
};
function resizeImage (originalstream, key, done) {
console.log("This is the original stream: ", originalstream.toString());
var resizedstream = new MemoryStream(null, {readable: false});
var resize = im().resize('160x160').quality(90);
// getting stuck here ******
originalstream.pipe(resize).pipe(resizedstream);
done();
};
I can't seem to get a grip on how the piping from originalstream --> to the resize ImageMagick function ---> to the resizestream works. Ideally, the resizestream should hold the base64 string for the resized image, which I can then upload to S3.
1) How do I wait for the piping to finish, and THEN use the data in resizedstream?
2) Am I doing the piping correctly? I can't debug it because I am unsure how to wait for the piping to finish!
I'm not using S3 but a local cloud provider in China to store images and their thumbnails. In my case I was using imagemagick library with imagemagick-stream and memorystream modules.
imagemagick-stream provides a way to process image with imagemagick through Stream so that I don't need to save the image in local disk.
memorystream provides a way to store the source image and thumbnail image binaries in memory, and with the ability to read/write to Stream.
So the logic I have is
1, Retrieve the image binaries from the client POST request.
2, Save the image into memory using memorystream
3, Upload it to, in your case, S3
4, Define the image process action in imagemagick-stream, for example resize to 180x180
5, Create a read stream from the original image binaries in step 1 using memorystream, pipe into imagemagick-stream created in step 4, and then pipe into a new memory writable created by memorystream where stores the thumbnail.
6, Upload the thumbnail I got in step 5 to S3.
The only problem in my solution is that, your virtual machine might run out of memory if many huge images came. But I know this should not be happened in my case so that's OK. But you'd better evaluate by yourself.
Hope this helps a bit.

Resources