"Error: Unknown Version 0" when using NodeJS PDFKit - node.js

I'm trying to get the very excellent NodeJS PDFKit to use custom fonts OpenSans and Roboto from Google Fonts. My code looks like the following:
this.doc = new PDFDocument({bufferPages: true});
this.doc.registerFont("Roboto-Black", path.join(__dirname, "fonts", "Roboto-Black.ttf"));
I've printed the path - it's finding the right file. I'm getting the following error:
C:\projects\qbdvision\node_modules\restructure\src\VersionedStruct.js:37
throw new Error("Unknown version " + res.version);
^
Error: Unknown version 0
at VersionedStruct.decode (C:\projects\qbdvision\node_modules\restructure\src\VersionedStruct.js:37:15)
at C:\projects\qbdvision\node_modules\restructure\src\Pointer.js:69:30
at Pointer.decode (C:\projects\qbdvision\node_modules\restructure\src\Pointer.js:79:16)
at ArrayT.decode (C:\projects\qbdvision\node_modules\restructure\src\Array.js:49:30)
at VersionedStruct.Struct._parseFields (C:\projects\qbdvision\node_modules\restructure\src\Struct.js:53:22)
at VersionedStruct.decode (C:\projects\qbdvision\node_modules\restructure\src\VersionedStruct.js:42:12)
at VersionedStruct.decode (C:\projects\qbdvision\node_modules\restructure\src\VersionedStruct.js:40:23)
at C:\projects\qbdvision\node_modules\restructure\src\Pointer.js:69:30
at Pointer.decode (C:\projects\qbdvision\node_modules\restructure\src\Pointer.js:79:16)
at ArrayT.decode (C:\projects\qbdvision\node_modules\restructure\src\Array.js:49:30)
FAILED
When I removed the Roboto font, and tried the OpenSans one, it worked at least, but everything looked terrible. Letters were bleeding together and looked almost smudged.
I've downloaded the fonts from fonts.google.com by clicking "Select this font", clicking on the "1 Family Selected" popup that comes up and then clicking on the download icon in the upper right hand corner of that popup.
Why won't these fonts work?

The solution is to convert the fonts into base64 encoding and then import them. So at the command line, using Linux / Cygwin, type:
base64 --wrap=0 Roboto-Black.ttf > Roboto-Black-Base64.ttf
That'll produce a new TTF file that should be all text inside. If you use an external service, make sure there isn't any wrapping. It should be one continuous block of text.
Then, in your NodeJS code, do:
let fs = require("fs");
let doc = new PDFDocument({bufferPages: true});
let filePath = path.join(__dirname, "fonts", "Roboto-Black-Base64.ttf");
let fileContents = fs.readFileSync(filePath, "utf8");
this.doc.registerFont(fontName, new Buffer(fileContents, "base64"));
Then your fonts will show up crystal clear. Props to this answer for giving me the clues I needed.

Related

Best way to write markdown content in Node.js

I have to write some markdown text in my Node.js script which will be rendered on UI with respective formatting.
Here are the two options I have explored so far:
Option 1:
module.exports = {
status: "ENABLED"
remediation: "**Adding markdown remediation here** ",
}
Option 2:
const remediation = "## this is another way which seems a bit better"
module.exports = {
status: "ENABLED"
remediation,
}
The second option renders a bit better but I am still struggling with a few things like defining new lines, adding code body etc.
Wanted to check if there can be a better way to include markdown text in the script.
I would suggest that instead of creating your own wheels, please check markdown-it.
npm install markdown-it --save
// node.js, "classic" way:
var MarkdownIt = require('markdown-it'),
md = new MarkdownIt();
var result = md.render('# markdown-it rulezz!');
// node.js, the same, but with sugar:
var md = require('markdown-it')();
var result = md.render('# markdown-it rulezz!');
// browser without AMD, added to "window" on script load
// Note, there is no dash in "markdownit".
var md = window.markdownit();
var result = md.render('# markdown-it rulezz!');

Problem with canvas using vega with nodejs (server side only)

I've been working for a few weeks now on a Discord bot that basically compiles stats on the server and deduces patterns. In order to improve it, I wanted to make it generate graphs as PNGs in order to send them back to the user - in short, no DOM.
In order to achieve this, I'm currenlty using vega (version 5.10.1 - latest) and node-canvas (version 2.6.1 - latest), with nodejs v12.16.1.
I've been scouring the web for help on vega usage, and found a couple contradicting sources. I've been using the example code provided here :
https://vega.github.io/vega/usage/
The thing is that I keep getting this error :
TypeError: Cannot read property 'getContext' of null
message:"Cannot read property 'getContext' of null"
stack:"TypeError: Cannot read property 'getContext' of null
at resize (e:\DEV\GIT REPOS\GITHUB\PERSO\JS\test-StatBot\node_modules\vega-scenegraph\build\vega-scenegraph.js:3665:28)
at CanvasRenderer.prototype$6.resize (e:\DEV\GIT REPOS\GITHUB\PERSO\JS\test-StatBot\node_modules\vega-scenegraph\build\vega-scenegraph.js:3714:5)
at CanvasRenderer.prototype$4.initialize (e:\DEV\GIT REPOS\GITHUB\PERSO\JS\test-StatBot\node_modules\vega-scenegraph\build\vega-scenegraph.js:3294:17)
at CanvasRenderer.prototype$6.initialize (e:\DEV\GIT REPOS\GITHUB\PERSO\JS\test-StatBot\node_modules\vega-scenegraph\build\vega-scenegraph.js:3709:28)
at initializeRenderer (e:\DEV\GIT REPOS\GITHUB\PERSO\JS\test-StatBot\node_modules\vega-view\build\vega-view.js:657:8)
at renderHeadless (e:\DEV\GIT REPOS\GITHUB\PERSO\JS\test-StatBot\node_modules\vega-view\build\vega-view.js:780:12)
at processTicksAndRejections (internal/process/task_queues.js:97:5)
at async View.renderToCanvas [as toCanvas] (e:\DEV\GIT REPOS\GITHUB\P...
Here is the code which is giving me trouble :
// Imports
const vega = require('vega');
// Render image from given graph spec (statsObject)
async function graphToImage (statsObject) {
graphObject = new vega.View(vega.parse(statsObject), { renderer: 'none'});
const pngName = generateFileName(10);
removeExistingFile(pngName);
graphObject.toCanvas().then(canvas => {
console.log('Writing PNG to file...');
writeFile(`../../../../generated/${pngName}.png`, canvas.toBuffer());
}).catch(err => {
console.log("Error writing PNG to file:");
console.error(err);
});
return pngName;
}
I don't really know how canvas or vega work, and so I have no idea what could be causing this issue and how to fix it... However, the problem seems to be located inside of the toCanvas() method. Any help is much appreciated !
Thanks in advance !
// Using view.toSVG() along with the npm package sharp worked well for me
const view = new vega.View(vega.parse(templateObject), {renderer: 'none'});
view.toSVG().then(async function (svg) {
await sharp(Buffer.from(svg))
.toFormat('png')
.toFile('fileName.png')
}).catch(function(err) {
console.error(err);
});
Edit : I managed to fix my issue, and I am posting the anwser here for future notice :
I succeeded to actually generate a graph picture by rendering the View object straight to an SVG string, by using view.toSVG() instead of the buggy view.toCanvas(), which worked great.
Then, all that was left to do was to convert the obtained SVG string into a PNG file, and that was it.
Here is the updated, working code :
// Imports
const vega = require('vega');
// Render image from given graph object
async function graphToImage (statsObject) {
// Generate a new 10-char hex string
const pngName = generateHexStringName(10);
// Remove any existing file with the same name in order to prevent confusion
removeExistingFile(pngName);
var view = new vega.View(vega.parse(statsObject), {renderer: 'none'});
// Generate an SVG string
view.toSVG().then(async function (svg) {
// Working SVG string
console.log(svg);
// Process obtained SVG string, e. g. write it to PNG file
}).catch(function(err) {
console.error(err);
});
// Return the name of the generated PNG file
return pngName;
}

Ordner nicht angegeben with OmniPascal in VSCode

People get the error when opening a file in Visual Studio Code when using OmniPascal:
Ordner nicht angegeben
which translates to:
Folder not specified
The first thought to ensure the paths in user settings.json are set:
objectpascal.delphiInstallationPath
objectpascal.objectpascal.searchPath
Would of course be a wrong tree to bark up:
settings.json:
// Place your settings in this file to overwrite the default settings
{
"objectpascal.delphiInstallationPath": "D:\\Programs\\Embarcadero\\Studio\\14.0",
"objectpascal.searchPath": "D:\\Delphi Components"
}
The error is definitely coming from OmniPascal, as it is a string inside
bin\win\OmniPascalServer.exe
I'm not the only person to get this
Anonymous has the same issue:
When I open a .pas file by right clicking on the file in windows explorer, the file opens correctly, but then a messagedialog appears with "Ordner nicht angegeben"' and an OK button.
Is there a way to debug Code?
I can see inside VSCode there is a variable to the workspace root path:
objectPascalServiceClient.js
var config = vscode.workspace.getConfiguration('objectpascal');
var delphiSDK = config.get('delphiInstallationPath', '');
var searchPath = config.get('searchPath', '');
var workspacePath = vscode.workspace.rootPath;
if (typeof delphiSDK == 'undefined')
delphiSDK = "";
if (typeof searchPath == 'undefined')
searchPath = "";
if (isWin) {
childProcess = cp.spawn(path.join(__dirname, 'bin/win/OmniPascalServer.exe'), [workspacePath, delphiSDK, searchPath]);
}
Is there source code?
It looks like OmniPascal is abandonware. Is there source code out there where someone can try to decipher exactly?
The real question is how to get rid of the modal dialog that blocks using the window.
It looks like OmniPascal is abandonware
No it's definetely not abandonware even though there was no new public release within the last months. OmniPascal is still in active development.
The real question is how to get rid of the modal dialog that blocks using the window.
This error message is coming from OmniPascalServer.exe shipped with the OmniPascal plugin for VSCode in (the current) version 0.10.0 released on 2016-04-14.
Workaround for version < 0.11.0
As far as I know this error message only appears when a file is opened in Visual Studio Code instead of a folder. So the simplest workaround is to open the folder which contains the file(s) you want to work with:
By command line: Type code C:\Projects\MyProjectRootFolder
With the Windows Explorer: Perform a right click on the folder (or a white area inside the folder) and select Open with Code. Do not select a .pas file to open VSCode!
From within VSCode: Go to File -> Open Folder...
Or apply the hotfix
Open the file C:\Users\USERNAME\.vscode\extensions\Wosi.omnipascal-0.10.0\objectPascalServiceClient.js
Replace this line
var workspacePath = vscode.workspace.rootPath;
with these lines
var workspacePath = vscode.workspace.rootPath;
if (typeof workspacePath == 'undefined') {
var filePath = vscode.workspace.textDocuments[0].fileName;
workspacePath = path.dirname(filePath);
}
Now the error should no longer appear.

pdfmake does not include fonts / text in node.js

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

node-canvas: Using custom font

I would like to know how to use custom font with node-canvas.
Here is my attempt but it does not work so far:
var Canvas = require('canvas')
, Image = Canvas.Image
, Font = Canvas.Font
, path = require('path');
var gubblebum = new Font('gubblebum', fontFile('GUBBLO___.ttf'));
function fontFile(name) {
return path.join(__dirname, '../fonts', name);
}
function draw() {
var canvas = new Canvas(100, 100)
, ctx = canvas.getContext('2d');
ctx.addFont(gubblebum);
ctx.font = 'bold 40 gubblebum';
ctx.fillText('test', 25, 45);
return canvas;
}
module.exports = draw;
When rendered in a browser, the font is left unchanged from the default, as well as the size.
The font file is correctly loaded. Otherwise, an exception would be thrown.
Interestingly, when I do ctx.font = 'bold 40 someGibberish'; the font size is applied correctly.
This should now "Just Work" in node-canvas 2.0+. See the new Canvas.registerFont method: https://github.com/Automattic/node-canvas/#registerfont.
So I ended up getting node canvas to work with custom fonts.
First I used an older version of Cairo. I used Brew to install all of the dependencies, since it told me which ones I had and which ones were linked correctly, and then once all the dependencies were working correctly, I uninstalled the Cairo version from Brew and installed version 1.12.X (patch version 18 I think it was) of Cairo. This solved a Mac OSX Issue with the font size, but I couldn't load in fonts.
So after some investigation I found there was also an issue with the latest Node Canvas module, so I hard set the version to 1.1.0 in my package.json and FINALLY I got custom fonts to load and size correctly.
So TL;DR: Use Cairo version 1.12.X and Node Canvas 1.1.0 and it should work I think? It took me a while to get it working.

Resources