GDI and even the abstract Windows printing model are probably not going to help you here. You're going to have to send the feed and cut command to the printer in the language that it expects to typically receive data.
For example, an Epson TM-T88III thermal receipt printer speaks the ESC/POS language natively, not a sequence of GDI or PCL commands. However, most of these printers do come with printer drivers that make Windows see them as regular GDI printers. The way these drivers typically work is that they rasterize all of the GDI commands into one big bitmap in software, and then dole out the bitmap to the printer for printing via its native-language "print the bit-image" command. This usually has less-than-desirable effects:
- It is much less efficient (in sense of time required and data transmitted) to send a lot of bitmap data to the printer than a sequence of binary commands that it knows how to interpret. (Would you rather send an image of text to print, or just the actual text and a font size specification? Analogies with HTML/CSS vs. an image of text.)
- These printers typically have low resolutions and are monochrome (that is, all black or all white, no grayscale or color). Their pre-loaded fonts are designed to work well under these limitations for crisp, clear rendering. By rasterizing to a bitmap, we lose this careful design as pixels are snapped and rounded off of the grid, resulting in jagged text rendering on the actual printout. If you're trying to draw something that's really sensitive to this kind of rounding, like a barcode, you're SOL, unless you're painstakingly keeping the DPI of the printer device context in mind while working with GDI.
For example, here is a snippet of code from an extensive example on my usually-irrelevant blog. You can see near the end how I fill the BinaryWriter
with the necessary sequence of bytes that equals the "feed paper and cut" command on our Epson thermal receipt printer (AsciiControlChars
is just a static class with constants):
using (var ms = new MemoryStream())
using (var bw = new BinaryWriter(ms))
{
// Reset the printer bws (NV images are not cleared)
bw.Write(AsciiControlChars.Escape);
bw.Write('@');
// Render the logo
RenderLogo(bw);
// Feed 3 vertical motion units and cut the paper with a 1 point cut
bw.Write(AsciiControlChars.GroupSeparator);
bw.Write('V');
bw.Write((byte)66);
bw.Write((byte)3);
bw.Flush();
return ms.ToArray();
}
You can then just send the bytes directly to the printer as a RAW document, either using the code at the end of that article, which works against various Win32 printer functions, or Microsoft's RawPrinterHelper class.
You'll need to look up the commands specific for your printer. Chances are that its not too different from the one that you see here: POS languages are beginning to standardize, but that's also like saying SQL is a standard--mutually intelligible by humans but not really interoperable without some adjustments.
If you really still want to use GDI, you can print the GDI document in the usual way to the printer (again, assuming that a GDI printer driver exists, which it probably does), and then issue a second, small, RAW document to the printer that contains the native feed and cut command. (Alternatively, some of the GDI printer drivers let you specify "always cut after printing a document" right in the Printers control panel--but good luck accessing that driver feature in a well-documented fashion programmatically!)
Hope this helps to paint a picture of GDI's relationship to POS printers.