How to deliver a node.js + imagemagick tool? - node.js

I've developed a node.js tool which uses imagemagick from the command line. That is, exec('my_imagemagick_commands'). What's the best way to deliver that tool to a client using Windows? That is, how can I make a Windows installer that'll install node.js, imagemagick and the tool - preferably as a binary, not the source - in a specific folder?

If you want an easy bundle... Zip the list below, deploy on client and drag/drop images to be processed onto the yourtool.cmd file (I'm doing something similar for image optimizers)
Bundle: (put these in one directory)
yourtool.cmd
yourtool.js
node.exe
node_modules/ (if applicable)
yourtool.cmd
REM Get the drive/path the batch file is in
set batchdir=%~d0%~p0
REM Run tool for items dragged over...
"%batchdir%node.exe" "%batchdir%yourtool.js" %*
yourtool.js
// start at 2 for arguments passed...
// 0 is node.exe
// 1 is the js file run
for (var i=2; i<process.argv.length; i++) {
var imagePath = process.argv[i];
//do something with image...
}
For others interested in imagemagick with node, you should check out node-imagemagick

Related

Synchronous pymol

I am trying to load an mrc file, generate the map of it and then save the image, the problem is that it only saves a blank image, the code I run is the following:
from pymol import cmd
cmd.load('./6vof.mrc', ' 6vof')
cmd.volume( '6vof _volume', ' 6vof')
cmd.png('./test.png', 300, 200)
The equivalent code in the interface does work, I wanted to know how I can make the save method wait for the rendering of everything.
Hi Luis José Castillo,
it seems I encountered the same problem as you did.
I wanted to use Pymol from within a Ruby on Rails application and always got his message, when I launched it from within ruby:
CmdLoad: "mypol/4hhb.pdb" loaded as "4hhb".
Ray: render time: 0.02 sec. = 178776.9 frames/hour (0.02 sec. accum.).
The result was a blank transparent png. If I ran it in the command line with the same script I got this message and a perfect png:
CmdLoad: "4hhb.pdb" loaded as "4hhb".
Ray: render time: 4.04 sec. = 890.8 frames/hour (4.04 sec. accum.).
I got this behavoir on Ubuntu 20, Ubuntu 18 Server and in Docker.
I figured out, that the only difference was, I used relative paths from within ruby, but was always running everything in the same folder in the command line.
Well, so I just make this detour for my Rails application and now it does work:
def get_protein_image(pdb_id)
dir_path = get_pdb_file(pdb_id)
`cp lib/png_from_pdb.py #{dir_path} && cd #{dir_path} && pymol protein.pdb png_from_pdb.py -qc`
end
Sorry for the ruby code here, but here the essential solution, try to run everything inside the same folder (I simply delete the tmp subfolder after png generation).
cp lib/png_from_pdb.py #{dir_path} && cd #{dir_path} && pymol protein.pdb png_from_pdb.py -qc
I hope this trick will help you too!
Best regards,
Stephan

How files in a lambda layer will be copied to the /opt/bin directory?

I am working with a PDF to Image Conversion Project in AWS Lambda, but had some issues, since AWS lambda doesn't have the relevant binaries like ImageMagick in the environment, then I followed some links and StackOverflow question and put the relevant binaries as a layer, for the job I had to use Ghostscript compiled binaries.
The layer zip contain files like this
GhostScript.zip > bin > gs
I have a wrapper library call pdf2png and It will execute a child process which do the convertion, the command this child process use is the above mentioned gs utitity, but my issue is the path I mentioned for the utility is wrong, it throws an error saying,
Error: spawn /opt/bin/bin/gs ENOENT
So What I want to know is how will the lambda layer files be copied to the /opt/bin/ directory? how should I replace the path?
Corresponding code,
gs()
.batch()
.nopause()
.option('-r' + options.density)
// .option('-dDownScaleFactor=2')
.option('-dFirstPage=' + page)
.option('-dLastPage=' + page)
.executablePath('/opt/bin/bin/gs')
.device('png16m')
.output(output)
.input(filepath)
.exec(function (err, stdout, stderr) {
The executable path in my case have to be like this
.executablePath('/opt/bin/gs')
It has extracted the files in the bin folder inside the layer into the /opt/bin/ folder directly.

Using node-cmd module while handling Squirrel Events function

I'm building a desktop app for Windows using electron-packager and electron-squirrel-startup, I would like to execute some Windows cmd commands during the installation of my application. To do so I was planning to use node-cmd node module, but I doesn't really work inside the handleSquirrelEvents function. An example command like this:
function handleSquirrelEvent(application) {
const squirrelEvent = process.argv[1];
switch (squirrelEvent) {
case '--squirrel-install':
case '--squirrel-updated':
var cmd=require('node-cmd');
cmd.run('touch example.created.file');
}
};
Seems to work. A file example.created.file in my_app/node_module/node-cmd/example directory is created.
But any other code does not work. Even if I only change the name of the file to be "touched" nothing happens.
Ok, example.created.file already exists in this directory and I suspect that you can only use update.exe supported commands in case '--squirrel-updated' sections. So this will not work.

AWS Lambda function - convert PDF to Image

I am developing application where user can upload some drawings in pdf format. Uploaded files are stored on S3. After uploading, files has to be converted to images. For this purpose I have created lambda function which downloads file from S3 to /tmp folder in lambda execution environment and then I call ‘convert’ command from imagemagick.
convert sourceFile.pdf targetFile.png
Lambda runtime environment is nodejs 4.3. Memory is set to 128MB, timeout 30 sec.
Now the problem is that some files are converted successfully while others are failing with the following error:
{ [Error: Command failed: /bin/sh -c convert /tmp/sourceFile.pdf
/tmp/targetFile.png convert: %s' (%d) "gs" -q -dQUIET -dSAFER -dBATCH
-dNOPAUSE -dNOPROMPT -dMaxBitmap=500000000 -dAlignToPixels=0 -dGridFitTT=2 "-sDEVICE=pngalpha" -dTextAlphaBits=4 -dGraphicsAlphaBits=4 "-r72x72" "-sOutputFile=/tmp/magick-QRH6nVLV--0000001" "-f/tmp/magick-B610L5uo"
"-f/tmp/magick-tIe1MjeR" # error/utility.c/SystemCommand/1890.
convert: Postscript delegate failed/tmp/sourceFile.pdf': No such
file or directory # error/pdf.c/ReadPDFImage/678. convert: no images
defined `/tmp/targetFile.png' #
error/convert.c/ConvertImageCommand/3046. ] killed: false, code: 1,
signal: null, cmd: '/bin/sh -c convert /tmp/sourceFile.pdf
/tmp/targetFile.png' }
At first I did not understand why this happens, then I tried to convert problematic files on my local Ubuntu machine with the same command. This is the output from terminal:
**** Warning: considering '0000000000 XXXXX n' as a free entry.
**** This file had errors that were repaired or ignored.
**** The file was produced by:
**** >>>> Mac OS X 10.10.5 Quartz PDFContext <<<<
**** Please notify the author of the software that produced this
**** file that it does not conform to Adobe's published PDF
**** specification.
So the message was very clear, but the file gets converted to png anyway. If I try to do convert source.pdf target.pdf and after that convert target.pdf image.png, file is repaired and converted without any errors. This doesn’t work with lambda.
Since the same thing works on one environment but not on the other, my best guess is that the version of Ghostscript is the problem. Installed version on AMI is 8.70. On my local machine Ghostsript version is 9.18.
My questions are:
Is the version of ghostscript problem? Is this a bug with older
version of ghostscript? If not, how can I tell ghostscript (with or
without using imagemagick) to repair or ignore errors like it does on
my local environment?
If the old version is a problem, is it possible to build ghostscript
from source, create nodejs module and then use that version of
ghostscript instead the one that is installed?
Is there an easier way to convert pdf to image without using
imagemagick and ghostscript?
UPDATE
Relevant part of lambda code:
var exec = require('child_process').exec;
var AWS = require('aws-sdk');
var fs = require('fs');
...
var localSourceFile = '/tmp/sourceFile.pdf';
var localTargetFile = '/tmp/targetFile.png';
var writeStream = fs.createWriteStream(localSourceFile);
writeStream.write(body);
writeStream.end();
writeStream.on('error', function (err) {
console.log("Error writing data from s3 to tmp folder.");
context.fail(err);
});
writeStream.on('finish', function () {
var cmd = 'convert ' + localSourceFile + ' ' + localTargetFile;
exec(cmd, function (err, stdout, stderr ) {
if (err) {
console.log("Error executing convert command.");
context.fail(err);
}
if (stderr) {
console.log("Command executed successfully but returned error.");
context.fail(stderr);
}else{
//file converted successfully - do something...
}
});
});
You can find a compiled version of Ghostscript for Lambda in the following repository.
You should add the files to the zip file that you are uploading as the source code to AWS Lambda.
https://github.com/sina-masnadi/lambda-ghostscript
This is an npm package to call Ghostscript functions:
https://github.com/sina-masnadi/node-gs
After copying the compiled Ghostscript files to your project and adding the npm package, you can use the executablePath('path to ghostscript') function to point the package to the compiled Ghostscript files that you added earlier.
Its almost certainly a bug, or perhaps limitation, with the older version of Ghostscript.
Many PDF producers create PDF files which do not conform to the specification, and yet will open without complain in Adobe Acrobat. Ghostscript endeavours to do the same, but obviously we can't know what Acrobat is going to allow, so we are continually chasing this nebulous target. (FWIW that warning is a legitimate out-of-spec PDF file).
There's nothing you can do with the old version other than replace it.
Yes you can build Ghostscript from source, I have no idea about a nodejs module, not sure why that's relevant.
There are numerous other applications which will render a PDF file, MuPDF is another one I know of. And, of course, you can use Ghostscript directly without using ImageMagick. Of course, if you can load another application, then you should simply be able to replace your Ghostscript installation too.
The version of GS on aws is an old version with known bugs. We can get around this by uploading an x64 GS file, compiled specifically for Linux. Then upload that using new AWS lambda layers. I have written a node function that does just this here:
https://github.com/rcastoro/PDFImagine
Make sure you have that GS layer for your lambda, however!

TiddlyWiki on node-webkit not displaying content

I followed the tutorial (In the "Getting Started" section) on how to use TiddlyWiki with node-webkit. When I then run nw.exe it doesn't display anything.
Im on windows (64bit) and have installed the 32bit version for windows. Not sure what Im doing wrong or if its just a bug.
I have also tried adding index.html and package.json to an archive (called app.nw) and run it with nw.exe, but still no luck.
I followed the instructions and couldn't get it to work either. I used TiddlyWiki 5.0.13-beta, Windows 64 bit, node-webkit 0.9.2. It throws an exception that it can't find sjcl.js. sjcl.js is packaged into TiddlyWiki.
I suggest to use TiddlyDesktop instead. It's node-webkit ready-made for TiddlyWiki. It works like a charm for me under Windows. You can get it here:
https://github.com/Jermolene/TiddlyDesktop/releases
I suspect the plain node-webkit solution has lost attention, now that there is TiddlyDesktop.
The offending code is in bootprefix.js. When bootprefix runs it checks if it is using node and then assumes it is a Node JS file based system. One solution, on a per-TiddlyWiki basis is to modify the following code near the top of bootprefix.js, which is in a script tag in single file TiddlyWiki.
// Detect platforms
$tw.browser = typeof(window) !== "undefined" ? {} : null;
$tw.node = typeof(process) === "object" ? {} : null;
$tw.nodeWebKit = $tw.node && global.window && global.window.nwDispatcher ? {} : null;
if($tw.nodeWebKit) $tw.node = null; //this is the line to add.

Resources