Zebra Printer - Cut on last page - printing

I've a Zebra ZT610 and I want to print a label, in pdf format, containing multiple pages and then have it cut on the last page. I've tried using the delayed cut mode and sending the ~JK command but I'm using a self written java application to do the invocation of printing. I've also tried to add the string "${^XB}$" into the PDF document before each page break, except the last, and used the pass-through setting in the driver to inhibit the cut command but that seems to not work either as the java print job is rendering such text as an image.
I've tried the official Zebra driver as well as using the NiceLabel zebra driver too in the hope that they may have more "Custom Commands" options in the settings but nothing has yet come to light.

After we had the same issues for several weeks and neither the vendor nor google nor Zebra's own support came up with a FULL working solution, we've worked out the following EASY 5 step solution for this (apparently pretty common) Zebra Cutter issue/problem:
Step 1:
Set Cutter-Mode to Tear-Off in the settings.
This will disable the auto-cutting after every single page.
Step 2: Go to Customer-Commands in the settings dialog (Allows ZPL coding).
Step 3: Set the first drop-down to "DOCUMENT".
Step 4: Set the Start-Section to "TEXT" and paste in
^XA^MMD^XZ^XA^JUS^XZ
MMD enables PAUSE-Mode. The JK command is only available in Pause-Mode and many Zebra printers do not support the much easier command CN (Cut-Now).
JUS saves the setting to the printer.
Step 5: Set the End-Section to "ANALYZED TEXT" and paste in
˜JK˜PS
JK sets the cut command to the end of the document, PS disables the pause mode (and thus starts printing immediately). When everything looks as described above, hit "APPLY" and your Zebra printer will automatically cut after the end of each document you send to it. You just send your PDF using sumatra or whatever you prefer. The cutter handling is now automatically done by the printer settings.
Alternatively, if you want to do this programmaticaly, use the START and END codes at the corresponding positions in your ZPL code instead. Note that ˜CMDs cannot be send in combination with ^CMDs, thats why there's no XA...XZ block to reset any settings (which is not necessary in this scenario as it only affects the print session and PS turns the pause mode back to OFF).

I had similar concern but as the print server was CUPS, I wasn't able to use Windows drivers and utilities (settings dialog). So basically, I did the following:
On the printer, set Cutter mode. This will cut after each printed label.
In my Java code, thanks to Apache PDFBox lib, open the PDF and for each page, render it as a monochrome BufferedImage, get bytes array from it, and get its hex representation.
Write a few ZPL commands to download hex as graphic data, and add the ^XB command before the ^XZ one, in order to prevent a cut here, except for the last page, so that there is a cut only at the end of the document.
Send the generated ZPL code to the printer. In my case, I send it as a raw document through IPP, using application/vnd.cups-raw as mime-type, thanks to the great lib ipp-client-kotlin, but it is also possible to use Java native printing API with bytes.
Below in a snippet of Java code, for demo purpose:
public void printPdfStream(InputStream pdfStream) throws IOException {
try (PDDocument pdDocument = PDDocument.load(pdfStream)) {
PDFRenderer pdfRenderer = new PDFRenderer(pdDocument);
StringBuilder builder = new StringBuilder();
for (int pageIndex = 0; pageIndex < pdDocument.getNumberOfPages(); pageIndex++) {
boolean isLastPage = pageIndex == pdDocument.getNumberOfPages() - 1;
BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(pageIndex, 300, ImageType.BINARY);
byte[] data = ((DataBufferByte) bufferedImage.getData().getDataBuffer()).getData();
int length = data.length;
// Invert bytes
for (int i = 0; i < length; i++) {
data[i] ^= 0xFF;
}
builder.append("~DGR:label,").append(length).append(",").append(length / bufferedImage.getHeight())
.append(",").append(Hex.getString(data));
builder.append("^XA");
builder.append("^FO0,0");
builder.append("^XGR:label,1,1");
builder.append("^FS");
if (!isLastPage) {
builder.append("^XB");
}
builder.append("^XZ");
}
IppPrinter ippPrinter = new IppPrinter("ipp://printserver/printers/myprinter");
ippPrinter.printJob(new ByteArrayInputStream(builder.toString().getBytes()),
documentFormat("application/vnd.cups-raw"));
}
}
Important: hex data can (and should) be compressed, as mentioned in ZPL Programming Guide, section Alternative Data Compression Scheme for ~DG and ~DB Commands. Depending on the PDF content, it may drastically reduce the data size (by a factor 10 in my case!).
Note that Zebra's support provides a few more alternatives in order to controller the cutter, but this one worked immediately.

Zebra Automatic Cut - Found another solution.
Create a file with the name: Delayed Cut Settings.txt
Insert the following code: ^XA^MMC,N^XZ
Send it to the printer
After you do the 3 steps above, all the documents you send to the printer will be cut automatically.
(To disable that function send again the 'Delayed Cut Setting.txt' with the following code:^XA^MMD^XZ )
The first document you send to the printer, you need to ADD (just once) the command ^MMC,N before the ^XZ
My EXAMPLE TXT:
^XA
^FX Top section with logo, name and address.
^CF0,60
^FO50,50^GB100,100,100^FS
^FO75,75^FR^GB100,100,100^FS
^FO93,93^GB40,40,40^FS
^FO220,50^FDIntershipping, Inc.^FS
^CF0,30
^FO220,115^FD1000 Shipping Lane^FS
^FO220,155^FDShelbyville TN 38102^FS
^FO220,195^FDUnited States (USA)^FS
^FO50,250^GB700,3,3^FS
^FX Second section with recipient address and permit information.
^CFA,30
^FO50,300^FDJohn Doe^FS
^FO50,340^FD100 Main Street^FS
^FO50,380^FDSpringfield TN 39021^FS
^FO50,420^FDUnited States (USA)^FS
^CFA,15
^FO600,300^GB150,150,3^FS
^FO638,340^FDPermit^FS
^FO638,390^FD123456^FS
^FO50,500^GB700,3,3^FS
^FX Third section with bar code.
^BY5,2,270
^FO100,550^BC^FD12345678^FS
^FX Fourth section (the two boxes on the bottom).
^FO50,900^GB700,250,3^FS
^FO400,900^GB3,250,3^FS
^CF0,40
^FO100,960^FDCtr. X34B-1^FS
^FO100,1010^FDREF1 F00B47^FS
^FO100,1060^FDREF2 BL4H8^FS
^CF0,190
^FO470,955^FDCA^FS
^MMC,N
^XZ

Related

How to prevent automatic hyperlink detection in the console of Firefox/Chrome developer tools?

Something that drives me nuts in the developper tools of Chrome (106) and Firefox (105) is the fact that whenever some text logged to the console via console.log(text) happens to contain a hyperlink, this link is not only turned clickable (I can live with it even when I usually prefer to have just plain text) but is abbreviated, if it is a long link. So when I want to control what precise link is in some variable, I cannot just write e.g. console.log(img.src), because some of the interesting information of the link is hidden.
You can try yourself with
var href = 'https://stackoverflow.com/search?q=%5Bgoogle-chrome-devtools%5D+%5Bconsole.log%5D+%5Bfirefox-developer-tools%5D+%5Bhyperlink%5D+automatic+detection&someMoreStuffTomakeTheLinkLonger';
console.log(href);
In both, Firefox and Chrome, the output for me contains some '...', e.g. in Firefox I obtain as output:
https://stackoverflow.com/search?q=%5Bgoogle-chrome-devtools…link%5D+automatic+detection&someMoreStuffTomakeTheLinkLonger
thus hiding the part after "-devtools". (Chrome hides a slightly different part). The console is mostly a debugging tool. I log things because I want to see them, not hide them. I always need to either hover with the mouse and wait for the tooltip (doesn't allow me to copy fractions of the link) or to right click copy the link and paste it somewhere where I can see it completely. Or take a substring to remove the "https://" in the front. But note that the variable isn't necessarily a single hyperlink, but can be any text containing several such hyperlinks. I didn't find a way to force console.log to just print plain text all content. Did anybody meet this problem as well and find a workaround?
I made this a community wiki answer, because the main insight is not from myself but from the comments. Feel free to improve.
The console.log() function allows several arguments, which allows also a formatted output similar to printf in some languages. The possibilities of formatting can be found in the documentation of console.log() on MDN. In any case, this formatted output provides a solution at least for Chrome, as #wOxxOm pointed out in the comments:
console.log('%O', href) // works in Chrome
This is rather surprising, because %O is described at MDN as
"Outputs a JavaScript object. Clicking the object name opens more information about it in the inspector".
It seems there is no 'clicking' in Chrome when the object is a string.
There is also %s for string output, but this just gives the standard behavior of replacing links in both browsers. And for Firefox none of the above two formatting options works. There one really has to replace the protocol "https://" by something that is not recognized as link. A space behind ':' seems enough, so "https: //". It turns out, that one can also insert a formatting string "https:%c//", which can even be empty, and thus yield an output which is the complete link and can be copied as well:
console.log(href.replace(/(https?:)/, "$1%c"), ""); // works in Firefox
In particular the FF solution is cumbersome, and there might also be several links within one console-output. So it is useful to define one's own log-function (or if one prefers, redefine console.log, but note the remark at the end)
function isChrome() {...} // use your favorite Chrome detection here
function isFirefox() {...} // use your favorite Firefox detection here
function plainLog() {
const msg = arguments[0];
if (isChrome() && arguments.length == 1 && typeof msg == "string") {
return console.log("%O", msg);
}
if (isFirefox() && arguments.length == 1 && typeof msg == "string") {
const emptyStyle = ""; // serves only as a separator, such that FF doesn't recognize the link anymore
const reg = /(https?:)\/\//g;
const emptyStyles = []; // we need to insert one empty Style for every found link
const matches = msg.matchAll(reg);
for (let match of matches) {
emptyStyles.push(emptyStyle);
}
return console.log(msg.replace(reg, '$1%c//'), ...emptyStyles);
}
return console.log(...arguments);
}
For browser detection isChrome() and isFirefox() see e.g. here on SO.
One can of course extend the redefinition also to the other console functions (console.info, console.warn, etc.)
The downside of the redefinition of console.log is that usually every output of the console shows also the last entry of the call stack as a practical link to the source of the logging. But due to the redefintion, this link is now always to the same place, namely the file and line number where plainLog() is defined and calls console.log(), instead of the place where the new log command plainLog() was called. This new problem is described on SO here, but the solution (see comment) is again a bit involved and also not completely satisfying to serve as a replacement for the built-in console.log . So if links appear only rarely in the logging, it's probably better to switch to the redefined plainLog() only for these links.

Ghostscript with a Zebra ZM600

I have created a program which takes a PDF and prints it using Ghostscript.NET.
The printer in question is a Zebra ZM600, and the printing works fine. However I would like to do some adjustments to the labels, and this can be done using the driver. When I print using Adobe Reader, the adjustments work, but when I use the program which I have created to print the file, it seems like GhostScript.NET does something with the properties as this doesn't work at all (it is printed but the adjustments doesn't work).
using (GhostscriptProcessor processor = new GhostscriptProcessor())
{
List<string> switches = new List<string>();
switches.Add("-empty");
switches.Add("-dPrinted");
switches.Add("-dBATCH");
switches.Add("-dNoCancel");
switches.Add("-dNOPAUSE");
switches.Add("-dNOSAFER");
switches.Add("-dNumCopies=1");
switches.Add("-sDEVICE=mswinpr2");
switches.Add("-sOutputFile=%printer%" + printerName);
switches.Add("-f");
switches.Add(path);
processor.StartProcessing(switches.ToArray(), null);
_logger.Info("After starting process");
}
The question is, does anybody know if there is a way to force Ghostscript to use the adjustments on the printer driver? Or if there are any better alternatives for printing PDFs on a label printer?

Aspose generated doc file turns underscores into white space for some users

I am updating archaic code that creates memos. The code was written to use bookmarks inside of manually created template.doc files that aspose can write to. The problem comes from this chunk of code.
foreach (Addressee infoAddressee in ConfigManager.GetConfig().Addressees)
{
if (infoAddressee.Abbreviation == Memo.AddresseeAbbr.ToUpper() &&
infoAddressee.NeedsThisLine)
{
WriteMeString = "FOO BARR ________";
break;
}
}
if (WriteMeString != "")
{
builder.MoveToBookmark("BOOKMARK");
builder.Write(WriteMeString);
}
}
This works for me, but the two people who have tested this chunk of code have the "FOO BARR _______" line appear as "FOO BARR "
the seven underlines are replaced with spaces(the spacing exists on the word doc, but Stack overflow concatenates consecutive spaces). I am not sure what could cause this.
To test we need to copy the file from the remote dev environment into our local environment, I believe this to be the source of the issue, but i do not know for sure.
What I have already tried:
The testers and me are supplying the exact same input for the document.
The testers and I had a slightly different way to save the document and copy paste it over to the local environment, but doing it my way did not change anything.
I am unsure of what could do this for some users but not for others, any suggestions for things i could check out, be it literature with information on the subject or proposed solutions, would be greatly appreciated
I checked the scenario on my side and cannot reproduce the problem. Underscores are properly displayed in the output document. Here are few things to try.
Try setting bookmark text instead of moving to it and writing text.
doc.Range.Bookmarks["BOOKMARK"].Text = WriteMeString;
Try checking whether string is written correctly into the document.
builder.MoveToBookmark("BOOKMARK");
builder.Write("FOO BARR ________");
Assert.AreEqual("FOO BARR ________", builder.Document.Range.Bookmarks["BOOKMARK"].Text);
using (MemoryStream ms = new MemoryStream())
{
builder.Document.Save(ms, SaveFormat.Doc);
ms.Position = 0;
Document tempDoc = new Document(ms);
Assert.AreEqual("FOO BARR ________", tempDoc.Range.Bookmarks["BOOKMARK"].Text);
}
Compare the documents produced on your side and on the testers side yourself (I suppose, you have already done this, but just in case). Probably the documents are correct, but there is difference in viewer used on your and testers side.
Disclosure: I work at Aspose.Words team.

ABCPDF Font Printing Layout - Machine Dependent

I am using ABCPDF to print a PDF file to a local printer via EMF file. I've based this very closely on ABC PDF's sample "ABCPDFView" project. My application worked fine on my Windows 7 and Windows XP dev boxes, but when I moved to a Windows 2003 test box, simple embedded fonts (like Times New Roman 12) rendered completely wrong (wrong spot, and short and squat, almost like the DPI's were crazily wrong).
Note that I've hardcoded the DPI to 240 here b/c I'm using a weird mainframe print driver that forces 240x240. I can discount that driver as the culprit as, if I save the EMF file locally during print, it shows the same layout problems. If I render to PNG or TIFF files, this looks just fine on all my servers using this same code (put .png in place of .emf). Finally, if I use the ABCPDFView project to manually add in a random text box to my PDF, that text also renders wrong in the EMF file. (Side note, if I print the PDF using Acrobat, the text renders just fine)
Update: I left out a useful point for anyone else having this problem. I can work around the problem by setting RenderTextAsText to "0" (see code below). This forces ABCPDF to render the text as polygons and makes the problem go away. This isn't a great solution though, as it greatly increases the size of my EMF files, and those polygons don't render nearly as cleanly in my final print document.
Anyone have any thoughts on the causes of this weird font problem?
private void DoPrintPage(object sender, PrintPageEventArgs e)
{
using (Graphics g = e.Graphics)
{
//... omitted code to determine the rect, used straight from ABC PDF sample
mDoc.Rendering.DotsPerInch = 240 ;
mDoc.Rendering.ColorSpace = "RGB";
mDoc.Rendering.BitsPerChannel = 8;
mDoc.SetInfo(0, "RenderTextAsText", "0");//the magic is right here
byte[] theData = mDoc.Rendering.GetData(".emf");
using (MemoryStream theStream = new MemoryStream(theData))
{
using (Metafile theEMF = new Metafile(theStream))
{
g.DrawImage(theEMF, theRect);
}
}
//... omitted code to move to the next page
}
Try upgrading to the new version of abcpdf 8, it has its own rendering engine based on Gecko and so you can bypass issues like this when abcpdf is using the inbuilt server version of IE for rendering.
I was originally RDPing in with 1920x1080 resolution, by switching to 1024x768 res for RDP, the problem went away. My main program runs as a service, and starting this service from an RDP session w/ 1024x768 fixes it.
I have an email out w/ ABC PDF to see if they can explain this and offer a more elegant solution, but for now this works.
Please note that this is ABC PDF 7, I have no idea if this issue applies to other versions.
Update: ABC PDF support confirmed that its possible the service is caching the display resolution from the person that started the process. They confirmed that they've seen some other weird issues with Remote Desktop and encouraged me to use this 1024x768 workaround and/or start the service remotely.

Offending Command error while Printing EPS

I am printing an EPS File generated with following credentials.
%-12345X#PJL JOB
#PJL ENTER LANGUAGE = POSTSCRIPT
%!PS-Adobe-3.0
%%Title: InvoiceDetail_combine
%%Creator: PScript5.dll Version 5.2.2
%%CreationDate: 10/7/2011 4:46:59
%%For: Administrator
%%BoundingBox: (atend)
%%Pages: (atend)
%%Orientation: Portrait
%%PageOrder: Special
%%DocumentNeededResources: (atend)
%%DocumentSuppliedResources: (atend)
%%DocumentData: Clean7Bit
%%TargetDevice: (HP Color LaserJet 4500) (2014.200) 0
%%LanguageLevel: 2
%%EndComments
While doing Selection Printing on Ricoh Afficio 2090 or any other drivers/printers get the following error printed on the sheets
ERROR: undefined
OFFENDING COMMAND: F4S47
Stack:
.
Kindly Review and suggest a turn around for the same as i am already stuck in this hell. I have tried to convert/extract in PS but all in vain. I am using gsview to Print and view these files.
This is the problem:
%%PageOrder: Special
A ps document with "Special" page order can NOT be re-ordered. You cannot do a selection or range with this file because it is broken for this use. You must reprocess the file using Distiller or ghostscript (ps2ps or ps2pdf) in order to print selected or re-ordered pages from the document.
You can avoid this by generating your postscript files with a real Postscript™ driver (one not created by Microsoft).
The GSView Documentation has more about this.
Previously:
This line ...
%%TargetDevice: (HP Color LaserJet 4500) (2014.200) 0
... tells us that the file was generated with HP printers as a target. So this really is not an EPS file. Because it's not Encapsulatable. To generate output on a printer the file has to execute the showpage operator, which is a no-no for EPS files.
So uncheck the EPS box (it's a big fat lie, anyway), and select (install) a Generic Postscript driver. If you need to send it to multiple makes of printer, the file needs to make as few assumptions about the printer as possible.
The first thing is that this is not a valid EPS file, as it has PJL attached at the front. Many PostScript printers will strip this off, but by no means all.
This probably is not the source of the problem.
There is no way to 'review' the problem as you have not supplied the complete PostScript program. Without that there is no way to tell what is actually wrong, the error message tells you that the interpreter encountered 'F4547' while trying to parse a token, and that this has not been defined as a routine.
Most likely the file is corrupt, either damaged in some way, or possibly it is a biinary file and has been transmitted by some process which does has done some kind of conversion (CR/LF is common). The offending command looks like its ASCIIHex encoded, so that may be a red herring.
If you want additional help, you are going to have to make the whole program available somewhere.

Resources