PrintDocument.Print() prints very slowly to network printer [duplicate] - c#

I have a web application hosted on server 'A' (SA) and a web service for printing hosted on server 'B' (SB). SA creates and image that needs printing and sends it to SB. When doing this, printing is fairly slow, around fifteen seconds. However, if I log into SB using remote desktop as the user from the webconfig of the app hosted on SA, then it will print in less than two seconds. It seems as if SB is starting something up when I log into it that is making it print faster. Any idea what this could be and if there's a way that I could keep this printing fast even if I'm not logged in?
Edit: Size of the image being printed is about 20 KB.
Here's the code from of the service that is hosted on SB:
public void PrintImage(Stream printImage, string printServer, string printer)
{
string printerName = String.Format(#"\\{0}\{1}", printServer, printer);
Image image = Image.FromStream(printImage);
PrintDocument printDocument = new PrintDocument();
PrinterSettings settings = new PrinterSettings();
settings.PrinterName = printerName;
printDocument.PrinterSettings = settings;
printDocument.PrintPage += (s, e) =>
{
e.Graphics.DrawImage(image, 0, 0);
};
printDocument.Print();
}
Thanks for taking time to read through this :)

We found that if we created a printer mapping on SB, it would execute just as fast without a remote desktop connection.

Note that printing from a web app (or a service) is generally unsupported. see msdn and this SO post.

Related

PrintDocument.PrinterSettings.Print() Changing default printer

I have the following code, to test out printing to a specific printer. The code sends the print to the correct printer. But I have notices upon completing the print, the systems default printer has changed.
I thought maybe at first maybe the PrinterName property was setting the default printer, and quickly realized that is not the case. I have to assume it is happening inside the Print() method.
I did some reading on changing the default printer, the solutions I found seemed to use the System.Management Namespace. But did not find anything related to changing the default printer back in the System.Drawing.Printing Namespace.
I figure there might be a simple way to change it back using the same Namespace that used it in the first place. Other than reprinting the document or a blank document to the previously default printer.
static void Main(string[] args)
{
Receipt();
}
static private void Receipt()
{
PrintDocument p = new PrintDocument();
p.PrinterSettings.PrinterName = "Star HSP7000 Receipt";
p.PrintPage += delegate(object sender1, PrintPageEventArgs e)
{
e.Graphics.DrawString("testtesttestest", new Font("Times New Roman", 12), new SolidBrush(Color.Black), new RectangleF(0, 0, p.DefaultPageSettings.PrintableArea.Width, p.DefaultPageSettings.PrintableArea.Height));
};
p.Print();
}
After asking this question, I continued searching, and found that windows 10 quietly manages the Default Printer to the last printer that is printed from (by default).
If you are having an issue on a windows 10 machine where the default printer is changing after a print job. Make sure to change this.

WPF Printing (XpsDocumentWriter) working in debug but not in deployment

Hopefully some of the experienced WPF developers have come across this issue before.
BACKGROUND: This information is probably not necessary to helping fixing the problem, but in case it is relevant.
My solution consists of three projects. A front-end GUI, a business logic service, and a printer service. The three projects have IPC via named pipes. The business logic hands the printing logic a label type and a pallet id.
The Problem: The printing logic then creates the label and prints it (by adding it to the print queue of a printer) As the title suggests this all works fine when I am debugging in visual studio. However when I deploy / install the services on my developer pc it is not working.
Update: It is not throwing an exception but I am only logging "About to send doc to printer" and not the line "Sent doc to printer" So it is hanging on the dw1.Write(fixedDoc); line
More Information: I am using .Net 4.0 in the printing project / visual studio 2013
public void printLabel(string labelType, string _palletID = null)
{
try
{
ILabelTemplate Label = createLabel(labelType, _palletID);
PrintDialog pd = new PrintDialog();
FixedDocument fixedDoc = new FixedDocument();
PageContent pageContent = new PageContent();
FixedPage fixedPage = getFixedPage();
fixedDoc.DocumentPaginator.PageSize = new System.Windows.Size(fixedPage.Width, fixedPage.Height);
IXamlTemplate vm = CreateViewModel(Label);
ILabelPrintDocument template = CreateTemplate(Label);
template.dockPanel.DataContext = vm;
template.dockPanel.Height = fixedPage.Height;
template.dockPanel.Width = fixedPage.Width;
template.dockPanel.UpdateLayout();
fixedPage.Children.Add(template.dockPanel);
((System.Windows.Markup.IAddChild)pageContent).AddChild(fixedPage);
fixedDoc.Pages.Add(pageContent);
XpsDocumentWriter dw1 = PrintQueue.CreateXpsDocumentWriter(new System.Printing.PrintQueue(new System.Printing.PrintServer(), Label.PrinterName));
Library.WriteErrorLog("About to send doc to printer");
dw1.Write(fixedDoc);
Library.WriteErrorLog("Sent doc to printer");
}
catch (Exception ex)
{
Library.WriteErrorLog(ex);
}
SOLVED ... kind of
After several hours of trying different things and reading about this, I found that it was due to my application running as me when I'm debugging but as a LOCAL SYSTEM when I have it deployed. And a local system service does not have access to network resources such as printers. Despite learning this, I then started down the path of how to make a C# service print. Well after seeing many posts (too late in the game to be very helpful)
Like this and also this one I have learned that I was going down the wrong path.
The moral of the story is, if you're reading this post you're probably not at the level of "writing your own printing DLL using the Win32 API (in C/C++ for instance), then use it from your service with P/Invoke"
The solution that did work for me was instead of running this project as a service which was started via my GUI. I have instead turned it into a process which is still started and stopped via my GUI.
The code in question is
if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "\\yourAppNameGoesHere.exe"))
{
Process.Start(AppDomain.CurrentDomain.BaseDirectory + "\\yourAppNameGoesHere.exe");
}
then when the GUI is closed I run the code
if (File.Exists(AppDomain.CurrentDomain.BaseDirectory + "\\yourAppNameGoesHere.exe"))
{
Process[] myapps = Process.GetProcesses("yourAppNameGoesHere.exe");
foreach (Process _p in myapps)
{
_p.Kill();
}
}

Squeezing more speed out of Windows print spooler

Our customer and I are trying to find a way to eliminate our printing bottleneck in a labeling system my company integrated at their warehouse.
The way our system is set up, a box scans, my software does this:
PrintDocument pd = new PrintDocument();
pd.PrinterSettings.PrinterName = PrinterName;
pd.PrintController = new StandardPrintController(); //Prevent print windows
pd.DefaultPageSettings.Landscape = false;
pd.DefaultPageSettings.Margins = new Margins(0, 25, 25, 0);
pd.PrintPage += (sender, args) =>
{
Image i = Image.FromFile(#"D:\Product\Labels\" + LabelID + ".png");
Rectangle m = args.MarginBounds;
args.Graphics.DrawImage(i, m);
};
pd.Print();
which sends it to the spooler. The program runs on a rack server with Windows Server 2012, and we're printing shipping labels to five label tampers powered by Intermec PX4i label printers. Each print job is sent from a different thread, because our scanpoint processing is asynchronous. Right now, the fastest our system can handle is 5 boxes, one on each line, every 2.75 seconds, and they want to speed it up to 5 boxes every 2 seconds - the problem is, if we let it go any faster, print jobs start getting held, and spoolsv.exe starts eating up whatever CPU load my program and SQL Server aren't.
Unfortunately, our customer can only provide the monochrome .PNG image files for the labels (each about 27kb, which you wouldn't think would bog down a print spooler...) and not IPL/ZPL equivalents (which we could just send to the printers via TCP in a matter of milliseconds).
Is there a way - either in the code or in the print settings - that I can eliminate this bottleneck? Please let me know if there's anything on which you'd like me to elaborate.

PrintDocument.Print is slow unless user is logged in to the printing computer

I have a web application hosted on server 'A' (SA) and a web service for printing hosted on server 'B' (SB). SA creates and image that needs printing and sends it to SB. When doing this, printing is fairly slow, around fifteen seconds. However, if I log into SB using remote desktop as the user from the webconfig of the app hosted on SA, then it will print in less than two seconds. It seems as if SB is starting something up when I log into it that is making it print faster. Any idea what this could be and if there's a way that I could keep this printing fast even if I'm not logged in?
Edit: Size of the image being printed is about 20 KB.
Here's the code from of the service that is hosted on SB:
public void PrintImage(Stream printImage, string printServer, string printer)
{
string printerName = String.Format(#"\\{0}\{1}", printServer, printer);
Image image = Image.FromStream(printImage);
PrintDocument printDocument = new PrintDocument();
PrinterSettings settings = new PrinterSettings();
settings.PrinterName = printerName;
printDocument.PrinterSettings = settings;
printDocument.PrintPage += (s, e) =>
{
e.Graphics.DrawImage(image, 0, 0);
};
printDocument.Print();
}
Thanks for taking time to read through this :)
We found that if we created a printer mapping on SB, it would execute just as fast without a remote desktop connection.
Note that printing from a web app (or a service) is generally unsupported. see msdn and this SO post.

POS Application Development - Receipt Printing

I've been building a POS application for a restaurant/bar. The design part is done and for the past month I've been coding it. Everything works fine except now I need to print. I have to print to a receipt printer connected to the computer running the software and later I'll try to print in a remote printer like a kitchen one.
I've searched for help in the matter only to find that the standard for printing in these types of printers is using POS for .NET. The thing is, this is now a bit outdated or at least it hasn't had any updates since a couple of years. There's a lot of questions being asked on how to use this library and most of the answers aren't quite easy to follow. So if anybody could give a step by step help on printing like a simple phrase ("Hello World") on a receipt printer i would be very grateful. I'm using visual studio 2012 running on a 64 bit windows 7 and i'm coding WPF in c#.
I know this is an old post, but for those still looking for a solution, I can tell you what I did.
After spending many hours messing with OPOS and POS for .Net, I ended up just abandoning those and just using the built-in System.Drawing.Printing libraries. The OPOS and POS for .Net ended up being a pain to get working and ultimately didn't work as well as the built-in libraries.
I'm using an Epson TM-T20II receipt printer.
Here's some code that worked well for me.
public static void PrintReceiptForTransaction()
{
PrintDocument recordDoc = new PrintDocument();
recordDoc.DocumentName = "Customer Receipt";
recordDoc.PrintPage += new PrintPageEventHandler(ReceiptPrinter.PrintReceiptPage); // function below
recordDoc.PrintController = new StandardPrintController(); // hides status dialog popup
// Comment if debugging
PrinterSettings ps = new PrinterSettings();
ps.PrinterName = "EPSON TM-T20II Receipt";
recordDoc.PrinterSettings = ps;
recordDoc.Print();
// --------------------------------------
// Uncomment if debugging - shows dialog instead
//PrintPreviewDialog printPrvDlg = new PrintPreviewDialog();
//printPrvDlg.Document = recordDoc;
//printPrvDlg.Width = 1200;
//printPrvDlg.Height = 800;
//printPrvDlg.ShowDialog();
// --------------------------------------
recordDoc.Dispose();
}
private static void PrintReceiptPage(object sender, PrintPageEventArgs e)
{
float x = 10;
float y = 5;
float width = 270.0F; // max width I found through trial and error
float height = 0F;
Font drawFontArial12Bold = new Font("Arial", 12, FontStyle.Bold);
Font drawFontArial10Regular = new Font("Arial", 10, FontStyle.Regular);
SolidBrush drawBrush = new SolidBrush(Color.Black);
// Set format of string.
StringFormat drawFormatCenter = new StringFormat();
drawFormatCenter.Alignment = StringAlignment.Center;
StringFormat drawFormatLeft = new StringFormat();
drawFormatLeft.Alignment = StringAlignment.Near;
StringFormat drawFormatRight = new StringFormat();
drawFormatRight.Alignment = StringAlignment.Far;
// Draw string to screen.
string text = "Company Name";
e.Graphics.DrawString(text, drawFontArial12Bold, drawBrush, new RectangleF(x, y, width, height), drawFormatCenter);
y += e.Graphics.MeasureString(text, drawFontArial12Bold).Height;
text = "Address";
e.Graphics.DrawString(text, drawFontArial10Regular, drawBrush, new RectangleF(x, y, width, height), drawFormatCenter);
y += e.Graphics.MeasureString(text, drawFontArial10Regular).Height;
// ... and so on
}
Hopefully it helps someone skip all the messing around with custom drivers. :)
POS for .NET is probably the way to go.
Most receipt printer manufacturers will provide an OPOS service object.
And as this MSDN article states, POS for .NET is compatible with OPOS v1.8 service objects.
OPOS / UPOS (on which POS for .NET is based) is IMHO a poorly-designed API (designed by device manufacturers rather than application developers), but it's the best you have today.
I don't have any specific samples but the basics are the same as OPOS - you need to Open, Claim, Enable a device, then you can call its methods (such as Print). You might try looking at an OPOS sample, for example this PosPrinter1 sample, which will probably be very similar to POS for .NET.
This blog has some information about setting up POS for .NET that might be helpful.
UPDATE
Here's a VB Hello World for an OPOS printer. You first need to create a printer and add it to the registry with the required Logical Device Name = LDN. I believe the Epson ADK includes a utility to add a printer in the registry. This utility can also perform a health check on the printer to check it is installed correctly. Once you've done this, it should be easy enough to adapt the code below to POS for .NET
OPOSPOSPrinter.Open "MyPrinter" ' LDN of your printer
OPOSPOSPrinter.Claim 500 ' Timeout
OPOSPOSPrinter.DeviceEnabled = True
'- Print
OPOSPOSPrinter.PrintNormal 2, "Hello world"
'- Close the printer
If OPOSPOSPrinter.Claimed then
OPOSPOSPrinter.Release
End If
OPOSPOSPrinter.Close
.NET Printing
Printing under .NET isn't too difficult. Take a look here and on msdn.
Printing to a POS / receipt printer will be the same as printing to any other printer, assuming it is a Windows printer, network or otherwise. If you are using a serial printer, things may be a little more difficult because you will more then likely need to use manufacturer specific API's, fortunately though most good POS printers these days are fully supported by the OS.
First, you will need to add a reference to System.Printing dll to your project.
Then printing is as simple as
private void PrintText(string text)
{
var printDlg = new PrintDialog();
var doc = new FlowDocument(new Paragraph(new Run(text)));
doc.PagePadding = new Thickness(10);
printDlg.PrintDocument((doc as IDocumentPaginatorSource).DocumentPaginator, "Print Caption");
}
To use..
PrintText("Hello World");
You can also leverage the PrintDialog.PrintVisual and define your document using xaml template.
The print settings can be set using the PrintDialog properties.
Getting the printer you want to print to
private PrintQueue FindPrinter(string printerName)
{
var printers = new PrintServer().GetPrintQueues();
foreach (var printer in printers)
{
if (printer.FullName == printerName)
{
return printer;
}
}
return LocalPrintServer.GetDefaultPrintQueue();
}
A few things to keep in mind though when printing to a receipt printer, you will need to take into account formatting. More specifically you will need to consider the width of your page and how many characters you can fit on each line; this was a lot of trial and error for me, especially with different font sizes.
In most cases you don't really need to worry about paging, the printer will cut the paper automatically when it has completed your document.
If you want to print at the full speed of the printer, you will probably need to use printer-specific escape codes, and generate the "raw" output.
Have a look at Michael Buen's answer to this SO question, especially the UPDATE bit.

Categories