Silent printing in electron - node.js

I am currently building an electron app. I have a PDF on my local file system which I need to silently print out (on the default printer). I came across the node-printer library, but it doesn't seem to work for me. Is there an easy solution to achieve this?

Well first of all it is near impossible to understand what you mean with "silent" print. Because once you send a print order to your system printer it will be out of your hand to be silent at all. On Windows for example once the order was given, at least the systemtray icon will indicate that something is going on. That said, there are very good described features for printing with electron even "silent" is one of them:
You need to get all system printers if you do not want to use the default printer:
contents.getPrinters()
Which will return a PrinterInfo[] Object.
Here is an example how the object will look like from the electron PrtinerInfo Docs:
{
name: 'Zebra_LP2844',
description: 'Zebra LP2844',
status: 3,
isDefault: false,
options: {
copies: '1',
'device-uri': 'usb://Zebra/LP2844?location=14200000',
finishings: '3',
'job-cancel-after': '10800',
'job-hold-until': 'no-hold',
'job-priority': '50',
'job-sheets': 'none,none',
'marker-change-time': '0',
'number-up': '1',
'printer-commands': 'none',
'printer-info': 'Zebra LP2844',
'printer-is-accepting-jobs': 'true',
'printer-is-shared': 'true',
'printer-location': '',
'printer-make-and-model': 'Zebra EPL2 Label Printer',
'printer-state': '3',
'printer-state-change-time': '1484872644',
'printer-state-reasons': 'offline-report',
'printer-type': '36932',
'printer-uri-supported': 'ipp://localhost/printers/Zebra_LP2844',
system_driverinfo: 'Z'
}
}
To print your file you can do it with
contents.print([options])
The options are descriped in the docs for contents.print():
options Object (optional):
silent Boolean (optional) - Don’t ask user for print settings. Default is false.
printBackground Boolean (optional) - Also prints the background color and image of the web page. Default is false.
deviceName String (optional) - Set the printer device name to use. Default is ''.
Prints window’s web page. When silent is set to true, Electron will pick the system’s default printer if deviceName is empty and the default settings for printing.
Calling window.print() in web page is equivalent to calling webContents.print({silent: false, printBackground: false, deviceName: ''}).
Use page-break-before: always; CSS style to force to print to a new page.
So all you need is to load the PDF into a hidden window and then fire the print method implemented in electron with the flag set to silent.
// In the main process.
const {app, BrowserWindow} = require('electron');
let win = null;
app.on('ready', () => {
// Create window
win = new BrowserWindow({width: 800, height: 600, show: false });
// Could be redundant, try if you need this.
win.once('ready-to-show', () => win.hide())
// load PDF.
win.loadURL(`file://directory/to/pdf/document.pdf`);
// if pdf is loaded start printing.
win.webContents.on('did-finish-load', () => {
win.webContents.print({silent: true});
// close window after print order.
win = null;
});
});
However let me give you a little warning:
Once you start printing it can and will get frustrating because there are drivers out there which will interpret data in a slightly different way. Meaning that margins could be ignored and much more. Since you already have a PDF this problem will most likely not happen. But keep this in mind if you ever want to use this method for example contents.printToPDF(options, callback). That beeing said there are plently of options to avoid getting frustrated like using a predefined stylesheet like descriped in this question: Print: How to stick footer on every page to the bottom?
If you want to search for features in electron and you do not know where they could be hidden, all you have to do is to go to "all" docs and use your search function: https://electron.atom.io/docs/all/
regards,
Megajin

I recently published NPM package to print PDF files from Node.js and Electron. You can send a PDF file to the default printer or to a specific one. Works fine on Windows and Unix-like operating systems: https://github.com/artiebits/pdf-to-printer.
It's easy to install, just (if using yarn):
yarn add pdf-to-printer
or (if using npm):
npm install --save pdf-to-printer
Then, to silently print the file to the default printer you do:
import { print } from "pdf-to-printer";
print("assets/pdf-sample.pdf")
.then(console.log)
.catch(console.error);

To my knowledge there is currently no way to do this directly using Electron because while using contents.print([]) does allow for 'silently' printing HTML files, it isn't able to print PDF views. This is currently an open feature request: https://github.com/electron/electron/issues/9029
Edit: I managed to work around this by converting the PDF to a PNG and then using Electron's print functionality (which is able to print PNGs) to print the image based view. One of the major downsides to this is that all of the PDF to PNG/JPEG conversion libraries for NodeJS have a number of dependencies, meaning I had to implement them in an Express server and then have my Electron app send all PDFs to the server for conversion. It's not a great option, but it does work.

Related

Chrome screen sharing get monitor info

I implemented chrome extension which using chrome.desktopCapture.chooseDesktopMedia to retrieve screen id.
This is my background script:
chrome.runtime.onConnect.addListener(function (port) {
port.onMessage.addListener(messageHandler);
// listen to "content-script.js"
function messageHandler(message) {
if(message == 'get-screen-id') {
chrome.desktopCapture.chooseDesktopMedia(['screen', 'window'], port.sender.tab, onUserAction);
}
}
function onUserAction(sourceId) {
//Access denied
if(!sourceId || !sourceId.length) {
return port.postMessage('permission-denie');
}
port.postMessage({
sourceId: sourceId
});
}
});
I need to get shared monitor info(resolution, landscape or portrait).
My question is: If customer using more than one monitor, how can i determine which monitor he picked?
Can i add for example "system.display" permissions to my extension and get picked monitor info from "chrome.system.display.getInfo"?
You are right. You could add system.display permission and call chrome.system.display.getDisplayLayout(callbackFuncion(DisplayLayout)) and handle the DisplayLayout.position in the callback to get the layout and the chrome.system.display.getInfo to handle the array of displayInfo in the callback. You should look for 'isPrimary' value
This is a year old question, but I came across it since I was after the same information and I finally managed to figure how you can identify which monitor the user selected for screen-sharing in Chrome.
First of all: this information will not come from the extension that you probably built for screen-sharing in Chrome, because:
The chrome.desktopCapture.chooseDesktopMedia API callback only returns a sourceId, which is a string that represents a stream id, that you can then use to call the getMediaSource API to build the media stream.
The chrome.system.display.getInfo will give you a list of the displays, yes, but from that info you can't tell which one is being shared, and there is no way to match the sourceId with any of the fields returned for each display.
So... the solution I've found comes from the MediaStream object itself. Once you have the stream, after calling getMediaSource, you need to get the video track, and in there you will find a property called "label". This label gives you an idea of which screen the user picked.
You can get the video track with something like:
const videoTrack = mediaStream.getVideoTracks()[0];
(Check the getVideoTracks API here: https://developer.mozilla.org/en-US/docs/Web/API/MediaStream/getVideoTracks).
If you print that object, you will see the "label" field. In Chrome screen 1 shows as "0:0", whereas screen 2 shows as "1:0", and I assume screen i would be "i-1:0" (I've only tested with 2 screens).
Here is a capture of that object printed in the console:
And not only works for Chrome, but for other browsers that implement it! In Firefox they show up as "Screen i":
Also, if you check Chrome chrome://webrtc-internals you'll see this is what they show in the addStream event:
And that's it! It's not ideal, since this is a label, more than a real screen identifier, but well, it's something to work with. Once you have the screen identified, in Chrome you can work with the chrome.system.display.getInfo to get information for that display.

Remove terminal icon in node notifier

I am using the https://github.com/mikaelbr/node-notifier package to show notifications in shell.
This is my code:
var notifier = require('node-notifier');
var path = require('path');
notifier.notify({
title: 'My awesome title',
message: 'Hello from node, Mr. User!',
icon: path.join(__dirname, 'coulson.jpg'), // absolute path (not balloons)
sound: true, // Only Notification Center or Windows Toasters
wait: true // wait with callback until user action is taken on notification
}, function (err, response) {
// response is response from notification
});
notifier.on('click', function (notifierObject, options) {
// Happens if `wait: true` and user clicks notification
});
notifier.on('timeout', function (notifierObject, options) {
// Happens if `wait: true` and notification closes
});
The notification comes like this:
As you can see a terminal icon is coming before the name.
Can you help me how to remove that icon?
It is known issue with node-notifier.
From issue #71:
mikaelbr:
No, I'm afraid that's how the notification work, as it's the terminal that initiates the message. The only way to avoid this is to use your custom terminal-notifier where the Terminal icon is swapped for your own. It's not a big task, and you can easily set customPath for notification center reporter.
kurisubrooks:
This happens because of the way notifications in OS X work. The notification will show the referring app icon, and because we're using terminal-notifier to push notifications, we have the icon of terminal-notifier.
To work around this, you'll need to compile terminal-notifier with your own app.icns. Download the source, change out the AppIcon bundle with your own in Xcode, recompile terminal-notifier and pop it into node-notifier. (/node-notifier/vendor/terminal-notifier.app)
Now that you have your own terminal-notifier inside node-notifier, remove all the icon references from your OS X Notification Center code, and run the notification as if it has no icon. If the old app icon is showing in your notifications, you need to clear your icon cache. (Google how to do this)
Another valuable comment from mikaelb:
That's correct. But keep in mind, node-notifier uses a fork of terminal-notifier (github.com/mikaelbr/terminal-notifier) to add option to wait for notification to finish, so this should be used to add your own icon. A easy way to do it is to copy/paste from the vendor-folder and use customPath to point to your own vendor.
I tried #Aleksandr M's steps but it didn't seem to work for me. Maybe I didn't understand the steps well enough. Here's how it worked for me.
I cloned https://github.com/mikaelbr/terminal-notifier . Then opened the project with xcode and deleted the Terminal.icns file and replaced it with my custom icon Myicon.icns.
Then edited terminal-notifier/Terminal Notifier/Terminal Notifier-Info.plist by setting the key icon file to Myicon.
After doing this, simply building the project did NOT work. I had to change the values of the build version and build identifier (any new value would do) see this.
Afterwards I just built the project with xcode and then copied the built .app file (you can find it by clicking the Products directory of the project from xcode Products > right click the file > show in finder) to my electron project
e.g your final path may look like this. electron-project/vendor/terminal-notifier.app.
Then I set customPath as #Aleksandr M suggested.
Here's what mine looked like
var notifier = new NotificationCenter({
customPath: 'vendor/terminal-notifier.app/Contents/MacOS/terminal-notifier'
});
And THEN it worked! 🙂
This solved my problem and you only need to have your icns file ready:
run this command in terminal after downloading :customise-terminal-notifier
** path/customise-terminal-notifier-master/customise-terminal-notifier -i path/Terminal.icns -b com.bundle.identifier

How to get the file path and file name of image captured from firefox camera in Firefox OS (ZTE device)

I am using Web activity to launch default Firefox camera from my web app in Firefox OS. Able to launch default Firefox camera and took picture. Got this.result as return value inside pick success.
Now I need to get file path, where image get saved and also image file name.
Tried to parse the this.result.blob, but couldn't find the path or file related parameter .
Below is the code I'm using
var activity = new MozActivity({
// Ask for the "pick" activity
name: "pick",
// Provide the data required by the filters of the activity
data: {
type: "image/jpeg"
}
});
activity.onsuccess = function() {
var picture = this.result;
console.log("A picture has been retrieved");
};
The image file name is not returned, as you can see from the code. If you would need the file name (I can't really think of a very good use case to be honest) you can iterate over the pictures storage in the DeviceStorageAPI and get the last saved file. It's probably the one from the camera (compare blobs to be totally sure).
In your success handler, you will get the file name if you use:
this.result.blob.name
And, you can get the path to the file as:
window.URL.createObjectURL(this.result.blob);
Source

How to modify dashlets to auto-refresh?

Is there a simple way to modify a dashlet to automatically re-load itself periodically?
I am particularly thinking of the "My Tasks" dashlet - we are using pooled review workflows, so tasks may come and go all the time as they are created and then are claimed.
It may be frustrating for users to keep clicking on tasks that turn out to have already been claimed - or having to remember to keep re-loading their Dashboard page. I'd prefer the dashlet to refresh on a timed interval so it's always reasonably up to date.
In order to do this you will need to add a new capability to the client-side class Alfresco.dashlet.MyTasks (docs, source) found in the file components/dashlets/my-tasks.get.js. First you will need to add a new method to the prototype extension specified as the second parameter in the YAHOO.lang.augmentObject() call, e.g.
...
}, // end of last OOTB function - add a comment here
// begin changes
reloadData: function MyTasks_onReady()
{
this.widgets.alfrescoDataTable.loadDataTable(
this.options.filters[this.widgets.filterMenuButton.value]
);
}
// end changes
});
})();
It's not the ideal development environment, you can modify the JS file directly in the Share webapp, although you will also need to update the corresponding -min.js file.
Once you've done this, check that it works by running the following line in your browser's JavaScript console
Alfresco.util.ComponentManager.findFirst("Alfresco.dashlet.MyTasks").reloadData();
If that works, then you can wire up your new method to a title bar action (see my DevCon presentation for more background info), in the dashlet web script. The method depends on whether you are using v4.2 or a previous version, but if it is the latter then you need to add some code to the dashlet's Freemarker file my-tasks.get.html.ftl (under WEB-INF/classes/alfresco/site-webscripts/org/alfresco/components/dashlets).
In that file you should see some JavaScript code inside a <script> tag, this sets up an instance of the client-side class and some utility classes, the contents of which you can replace with the following, to add your custom title bar action.
(function()
{
var dashlet = new Alfresco.dashlet.MyTasks("${jsid}").setOptions(
{
hiddenTaskTypes: [<#list hiddenTaskTypes as type>"${type}"<#if type_has_next>, </#if></#list>],
maxItems: ${maxItems!"50"},
filters:
{<#list filters as filter>
"${filter.type?js_string}": "${filter.parameters?js_string}"<#if filter_has_next>,</#if>
</#list>}
}).setMessages(${messages});
new Alfresco.widget.DashletResizer("${id}", "${instance.object.id}");
var refreshDashletEvent = new YAHOO.util.CustomEvent("onDashletRefresh");
refreshDashletEvent.subscribe(dashlet.reloadData, dashlet, true);
new Alfresco.widget.DashletTitleBarActions("${args.htmlid}").setOptions(
{
actions:
[
{
cssClass: "refresh",
eventOnClick: refreshDashletEvent,
tooltip: "${msg("dashlet.refresh.tooltip")?js_string}"
},
{
cssClass: "help",
bubbleOnClick:
{
message: "${msg("dashlet.help")?js_string}"
},
tooltip: "${msg("dashlet.help.tooltip")?js_string}"
}
]
});
})();
You will need to add some styles for the class name specified, in the dashlet's CSS file my-tasks.css, such as the following
.my-tasks .titleBarActions .refresh
{
display: none;
background-image: url('refresh-icon.png');
}
The icon file (here is one you could re-use) must be in the same directory as the CSS file.
Lastly you'll need to define the label dashlet.refresh.tooltop used for the title bar action's tooltip. You can do this in the dashlet web script's .properties file.
For a similar example, check out the source of my Train Times dashlet, which features a refresh title bar action.
In some ways it's actually easier to define your own dashlets than it is to extend the Alfresco-supplied ones, but if you have the option of using 4.2.x, the new method allows you to extend the existing components without duplicating any code, which obviously makes upgrades much easier.

Flash trace output in firefox, linux

I'm developing an applications which I've got running on a server on my linux desktop. Due to the shortcomings of Flash on Linux (read: too hard) I'm developing the (small) flash portion of the app in Windows, which means there's a lot of frustrating back and forth. Now I'm trying to capture the output of the flash portion using flash tracer and that is proving very difficult also. Is there any other way I could monitor the output of trace on linux? Thanks...
Hope this helps too (for the sake of google search i came from):
In order to do trace, you need the debugger version of Flash Player from
http://www.adobe.com/support/flashplayer/downloads.html (look for "debugger" version specifically - they are hard to spot on first look)
Then an mm.cfg file in your home containing
ErrorReportingEnable=1 TraceOutputFileEnable=1 MaxWarnings=50
And then you are good to go - restart the browser. When traces start to fill in, you will find the log file in
~/.macromedia/Flash_Player/Logs/flashlog.txt
Something like
tail ~/.macromedia/Flash_Player/Logs/flashlog.txt -f
Should suffice to follow the trace.
A different and mind-bogglingly simple workaround that I've used for years is to simply create an output module directly within the swf. All this means is a keyboard shortcut that attaches a MovieClip with a textfield. All my traces go to this textfield instead of (or in addition to) the output window. Over the years I've refined it of course, making the window draggable, resizable, etc. But I've never needed any other approach for simple logging, and it's 100% reliable and reusable across all platforms.
[EDIT - response to comment]
There's no alert quite like javascript's alert() function. But using an internal textfield is just this simple:
ACTIONSCRIPT 1 VERSION
(See notes at bottom)
/* import ExternalInterface package */
import flash.external.*;
/* Create a movieclip for the alert. Set an arbitrary (but very high) number for the depth
* since we want the alert in front of everything else.
*/
var alert = this.createEmptyMovieClip("alert", 32000);
/* Create the alert textfield */
var output_txt = alert.createTextField("output_txt", 1, 0, 0, 300, 200);
output_txt.background = true;
output_txt.backgroundColor = 0xEFEFEF;
output_txt.selectable = false;
/* Set up drag behaviour */
alert.onPress = function()
{
this.startDrag();
}
alert.onMouseUp = function()
{
stopDrag();
}
/* I was using a button to text EI. You don't need to. */
testEI_btn.onPress = function()
{
output_txt.text = (ExternalInterface.available);
}
Notes: This works fine for AS1, and will translate well into AS2 (best to use strong data-typing if doing so, but not strictly required). It should work in Flash Players 8-10. ExternalInterface was added in Flash 8, so it won't work in previous player versions.
ACTIONSCRIPT 3 VERSION
var output_txt:TextField = new TextField();
addChild(output_txt);
output_txt.text = (String(ExternalInterface.available));
If you want to beef it out a bit:
var alert:Sprite = new Sprite();
var output_txt:TextField = new TextField();
output_txt.background = true;
output_txt.backgroundColor = 0xEFEFEF;
output_txt.selectable = false;
output_txt.width = 300;
output_txt.height = 300;
alert.addChild(output_txt);
addChild(alert);
alert.addEventListener(MouseEvent.MOUSE_DOWN, drag);
alert.addEventListener(MouseEvent.MOUSE_UP, stopdrag);
output_txt.text = (String(ExternalInterface.available));
function drag(e:MouseEvent):void
{
var alert:Sprite = e.currentTarget as Sprite;
alert.startDrag();
}
function stopdrag(e:MouseEvent):void
{
var alert:Sprite = e.currentTarget as Sprite;
alert.stopDrag();
}
[/EDIT]
If you only need the trace output at runtime, you can use Firebug in Firefox and then use Flash.external.ExternalInterface to call the console.log() Javascript method provided by Firebug.
I've used that strategy multiple times to a large degree of success.
Thunderbolt is a great logging framework with built-in firebug support.
I use the flex compiler on linux to build actionscript files, [embed(source="file")] for all my assets including images and fonts, I find actionscript development on linux very developer friendly.
Then again, I'm most interested in that flash has become Unix Friendly as aposed to the other way around :)
To implement FlashTracer, head to the following address and be sure you have the latest file. http://www.sephiroth.it/firefox/flashtracer/ . Install it and restart the browser.
Head over to adobe and get the latest flash debugger. Download and install the firefox version as FlashTracer is a firefox addition.
Now that firefox has the latest flash debugger and flash tracer we need to locate mm.cfg
Location on PC: C:\Documents and Settings\username
Inside of mm.cfg should be:
ErrorReportingEnable=1
TraceOutputFileEnable=1
MaxWarnings=100 //Change to your own liking.
Once that is saved, open firefox, head to the flash tracer window by heading to tools > flash tracer. In the panel that pops up there is two icons in the bottom right corner, click the wrench and make sure the path is set to where your log file is being saved. Also check to see that flash tracer is turned on, there is a play/pause button at the bottom.
I currently use this implementation and hope that it works for you. Flash Tracer is a little old, but works with the newest versions of FireFox. I am using it with FireFox 3.0.10.

Resources