Generating pdf in Angular 2 - pdf

Me again with another Angular 2 question.
We are trying to generate a PDF file from a html source. I searched and searched trying to find an Angular 2 wrapper for the jsPdf or makePdf libraries, but I can't find any. Is there something I am missing? Is there a pure javascript way and is that good practice? Hope you guys can help.
Thanks in advance.
Francois

I was searching for the same thing, some weeks ago. I decided to do the generating on server-side (Node.js in my case). However you can do it on client-side, with jsPDF, like you mentioned.
Don't need a wrapper, just include the script and then access jsPDF through the window object. Wrapper will make it easier to test though.
I don't remember exactly but I thought it was something like this:
var doc = new window.jsPDF();

PDF is a complex file format, there may be some pdf parsers/generators built with js, but they will be limited & slow, your best bet is to do something server side.

HTML code:
<button type="button" (click)="downloadPdf()"
class="button">download</button>
Component.ts:
downloadPdf(){
this.authService.downloadPdf().subscribe(data => {
this.partnerDetails = data
} ); }
routes.js:
router.get('/downloadPdf',partnerCntrl.downloadPdf);
partnercntrl:
module.exports.downloadPdf = function (req, res) {
var fs = require('fs');
var pdf = require('html-pdf');
var html = fs.readFileSync('./test/businesscard.html', 'utf8');
var options = { format: 'Letter' };
pdf.create(html, options).toFile('./businesscard.pdf', function(err, res) {
if (err) return console.log(err);
console.log(res); // { filename: '/app/businesscard.pdf' }
});

Related

Display an image when Blob is returned from an API

I’m writing a Vue app which uses the Microsoft Graph API and SDK for initial authentication on the front end and then uses different aspects of the API throughout the app. Like displaying emails, OneDrive files, etc.
I’m using the profile photo from a users Microsoft account to display an avatar to other users. My issue is that when I call {graphApi}/me/photo/$value the result returned is a Blob. This is the endpoint provided in MS Graph.
I’ve read the MS Graph docs thoroughly, combed MDN & other sources and have not found a way to transform this result into a simple image in my markup.
Template markup:
<template>
<img :src="userPhoto" :alt="user.displayName" />
</template>
Setup function logic:
<script setup>
import { client } from "./foobar"
const userPhoto = ref();
async function getPhoto(){
const photo = await client.api("/me/photo/$value").get()
console.log(photo.value)
userPhoto.value = photo
};
</script>
Returned result:
{Blob, image:{id: default, size:48x48}}
So how do I decode or download the Blob properly to display an image in my Vue markup?? I’ve tried createObjectURL and FileReader() without any luck. I’m sure there is a simple solution but I am not finding it. Thanks for the help.
Explanation:
In below snippet as you can see I am passing the objectId of the Employee fetched from Graph previously.
Then making call for employee to get their Avatar/DP
The Graph Profile Photo endpoint returns binary Data of the photo.
Convert that binary data into data:image/png;base64,<readAsDataURL> URL e.g. data:image/png;base64,iVBORw0KGgoAAAANSU...
Use in <img src="dataUrl"/>
let imageUrl = (await request.get(GRAPH_CONFIG.GRAPH_DP_ENDPT + objectId + "/photos/48x48/\$value", { responseType: 'arraybuffer', validateStatus: (status) => status === 200 || status === 404 }))
if (imageUrl.status === 200) {
let reader = new FileReader()
let blob = new Blob([imageUrl.data], {type: 'image/jpeg'})
reader.onload = (event) => {
return event.target?.result.toString();
}
reader.readAsDataURL(blob)
}

How to add an uploaded file to a list of already uploaded files in Vue?

I currently have a file uploader that accepts a single CSV file. Then with axios I POST such file to the server and everything works just fine. What I'm not being able to achieve is being able to upload another CSV that will get added to the list of CSVs uploaded. I'm not talking about uploading various files at once, I'm taking about uploading different files at different points in time.
This is the method that is used to select a CSV file in the .vue file.
staticCampaignCSVSelected: function (file) {
console.log('campaign-detail.vue#staticCampaignCSVSelected', file)
let vc = this
vc.selectedHeuristicId = -1
Campaign.uploadStaticCSV(vc.campaign, file[0])
.then(
function (data) {
alert('CSV cargado con exito')
}
)
.catch(
function (err, data) {
console.log("campaign-detail#staticCampaignCSVSelected - catch", err.response)
alert(err.response.data.error)
}
)
},
This is the function that I have in some other JS file to POST to the API:
function uploadStaticCSV (campaign, csv) {
console.log('Campaign#uploadStaticCSV', campaign, csv)
//long list of assertions
let formData = new FormData()
formData.append('csv', csv)
return axios.post(API.campaignUploadStaticCSV(campaign.id), formData)
}
And this is the function I have in my endpoints.js file:
campaignUploadStaticCSV: function (id) { return this.campaign(id) + '' + '/csv' },
I haven't found a way to properly pass a[file] array as a parameter to the functions, which is what I believe I need to somehow do.
Any help would be appreciated :)
As far as i understood your question you need a way to pass a file from browser interface to your staticCampaignCSVSelected(file) method. If so why not to use an input model or a simple event or a watcher. E.g.
<input type="file" #input="staticCampaignCSVSelected($event.target.files[0])" />
But also i see a mistake in your code. You should append .then().catch() callbacks to axios.post() itself but not to Campaign.uploadStaticCSV() method.
And
return axios.post()
will not return a server response. You have to handle it in
axios.post().then(response => {})
callback

Download a PDF generated by Apps Script via web app

I'm trying to figure out how to make a Google Apps Script deployed as a web app download a PDF that's generated on a click. It almost works, but the resulting file isn't valid. I can't figure out if it's an encoding issue or something else.
In Apps Script the code looks simple:
function makePDF() {
...
var pdfBlob = doc.getAs('application/pdf');
return Utilities.base64Encode(pdfBlob.getBytes());
}
In the browser, there's a click handler:
function clickHandler(ev) {
ev.preventDefault();
google.script.run
.withSuccessHandler(function(data) {
var pdf = new Blob([window.atob(data)]);
var href = window.URL.createObjectURL(pdf);
var link = document.querySelector('#hiddenLink');
link.href = href;
link.click();
})
.makePDF();
}
Any suggestions?
Thanks!
I figured it out, so posting the answer if anyone else is trying to pass a PDF from Apps Script to the client javascript. It's all much simpler than I had made it.
Rather than messing around with base64 encodings, just pass back the bytes array:
function makePDF() {
...
var pdfBlob = DocumentApp.openById('1234').getAs('application/pdf');
return pdfBlob.getBytes();
}
Now, on the client side, construct a new Blob from an ArrayBuffer. That's easy too:
function clickHandler(ev) {
google.script.run
.withSuccessHandler(function(data) {
var arr = new Uint8Array(data);
var blob = new Blob([arr.buffer], {type: 'application/pdf'});
var obj_url = window.URL.createObjectURL(blob);
var hiddenLink = document.getElementById('hiddenPDFLink');
hiddenLink.setAttribute('href', obj_url);
hiddenLink.setAttribute('download', 'filename.pdf');
hiddenLink.click();
})
.makePDF();
}
And that's it! Hope someone else finds this helpful.
I assume that your makePDF function is doing some other stuffs/Calculation and at the end you need that document to be downloaded to local computer.
What you can do is inside success handler
var link = document.querySelector('#hiddenLink');
link.href = "https://docs.google.com/feeds/download/documents/export/Export?id=**TheIdOfDocumenToBeDownloaded**&exportFormat=pdf";
link.click();
It will then give you a prompt to save document on to local computer.

How do I create easily a PDF from an SVG with jsPDF?

I'm trying to create a pdf but I have some SVG pictures. I found information about this problem, but I just have to use JavaScript, that's to say, no jQuery.
I found jsPDF here : https://github.com/MrRio/jsPDF
There is the plugin jspdf.plugin.sillysvgrenderer.js (in the same folder) and where we can find an exemple of PDF created in the folder test.
But when I try to generate the PDF on my own, it doesn't work and I don't understand why.
Do you know how to do it?
I got this plugin working, but only with SVG file from the tests and the I saw in the doc that only PATHs are supported :(
There is already the issue on github
https://github.com/MrRio/jsPDF/issues/384
If paths are ok for here is my code (it's more or less the code from the tests):
function demoSvgDocument() {
var doc = new jsPDF();
var test = $.get('013_sillysvgrenderer.svg', function(svgText){
var svgAsText = new XMLSerializer().serializeToString(svgText.documentElement);
doc.addSVG(svgAsText, 20, 20, doc.internal.pageSize.width - 20*2)
// Save the PDF
doc.save('TestSVG.pdf');
});
}
Another point to consider, you have to run all examples on a server. Otherwise you won't see any results probably because of the security
Try canvg for that to covert SVG to Canvas. Then convert the canvas to base64 string using .toDataURL().
More detailed answer is here https://stackoverflow.com/a/35788928/2090459
Check the demo here http://jsfiddle.net/Purushoth/hvs91vpq/
Canvg Repo: https://github.com/gabelerner/canvg
There now is svg2pdf.js which uses a fork of jsPDF.
It has been created to solve this exact task: Exporting an SVG to a PDF.
Also in the meantime, jsPDF also added a demo that shows how to possibly export SVG using canvg and the jsPDF canvas implementation.
The two solutions have different advantages and disadvantages, so you might want to try both and see if one of them suits your needs.
You can use the canvas plugin that comes with jsPDF to render the SVG on the PDF with canvg. I've had to set a few dummy properties on the jsPDF canvas implementation, and disable the interactive/animation features of canvg for this to work without errors:
var jsPdfDoc = new jsPDF({
// ... options ...
});
// ... whatever ...
// hack to make the jspdf canvas work with canvg
jsPdfDoc.canvas.childNodes = {};
jsPdfDoc.context2d.canvas = jsPdfDoc.canvas;
jsPdfDoc.context2d.font = undefined;
// use the canvg render the SVG onto the
// PDF via the jsPDF canvas plugin.
canvg(jsPdfDoc.canvas, svgSource, {
ignoreMouse: true,
ignoreAnimation: true,
ignoreDimensions: true,
ignoreClear: true
});
This seems to me a much better solution than the SVG plugin for jsPDF, as canvg has much better support of SVG features. Note that the width and height properties should be set on the <svg/> element of your SVG for canvg to render it correctly (or at least so it seemed to me).
I modified this from: https://medium.com/#benjamin.black/using-blob-from-svg-text-as-image-source-2a8947af7a8e
var yourSVG = document.getElementsByTagName('svg')[0];
//or use document.getElementById('yourSvgId'); etc.
yourSVG.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns', 'http://www.w3.org/2000/svg');
yourSVG.setAttributeNS('http://www.w3.org/2000/xmlns/', 'xmlns:xlink', 'http://www.w3.org/1999/xlink');
var serializer = new XMLSerializer();
var serialSVG = serializer.serializeToString(yourSVG);
var svg = serialSVG;
var blob = new Blob([svg], {type: 'image/svg+xml'});
var url = URL.createObjectURL(blob);
var image = document.createElement('img');
// image.addEventListener('load', () => URL.revokeObjectURL(url), {once: true});
//changed above line using babel to code below;
image.addEventListener('load', function () {
return URL.revokeObjectURL(url);
}, { once: true });
image.src = url;
//Then just use your pdf.addImage() function as usual;

Can I read PDF or Word Docs with Node.js?

I can't find any packages to do this. I know PHP has a ton of libraries for PDFs (like http://www.fpdf.org/) but anything for Node?
textract is a great lib that supports PDFs, Doc, Docx, etc.
Looks like there's a few for pdf, but I didn't find any for Word.
CPU bound processing like that isn't really Node's strong point anyway (i.e. you get no additional benefits using node to do it over any other language). A pragmatic approach would be to find a good tool and utilise it from Node.
I have heard good things around the office about docsplit http://documentcloud.github.com/docsplit/
While it's not Node, you could easily invoke it from Node with http://nodejs.org/docs/latest/api/all.html#child_process.exec
You can easily convert one into another, or use for example a .doc template to generate a .pdf file, but you will probably want to use an existing web service for this task.
This can be done using the services of Livedocx for example
To use this service from node, see node-livedocx (Disclaimer: I am the author of this node module)
I would suggest looking into unoconv for your initial conversion, this uses LibreOffice or OpenOffice for the actual conversion. Which adds some overhead.
I'd setup a few workers with all the necessities setup, and use a request/response queue for handling the conversion... (may want to look into kue or zmq)
In general this is a CPU bound and heavy task that should be offloaded... Pandoc and others specifically mention .docx, not .doc so they may or may not be options as well.
Note: I know this question is old, just wanted to provide a current answer for others coming across this.
you can use pdf-text for pdf files. it will extract text from a pdf into an array of text 'chunks'. Useful for doing fuzzy parsing on structured pdf text.
var pdfText = require('pdf-text')
var pathToPdf = __dirname + "/info.pdf"
pdfText(pathToPdf, function(err, chunks) {
//chunks is an array of strings
//loosely corresponding to text objects within the pdf
//for a more concrete example, view the test file in this repo
})
var fs = require('fs')
var buffer = fs.readFileSync(pathToPdf)
pdfText(buffer, function(err, chunks) {
console.log(chunks)
})
for docx files you can use mammoth, it will extract text from .docx files.
var mammoth = require("mammoth");
mammoth.extractRawText({path: "./doc.docx"})
.then(function(result){
var text = result.value; // The raw text
console.log(text);
var messages = result.messages;
})
.done();
I hope this will help.
For parsing pdf files you can use pdf2json node module
It allows you to convert pdf file to json as well as to raw text data.
Another good option if you only need to convert from Word documents is Mammoth.js.
Mammoth is designed to convert .docx documents, such as those created
by Microsoft Word, and convert them to HTML. Mammoth aims to produce
simple and clean HTML by using semantic information in the document,
and ignoring other details. For instance, Mammoth converts any
paragraph with the style Heading 1 to h1 elements, rather than
attempting to exactly copy the styling (font, text size, colour, etc.)
of the heading.
There's a large mismatch between the structure used by .docx and the
structure of HTML, meaning that the conversion is unlikely to be
perfect for more complicated documents. Mammoth works best if you only
use styles to semantically mark up your document.
Here is an example showing how to download and extract text from a PDF using PDF.js:
import _ from 'lodash';
import superagent from 'superagent';
import pdf from 'pdfjs-dist';
const url = 'http://unec.edu.az/application/uploads/2014/12/pdf-sample.pdf';
const main = async () => {
const response = await superagent.get(url).buffer();
const data = response.body;
const doc = await pdf.getDocument({ data });
for (const i of _.range(doc.numPages)) {
const page = await doc.getPage(i + 1);
const content = await page.getTextContent();
for (const { str } of content.items) {
console.log(str);
}
}
};
main().catch(error => console.error(error));
You can use Aspose.Words Cloud SDK for Node.js to extract text from DOC/DOCX,Open Office, and PDF. It's paid API but the free plan provides 150 free monthly API calls.
P.S: I'm developer evangelist at Aspose.
const { WordsApi, ConvertDocumentRequest } = require("asposewordscloud");
const fs = require('fs');
// Get Customer ID and Customer Key from https://dashboard.aspose.cloud/
wordsApi = new WordsApi("xxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxx", "xxxxxxxxxxxxxxxxxxxx");
const request = new ConvertDocumentRequest({
format: "txt",
document: fs.createReadStream("C:/Temp/02_pages.pdf"),
});
const outputFile = "C:/Temp/ConvertPDFtotxt.txt";
wordsApi.convertDocument(request).then((result) => {
console.log(result.response.statusCode);
console.log(result.body.byteLength);
fs.writeFileSync(outputFile, result.body);
}).catch(function(err) {
// Deal with an error
console.log(err);
});