PDF Generation in Nodejs - node.js

I have requirement where i need to create a PDF from html in node .In addition to that i must be able to add custom header and footer. Then content of the web page should be in multiple pages based on custom requirement. that is we must able to decide what content should be which page.
After searching i found some solutions like phantom , but there is no proper documentation which could help me.
I need some way to do this.
Found a solution
here , but explanation is not good enough.

I have been using https://github.com/baudehlo/node-phantom-simple module with webshot
Step I follow:-
Create HTML using the node-phantom-simple
After creating the HTML use that HTML to pass it in webshot.
var driver = require('node-phantom-simple');
var webshot = require('webshot');
driver.create({path: require('phantomjs').path, 'parameters': {'disk-cache': 'yes'}}, function (err, browser) {
return browser.createPage(function (err, page) {
return page.open(url, function (err, status) {
console.log("opened site? ", status,page.content);
return page.evaluate(File.cleanHtml, function (err, html) {
var options = {
streamType: 'pdf',
screenSize: {
width: 1200,
height: 300
},
shotSize: {
width: 1200,
height: 300
},
siteType:'html',// include this to generate PDF from html
phantomConfig: {'ssl-protocol':'any','ignore-ssl-errors': 'true'}
}
var pdfname = 'test_' + Date.now() + '.pdf';
webshot(html,pdfname,options, function(err) {
console.log("err in webshot",err);
})
});
// });
});
});
});
Here File.cleanHtml is a function I have created which is used to remove extra content from HTML.you can directly return same HTML from this function.may be something like this :)
cleanHtml: function () {
var data = $("html");
return "<html>" + data.html() + "</html>";
}

Related

Why the pug page not work in my nodejs code

I want to show the images and videos related to each Id of the saved files(on my server) on the 'media.pug' page.
I am using the following codes, but it does not render the desired media.pug page.
My form submit:
form(action="/medias/" + some_id method="GET")
input(type="submit" value="Photo / Image")
some_id is for example 54.
The router:
router.get("/medias/:some_id" , InfoCtrl.apiMedias);
And in the InfoCtrl controller:
static async apiMedias(req, res, next) {
try {
const Id= req.params.some_id;
const imagesPath = path.join(__dirname, `../public/media/${Id}/image`);
const videosPath = path.join(__dirname, `../public/media/${Id}/video`);
let images = [];
let videos = [];
function foo (folder, enconding) {
return new Promise(function(resolve, reject) {
fs.readdir(folder,enconding, function(err, filenames){
if (err)
reject(err);
else
resolve(filenames);
});
});
};
foo(imagesPath).then((value)=>{
images= value;
}).then(foo(videosPath).then((value)=>{
videos= value;
}).then((value)=>{
var model = {"phoneId": phoneId, "images": images , "videos": videos};
console.log(model);
res.render("media", {
"model": model,
});
}));
} catch (error) {
console.log(error);
}
}
What is wrong and how to solve it?
Actually there was not any problem with my above code, but there was a problem with my layout page which the reference to the style and other scripts was wrong so they were pending when was loading.
before editing it was like this:
link(href="./css/style.css" rel="stylesheet")
But I canged to:
link(href="../css/style.css" rel="stylesheet")
and it works now.

PDFToolKit is sending weird data

I have installed PDFKit for node.js. When i call my method to download a PDF file, i get this kind of characers on my browser:
xœU»nÜ0ìùüËûâ’Œ+8Ò¹.H‘œOn|Eà¿ï!ï> AÔ’”†ÃåÌŠ#áºa4Χð+ðÕ؇ýe£ªMfç)av
This is my code:
var doc = new PDFDocument({ layout: 'landscape' });
doc.pipe(res);
doc.moveDown(1);
doc.text(reportName, { align: "center" });
doc.text(bNames.join(','), { align: "center" });
doc.text(dateFrom + " - " + dateTo, { align: "center" });
doc.moveDown(2);
const table0 = {
headers: allNames,
rows: allData
};
doc.table(table0, {
prepareHeader: () => doc.font('Helvetica-Bold').fontSize(10),
prepareRow: (row, i) => doc.font('Helvetica').fontSize(10)
});
doc.end();
Is there something else i have to tell PDFKit to work right?
EDIT1:
I am running this code on my backend and sending it to my frontend so i can download it there
If you want a PDF response straight to the browser, you need to add the header so it understands the binary data.
Set this before the response is piped.
res.setHeader('Content-type', 'application/pdf')

How can I pipe external html content in jade?

I'm trying to get some html from a page online and place inside my jade template so I can style without copying and pasting every time a need it.
var request = require("request");
var cheerio = require("cheerio");
var loadContent = function() {
request({
uri: "http://www.mywebsite.com.br/test"
}, function(error, response, body) {
var $ = cheerio.load(body);
var result;
$('.content').each(function(){
result={"content":$(this).html()};
});
placeContent(result);
return true;
});
};
var placeContent = function(content) {
return content;
};
module.exports = loadContent;
Inside my gulpfile.js, besides the right requirements, I have:
gulp.task('jadeBuild', function() {
var options = {
pretty: true
};
return gulp.src(src+'/*.jade')
.pipe(data(function(){
return loadContent();
}))
.pipe(jade(options))
.pipe(gulp.dest(build))
.pipe(connect.reload());
});
And my jade file:
.mycontent
#{content}
What am I missing?
Try changing #{content} to !{content} in your jade file. This will tell jade not to escape any of the characters(which can be dangerous depending on where the input is coming from!).
See http://jade-lang.com/reference/interpolation/
Also, when you loop over each .content you are overwriting result every time. You need to append to result if you want to aggregate all the content together. Something like:
var result = {content: ''};
$('.content').each(function(){
result.content += $(this).html();
});

Secondary tile web url

I have to pin secondary tile in my windows phone 8.1 application.
I followed the msdn tutorial : http://code.msdn.microsoft.com/windowsapps/secondary-tiles-sample-edf2a178/
It does work with internal image (ms-appx://.. ) but not with web url (http://)
working sample:
var logo = new Windows.Foundation.Uri("ms-appx:///Images/square30x30Tile-sdk.png");
var currentTime = new Date();
var TileActivationArguments = data.ad_id + " WasPinnedAt=" + currentTime;
var tile = new Windows.UI.StartScreen.SecondaryTile(data.ad_id,
data.subject,
TileActivationArguments,
logo,
Windows.UI.StartScreen.TileSize.square150x150);
tile.visualElements.foregroundText = Windows.UI.StartScreen.ForegroundText.light;
tile.visualElements.square30x30Logo = logo;
tile.visualElements.showNameOnSquare150x150Logo = true;
var selectionRect = this.element.getBoundingClientRect();
// Now let's try to pin the tile.
// We'll make the same fundamental call as we did in pinByElement, but this time we'll return a promise.
return new WinJS.Promise(function (complete, error, progress) {
tile.requestCreateForSelectionAsync({ x: selectionRect.left, y: selectionRect.top, width: selectionRect.width, height: selectionRect.height }, Windows.UI.Popups.Placement.above).done(function (isCreated) {
if (isCreated) {
complete(true);
} else {
complete(false);
}
});
});
And if I use
var logo = new Windows.Foundation.Uri(data.images[0]);
I got an invalid parameter exception.
You can take a look at the documentation for the SecondaryTile.Logo property. In it you'll see this:
The location of the image. This can be expressed as one of these schemes:
ms-appx:///
ms-appdata:///local/
You can download the image first and then set it using the ms-appdata:///local/ scheme. I'm not sure that changing the logo with something from the Internet is a good idea, though. This should be the app's logo, so it should be in the package.
I found the solution
fileExists: function (fileName) {
var applicationData = Windows.Storage.ApplicationData.current;
var folder = applicationData.localFolder;
return folder.getFileAsync(fileName).then(function (file) {
return file;
}, function (err) {
return null;
});
},
download: function (imgUrl, imgName) {
return WinJS.xhr({ url: imgUrl, responseType: "blob" }).then(function (result) {
var blob = result.response;
var applicationData = Windows.Storage.ApplicationData.current;
var folder = applicationData.localFolder;
return folder.createFileAsync(imgName, Windows.Storage.
CreationCollisionOption.replaceExisting).then(function (file) {
// Open the returned file in order to copy the data
return file.openAsync(Windows.Storage.FileAccessMode.readWrite).
then(function (stream) {
return Windows.Storage.Streams.RandomAccessStream.copyAsync
(blob.msDetachStream(), stream).then(function () {
// Copy the stream from the blob to the File stream
return stream.flushAsync().then(function () {
stream.close();
});
});
});
});
}, function (e) {
//var msg = new Windows.UI.Popups.MessageDialog(e.message);
//msg.showAsync();
});
},
var self = this;
this.download(data.images[0], data.ad_id).then(function () {
self.fileExists(data.ad_id).then(function (file) {
var logo = new Windows.Foundation.Uri("ms-appdata:///Local/" + data.ad_id);
....
I need to download the image, store it and then I can use ms-appdata:///Local

How to attach file to post request nodejs?

I am using nodejs for file upload. I am trying something like this below link. But not getting how to post the stuff. I need to post the JSON data along with the file. How can I do?
function myCtrl() {
//an array of files selected
$scope.files = [];
//listen for the file selected event
$scope.$on("fileSelected", function (event, args) {
alert("file selected:")
$scope.$apply(function () {
//add the file object to the scope's files collection
$scope.files.push(args.file);
});
});
//the save method
$scope.save = function(filename) {
$http({
method: 'POST',
url: "http://localhost:3000/uploadfile",
headers: { 'Content-Type': false },
//This method will allow us to change how the data is sent up to the
//server for which we'll need to encapsulate the model data
//in 'FormData'
transformRequest: function (data) {
var formData = new FormData();
formData.append("model", angular.toJson(data.model));
for (var i = 0; i < data.files; i++) {
//add each file to the form data and iteratively name them
formData.append("file" + i, data.files[i]);
}
return formData;
},
//Create an object that contains the model and files which will
//be transformed in the above transformRequest method
data: {files: $scope.files }
}).
success(function (data, status, headers, config) {
alert("success!:"+JSON.stringify(data));
}).
error(function (data, status, headers, config) {
alert("failed!:"+JSON.stringify(data));
});
};
}
Here is my angular directive "file-upload", I used to recognize the selected files to upload.
angular.module('myApp', []).directive('file-upload', function () {
return {
scope: true, //create a new scope
link: function (scope, el, attrs) {
el.bind('change', function (event) {
var files = event.target.files;
//iterate files since 'multiple' may be
//specified on the element
for (var i = 0;i<files.length;i++) {
//emit event upward
scope.$emit("fileSelected", { file: files[i] });
}
});
}
};
});
I am using on ng-click I am calling save(). Not working. What is the problem?
I don't see any ng-click in your code.
The correct way is to bind to "change" event which seems like that's what you are doing.
You can use the lightweight angular-file-upload library which does what you are looking for with a directive.
It also support IE9 with flash polyfill since IE9 doesn't support FormData.
<script src="angular.min.js"></script>
<script src="angular-file-upload.js"></script>
<div ng-controller="MyCtrl">
<input type="file" ng-file-select="onFileSelect($files)" multiple>
</div>
JS:
//inject angular file upload directive.
angular.module('myApp', ['angularFileUpload']);
var MyCtrl = [ '$scope', '$http', function($scope, $http) {
$scope.onFileSelect = function($files) {
//$files: an array of files selected, each file has name, size, and type.
for (var i = 0; i < $files.length; i++) {
var $file = $files[i];
$http.uploadFile({
url: 'my/upload/url',
file: $file
}).then(function(data, status, headers, config) {
// file is uploaded successfully
console.log(data);
});
}
}
}];

Resources