JavaFX WebView HyperLinks Cannot Be Disabled on Mobile Devices - ios

The below code is used to disable hyperlinks in a JavaFX WebView object. However, when I run it on a mobile device it does not work, whilst it is working OK on desktop. Any alternative solution to affect mobile devices?
private void init() {
webEngine = webView.getEngine();
webEngine.getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> {
if(newState == State.SUCCEEDED && webEngine.getDocument() != null)
disableHyperLinks(webEngine.getDocument());
});
} // init()
private void disableHyperLinks(Document document) {
NodeList nodeList = document.getElementsByTagName("a");
for (int i = 0; i < nodeList.getLength(); i++)
{
Node node= nodeList.item(i);
EventTarget eventTarget = (EventTarget) node;
eventTarget.addEventListener("click", (evt) -> {
evt.preventDefault();
}, false);
} // for
} // disableHyperLinks()

When you run on mobile, the WebView is not implemented with the JavaFX control, but instead the native one is used, both on Android and iOS.
You can see here the implementation for Android, and here the one for iOS.
On iOS there is no Document native method implemented, and it only returns the html content of the loaded page (providing that the content can be parsed, otherwise it will be null). So even if you are able to read and modify that content, it wouldn't have any effect over the real control.
The good news is that you can use executeScript, as it is implemented for iOS.
Something like this should work:
private void init() {
webEngine = webView.getEngine();
webEngine.getLoadWorker().stateProperty().addListener((ov, oldState, newState) -> {
if(newState == State.SUCCEEDED)
disableHyperLinks();
});
} // init()
private void disableHyperLinks() {
Object res = webView.getEngine().executeScript("(function() { " +
"var links = document.getElementsByTagName(\"a\");\n" +
" for (var i=0; i<links.length; i++) {\n" +
" links[i].addEventListener(\"click\",function(e) {\n" +
" e.preventDefault();\n" +
" })\n" +
" }"
+ "return ('<html>'+ links.length +'</html>'); })();");
if (res != null) {
System.out.println("Hyperlinks disabled: " + res);
} else {
System.out.println("ERROR disabling hyperlinks");
}
} // disableHyperLinks()
The above code won't work on Android, though. There is a (very hacky) possible way to do it, accessing the native control on runtime (but since the question is about iOS I won't explain here).

Related

how to display a WebView only after a javascript code is done?

I'm trying to force WebView to 'skip' images by using javascript. (like here: https://stackoverflow.com/a/31848599/13174607).
The problem is that the images are disappeared only after the WebView finished loaded. I want to display the WebView only after the javascript is finished.
This is my code:
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(webView, url);
webView.loadUrl("javascript:(function(){ var imgs=document.getElementsByTagName('img');" + "for(i=0;i<imgs.length;i++) { imgs[i].style.display='none'; } })()");
}
});
}
I tried to use setVisibility() method, like this:
webView.setWebViewClient(new WebViewClient() {
#Override
public void onPageStarted(WebView view, String url, Bitmap favicon) {
webView.setVisibility(View.INVISIBLE);
}
#Override
public void onPageFinished(WebView view, String url) {
super.onPageFinished(webView, url);
webView.loadUrl("javascript:(function(){ var imgs=document.getElementsByTagName('img');" + "for(i=0;i<imgs.length;i++) { imgs[i].style.display='none'; } })()");
webView.setVisibility(View.VISIBLE);
}
});
}
but it didn't help.
Thanks!
EDIT:
By using the proposed solution and the #mustansir comments I wrote this code on 'onPageFinished':
webView.loadUrl("javascript:" + "function taskOne() {" +
"var imgFlag = 0;" + //will sign when the for loop ended
"var imgs = document.getElementsByTagName('img');" +
"if (imgs==0){imgFlag=1;} " +
"for (i = 0; i < imgs.length; i++) {" +
"imgs[i].style.display = 'none';" +
"if (i==imgs.length-1)" +
"{" +
"imgFlag=1;" +
"}"+
"}}" +
"taskOne();" +
"function taskTwo () {" +
"if(imgFlag==1){" +
"window.visibility.changeVisibility(); }" +
"else {" +
"setTimeout(taskTwo(),100);}}" +
"taskTwo();");
but the the webview doesn't become visible. Any idea why?
You can try injecting a JavaScript interface and call that interface method when you reach at the last image in the loop to change WebView visibility.
Something like this:
webview.addJavascriptInterface(this, "visibility");
and call this interface from your JavaScript like this:
var imgs = document.getElementsByTagName('img');
for (i = 0; i < imgs.length; i++) {
imgs[i].style.display = 'none';
if (i == imgs.length-1) {
visibility.changeVisibility();
}
}
Now define changeVisibility() with #JavascriptInterface annotation in that activity in which you have added javascriptInterface like this:
#JavascriptInterface
public void changeVisibility() {
runOnUiThread(() -> webview.setVisibility(View.VISIBLE));
}

Printing using ngx-extended-pdf-viewer on iOS and Mobile Safari or Chrome

I have an Angular 7 app that is using ngx-extended-pdf-viewer to render a PDF that I get as a byte array from the web.api. I have no issues rendering the PDF or even printing it from any desktop application. ngx-extended-pdf-viewer as a print button built right in. However, when trying to print from Safari on an iPhone (iOS 12) it only prints a blank page with the url at the bottom. The actual PDF does not print. With Chrome on iOS it doesn't do anything that I can see. I am pretty new to Angular and actually to mobile web development, so perhaps lack of knowledge is getting me. The PDF viewer is in a mat-tab, so not sure if maybe that is causing some issues??
I have tried other packages, but they all seem to be based on the same pdf.js code from Mozilla. Also this is the only one I've found so far that has a print. I was thinking about perhaps trying pdf.js outside of an npm package, but so far have not found solid directions on getting this to work in Angular. I'm sure it will, but all directions I have found seem to omit details. Such as, put this code in your app. They just fail to say where in the app.
From the web.api:
[HttpPost("GetPdfBytes/{PdfId}")]
public ActionResult<byte[]> GetPdfBytesId([FromBody]int id)
{
string exactPath = string.Empty;
if (id == 1)
{
exactPath = Path.GetFullPath("pdf-test.pdf");
}
else if (id == 2)
{
exactPath = Path.GetFullPath("DPP.pdf");
}
else if (id == 3)
{
exactPath = Path.GetFullPath("Request.pdf");
}
else
{
exactPath = Path.GetFullPath("Emergency Issue.pdf");
}
byte[] bytes = System.IO.File.ReadAllBytes(exactPath);
return Ok(bytes);
}
The HTML:
<mat-tab label="PDF">
<ng-template matTabContent>
<ngx-extended-pdf-viewer *ngIf="visible[2]" id="pdf3" [src]="pdfSrc3" useBrowserLocale="true" delayFirstView="1000" showSidebarButton="false"
showOpenFileButton="false" >
</ngx-extended-pdf-viewer>
</ng-template>
</mat-tab>
TypeScript:
getPDFBytesId(id: string) {
this.getPDFFromServicePdfBytesId(Number(id)).subscribe(
(data: any) => {
this.pdfSrc3 = this.convertDataURIToBinary(data);
},
error => {
console.log(error);
}
);
}
// hits the web.api
getPDFFromServicePdfBytesId(id: number): Observable<any> {
const body = id;
return this.http.post<any>('http://localhost:5000/api/values/GetPdfBytes/' + id, body);
}
// converts what we got back to a Uint8Array which is used by the viewer
convertDataURIToBinary(dataURI: string) {
const raw = window.atob(dataURI);
const rawLength = raw.length;
const array = new Uint8Array(new ArrayBuffer(rawLength));
for (let i = 0; i < rawLength; i++) {
array[i] = raw.charCodeAt(i);
}
return array;
}

How to add Content Security Policy to Firefox extension

I have a plugin which I have to support both on Chrome and Firefox browsers. The plugin does cross script loading.
In Chrome, by adding the content security policy in my manifest.json file, I could get away with it. How can I do it Firefox extension?
I couldn't find a simple solution for my problem and upon looking up some firefox plugin extensions i had to come up with my own solution as below. The below solution was tested on FF 24.0 but should work on other versions as well.
Cc["#mozilla.org/observer-service;1"].getService(Ci.nsIObserverService)
.addObserver(_httpExamineCallback, "http-on-examine-response", false);
function _httpExamineCallback(aSubject, aTopic, aData) {
var httpChannel = aSubject.QueryInterface(Ci.nsIHttpChannel);
if (httpChannel.responseStatus !== 200) {
return;
}
var cspRules;
var mycsp;
// thre is no clean way to check the presence of csp header. an exception
// will be thrown if it is not there.
// https://developer.mozilla.org/en-US/docs/XPCOM_Interface_Reference/nsIHttpChannel
try {
cspRules = httpChannel.getResponseHeader("Content-Security-Policy");
mycsp = _getCspAppendingMyHostDirective(cspRules);
httpChannel.setResponseHeader('Content-Security-Policy', mycsp, false);
} catch (e) {
try {
// Fallback mechanism support
cspRules = httpChannel.getResponseHeader("X-Content-Security-Policy");
mycsp = _getCspAppendingMyHostDirective(cspRules);
httpChannel.setResponseHeader('X-Content-Security-Policy', mycsp, false);
} catch (e) {
// no csp headers defined
return;
}
}
};
/**
* #var cspRules : content security policy
* For my requirement i have to append rule just to 'script-src' directive. But you can
* modify this function to your need.
*
*/
function _getCspAppendingMyHostDirective(cspRules) {
var rules = cspRules.split(';'),
scriptSrcDefined = false,
defaultSrcIndex = -1;
for (var ii = 0; ii < rules.length; ii++) {
if ( rules[ii].toLowerCase().indexOf('script-src') != -1 ) {
rules[ii] = rules[ii] + ' <My CSP Rule gets appended here>';
scriptSrcDefined = true;
}
if (rules[ii].toLowerCase().indexOf('default-src') != -1) {
defaultSrcIndex = ii;
}
}
// few publishers will put every thing in the default (default-src) directive,
// without defining script-src. We need to modify those as well.
if ((!scriptSrcDefined) && (defaultSrcIndex != -1)) {
rules[defaultSrcIndex] = rules[defaultSrcIndex] + ' <My CSP rule gets appended here>';
}
return rules.join(';');
};
There are plans in the future to add content policy natively in the SDK (bug 852297), but there is a 3rd party module that should get you close to where you want to be: policy.js

Can't open sqlite database with phonegap but it works fine on objectiveC

I have a SQLITE database on my iOS project, which I can access from my native IOS code. I can access it and read data from it.
You can see the way i'm doing it and my project structure in the following pic:
And i try to do the same using Phonegap:
var db;
var shortName = 'myTestDb.db';
var version = '1.0';
var displayName = 'myTestDb';
var maxSize = 65535;
// list the values in the database to the screen using jquery to
//update the #lbUsers element
function ListDBValues() {
if (!window.openDatabase) {
alert('Databases are not supported in this browser.');
return;
}
$('#myDbElements').html('');
db.transaction(function(transaction) {
transaction.executeSql("SELECT FIRST_NAME FROM dbo_RE_USER;", [],
function(transaction, result) {
console.log("result");
if (result != null && result.rows != null) {
console.log("result is not null");
for (var i = 0; i < result.rows.length; i++) {
var row = result.rows.item(i);
//console.log(row);
debugObject(row);
$('#myDbElements').append('<br>' + row["FIRST_NAME"]);// + " " + row.LAST_NAME );
}
}
PrecApp.I_SCROLL.refresh();
},errorHandler);
},errorHandler,nullHandler);
return;
}
function debugObject(obj) {
console.log("ROW:");
for (n in obj)
// alert(n + ":" + obj[n]);
console.log(n + ":" + obj[n]);
}
But it can't find my dbo_re_users table. Why?
The database opened in JavaScript is an entirely different database - it has the same name, but is not in the app bundle, which is read only.
If you need to access a specific database file, you will need to use a plugin.

Print barcodes from web page to Zebra printer

We're trying to print barcodes from a web page to our Zebra printer.
I'm wondering if there's a way to print them using the printer's own font perhaps using web fonts or if I knew the font name used?
I have been trying to use php barcode generators, that basically generates images containing the barcode. I have in fact been trying this approach for a few days already, without success.
The problem is when I print them it's not readable by the scanners. I have tried to change the image resolution to match that of the printer (203dpi), also tried playing with the image size and formats, but the barcodes after printed still can't be scanned.
So does anybody have experience with this?
Printer: Zebra TLP 2844
Barcodes required per page:
01 Code39 horizontal (scanable only if printed at very specific size and browser)
01 Code128 vertical (still can't get it to work, print is always very blurry and won't get scanned)
===========
I've made a little bit of progress, I found out this printer supports EPL2 language, so I'm trying to use it to print out the barcodes.
First I needed to enable pass through mode, I did that on Printer Options > Advanced Setup > Miscellaneous.
Now I'm able to print barcodes impeccably using the printer's built-in font :D using this command:
ZPL:
B10,10,0,1,2,2,60,N,"TEXT-GOES-HERE"
:ZPL
But I can only print it from Notepad, I'm still unable to print this from a browser... It's probably a problem with LF being replaced with CR+LF...
How to overcome this problem??
===========
The label I'm trying to print actually has a bit of text before the barcode, with some html tables formatting it nicely. So I need to print this first, and in the middle I need to stick in a nice label and then add some more text.
So I can't use pure EPL2 to print the whole thing, I'm wondering if I can use some of both html + EPL2 + html to achieve my goal or is that not allowed?? =/
You are running into a few obstacles:
1) When you print through the OS installed printer driver, the printer driver is trying to take the data that is sent to it and (re)rasterize or scale it for the output device (the Zebra printer). Since the printer is a relatively low resolution at 203dpi, then it does not take too much for the scaling the print driver is having to do for it to loose some integrity in the quality of the barcode. This is why barcodes generated using the direct ZPL commands are much more reliable.
2) Due to the security that web browsers purposefully provide by not allowing access to the client computer, you cannot directly communicate with the client connected printer. This sandboxing is what helps to protect users from malware so that nefarious websites cannot do things like write files to the client machine or send output directly to devices such as printers. So you are not able to directly send the ZPL commands through the browser to the client connected printer.
However, there is a way to do what you describe. The steps necessary are typically only going to be useful if you have some degree of control over the client computer accessing the site that is trying to print to the Zebra printers. For example this is only going to be used by machines on your company network, or by clients who are willing to install a small application that you need to write. To do this, you will need to look at the following steps:
A) You need to make up your own custom MIME type. This is basically just any name you want to use that is not going to collide with any registered MIME types.
B) Next you will define a filename extension that will map to your custom MIME type. To do this, you typically will need to configure your web server (steps for this depend on what web server you are using) to allow the new MIME type you want to define and what file extension is used for these types of files.
C) Then on your web application, when you want to output the ZPL data, you write it to a file using a filename extension that is mapped to your new MIME type. Then once the file is generated, you can either provide an HTML link to it, or redirect the client browser to the file. You can test if your file is working correctly at this point by manually copying the file you created directly to the raw printer port.
D) Next you need to write a small application which can be installed on the client. When the application is installed, you need to have it register itself as a valid consuming application for your custom MIME type. If a browser detects that there is an installed application for a file of the specified MIME type, it simply writes the file to a temporary directory on the client machine and then attempts to launch the application of the same registered MIME type with the temporary file as a parameter to the application. Thus your application now just reads the file that the browser passed to it and then it attempts to dump it directly to the printer.
This is an overview of what you need to do in order to accomplish what you are describing. Some of the specific steps will depend on what type of web server you are using and what OS your clients machines are. But this is the high level overview that will let you accomplish what you are attempting.
If you'd consider loading a java applet, qz-print (previously jzebra) can do exactly what you are describing and works nicely with the LP2844 mentioned in the comments.
https://code.google.com/p/jzebra/
What we did for our web app :
1) Download the free printfile app http://www.lerup.com/printfile/
"PrintFile is a freeware MS Windows utility program that will enable you to print files fast and easily. The program recognizes plain text, PostScript, Encapsulated PostScript (EPS) and binary formats. Using this program can save you a lot of paper and thereby also saving valuable natural resources."
When you first run PrintFile, go into the advanced options and enable "send to printer directly".
2) Setup the ZEBRA printer in windows as a Generic Text Printer.
2) Generate a file.prt file in the web app which is just a plain text EPL file.
3) Double clicking on the downloaded file will instantly print the barcode. Works like a charm. You can even setup PrintFile so that you don't even see a gui.
I am using QZ Tray to print labels from a web page to Zebra thermal printer.
In the demo/js folder of QZ Tray there are three JavaScript files that are required to communicate with QZ Tray application - dependencies/rsvp-3.1.0.min.js, dependencies/sha-256.min.js and qz-tray.js.
Include these JavaScript files in your project as follows:
<script type="text/javascript" src="/lib/qz-tray/rsvp-3.1.0.min.js"></script>
<script type="text/javascript" src="/lib/qz-tray/sha-256.min.js"></script>
<script type="text/javascript" src="/lib/qz-tray/qz-tray.js"></script>
The most simple way to print a label to Zebra thermal printer is shown below.
<script type="text/javascript">
qz.websocket.connect().then(function() {
// Pass the printer name into the next Promise
return qz.printers.find("zebra");
}).then(function(printer) {
// Create a default config for the found printer
var config = qz.configs.create(printer);
// Raw ZPL
var data = ['^XA^FO50,50^ADN,36,20^FDRAW ZPL EXAMPLE^FS^XZ'];
return qz.print(config, data);
}).catch(function(e) { console.error(e); });
</script>
See How to print labels from a web page to Zebra thermal printer for more information.
You can also send the ZPL commands in a text file (you can pack multiple labels in a single file) and have the user open and print the file via windows notepad. The only caveat is that they have to remove the default header and footer (File --> Page Setup).
Its a bit of user training, but may be acceptable if you don't have control over the client machines.
I'm developing something similar here.
I need to print in a LP2844 from my webapp. The problem is that my webapp is in a remote server in the cloud (Amazon EC2) and the printer is going to be in a warehouse desk.
My solution:
The webapp generates the EPL2 code for the label with the barcodes, then publish a PubNub message.
I wrote a little C# program that runs in the computer where the printer is connected. The program receives the message and then send the code to the printer.
I followed the idea proposed by "Tres Finocchiaro" on my application based on:
ASP.NET 4.0
IIS
Chrome, IExplorer, Firefox
Zebra TLP 2844
EPL protocolo
Unfortunatly the jzebra needs some improvements to work corectly due to the issues of security of current browser.
Installing jzebra
Downlod jzebdra and from dist directory I copy into your directory (eg. mydir):
web
mydir
js
..
deployJava.js
lib
..
qz-print.jar
qz-print_jnlp.jnlp
Create your print.html
<html>
<script type="text/javascript" src="js/deployJava.js"></script>
<script type="text/javascript">
/**
* Optionally used to deploy multiple versions of the applet for mixed
* environments. Oracle uses document.write(), which puts the applet at the
* top of the page, bumping all HTML content down.
*/
deployQZ();
/** NEW FUNCTION **/
function initPrinter() {
findPrinters();
useDefaultPrinter();
}
/** NEW FUNCTION **/
function myalert(txt) {
alert(txt);
}
/**
* Deploys different versions of the applet depending on Java version.
* Useful for removing warning dialogs for Java 6. This function is optional
* however, if used, should replace the <applet> method. Needed to address
* MANIFEST.MF TrustedLibrary=true discrepency between JRE6 and JRE7.
*/
function deployQZ() {
var attributes = {id: "qz", code:'qz.PrintApplet.class',
archive:'qz-print.jar', width:1, height:1};
var parameters = {jnlp_href: 'qz-print_jnlp.jnlp',
cache_option:'plugin', disable_logging:'false',
initial_focus:'false'};
if (deployJava.versionCheck("1.7+") == true) {}
else if (deployJava.versionCheck("1.6+") == true) {
delete parameters['jnlp_href'];
}
deployJava.runApplet(attributes, parameters, '1.5');
}
/**
* Automatically gets called when applet has loaded.
*/
function qzReady() {
// Setup our global qz object
window["qz"] = document.getElementById('qz');
var title = document.getElementById("title");
if (qz) {
try {
title.innerHTML = title.innerHTML + " " + qz.getVersion();
document.getElementById("content").style.background = "#F0F0F0";
} catch(err) { // LiveConnect error, display a detailed meesage
document.getElementById("content").style.background = "#F5A9A9";
alert("ERROR: \nThe applet did not load correctly. Communication to the " +
"applet has failed, likely caused by Java Security Settings. \n\n" +
"CAUSE: \nJava 7 update 25 and higher block LiveConnect calls " +
"once Oracle has marked that version as outdated, which " +
"is likely the cause. \n\nSOLUTION: \n 1. Update Java to the latest " +
"Java version \n (or)\n 2. Lower the security " +
"settings from the Java Control Panel.");
}
}
}
/**
* Returns whether or not the applet is not ready to print.
* Displays an alert if not ready.
*/
function notReady() {
// If applet is not loaded, display an error
if (!isLoaded()) {
return true;
}
// If a printer hasn't been selected, display a message.
else if (!qz.getPrinter()) {
/** CALL TO NEW FUNCTION **/
initPrinter();
return false;
}
return false;
}
/**
* Returns is the applet is not loaded properly
*/
function isLoaded() {
if (!qz) {
alert('Error:\n\n\tPrint plugin is NOT loaded!');
return false;
} else {
try {
if (!qz.isActive()) {
alert('Error:\n\n\tPrint plugin is loaded but NOT active!');
return false;
}
} catch (err) {
alert('Error:\n\n\tPrint plugin is NOT loaded properly!');
return false;
}
}
return true;
}
/**
* Automatically gets called when "qz.print()" is finished.
*/
function qzDonePrinting() {
// Alert error, if any
if (qz.getException()) {
alert('Error printing:\n\n\t' + qz.getException().getLocalizedMessage());
qz.clearException();
return;
}
// Alert success message
alert('Successfully sent print data to "' + qz.getPrinter() + '" queue.');
}
/***************************************************************************
* Prototype function for finding the "default printer" on the system
* Usage:
* qz.findPrinter();
* window['qzDoneFinding'] = function() { alert(qz.getPrinter()); };
***************************************************************************/
function useDefaultPrinter() {
if (isLoaded()) {
// Searches for default printer
qz.findPrinter();
// Automatically gets called when "qz.findPrinter()" is finished.
window['qzDoneFinding'] = function() {
// Alert the printer name to user
var printer = qz.getPrinter();
myalert(printer !== null ? 'Default printer found: "' + printer + '"':
'Default printer ' + 'not found');
// Remove reference to this function
window['qzDoneFinding'] = null;
};
}
}
/***************************************************************************
* Prototype function for finding the closest match to a printer name.
* Usage:
* qz.findPrinter('zebra');
* window['qzDoneFinding'] = function() { alert(qz.getPrinter()); };
***************************************************************************/
function findPrinter(name) {
// Get printer name from input box
var p = document.getElementById('printer');
if (name) {
p.value = name;
}
if (isLoaded()) {
// Searches for locally installed printer with specified name
qz.findPrinter(p.value);
// Automatically gets called when "qz.findPrinter()" is finished.
window['qzDoneFinding'] = function() {
var p = document.getElementById('printer');
var printer = qz.getPrinter();
// Alert the printer name to user
alert(printer !== null ? 'Printer found: "' + printer +
'" after searching for "' + p.value + '"' : 'Printer "' +
p.value + '" not found.');
// Remove reference to this function
window['qzDoneFinding'] = null;
};
}
}
/***************************************************************************
* Prototype function for listing all printers attached to the system
* Usage:
* qz.findPrinter('\\{dummy_text\\}');
* window['qzDoneFinding'] = function() { alert(qz.getPrinters()); };
***************************************************************************/
function findPrinters() {
if (isLoaded()) {
// Searches for a locally installed printer with a bogus name
qz.findPrinter('\\{bogus_printer\\}');
// Automatically gets called when "qz.findPrinter()" is finished.
window['qzDoneFinding'] = function() {
// Get the CSV listing of attached printers
var printers = qz.getPrinters().split(',');
for (i in printers) {
myalert(printers[i] ? printers[i] : 'Unknown');
}
// Remove reference to this function
window['qzDoneFinding'] = null;
};
}
}
/***************************************************************************
* Prototype function for printing raw EPL commands
* Usage:
* qz.append('\nN\nA50,50,0,5,1,1,N,"Hello World!"\n');
* qz.print();
***************************************************************************/
function print() {
if (notReady()) { return; }
// Send characters/raw commands to qz using "append"
// This example is for EPL. Please adapt to your printer language
// Hint: Carriage Return = \r, New Line = \n, Escape Double Quotes= \"
qz.append('\nN\n');
qz.append('q609\n');
qz.append('Q203,26\n');
qz.append('B5,26,0,1A,3,7,152,B,"1234"\n');
qz.append('A310,26,0,3,1,1,N,"SKU 00000 MFG 0000"\n');
qz.append('A310,56,0,3,1,1,N,"QZ PRINT APPLET"\n');
qz.append('A310,86,0,3,1,1,N,"TEST PRINT SUCCESSFUL"\n');
qz.append('A310,116,0,3,1,1,N,"FROM SAMPLE.HTML"\n');
qz.append('A310,146,0,3,1,1,N,"QZINDUSTRIES.COM"');
// Append the rest of our commands
qz.append('\nP1,1\n');
// Tell the applet to print.
qz.print();
}
/***************************************************************************
* Prototype function for logging a PostScript printer's capabilites to the
* java console to expose potentially new applet features/enhancements.
* Warning, this has been known to trigger some PC firewalls
* when it scans ports for certain printer capabilities.
* Usage: (identical to appendImage(), but uses html2canvas for png rendering)
* qz.setLogPostScriptFeatures(true);
* qz.appendHTML("<h1>Hello world!</h1>");
* qz.printPS();
***************************************************************************/
function logFeatures() {
if (isLoaded()) {
var logging = qz.getLogPostScriptFeatures();
qz.setLogPostScriptFeatures(!logging);
alert('Logging of PostScript printer capabilities to console set to "' + !logging + '"');
}
}
/***************************************************************************
****************************************************************************
* * HELPER FUNCTIONS **
****************************************************************************
***************************************************************************/
function getPath() {
var path = window.location.href;
return path.substring(0, path.lastIndexOf("/")) + "/";
}
/**
* Fixes some html formatting for printing. Only use on text, not on tags!
* Very important!
* 1. HTML ignores white spaces, this fixes that
* 2. The right quotation mark breaks PostScript print formatting
* 3. The hyphen/dash autoflows and breaks formatting
*/
function fixHTML(html) {
return html.replace(/ /g, " ").replace(/’/g, "'").replace(/-/g,"‑");
}
/**
* Equivelant of VisualBasic CHR() function
*/
function chr(i) {
return String.fromCharCode(i);
}
/***************************************************************************
* Prototype function for allowing the applet to run multiple instances.
* IE and Firefox may benefit from this setting if using heavy AJAX to
* rewrite the page. Use with care;
* Usage:
* qz.allowMultipleInstances(true);
***************************************************************************/
function allowMultiple() {
if (isLoaded()) {
var multiple = qz.getAllowMultipleInstances();
qz.allowMultipleInstances(!multiple);
alert('Allowing of multiple applet instances set to "' + !multiple + '"');
}
}
</script>
<input type="button" onClick="print()" />
</body>
</html>
the code provided is based on "jzebra_installation/dist/sample.html".
try creating a websocket that controls the print on the client side and send data with ajax from the page to localhost.
/// websocket
using System;
using System.Net;
using System.Net.WebSockets;
using System.Text;
using System.Threading;
namespace Server
{
class Program
{
public static WebsocketServer ws;
static void Main(string[] args)
{
ws = new Server.WebsocketServer();
ws.LogMessage += Ws_LogMessage;
ws.Start("http://localhost:2645/service/");
Console.WriteLine("Press any key to exit...");
Console.ReadKey();
}
private static void Ws_LogMessage(object sender, WebsocketServer.LogMessageEventArgs e)
{
Console.WriteLine(e.Message);
}
}
public class WebsocketServer
{
public event OnLogMessage LogMessage;
public delegate void OnLogMessage(Object sender, LogMessageEventArgs e);
public class LogMessageEventArgs : EventArgs
{
public string Message { get; set; }
public LogMessageEventArgs(string Message)
{
this.Message = Message;
}
}
public bool started = false;
public async void Start(string httpListenerPrefix)
{
HttpListener httpListener = new HttpListener();
httpListener.Prefixes.Add(httpListenerPrefix);
httpListener.Start();
LogMessage(this, new LogMessageEventArgs("Listening..."));
started = true;
while (started)
{
HttpListenerContext httpListenerContext = await httpListener.GetContextAsync();
if (httpListenerContext.Request.IsWebSocketRequest)
{
ProcessRequest(httpListenerContext);
}
else
{
httpListenerContext.Response.StatusCode = 400;
httpListenerContext.Response.Close();
LogMessage(this, new LogMessageEventArgs("Closed..."));
}
}
}
public void Stop()
{
started = false;
}
private async void ProcessRequest(HttpListenerContext httpListenerContext)
{
WebSocketContext webSocketContext = null;
try
{
webSocketContext = await httpListenerContext.AcceptWebSocketAsync(subProtocol: null);
LogMessage(this, new LogMessageEventArgs("Connected"));
}
catch (Exception e)
{
httpListenerContext.Response.StatusCode = 500;
httpListenerContext.Response.Close();
LogMessage(this, new LogMessageEventArgs(String.Format("Exception: {0}", e)));
return;
}
WebSocket webSocket = webSocketContext.WebSocket;
try
{
while (webSocket.State == WebSocketState.Open)
{
ArraySegment<Byte> buffer = new ArraySegment<byte>(new Byte[8192]);
WebSocketReceiveResult result = null;
using (var ms = new System.IO.MemoryStream())
{
do
{
result = await webSocket.ReceiveAsync(buffer, CancellationToken.None);
ms.Write(buffer.Array, buffer.Offset, result.Count);
}
while (!result.EndOfMessage);
ms.Seek(0, System.IO.SeekOrigin.Begin);
if (result.MessageType == WebSocketMessageType.Text)
{
using (var reader = new System.IO.StreamReader(ms, Encoding.UTF8))
{
var r = System.Text.Encoding.UTF8.GetString(ms.ToArray());
var t = Newtonsoft.Json.JsonConvert.DeserializeObject<Datos>(r);
bool valid = true;
byte[] toBytes = Encoding.UTF8.GetBytes(""); ;
if (t != null)
{
if (t.printer.Trim() == string.Empty)
{
var printers = "";
foreach (var imp in System.Drawing.Printing.PrinterSettings.InstalledPrinters)
{
printers += imp + "\n";
}
toBytes = Encoding.UTF8.GetBytes("No se Indicó la Impresora\nLas Impresoras disponibles son: " + printers);
valid = false;
}
if (t.name.Trim() == string.Empty)
{
toBytes = Encoding.UTF8.GetBytes("No se Indicó el nombre del Documento");
valid = false;
}
if (t.code == null)
{
toBytes = Encoding.UTF8.GetBytes("No hay datos para enviar a la Impresora");
valid = false;
}
if (valid)
{
print.RawPrinter.SendStringToPrinter(t.printer, t.code, t.name);
toBytes = Encoding.UTF8.GetBytes("Correcto...");
}
await webSocket.SendAsync(new ArraySegment<byte>(toBytes, 0, int.Parse(toBytes.Length.ToString())), WebSocketMessageType.Binary, result.EndOfMessage, CancellationToken.None);
}
else
{
toBytes = Encoding.UTF8.GetBytes("Error...");
await webSocket.SendAsync(new ArraySegment<byte>(toBytes, 0, int.Parse(toBytes.Length.ToString())), WebSocketMessageType.Binary, result.EndOfMessage, CancellationToken.None);
}
}
}
}
}
}
catch (Exception e)
{
LogMessage(this, new LogMessageEventArgs(String.Format("Exception: {0} \nLinea:{1}", e, e.StackTrace)));
}
finally
{
if (webSocket != null)
webSocket.Dispose();
}
}
}
public class Datos
{
public string name { get; set; }
public string code { get; set; }
public string printer { get; set; } = "";
}
}
raw Print:
using Microsoft.VisualBasic;
using System;
using System.Collections;
using System.Collections.Generic;
using System.Data;
using System.Diagnostics;
using System.Runtime.InteropServices;
using System.IO;
namespace print
{
public class RawPrinter
{
// Structure and API declarions:
[StructLayout(LayoutKind.Sequential, CharSet = CharSet.Ansi)]
public class DOCINFOA
{
[MarshalAs(UnmanagedType.LPStr)]
public string pDocName;
[MarshalAs(UnmanagedType.LPStr)]
public string pOutputFile;
[MarshalAs(UnmanagedType.LPStr)]
public string pDataType;
}
[DllImport("winspool.Drv", EntryPoint = "OpenPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool OpenPrinter([MarshalAs(UnmanagedType.LPStr)]
string szPrinter, ref IntPtr hPriknter, IntPtr pd);
[DllImport("winspool.Drv", EntryPoint = "ClosePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool ClosePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartDocPrinterA", SetLastError = true, CharSet = CharSet.Ansi, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartDocPrinter(IntPtr hPrinter, Int32 level, [In(), MarshalAs(UnmanagedType.LPStruct)]
DOCINFOA di);
[DllImport("winspool.Drv", EntryPoint = "EndDocPrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndDocPrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "StartPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool StartPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "EndPagePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool EndPagePrinter(IntPtr hPrinter);
[DllImport("winspool.Drv", EntryPoint = "WritePrinter", SetLastError = true, ExactSpelling = true, CallingConvention = CallingConvention.StdCall)]
public static extern bool WritePrinter(IntPtr hPrinter, IntPtr pBytes, Int32 dwCount, ref Int32 dwWritten);
// SendBytesToPrinter()
// When the function is given a printer name and an unmanaged array
// of bytes, the function sends those bytes to the print queue.
// Returns true on success, false on failure.
public static bool SendBytesToPrinter(string szPrinterName, IntPtr pBytes, Int32 dwCount, string DocName = "")
{
Int32 dwError = 0;
Int32 dwWritten = 0;
IntPtr hPrinter = new IntPtr(0);
DOCINFOA di = new DOCINFOA();
bool bSuccess = false;
// Assume failure unless you specifically succeed.
di.pDocName = string.IsNullOrEmpty(DocName) ? "My C#.NET RAW Document" : DocName;
di.pDataType = "RAW";
// Open the printer.
if (OpenPrinter(szPrinterName.Normalize(), ref hPrinter, IntPtr.Zero))
{
// Start a document.
if (StartDocPrinter(hPrinter, 1, di))
{
// Start a page.
if (StartPagePrinter(hPrinter))
{
// Write your bytes.
bSuccess = WritePrinter(hPrinter, pBytes, dwCount, ref dwWritten);
EndPagePrinter(hPrinter);
}
EndDocPrinter(hPrinter);
}
ClosePrinter(hPrinter);
}
// If you did not succeed, GetLastError may give more information
// about why not.
if (bSuccess == false)
{
dwError = Marshal.GetLastWin32Error();
}
return bSuccess;
}
public static bool SendFileToPrinter(string szPrinterName, string szFileName)
{
// Open the file.
FileStream fs = new FileStream(szFileName, FileMode.Open);
// Create a BinaryReader on the file.
BinaryReader br = new BinaryReader(fs);
// Dim an array of bytes big enough to hold the file's contents.
Byte[] bytes = new Byte[fs.Length];
bool bSuccess = false;
// Your unmanaged pointer.
IntPtr pUnmanagedBytes = new IntPtr(0);
int nLength = 0;
nLength = Convert.ToInt32(fs.Length);
// Read the contents of the file into the array.
bytes = br.ReadBytes(nLength);
// Allocate some unmanaged memory for those bytes.
pUnmanagedBytes = Marshal.AllocCoTaskMem(nLength);
// Copy the managed byte array into the unmanaged array.
Marshal.Copy(bytes, 0, pUnmanagedBytes, nLength);
// Send the unmanaged bytes to the printer.
bSuccess = SendBytesToPrinter(szPrinterName, pUnmanagedBytes, nLength);
// Free the unmanaged memory that you allocated earlier.
Marshal.FreeCoTaskMem(pUnmanagedBytes);
return bSuccess;
}
public static bool SendStringToPrinter(string szPrinterName, string szString, string DocName = "")
{
IntPtr pBytes = default(IntPtr);
Int32 dwCount = default(Int32);
// How many characters are in the string?
dwCount = szString.Length;
// Assume that the printer is expecting ANSI text, and then convert
// the string to ANSI text.
pBytes = Marshal.StringToCoTaskMemAnsi(szString);
// Send the converted ANSI string to the printer.
SendBytesToPrinter(szPrinterName, pBytes, dwCount, DocName);
Marshal.FreeCoTaskMem(pBytes);
return true;
}
}
}
html page:
<!DOCTYPE html>
<html>
<head>
</head>
<body ng-app="myapp">
<div ng-controller="try as ctl">
<input ng-model="ctl.ticket.nombre">
<textarea ng-model="ctl.ticket.code"></textarea>
<button ng-click="ctl.send()">Enviar</button>
</div>
<script src="https://ajax.googleapis.com/ajax/libs/angularjs/1.5.6/angular.min.js"></script>
<script>
var ws = new WebSocket("ws://localhost:2645/service");
ws.binaryType = "arraybuffer";
ws.onopen = function () {
console.log('connection is opened!!!');
};
ws.onmessage = function (evt) {
console.log(arrayBufferToString(evt.data))
};
ws.onclose = function () {
console.log("Connection is Closed...")
};
function arrayBufferToString(buffer) {
var arr = new Uint8Array(buffer);
var str = String.fromCharCode.apply(String, arr);
return decodeURIComponent(escape(str));
}
var app = angular.module('myapp', []);
app.controller('try', function () {
this.ticket= {nombre:'', estado:''}
this.send = () => {
var toSend= JSON.stringify(this.ticket);
ws.send(toSend);
}
});
</script>
</body>
</html>
then send a ZPL code from html(write this on textarea code);
^XA
^FO200,50^BY2^B3N,N,80,Y,N^FD0123456789^FS
^PQ1^XZ

Resources