jsPDF works well within node, but adding an images does not work. There are no error messages, the images just don't show up in the pdf document.
Working with:
macOS: 10.13.4
nodejs: v10.15.0
jsPDF: 1.4.1
The code I use:
// setting up node to act as browser
// library jspdf is built for the browser
// global.window does not work on older versions of node
global.window = {document: {createElementNS: () => {return {}}}};
global.navigator = {};
global.btoa = () => {};
global.node = true;
var fs = require('fs');
atob = require('atob') // npm install atob
var jsPDF = require('/absolute/path/to/jspdf.js');
var pdf = new jsPDF
var imgData = 'data:image/jpeg;base64,/9j/4AAQSkZJRgABAQAASABIAAD/4QCsRXhpZgAATU0AKgAAAAgABQESAAMAAAABAAEAAAEaAAUAAAABAAAASgEbAAUAAAABAAAAUgExAAIAAAAgAAAAWodpAAQAAAABAAAAegAAAAAAAABIAAAAAQAAAEgAAAABQWRvYmUgUGhvdG9zaG9wIENDIDIwMTQgV2luZG93cwAAA6ABAAMAAAABAAEAAKACAAQAAAABAAAAMKADAAQAAAABAAAAMAAAAAD/4QruaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wLwA8P3hwYWNrZXQgYmVnaW49Iu+7vyIgaWQ9Ilc1TTBNcENlaGlIenJlU3pOVGN6a2M5ZCI/PiA8eDp4bXBtZXRhIHhtbG5zOng9ImFkb2JlOm5zOm1ldGEvIiB4OnhtcHRrPSJYTVAgQ29yZSA1LjQuMCI+IDxyZGY6UkRGIHhtbG5zOnJkZj0iaHR0cDovL3d3dy53My5vcmcvMTk5OS8wMi8yMi1yZGYtc3ludGF4LW5zIyI+IDxyZGY6RGVzY3JpcHRpb24gcmRmOmFib3V0PSIiIHhtbG5zOnhtcE1NPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvbW0vIiB4bWxuczpzdFJlZj0iaHR0cDovL25zLmFkb2JlLmNvbS94YXAvMS4wL3NUeXBlL1Jlc291cmNlUmVmIyIgeG1sbnM6eG1wPSJodHRwOi8vbnMuYWRvYmUuY29tL3hhcC8xLjAvIiB4bXBNTTpJbnN0YW5jZUlEPSJ4bXAuaWlkOjYyOERCQkYzMjQwODExRTc5QkZEOUI0RUIwREJBOUQ1IiB4bXBNTTpEb2N1bWVudElEPSJ4bXAuZGlkOjYyOERCQkY0MjQwODExRTc5QkZEOUI0RUIwREJBOUQ1IiB4bXA6Q3JlYXRvclRvb2w9IkFkb2JlIFBob3Rvc2hvcCBDQyAyMDE0IFdpbmRvd3MiPiA8eG1wTU06RGVyaXZlZEZyb20gc3RSZWY6aW5zdGFuY2VJRD0iN0M1QzRFNEY2RTlDOTBBNjlBRjYxRUEwQzg4OTE4NzIiIHN0UmVmOmRvY3VtZW50SUQ9IjdDNUM0RTRGNkU5QzkwQTY5QUY2MUVBMEM4ODkxODcyIi8+IDwvcmRmOkRlc2NyaXB0aW9uPiA8L3JkZjpSREY+IDwveDp4bXBtZXRhPiAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgICAgIDw/eHBhY2tldCBlbmQ9InciPz4A/+0AOFBob3Rvc2hvcCAzLjAAOEJJTQQEAAAAAAAAOEJJTQQlAAAAAAAQ1B2M2Y8AsgTpgAmY7PhCfv/AABEIADAAMAMBIgACEQEDEQH/xAAfAAABBQEBAQEBAQAAAAAAAAAAAQIDBAUGBwgJCgv/xAC1EAACAQMDAgQDBQUEBAAAAX0BAgMABBEFEiExQQYTUWEHInEUMoGRoQgjQrHBFVLR8CQzYnKCCQoWFxgZGiUmJygpKjQ1Njc4OTpDREVGR0hJSlNUVVZXWFlaY2RlZmdoaWpzdHV2d3h5eoOEhYaHiImKkpOUlZaXmJmaoqOkpaanqKmqsrO0tba3uLm6wsPExcbHyMnK0tPU1dbX2Nna4eLj5OXm5+jp6vHy8/T19vf4+fr/xAAfAQADAQEBAQEBAQEBAAAAAAAAAQIDBAUGBwgJCgv/xAC1EQACAQIEBAMEBwUEBAABAncAAQIDEQQFITEGEkFRB2FxEyIygQgUQpGhscEJIzNS8BVictEKFiQ04SXxFxgZGiYnKCkqNTY3ODk6Q0RFRkdISUpTVFVWV1hZWmNkZWZnaGlqc3R1dnd4eXqCg4SFhoeIiYqSk5SVlpeYmZqio6Slpqeoqaqys7S1tre4ubrCw8TFxsfIycrS09TV1tfY2dri4+Tl5ufo6ery8/T19vf4+fr/2wBDABALCwsMCxAMDBAXDw0PFxsUEBAUGx8XFxcXFx8eFxoaGhoXHh4jJSclIx4vLzMzLy9AQEBAQEBAQEBAQEBAQED/2wBDAREPDxETERUSEhUUERQRFBoUFhYUGiYaGhwaGiYwIx4eHh4jMCsuJycnLis1NTAwNTVAQD9AQEBAQEBAQEBAQED/3QAEAAP/2gAMAwEAAhEDEQA/AO/oJA6nFQXt5HZ27TSHpwo9Segrk3li1K4aS9nxHuwqs+0H/ZVc4x71nOqoyUd5Ppe2h1YfCyqqU23CEeqXM2+yWh2eRjNQWcssyPLJtEbuTAACD5YwFLEk5JwT9CK5mS125FpezwAjbt3l0IPs+f0rEk8QaxZM9r9obdEdquOOF6HBBBBHtQ6lt0/kXHAud+SpF26STT/U9Ipa5Xw34ta/mWxvwBO/+qmXgOeu1l7H0xwfaupq4yTV0c1WlOlJwmrNfc13R//Q0vGl48dzZ24Py4dyB3PCj9M1y13dAqVU54A/rXWeMLbdNBNjjaVz6HP/ANeuOljCucCuWrR5qnNfse5gayjh4xS1Sf5sE1W7jTYj/KOmeT+pqr57s7SMd0jclj1qUxrj0FNCKF6DmqUH32NW0tUtXuS2srNMkij97CVeMj1Rgw/lXriNuRW9QD+fNeZ6HZCe6RUXlmC59ief0r00AAADoOK2irI8rHSTml2TP//R7PVbEXto0YGXX5k+vp+NedarF5EhBGDnp0r1E5xx1rmNb8KXeqT+ctxFGT1yjcn1+VhUyV9tzrwmIVNtT+Hf5nCs+eneotx3Y/Supb4f6pxtuoGx6hx/U1JbeAL1ZVknuYSoOSoVzn8S1Qoz8vvO2WOoW05vuNTwhpflWy3sg5cfu/x6t/hXS1m2elz25XNyxC4+UdMDtzWlWtrHlVZuc3J9T//Z'
pdf.setFontSize(40)
pdf.text(35, 25, 'Some Sample Text')
pdf.addImage(imgData, 'JPEG', 15, 40, 180, 160)
fs.writeFileSync('my_image_pdf_test.pdf', pdf.output());
The pdf file is larger when the image is added (97806 bytes).
Without the image it is just 2448 bytes.
What can be wrong? Any node packages missing?
It seems that when you write pdf files with images in nodejs, you have to use pdf.output('arraybuffer')
So replace the following line:
fs.writeFileSync('my_image_pdf_test.pdf', pdf.output());
with:
fs.appendFileSync('another_image_pdf_test.pdf', new Buffer.from(pdf.output('arraybuffer')));
Related
I would like to tranform canvas ImageData (of type Uint8ClampedArray) into a n image matrix using opencv4nodejs npm package.
https://www.npmjs.com/package/opencv4nodejs
https://github.com/justadudewhohacks/opencv4nodejs#readme
The github README explains clearly how to transform an image matrix into canvas ImageData, but it does not show what methods to use for the opposite.
const img = ...
// convert your image to rgba color space
const matRGBA = img.channels === 1
? img.cvtColor(cv.COLOR_GRAY2RGBA)
: img.cvtColor(cv.COLOR_BGR2RGBA);
// create new ImageData from raw mat data
const imgData = new ImageData(
new Uint8ClampedArray(matRGBA.getData()),
img.cols,
img.rows
);
I would like to know how to convert a gray-scale canvas ImageData into the a matGRAY. (or a rgba ImageData into BGR matrix). Either strategy would be very helpful to me! I haven't found other documentation for this yet.
Goal:
const ctx = canvas.getContext('2d');
const imageData = ctx.getImageData(0,0,canvas.width, canvas.height);
//Then something like this....
// const matGRAY = opencv4nodejs.imagedata2matrix(imageData);
const _ = require('lodash'); // allows fast array transformations in javascript
const Canvas = require('canvas'); //node-canvas on server side
const cv = require('opencv4nodejs');
You can receive the Uint8ClampedArray image data from client directly
..but here we will create it from scratch.
const canvas = Canvas.createCanvas('2d');
const ctx = getContext('2d');
const image = new Canvas.Image();
image.onload = () => {
ctx.drawImage(image,0,0);
}
image.src = 'path/to/image.jpg'
//get imageData from the image on our canvas
const imageDataObject = ctx.getImageData(0,0,canvas.width,canvas.height);
const imageData = imageDataObject.data;
const width = imageDataObject.width;
const height = imageDataObject.height;
//imageData is Uint8ClampedArray
Now that we have the Uint8ClampedArray, we can convert to matrix
// convert to normal array
const normalArray = Array.from(imageData);
//nest the pixel channels
const channels = 4 //canvas pixels contain 4 elements: RGBA
const nestedChannelArray = _.chunk(normalArray, channels);
const nestedImageArray = _.chunk(nestedChannelArray, height);
//nestedImageArray is the correct shape to be converted to matrix.
const RGBAmat = new cv.Mat(nestedImageArray, cv.CV_8UC4);
//openCV often defaults to BGR-type image matrix, so lets color convert the pixel order
const BGRAmat = RGBAmat.cvtColor(cv.COLOR_RGBA2BGRA);
BGRAmat is an openCV matrix, ready for processing!
In case you are new to Node.js, here is the terminal code to get started.
First, install Node.js then run at your terminal
$ mkdir canvasToMatrix
$ cd canvasToMatrix
$ npm init -y
$ npm install lodash canvas opencv4nodejs
Create new file.js, and paste in the code above. After saving, run
$ node file.js
I am working on a small project that works with generating pdf's in node and express, and been trying to use the jspdf npm module but somehow whenever I install that package and require it its crashing my sever. Here in how I am requiring in my server.js file:
var jsPDF = require('jspdf')
And this is the response that it is giving me when l try to run my server:
(window.AcroForm=function(t){var n=window.AcroForm;n.scale=function(t) {return t*(r.internal.scaleFactor/1)},n.antiScale=function(t){return 1/r.internal.scaleFactor*t};var r={fields:[],xForms:[],acroFormDictionaryRoot:null,printedOut:!1,internal:null};e.API.acroformPlugin=r;var i=function(){for(var t in this.acroformPlugin.acroFormDictionaryRoot.Fields){var e=this.acroformPlugin.acroFormDictionaryRoot.Fields[t];e.hasAnnotation&&a.call(this,e)}},o=function(){if(this.acroformPlugin.acroFormDictionaryRoot)throw new Error("Exception while creating AcroformDictionary");this.acroformPlugin.acroFormDictionaryRoot=new n.AcroFormDictionary,this.acroformPlugin.internal=this.internal,this.acroformPlugin.acroFormDictionaryRoot._eventID=this.internal.events.subscribe("postPutResources",l),this.internal.events.subscribe("buildDocument",i),this.internal.events.subscribe("putCatalog",c),this.internal.events.subscribe("pos
ReferenceError: window is not defined
The jsPDF library is for the client side (web browser) which is why it's expecting a window variable to be present. Luckily someone has already answered how to make this work server side here. Taken from that answer:
global.window = {document: {createElementNS: () => {return {}} }};
global.navigator = {};
global.btoa = () => {};
var fs = require('fs');
var jsPDF = require('jspdf');
var doc = new jsPDF();
doc.text("Hello", 10, 10);
var data = doc.output();
fs.writeFileSync('./document.pdf', data);
delete global.window;
delete global.navigator;
delete global.btoa;
Here is a prior post that discusses how the pre-loaded Imagemagick is limited for security reasons on AWS Lambda.
"Note: This update contains an updated /etc/ImageMagick/policy.xml
file that disables the EPHEMERAL, HTTPS, HTTP, URL, FTP, MVG, MSL,
TEXT, and LABEL coders"
I need to use the 'label' function (which works successfully on my development machine - example pic further below))
Within the discussion in the linked post, frenchie4111 generously offers use of a node module he created that uploads imagemagick to a lambda app: github link https://github.com/DoubleDor/imagemagick-prebuilt
I would like to understand how uploading a fresh version of Imagemagick works, and how I will then use that version with the GM module that incorporates IM and nodejs together.
If I read correctly the full version of imagemagick will be reloaded to the address below each time my lambda app boots up ?
/tmp/imagemagick
DoubleDor's readme directions provides the option below:
var imagemagick_prebuilt = require( 'imagemagick-prebuilt' );
var child_process = require( 'child_process' );
exports.handler = function( event, context ) {
return q
.async( function *() {
imagemagick_bin_location = yield imagemagick_prebuilt();
console.log( `ImageMagick installed: ${imagemagick_bin_location}` );
// ImageMagick logo creation test:
// convert logo: logo.gif
var convert_process = child_process
.spawn( imagemagick_bin_location, [ 'logo:', 'logo.gif' ] )
convert_process
.on( 'close', function() {
context.success();
} );
} )();
};
What would I include/require to define 'gm' to work within my partial file below (in my nodejs lambda app)?
Will I need to edit the GM module too?
//imagemaker.js > gets included and called from another file that uploads picture to s3, and/or tweets it after picture is created in /tmp/filename.jpg This works presently.. I can make and upload imagemagick text generated images but I just can't use the 'label' tool which scales text within appended gm images
'use strict';
var Promise = require('bluebird');
var exec = require('child_process').exec;
var async = require('async');
var request = require('request');
var fs = require('fs');
var dateFormat = require('dateformat');
var gm = require('gm').subClass({imageMagick: true});
var aws = require('aws-sdk');
performers = [ { name: 'Matt Daemon', score: 99}, { name: “Jenifer Lawrence”, score: 101}
//created in a makeTitle function I omit for brevity sake.
url = “/temp/pathtotitlepicture.jpg”
// function below successfully appends a gm title image created with other functions that I haven't included
function makeBody(url){
var img = gm(400,40)
.append(url)
.gravity('West')
.fill('black')
.quality('100')
.font('bigcaslon.ttf')
.background('#f0f8ff')
for (var i = 0; i < performers.length; i++) {
var pname = " " + (i+1) + ") " +performers[i].name;
img.out('label:'+pname);
};
img.borderColor('#c5e4ff')
.border('5', '5')
.write(url, function (err) {
if (err) throw err;
var stream = fs.createReadStream("/tmp/fooberry.jpg")
return resolve(stream)
});
}
Just for fun, the image below shows what I've been able to do with gm(graphics magic) and imagemagick on my development machine that I'd now like to get working on AWS Lambda >> I really need that 'label' function and I guess that means learning how to get that whole library uploaded to AWS Lambda each time it boots!(?)
I have a problem with pdfmake. I would like to generate a PDF on a node.js server. I would like to load data from a database and draw a nice table and simply save it to a folder.
var pdfMakePrinter = require('pdfmake/src/printer');
...
var fonts = {
Roboto: {
normal: './fonts/Roboto-Regular.ttf',
bold: './fonts/Roboto-Medium.ttf',
italics: './fonts/Roboto-Italic.ttf',
bolditalics: './fonts/Roboto-Italic.ttf'
}
};
var PdfPrinter = require('pdfmake/src/printer');
var printer = new PdfPrinter(fonts);
var docDefinition = {
content: [
'First paragraph',
'Another paragraph, this time a little bit longer to make sure, this line will be divided into at least two lines'
]
};
var pdfDoc = printer.createPdfKitDocument(docDefinition);
pdfDoc.pipe(fs.createWriteStream('pdf/basics.pdf')).on('finish', function () {
res.send(true);
});
The generated PDF is empty. If I add an image, it is inserted well. But no font is included. The path of the fonts (which are given in the sample) is right.
Has anyone an idea, why no fonts are embedded and how this can be done in node.js? There are no valid samples on the pdfmake documentation.
After some debugging, I found out, that the app crashes in fontWrapper.js in this funktion:
FontWrapper.prototype.getFont = function(index){
if(!this.pdfFonts[index]){
var pseudoName = this.name + index;
if(this.postscriptName){
delete this.pdfkitDoc._fontFamilies[this.postscriptName];
}
this.pdfFonts[index] = this.pdfkitDoc.font(this.path, pseudoName)._font; <-- Crash
if(!this.postscriptName){
this.postscriptName = this.pdfFonts[index].name;
}
}
return this.pdfFonts[index];
};
Does anyone have an idea?
TTF is not issue in your case you can use any font to generate a PDF on a node.js server.
inside pdfmake
TTFFont.open = function(filename, name) {
var contents;
contents = fs.readFileSync(filename);
return new TTFFont(contents, name);
};
on contents = fs.readFileSync(filename); this line
fs can't read file on given path
as per This conversation you have to put your fonts at root folder,
but problem is when we create font object we gives root path and this path is not working for fs.readFileSync this line so you have to exact path of font
add process.cwd().split('.meteor')[0] befor font path
I have created example for same functionality please this below link
https://github.com/daupawar/MeteorAsyncPdfmake
After much struggling, I've managed to get node-canvas installed on Windows.
When I try to read in the image size of a GIF, however, it just gives me back 0 for the width and height.
var FileSystem = require('fs');
var Canvas = require('canvas');
FileSystem.readdir(baseDir, function(err, files) {
files.forEach(function(filename) {
var path = Path.join(baseDir, filename);
FileSystem.readFile(path, function(err, buf) {
var img = new Canvas.Image;
img.src = buf;
console.log(path, img.width, img.height);
});
});
Is it not supposed to be able to read GIFs?
You must install giflib and reinstall node-canvas like is said in here https://github.com/LearnBoost/node-canvas/wiki/Installation---OSX and then you will be able to manipulate your gif file (retrieve width/height). But beware, the image processed with canvas will stop being animated.