Set page scaling in PJL - c#

I have to write a functionality that takes a PDF-document and sends it to a printer with some PJL commands. So far so good, I take the document, convert it to Postscript, send the postscript file to the printer with the required commands and the printer prints the document.
Now to the actual problem: Most of the document that needs to be printed by our software are invoices, therefore they are carefully made, such that every element is precisely positioned, and if it's off by millimeters the printed document is invalid. When printing the document directly through Adobe or any pdf viewing software, I can select the actual size option and everything is fine. Although if I print it via C# and PJL the document has different margins depending on the printer it has been printed on. Until now we used pdfprinting.net, and that option could be selected through pdfPrint.Scale = PdfPrint.ScaleTypes.None, but how can I do it via PJL?
// This are all the commands that I've tried, none of which achieved what I need
var parameters = new Dictionary<string, string>
{
{ "SET USERNAME",userName},
//{"SET PAPER", "A4" },
//{"SET MEDIATYPE", "PAPER" },
//{"SET TOPMARGIN", "TM6MM" },
//{"SET PRINTAREA", "INKEDAREA" },
{"SET MARGINS", "SMALLER" },
//{ "ENTER LANGUAGE","PDF"},
{ "ENTER LANGUAGE","POSTSCRIPT"},
};
var documentText = "\x1B%-12345X#PJL JOB NAME=" + jobName + " DISPLAY=" + jobDisplay;
foreach (var parameter in parameters)
{
documentText += "\r\n#PJL " + parameter.Key + "=" + parameter.Value;
}
documentText += "\r\n";
documentText += pdfString;
documentText += "\r\n\x0D\x0A\x1B%-12345X\r\n";
RawPrint(printerAddress, documentText, documentName);
// RawPrint() calls the printer methods found in 'winspool.drv', imported via 'DllImport'

Checking the PJL Reference Manual (Edition 12, which is the latest I have seen) there is simply no way to scale the page content in PJL.
Even if there were, I'd be surprised if it carried over to the PostScript (as opposed to PCL) interpreter environment, because PostScript has a rich feature set to handle this sort of setup. So basically you're going to need to get the PostScript correct.
Now, when you take a PDF file and produce PostScript from it, you are almost certainly producing generic PostScript; its device-neutral so it doesn't take account of aspects of the physical device.
Most obviously this will be things like hardware margins and unprintable areas. Many devices have limitations on which parts of the media they can print on, due to the paper handling. These will, of course, be different between different printers.
Of course, when you print from the operating system, the printer device driver knows what the printable area of the media is (because its the specific driver for the printer in question), and so it can arrange for the content to be scaled to the actual media.
Ghostscript certainly can produce PostScript (using the ps2write device) which is suitably scaled and translated for a given printer, provided you know what the characteristics of that printer are. In fact if the printer is sophisticated enough, the PostScript program may be able to interrogate the printer to retrieve some of these characteristics (ImagingBBox, PageOffset, Margins, ImageShift) and its then possible to write a PostScript program to dynamically resize the content of the page, based on these values (the PostScript produced by ps2write does not do this...).

Related

Magnetic stripe printing: Where to start?

This is a WPF desktop app related to ID Card printing. One of the new features we're trying to add is magstripe encoding. After having spent several days, I'm still not sure where to start. New questions keep popping up the more I google. I'll summarize them here. I'll be glad to hear from experts (even if someone can answer one/some of the questions):
Do magstripe printers work as normal printers too (means can they print text and graphics too, or is that we print the cards on other, regular printers in the first pass and then insert them into magstripe printer for encoding magnetic data onto them, in the 2nd pass)?
If answer to Q1 is yes, how do I send magstripe data to the printer during regular printing job (done through WPF, using PrintDialog, FixedDocument etc).
I downloaded and examined Zebra printers SDK. It looks like these printers DO support text/graphics printing in addition to magstripe encoding, but their SDK requires me to call their native printing functions, which doesn't fit in WPF's standard printing model. How to overcome this?
In another place I read that magstripe printers require simple ASCII text in specific format to get them encoded onto the card, and that I can do this even from Notepad. If this is true, the answer to Q1 might be negative. But then again, how does this method work in conjunction with regular WPF printing?
Edit
I also learnt that there are magstripe fonts that when placed in a document, end up being encoded to the magnetic stripe instead of regular printing. If this is true, it would very nicely fit in WPF printing model. But googling hasn't returned too many promising results for magstripe fonts. Maybe this is a brand-specific feature.
I am currently working on a similar WPF project that requires magnetic encoding as well as image printing on ID cards. I have found that magnetic encoding is very simple as long as the drivers for the printer with magnetic coding are installed on the host. One vital piece to watch out for is the delimiter being used by the driver. This could be NULL, ZERO, or Space. This comes into play when encoding a specific track (i.e. Track 2 but not Track 1 as we are). I use the NULL setting which allows only the Track 2 data to be sent in the job. This setting is found in the Printer Preferences for the Fargo printers (Control Panel -> Hardware and Sound -> Devices and Printers -> Right-Click Printer -> Printer Preferences). Here is an example of these Preferences (note the ASCII Offset field):
I do not believe that you MUST use the SDK for the printer you are using. I am using a Fargo printer but wrote my own Print functionality using PrintDocument and PrintPage for both magnetic encoding and images.
An example and quick test is to send Track 2 data to the printer using Notepad++ (or similar). Copy and paste this into the first line of the editor and print (using the card printer).
~2;000099990000?
The driver should pick up the fact that it is Track data and handle it accordingly without any more input from you. You may need to play with the printer preferences as stated.
The ~2; denotes Track 2 followed by a 12-character data string followed by the end sentinel (?). There is plenty of documentation pertaining to Track data and layouts online. This is assuming a NULL delimiter value (between Track 1 and Track 2).
Printing on both sides of the card can be cumbersome, but that does not appear to be within the scope of this question. I recommend using Windows native PrintDocument and PrintPage methods within your WPF application; the SDK you have downloaded is likely using these methods in the background, anyhow.
An example of PrintDocument/PrintPage:
private int PageCount { get; set; }
public void Print()
{
PageCount = 0;
PrintDocument pd = new PrintDocument
{
// Define your settings
PrinterSettings = {
Duplex = Duplex.Horizontal,
PrinterName = ConfigurationManager.AppSettings["PrinterName"]
}
};
Margins margins = new Margins(0, 0, 0, 0);
pd.OriginAtMargins = true;
pd.DefaultPageSettings.Margins = margins;
pd.PrintPage += new PrintPageEventHandler(this.PrintPage);
PrintPreviewDialog ppd = new PrintPreviewDialog();
ppd.Document = pd;
// Uncomment to show a Print Dialog box
//if (ppd.ShowDialog() == DialogResult.OK)
pd.Print();
pd.Dispose();
}
private void PrintPage(object o, PrintPageEventArgs e)
{
PrintDocument p = (PrintDocument)o;
p.DefaultPageSettings.Landscape = true;
p.DefaultPageSettings.Margins = new Margins(0, 0, 0, 0);
p.DefaultPageSettings.PaperSize = new PaperSize("YourPaperSizeName", 340, 215);
p.OriginAtMargins = true;
o = p;
e.PageSettings.PrinterSettings.DefaultPageSettings.Landscape = true;
e.PageSettings.Landscape = true;
// Do Print First Side (MAG ENCODE)
if (PageCount == 0)
{
// Do Side 1 Stuff
// If Two-Sided Printing: true
e.HasMorePages = true;
//If no more, set above to false and PageCount = 0, else...
PageCount++;
}
else
{
// Do Print on Other Side
// STUFF
// STUFF
// Since only two sides/card printing: false
e.HasMorePages = false;
PageCount = 0;
}
}
Again, magnetic encoding should not be brand-specific and you should not have to rely solely on their SDK to perform print jobs.
I hope this helps!

Sending file to print not working using System.Drawing.Printing

I'm trying to send a file to print without opening it trough Adobe as suggested by several Answers here; instead, I'm using the PrintQueue library (from System.Drawing.Printing).
What I've accomplished so far:
I have the correct PrintQueue referenced as pq:
PrintQueue pq; //Assume it's correct. The way to get here it isn't easy and it is not needed for the question.
// Call AddJob
PrintSystemJobInfo myPrintJob = pq.AddJob();
// Write a Byte buffer to the JobStream and close the stream
Stream myStream = myPrintJob.JobStream;
Byte[] myByteBuffer = ObjectIHave.ToArray(); //Ignore the ObjectIhave, it actually is Linq object which is correct as well.
myStream.Write(myByteBuffer, 0, myByteBuffer.Length);
myStream.Close();
As I understood from the Microsoft Library it's correctly done but it is not working. Any ideas?
EDIT: Debugging the code I can see that something is being send to the printer but it seems the file is not sent.
You need to render your PDF to the printer. Calling the shell print verb on the file would be the ideal means to do that. If you insist on doing the low level rendering yourself then I recommend using a library like Ghostscript.NET and choose the mswinpr2 device as output.
The mswinpr2 device uses MS Windows printer drivers, and thus should work with any printer with device-independent bitmap (DIB) raster capabilities. The printer resolution cannot be selected directly using PostScript commands from Ghostscript: use the printer setup in the Control Panel instead.
See SendToPrinterSample.cs for example:
string printerName = "YourPrinterName";
string inputFile = #"E:\__test_data\test.pdf";
using (GhostscriptProcessor processor = new GhostscriptProcessor())
{
List<string> switches = new List<string>();
switches.Add("-empty");
switches.Add("-dPrinted");
switches.Add("-dBATCH");
switches.Add("-dNOPAUSE");
switches.Add("-dNOSAFER");
switches.Add("-dNumCopies=1");
switches.Add("-sDEVICE=mswinpr2");
switches.Add("-sOutputFile=%printer%" + printerName);
switches.Add("-f");
switches.Add(inputFile);
processor.StartProcessing(switches.ToArray(), null);
}
If the file has to be printed in both sides you just need to add:
switches.Add("-dDuplex");
switches.Add("-dTumble=0");
You can not just write PDF bytes to a print job. The printer doesn't know how to handle it. The RAW data you send to the printer must describe the document in a printer language specific to the printer. That's what the printer driver does.
You can not print a PDF by just sending it to the printer. You need some piece of software that renders the PDF and then sends the rendered image to the printer.
As the documentation states:
Use this method to write device specific information, to a spool file, that is not automatically included by the Microsoft Windows spooler.
I enhanced the important part of this information.

How to convert a png file to .GRF file used for zebra printer

I use Zebraprinter for printing the labels. My printer is 203dpi. For last couple of days i was searching in internet and i found there are Zebraprint utilities.. to convert to DFR format.. which sucks.. they are not fully explaining how to do this.. They just says convert to ~DG format. any print it, which is not happening!!
Rather I would like to convert a png file to a .GRF file and send to the printer for printing.. IS there any deadly available free software in internet which does my needs,
Also, i tired to develop a software which does the job for printing the letters.. which is wiring fine. i don't know how to print pictures using this printer.
I need to convert this image https://imageshack.com/i/pb0BArbep to .GRF format. How can i do all this under a single button press.. Any helps..
Thanks a lot.
Code snippet:-
private void button2_Click(object sender, EventArgs e)
{
string s = Print();
PrintFactory.sendTextToLPT1(s);
}
private string Print()
{
string s = "";
s += "^XA^LH"+ text.textbox + ".GRF,1,1^FS";
s += "^FO250,294^FD^FS";
s += "^XZ";
return s;
}
It's been a month since this was asked, so I don't know if an answer is still needed or not, but I'll have a go at it. I've actually been doing a lot of research on ZPL lately, (one of the reasons I came across this question), and I had to do something similar. With a 203 dpi printer as well, actually. I'm not sure how to convert a PNG to GRF, but I was able to print out a graphic using just a PNG:
^XA
^MNY
^LL203
~DYE:{name},P,P,{file size},,{data}
^XZ
The ^MN has to do with Media Tracking, and you may have to change it a bit to suit your needs, depending on the label. Same thing with ^LL, which specifies the label length. For an 8 dots/mm (203 dpi), the value you use as an argument is calculated by 203.2 * length of label in inches. After that, there's a few values to plug into ~DY (Download graphics, page 112 on the manual), the first of which is the name you want to use to reference the file. I didn't add a file extension, as the printer seemed to do that for me, since I specified it was a PNG in the arguments. The second is the size, in bytes, of the PNG file. And lastly, the actual data from the file in the form of ASCII hex. Now with the file being saved on the printer, I was then able to print the graphic in a script using:
^IME:{name}.PNG
^FS
Note: After uploading the file to the printer, I was able to confirm it did save as a PNG file by connecting to the printer VIA IP in a browser and going to "Directory Listing". I'm not sure if all those printers have this feature, but the one I used did. If it does, you can use this to confirm that the file properly uploaded. (It should be in Onboard Flash)
Hope this helps!
The manual I used is here.
I also came across numerous other StackOverflow questions that helped out a bit, and a few threads on other forums. One question that was also in C# that helped me quite a bit can be found here.

Getting started with manipulating print meta-data

When sending a document, lets say TIFF images to a printer we can send meta-data with the image such as the paper size "Legal, Photo etc". The printer is able to use this information to select a paper tray matching this paper size.
I have a program that generates a tif document and uses PrintDocument to generate a Print job. This process occurs programmatically (no UI). Is it possible to alter the metadata of the tif image programmatically before I send the job to the printer?
E.G. I want to change the paper size of the image to "Legal". This way I can tell the printer which tray to use. I have explored generating an XPS document out of the TIF. Then going back through a XPS API to set the property. However, this solution feels a little heavy. I hope for someone with more experience in this type of programming to point me in the right direction.
The paper size option is available in PrintDocument
private void SetPaperSize()
{
int legalPaperIndex = 5;//See all types: http://msdn.microsoft.com/en-us/library/system.drawing.printing.papersize.rawkind.aspx
for (int i = 0; i < printDocument.PrinterSettings.PaperSizes.Count - 1; i++)
{
if (printDocument.PrinterSettings.PaperSizes[i].RawKind == legalPaperIndex)
{
printDocument.DefaultPageSettings.PaperSize = printDocument.PrinterSettings.PaperSizes[i];
}
}
}

How do I print an HTML document from a web service?

I want to print HTML from a C# web service. The web browser control is overkill, and does not function well in a service environment, nor does it function well on a system with very tight security constraints. Is there any sort of free .NET library that will support the printing of a basic HTML page? Here is the code I have so far, which does not run properly.
public void PrintThing(string document)
{
if (Thread.CurrentThread.GetApartmentState() != ApartmentState.STA)
{
Thread thread =
new Thread((ThreadStart) delegate { PrintDocument(document); });
thread.SetApartmentState(ApartmentState.STA);
thread.Start();
}
else
{
PrintDocument(document);
}
}
protected void PrintDocument(string document)
{
WebBrowser browser = new WebBrowser();
browser.DocumentText = document;
while (browser.ReadyState != WebBrowserReadyState.Complete)
{
Application.DoEvents();
}
browser.Print();
}
This works fine when called from UI-type threads, but nothing happens when called from a service-type thread. Changing Print() to ShowPrintPreviewDialog() yields the following IE script error:
Error: dialogArguments.___IE_PrintType is null or not an object.
URL: res://ieframe.dll/preview.dlg
And a small empty print preview dialog appears.
You can print from the command line using the following:
rundll32.exe
%WINDIR%\System32\mshtml.dll,PrintHTML
"%1"
Where %1 is the file path of the HTML file to be printed.
If you don't need to print from memory (or can afford to write to the disk in a temp file) you can use:
using (Process printProcess = new Process())
{
string systemPath = Environment.GetFolderPath(Environment.SpecialFolder.System);
printProcess.StartInfo.FileName = systemPath + #"\rundll32.exe";
printProcess.StartInfo.Arguments = systemPath + #"\mshtml.dll,PrintHTML """ + fileToPrint + #"""";
printProcess.Start();
}
N.B. This only works on Windows 2000 and above I think.
I know that Visual Studio itself (at least in 2003 version) references the IE dll directly to render the "Design View".
It may be worth looking into that.
Otherwise, I can't think of anything beyond the Web Browser control.
Easy! Split your problem into two simpler parts:
render the HTML to PDF
print the PDF (SumatraPDF)
-print-to-default $file.pdf prints a PDF file on a default printer
-print-to $printer_name $file.pdf prints a PDF on a given printer
If you've got it in the budget (~$3000), check out PrinceXML.
It will render HTML into a PDF, functions well in a service environment, and supports advanced features such as not breaking a page in the middle of a table cell (which a lot of browsers don't currently support).
I tool that works very well for me is HiQPdf. https://www.hiqpdf.com/
The price is reasonable (starts at $245) and it can render HTML to a PDF and also manage the printing of the PDF files directly.
Maybe this will help. http://www.codeproject.com/KB/printing/printhml.aspx
Also not sure what thread you are trying to access the browser control from, but it needs to be STA
Note - The project referred to in the link does allow you to navigate to a page and perform a print without showing the print dialog.
I don't know the specific tools, but there are some utilities that record / replay clicks. In other words, you could automate the "click" on the print dialog. (I know this is a hack, but when all else fails...)

Categories