I have tried different configuration, but I cannot seem to succeed to execute "gs" (Ghostscript) in a node.js environment.
var fs = require( "fs" ),
child_process = require( 'child_process' );
...
var spawn = child_process.spawn;
var opts = [
"-q ",
"-dQUIET ",
"-dSAFER ",
"-dBATCH ",
"-dNOPAUSE ",
"-dNOPROMPT ",
"-dMaxBitmap=500000000 ",
"-dAlignToPixels=0 ",
"-dGridFitTT=2 ",
"-sDEVICE=jpeg ",
"-dTextAlphaBits=4 ",
"-dGraphicsAlphaBits=4 ",
"-r150 ",
"-sOutputFile=afile.jpg",
" afile.pdf"
];
var gs = spawn( "gs", opts, { cwd: "/mnt/drive/" } );
gs.stdout.on( 'data', function( data ) {
console.log( 'stdout: ' + data );
} );
gs.stderr.on( 'data', function( data ) {
console.log( 'stderr: ' + data );
} );
gs.on( 'close', function( code ) {
console.log( 'child process exited with code ' + code );
} );
---Output ---------------------------------------------------------
stdout: Unknown device: jpeg
stdout: Unrecoverable error: undefined
stdout: in .uninstallpagedevice
stdout: Operand stack:
defaultdevice
stdout:
child process exited with code 1
-------------------------------------------------------------------
The /mnt/drive directory is +read+write for all users. The gs -help execution returns:
root#Machine:/# gs -help
GPL Ghostscript 9.05 (2012-02-08)
Copyright (C) 2010 Artifex Software, Inc. All rights reserved.
Usage: gs [switches] [file1.ps file2.ps ...]
Most frequently used switches: (you can use # in place of =)
-dNOPAUSE no pause after page | -q `quiet', fewer messages
-g<width>x<height> page size in pixels | -r<res> pixels/inch resolution
-sDEVICE=<devname> select device | -dBATCH exit after last file
-sOutputFile=<file> select output file: - for stdout, |command for pipe,
embed %d or %ld for page #
Input formats: PostScript PostScriptLevel1 PostScriptLevel2 PostScriptLevel3 PDF
Default output device: bbox
Available devices:
...
ijs imagen inferno inkcov iwhi iwlo iwlq jetp3852 jj100 jpeg jpegcmyk
jpeggray la50 la70 la75 la75plus laserjet lbp310 lbp320 lbp8 lex2050
...
txtwrite uniprint xcf xes
Search path:
/usr/share/ghostscript/9.05/Resource/Init :
/usr/share/ghostscript/9.05/lib :
/usr/share/ghostscript/9.05/Resource/Font :
/usr/share/ghostscript/fonts : /var/lib/ghostscript/fonts :
/usr/share/cups/fonts : /usr/share/ghostscript/fonts :
/usr/local/lib/ghostscript/fonts : /usr/share/fonts
For more information, see /usr/share/doc/ghostscript/Use.htm.
Please report bugs to bugs.ghostscript.com.
root#Machine:/#
Where the device jpeg is available. The gs execution is not perform. Any hint would be help ?
The only way I got it to work, is by upgrading node from 10.26 to the latest 10.32, AND encapsulate the gs execution in a simple bash script file. Otherwise, even with the 10.32 node version, I still get the same error. I suspected an environment problem like suggest #Rudie,
You could consider to use Ghostscript4JS, it's a module that binds the Ghostscript C command API to bring its power to the Node.JS world.
https://www.npmjs.com/package/ghostscript4js
Ghostscript4JS is a native Node.JS addon so you can call the C command Ghostscript API directly from your JavaScript code. In this way you have two benefits:
Better error handling:
You directly intercept the error through the try/catch for the sync method and then/catch promise for the async method.
Performance
The call to the shell command takes more time and more resources than the call to the C or C++ API directly from Node.js environment.
As programmer you have more control against call external tool.
You just need to remove the spaces in the list of options
Related
I am working on creating an AEM Workflow. One of the steps in this workflow is a Process that calls an EMCAScript file which renames the Asset if it has spaces:
var workflowData = workItem.getWorkflowData();
var pType = workflowData.getPayloadType();
if (workflowData.getPayloadType() == "JCR_PATH") {
var path = workflowData.getPayload().toString();
var parentPath = path.replace('/jcr:content/renditions/original', '');
if (workflowSession.getSession().itemExists(parentPath)) {
var replaceChars = new RegExp(" ", "g");
var node = workflowSession.getSession().getItem(parentPath);
var name = node.getPath();
var newName = name.replace(replaceChars, "_");
log.warn('Name : ' + name + ". New Name: " + newName);
if(name != newName) {
log.warn(newName);
workflowSession.getSession().move(name, newName);
node.save();
}
} else {
log.warn("Item does not exist: " + path);
}
}
The logic works as expected - the file is renamed. Other steps in the workflow seem to complete correctly as well; i.e. the thumbnail seems to be properly extracted.
However, the asset itself is "stuck" in the processing state. When I look at the failure details for the job, I see the following:
com.adobe.granite.workflow.WorkflowException: Process execution resulted in an error
at com.adobe.granite.workflow.core.job.HandlerBase.executeProcess(HandlerBase.java:201)
at com.adobe.granite.workflow.core.job.JobHandler.process(JobHandler.java:260)
at org.apache.sling.event.impl.jobs.JobConsumerManager$JobConsumerWrapper.process(JobConsumerManager.java:502)
at org.apache.sling.event.impl.jobs.queues.JobQueueImpl.startJob(JobQueueImpl.java:293)
at org.apache.sling.event.impl.jobs.queues.JobQueueImpl.access$100(JobQueueImpl.java:60)
at org.apache.sling.event.impl.jobs.queues.JobQueueImpl$1.run(JobQueueImpl.java:229)
at java.base/java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1128)
at java.base/java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:628)
at java.base/java.lang.Thread.run(Thread.java:834)
Caused by: com.adobe.granite.workflow.WorkflowException: Failed to execute process
at com.day.cq.workflow.compatibility.CQWorkflowProcessRunner.execute(CQWorkflowProcessRunner.java:108)
at com.adobe.granite.workflow.core.job.HandlerBase.executeProcess(HandlerBase.java:191)
... 8 more
Caused by: com.day.cq.workflow.WorkflowException: execute: cannot process video, asset [{/content/dam/this file name has spaces.jpg/jcr:content/renditions/original}] in payload doesn't exist for workflow [{VolatileWorkItem_node2_var_workflow_instances_server0_2023-02-17_update_asset_58}].
at com.day.cq.dam.video.AbstractFFMpegProcess.execute(AbstractFFMpegProcess.java:75)
at com.day.cq.workflow.compatibility.CQWorkflowProcessRunner.execute(CQWorkflowProcessRunner.java:93)
... 9 more
I understand the error: the Workflow cannot find the original file since it has been moved/renamed. However, what I don't understand is why I am receiving that error from the "FFmpeg thumbnails" step when it is before the step (Process near the bottom) that does the renaming.
Is it possible to update the payload (Jcr Path) so that all steps in the Workflow see the updated name? I am using Adobe AEM 6.5.10.
I am trying to run a .bat file by passing arguments to it in nodejs. However, I get an empty command prompt. How to get the command pasted on the path.
code -
server.js
var bat = require.resolve('E:/API_Gateway_through_Swagger/New_Project/aws-bat-file-3.bat');
var num = "123"
var state_desc = "abc";
var ls = spawn(bat, [num, state_desc ]);
ls.stdout.on('data', function (data) {
console.log('stdout: ' + data);
});
ls.stderr.on('data', function (data) {
console.log('stderr: ' + data);
});
ls.on('exit', function (code) {
console.log('child process exited with code ' + code);
});
Bat file -
aws-bat-file-3.bat
echo off
echo "Batch Started"
set arg1=%1
set arg2=%2
START "Task Options" cmd.exe /b " cd C:\Users\myfolder & aws apigateway create deployment --rest-api-id %arg1% --stage-name dev --stage-description %arg2%"
output img file is -
NodeJS documented the problem of spawning batch files on Windows thoroughly in this section.
Excerpt:
When running on Windows, .bat and .cmd files can be invoked using child_process.spawn() with the shell option set, with child_process.exec(), or by spawning cmd.exe and passing the .bat or .cmd file as an argument (which is what the shell option and child_process.exec() do).
const bat = spawn('"my script.cmd"', ['a', 'b'], { shell: true });
I need to get the content from this page containing some scripts:
https://grouper.swissdrg.org/swissdrg/single?version=7.3&pc=1337_70_0_0_M_11_00_15_0_2018/08/07_2018/08/22_C18.4_C07_-_45.81.11$$&provider=acute&locale=de.
For other pages containing js its working fine but not for the one I need.
phantomjs.exe is in the root directoy and successfully invoked by a system call (win7 64 bit):
system("phantomjs WebScrapeV1.js")
The java script file WebScrapeV1.js is as follows:
var url ='https://grouper.swissdrg.org/swissdrg/single?version=7.3&pc=1337_70_0_0_M_11_00_15_0_2018/08/07_2018/08/22_C18.4_C07_-_45.81.11$$&provider=acute&locale=de';
var page = new WebPage()
var fs = require('fs');
page.open(url, function (status) {
just_wait();
});
function just_wait() {
setTimeout(function() {
fs.write('WebScrapeV1.html', page.content, 'w');
phantom.exit();
}, 2500);
}
This is the error I get:
Error: [mobx.array] Index out of bounds, function (t) {return{key:t.version,text:t["name_"+e.root.navigation.lang],value:t.version}} is larger than 30
https://grouper.swissdrg.org/packs/App-3dd15966701d9f6fd4db.js:1 in br
Unhandled promise rejection TypeError: undefined is not a constructor (evaluating 'n.push(this.pdx)')
A longer timeout may be what you need. I had to use 3600 to get all the contents (that site was super super slow for me). Here's a way you can modify the timeout in the event of errors without having to hand-modify a phantomjs script.
First, we'll make a function to wrap up all the complexity:
#' Read contents from a URL with phantomjs
#'
#' #param url the URL to scrape
#' #param timeout how long to wait, default is `2500` (ms)
#' #param .verbose, if `TRUE` (the default), display the generated
#' scraping script and any `stdout` output from phantomjs
read_phantom <- function(url, timeout=2500, .verbose = TRUE) {
suppressPackageStartupMessages({
require("glue", character.only = TRUE, quiet=TRUE)
require("crayon", character.only = TRUE, quiet=TRUE)
})
phantom_template <- "
var url = {url};
var page = new WebPage()
var fs = require('fs');
page.open(url, function (status) {{
just_wait();
});
function just_wait() {{
setTimeout(function() {{
fs.write({output_file}, page.content, 'w');
phantom.exit();
}, {timeout});
}
"
url <- shQuote(url)
phantom_bin <- Sys.which("phantomjs")
tf_in <- tempfile(fileext = ".js")
on.exit(unlink(tf_in), add=TRUE)
tf_out <- tempfile(fileext = ".html")
on.exit(unlink(tf_out), add=TRUE)
output_file <- shQuote(tf_out)
phantom_script <- glue(phantom_template)
if (.verbose) {
cat(
crayon::white("Using the following generated scraping script:\n"),
crayon::green(phantom_script), "\n", sep=""
)
}
writeLines(phantom_script, tf_in)
system2(
command = phantom_bin,
args = tf_in,
stdout = if (.verbose) "" else NULL
)
paste0(readLines(tf_out, warn = FALSE), collapse="\n")
}
Now, we'll use your URL with a longer timeout:
read_phantom(
url = "https://grouper.swissdrg.org/swissdrg/single?version=7.3&pc=1337_70_0_0_M_11_00_15_0_2018/08/07_2018/08/22_C18.4_C07_-_45.81.11$$&provider=acute&locale=de",
timeout = 3600
) -> doc
substr(doc, 1, 100)
## [1] "<html><head>\n<script src=\"https://js-agent.newrelic.com/nr-1071.min.js\"></script><script type=\" text"
nchar(doc)
## [1] 26858
Note that phantomjs is considered a legacy tool as the main developers have moved on since headless Chrome came on the scene. Unfortunately, there's no way to set a timeout for headless Chrome in the simple cmd line interface to it so you're kinda stuck with phantomjs for now.
I'd suggest trying splashr but you're on Windows and splashr requires Docker; alternatively, decapitated has an orchestration counterpart gepetto but that requires nodejs; either of those combos seem to be a painful for may folks to get working on that legacy operating system.
I've got a Node.js CLI I've been building using the Commander Library. Here's the code from the main execution file.
#!/usr/bin/env node
var program = require('commander');
var scmStash = require('./lib/hdqc/scmStash');
var command = {};
program
.version('0.0.1')
.option('-P, --Projects', 'List Projects')
.option('-R, --Repositories', 'List All Repositories on Server.')
.parse(process.argv);
function listProjects() {
scmStash.getProjectListing(function (data) {
for (var i = 0; i < data.size; i++) {
var project = data.values[i];
console.log(' ' + i + ' ' + project.name + ' # ' + project.link.url);
}
})
}
if (program.Projects) {
console.log(' - Projects');
listProjects();
}
I've been building this in WebStorm, and when I call the command using the node.js running everything works perfectly. for example, if I run the WebStorm runner executing the ./strack -P command to output the project, the output looks like this...
node strack -P
- Projects
0 Business Insights # /projects/BI
1 Platform # /projects/HDP
2 H # /projects/H
3 QC Application Code # /projects/QCCODE
4 QC Design # /projects/QCDESIGN
5 QC Reports # /projects/QCREP
6 Sandbox # /projects/SAN
7 Systemic Automation Tools # /projects/SAT
8 The Swamp # /projects/SWAMP
However when I run the same 'strack' command from the standard bash (inside WebStorm or outside of WebStorm in iTerm or such) then the following output is displayed.
23:11 $ node strack -P
- Projects
As I wrote up this question, I - like so often happens when typing up a stackoverflow question - realized the dillemma. The other call that prints out the projects themselves, is an asynchronous call, the actual app shoots off that call and then executes the remaining lines of code and finishes. Before the projects are even returned and can be printed to the console. I'm not sure what WebStorm is doing to keep the console attached to the running process but I'd love to have that work for my CLI. Any ideas, thoughts, or suggestions on how I should redesign this application to actually print out the projects to the command line?
All of the code is available on the github repo here.
I think the issue is with your array boundaries in your while loop. data.size is probably something you're remembering from one of the 8 other languages you know, lol. BUT it's not in js, you're looking for data.length. Try this, it's trimmed down and has a mock for the scmStash object but I think you'll see what I mean:
var command, listProjects, program, scmStash;
program = require('commander');
scmStash = {
getRepositories: function(cb) {
return cb([
{
name: 'a',
cloneUrl: 'b'
}, {
name: 'c',
cloneUrl: 'd'
}
]);
},
getProjectListing: function(cb) {
return cb([
{
name: "proj1",
link: {
url: "http://blah"
}
}, {
name: "proj2",
link: {
url: "http://bluh"
}
}
]);
}
};
command = {};
listProjects = function() {
return scmStash.getProjectListing(function(projects) {
var i, j, len, project, results;
results = [];
for (i = j = 0, len = projects.length; j < len; i = ++j) {
project = projects[i];
results.push(console.log(' ' + i + ' ' + project.name + ' # ' + project.link.url));
}
return results;
});
};
Output:
$ node .temp/adron.js -P
- Projects
0 proj1 # http://blah
1 proj2 # http://bluh
Also, there's an optimization to be had by storing the length of the array in a variable before iterating it but it's very minor. Worry about that when you have a million elements in an array.
There is an ES7 recommendation for async/await syntax.
In the meanwhile, there are plenty of flow control packages available. You might consider the 'async' NPM package.
My goal is to be able to execute a command on a remote machine and get the full stdout response from the command that was run. What I am getting is a truncated result. When I run the same command through command prompt, I get the full output from the command run. Here is my code:
var process = spawn('PsExec.exe', ['\\\\servername', 'ipconfig']);
var doOnce = true;
process.stdout.on('data', function (data) {
log.info('stdout: ' + data.toString());
if(doOnce){
doOnce = false;
process.stdin.write('ipconfig');}
});
process.stderr.on('data', function (data) {
log.info('stderr: ' + data.toString());
});
process.on('exit', function (code) {
log.info('child process exited with code ' + code);
});
When executed I get the following console output. As you can tell, all of ipconfig has been truncated. If I do another command such as netstat, I get most of the results before truncating occurs, so I don't believe this has anything to do with the buffer. I really am just out of ideas at this point.
info: stderr:
PsExec v2.11 - Execute processes remotely
Copyright (C) 2001-2014 Mark Russinovich
Sysinternals - www.sysinternals.com
info: stdout:
Windows IP Configuration
ipconfig exited on servername with error code 0.
info: child process exited with code 0
Try using the { stdio: 'inherit' } option
var spawn = require('child_process').spawn,
appname = spawn('psexec.exe', ['-accepteula', '\\\\remotepcname', '-u', 'domain\\username', '-p', 'supersecretpassword', 'ipconfig'], { stdio: 'inherit' });