I was recently asked if it was possible to add a print feature to a web site. But not the normal "print this page" link you see all the time on the web, this was printing address pulled from a database onto standard envelopes.
I mentally worked though a few possibilities with HTML and CSS, but decided that they might be too fragile. Plus when you print a HTML page, many browsers will put a header and footer on the printout by default. You can, of course, turn off headers and footers in the print setup options of your browser...but it's a bad idea to push that kind of responsibility onto your users if you can avoid it. Any good solution should be as simple as possible and certainly shouldn't ask the users to do something they have never had to do on any other web site.
I decided it would be simplest to create a PDF on the server side and send that to the user for printing. A PDF will print the same way every time. It will print the same in Firefox, IE, and Chrome. You can specify the page size of a PDF, which is important when you are printing onto envelopes. If you specify the PDF as a Landscape document, It's even easy to rotate text. Best of all, I won't have to worry that some strange CSS quirk will push the address halfway off the page when Chrome silently updates to a new version. I will admit that not everyone has a PDF reader installed, but in this particular case, I could count on that being present for everyone using the site.
Since this was a simple task, I thought that one of the open source PDF libraries would work fine. The site needed to work with .NET on Windows, so I checked out a few options and settled on PDF Sharp. Below you will find the proof of concept code that I put together. When the real solution is put together the addresses will be pulled from a database and each envelope will be printed in a loop. For the demo code though, this is sufficient to show that the approach works.
using System;
using System.Data;
using System.Configuration;
using System.Collections;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Web.UI.WebControls.WebParts;
using System.Web.UI.HtmlControls;
using PdfSharp;
using PdfSharp.Drawing;
using PdfSharp.Pdf;
using PdfSharp.Pdf.IO;
using PdfSharp.Drawing.Layout;
public partial class envelope_test : System.Web.UI.Page
{
protected PdfPage getNewPage()
{
PdfPage page = new PdfPage();
XUnit pdfWidth = new XUnit(4.125, XGraphicsUnit.Inch);
XUnit pdfHeight = new XUnit(9.5, XGraphicsUnit.Inch);
page.Height = pdfHeight;
page.Width = pdfWidth;
page.Orientation = PageOrientation.Landscape;
return page;
}
protected void Page_Load(object sender, EventArgs e)
{
Response.Clear();
Response.ContentType = System.Net.Mime.MediaTypeNames.Application.Pdf;
PdfDocument document = new PdfDocument();
PdfPage page = getNewPage();
document.AddPage(page);
XGraphics gfx = XGraphics.FromPdfPage(page);
// Create a font
XFont font = new XFont("Verdana", 12);
// Draw the text
double x = page.Width.Point / 3;
double y = page.Height.Point / 2;
gfx.DrawString(@"Al Crowley", font, XBrushes.Black, new XPoint(x,y));
gfx.DrawString(@"1 Oak Ave.", font, XBrushes.Black, new XPoint(x, y + 12 * 1.5));
gfx.DrawString(@"Marmora, NJ 08223", font, XBrushes.Black, new XPoint(x, y + 12 * 3));
page = getNewPage();
document.AddPage(page);
gfx = XGraphics.FromPdfPage(page);
gfx.DrawString(@"Joe Smith", font, XBrushes.Black, new XPoint(x, y));
gfx.DrawString(@"1 Fairview Drive", font, XBrushes.Black, new XPoint(x, y + 12 * 1.5));
gfx.DrawString(@"Marmora, NJ 08223", font, XBrushes.Black, new XPoint(x, y + 12 * 3));
System.IO.MemoryStream ms = new System.IO.MemoryStream();
document.Save(ms);
Response.Clear();
Response.ContentType = "application/pdf";
Response.Cache.SetCacheability(HttpCacheability.NoCache);
Response.BinaryWrite(ms.ToArray());
Response.Flush();
ms.Close();
Response.End();
// For testing purposes, also save the file locally
document.Save(@"c:\temp\env.pdf");
}
}
Thanks for the post. Is there a way to send this directly to the printer without ever viewing the envelope? In the case where it would be a loop, if it were a large number of addresses, it would be inconvenient to have to click print for every envelope.
Posted by: Josh | December 21, 2011 at 14:51
Sorry about my previous post. A coworker was running what I thought was this code, but it turned out to be similar but a little different from a different website. I didn't notice you were creating multiple pages, which makes my comment about having to click print for every page stupid.
However, I still have a question with it. When we click print, it is by default trying to print on an 8.5" x 11" paper from our default tray. Is there a way to have it automatically choose a different tray and be expecting to print on an envelope?
Also, I would still like to know if it is possible to print an envelope directly to the printer without a preview. Even though there isn't a problem of clicking print for multiple envelopes in one job, we would like to save our users the added step of clicking print in the viewer.
Posted by: Josh | December 21, 2011 at 16:30
Josh, from a web page there isn't much you can do (that I know of) to influence the printer settings. All I can do from the server side is generate the PDF suitable for printing on envelopes. From there I hand it off to the user to hit print and get it directed to the right tray.
If you really need full control of the print job I think you would need to write a native app on the client side, or maybe a Java applet if you get the permissions right....but I'm not a Java person so take that bit with a grain of salt.
Posted by: Al Crowley | February 17, 2012 at 08:40
If you are familiar with .NET web services you understand how efficient these calls to the host are, no html web page, just the data you want returned in (often) XML format. ASP .NET allows you to build powerful data driven applications...but all that reposting to the host costs a lot of bandwidth. The XMLHttpRequest object has been around since 2000 and is found on virtually every box running a Microsoft Windows OS in use today, in addition to most modern browsers. In this example we will call an ASP .NET web service written in C# using a SOAP (Simple Object Access Protocol) envelope from a Javascript client.
Posted by: Host SEO | April 15, 2012 at 13:29
i have a web service that works fine when i call it from the local machine. however, from other machines, i get the same error as in the topic title. i am calling the web service via ajax (not atlas). when i run the ajax code in the browser on my dev machine, it works great.
Posted by: los angeles seo | May 17, 2012 at 08:31