• Home
  • About
  • Site Rules
squashbrain
/little bytes of fun/
Menu
  • Home
  • About
  • Site Rules
Home  /  "How To" Guides • Articles • Delphi • Misc • Snippets  /  EPOS – ESC/P Printing graphics to receipt printers
18 October 2013

EPOS – ESC/P Printing graphics to receipt printers

Written by Chris McClenny
"How To" Guides, Articles, Delphi, Misc, Snippets 13 Comments

Here is a way to print graphics to an EPOS receipt printer using APA(All Points Addressable) format.  When printing to one of these little receipt printers, you could always use a windows driver which lets windows see it as standard GDI printer and therefore send graphics as a bitmap to the printer from any windows program.  This works but its extremely slow.  A 24dpi printer will take a long time to print a big bitmap image.

The ultimate way to send a bitmap to the printer is by using ESC/P commands  and building vertical segment slices in code and sending these to the printer.  It’s extremely fast.  There is some work involved in understanding how this is done.  The coding is not that complicated, however, if you don’t have a grasp of how these dot matrix printers handle bitmap image slices, you will have a tough time. So lets get started by showing you how these printers deal with graphics slices.

I was working on a project which uses either a “Ithaca Series 90 plus” or a “Cognitive TPG-A760” receipt printer to print a signature at the bottom of the receipts.  I opened both programming books and found generally the same graphics format.

Ithaca APA graphics command format:

APAGraphics

Cognitive TPG APA graphics command format:

APAGraphics_TPG_large

Well sure, that makes perfect sense.  It looks like I send [1B + 2A] to activate graphics mode then send [33] to select 24-dot double density then [n1 n2??????]. What?  Nowhere is this explained very well.  The bit layout at the bottom does a great job of explaining the layout of each slice, but what about n1..n2?  I assume that d1..d2 is the data.  so n1..n2 must be size of the data in some way.   It is quite confusing and terribly written but if you study the formula given for 8 dot mode, it starts to make, well, no sense at all.

As it turns out, the best explanation I have ever read that explains this so well, which is also the inspiration for creating this Delphi Snippet, is Nicholas Piasecki’s blog. (<- Nicholas took his site down so the link is dead)

And here is the snippet:

function BitmapToAPAGraphics(const bmp:TBitmap;
                                      const RowHeightEscapeStr:String;
                                      const SliceEscapeStr:String;
                                      const BitsPerSlice:byte = 8):String;
const threshhold = 127;
      CR = #13;
      LF = #10;
TYPE
    TBitArray = array of boolean;

    TRGBTripleArray = ARRAY[Word] of TRGBTriple;
    pRGBTripleArray = ^TRGBTripleArray; // Use a PByteArray for pf8bit color.
var
    iCol,iRow,index, sliceIndex, bytePos, bitPos, offset,luminance: integer;
    line: pRGBTripleArray;
    Pixel: TRGBTriple;
    tmpFile: TextFile;

    dots: TBitArray;
    slice,bit,tmpBit,bytesPerSlice, hold: byte;
    bVal: Boolean;

    p:pRGBTripleArray;
begin
  result := '';

  if not Assigned(bmp) then exit;
  if SliceEscapeStr = '' then exit;

  try
    bmp.PixelFormat := pf24bit;

    SetLength(dots, (bmp.Height * bmp.Width));

    index := 0;

    //1) Loop the bitmap scanlines and build a bitArray from each pixel
    for iRow := 0 to bmp.Height-1 do
      begin
        line := bmp.Scanline[iRow];

        for iCol := 0 to bmp.Width-1 do
          begin
            Pixel := line[iCol];
            luminance := Trunc((Pixel.rgbtRed * 0.3) + (Pixel.rgbtGreen * 0.59) + (Pixel.rgbtBlue * 0.11));
            dots[index] := (luminance < threshhold);
            inc(index);
          end;

      end;

    offset := 0;

    //Convert BitsPerSlice to byte count in each slice
    bytesPerSlice := (BitsPerSlice div 8);

    //if there is a remainder, we need another byte added (9 bits is 2 bytes, etc...)
    if BitsPerSlice mod 8 > 0 then
      inc(bytesPerSlice);

    result := result + RowHeightEscapeStr;

    //Loop height steping down by offset
    while offset < bmp.Height do
      begin

        result := result + SliceEscapeStr;

        //Loop width of bitmap
        for iCol := 0 to bmp.Width-1 do
          begin

            //Loop each byte from current slice
            for sliceIndex := 0 to bytesPerSlice -1 do
              begin
                slice := 0;

                //Loop each bit from current byte from current slice
                for bit := 0 to 7 do
                  begin
                    bytePos := (((offset div 8) + sliceIndex) * 8) + bit;
                    bitPos := (bytePos * bmp.Width) + iCol;

                    bVal := FALSE;
                    if bitPos < Length(dots) then
                      bVal := dots[bitPos];

                    //Delphi has no ternary operator so we have to compensate
                    if (bVal) then
                      tmpBit := 1
                    else
                      tmpBit := 0;

                    slice := slice or (tmpBit shl (7 - bit));

                  end;

                result := result + chr(slice);
              end;
          end;

        //Step down to next slice
        inc(offset,BitsPerSlice);

        result := result + CR+LF;

      end;

  finally
     dots := nil;
  end;

end;

Example:

function PrintBitmap(bitmapFileName:String):Boolean;
var RowHeightEscapeStr,SliceEscapeStr, prnBuffer:String;
    myBmp:TBitmap;
    nL, nH: Byte;
begin
  if FileExists(bitmapFileName) then
    begin
      myBMP := TBitmap.create;
      try
         myBMP.LoadFromFile(bitmapFileName);
         RowHeightEscapeStr := #27+#49; 

         nH := Hi(myBMP.Width);
         nL := Lo(myBMP.Width);

         SliceEscapeStr := #27+#42+#50 + chr(nL)+ chr(nH);  

         prnBuffer := prnBuffer + #13+  BitmapToAPAGraphics(myBMP,RowHeightEscapeStr,SliceEscapeStr,8);

      finally 
        myBMP.Free;
      end;
   end;
 end;

Chris McClenny

 Previous Article Run Android JellyBean 4.2 on Windows
Next Article   AES-256 GCM + Golang

Related Posts

  • AES-256 GCM + Golang

    February 14, 2023
  • Run Android JellyBean 4.2 on Windows

    August 6, 2013

13 Comments

  1. Les Reply
    October 30, 2013 at 9:14 pm

    This can also be done using the “GS v 0” ESC/POS command which is simpler to use and the image quality looks a little better.

    • Chris McClenny Reply
      October 30, 2013 at 9:21 pm

      Hi Les,
      Thanks for the connection on LinkedIn by the way!

      I have never used that specific command myself. I don’t even remember seeing that one in the programming manual as being supported by the TPGA760 that we were using at the time. I will definitely check it out and thanks for the tip. You are the hardware expert(per your credentials on LinkedIn). I will check this in the manual in the morning and report back.

      Thanks again.

  2. yoko-id Reply
    May 21, 2014 at 11:17 pm

    Hiii… Can you Share For Full Project..?

    • Chris McClenny Reply
      May 22, 2014 at 8:59 am

      Hi,
      Do you mean you would like to get a full working Delphi project using this EPOS code?

      Thanks!

  3. yoko-id Reply
    May 23, 2014 at 2:52 am

    yes, I tried to make a Delphi project with sample code, but it still does not work perfectly. algorithm seems a little different from the http://nicholas.piasecki.name/blog/2009/12/sending-a-bit-image-to-an-epson-tm-t88iii-receipt-printer-using-c-and-escpos/

  4. Kim Jensen Reply
    July 14, 2016 at 2:11 pm

    I have tried this code in D2007 and XE6 (change the Strings to AnsiString) but I only get all kind of weird characters.
    Did you ever get it to work?
    Kim

    • Chris McClenny Reply
      July 24, 2016 at 11:17 pm

      Hi Kim,
      Unfortunately, shortly after writing this post, I moved on to another company and I no longer have access to the POS printers from my previous employer. The code as written worked perfectly on the printers mentioned in the post and is still in use by that company today. If your printer is a 9-pin and supports ESC/P commands, it should work. I should have mwentioned in the post that it was written in Delphi 2010.

  5. Hendrik Steyn Reply
    September 21, 2016 at 2:32 am

    Very good explanation here:

    http://new-grumpy-mentat.blogspot.co.za/2014/06/java-escpos-image-printing.html

    It is a JAVA example, but it is very well explained and easy to follow.

  6. Ricardo Filho Reply
    February 5, 2017 at 6:46 am

    I would like to know if I would have this same example, working for delphi firemonkey?

    • Chris McClenny Reply
      July 2, 2017 at 8:40 pm

      Hi Ricardo,
      I haven’t updated the code in a while. I will try and get my hands on another printer for some update testing.

      Thanks

  7. Dan Reply
    November 29, 2017 at 8:24 am

    Hi Chris,

    Thanks for this article, it was really helpful when I put together my “thermal printer photo both” project: https://trandi.wordpress.com/2017/11/29/receipts-printer-photo-booth/

    I’m using Haskell to control the printer, but nonetheless, your post and others helped me make sense of the POS documentation… 🙂

    Thanks,
    Dan

  8. Dan Reply
    November 29, 2017 at 4:26 pm

    Hi Chris,

    I know it’s old, but this article was still one of the ones that helped me the most in coming up with a Haskell version of this code for my Raspberry Pi “photo booth” project : https://trandi.wordpress.com/2017/11/29/receipts-printer-photo-booth/

    So thanks !
    Dan

    • Chris McClenny Reply
      November 29, 2017 at 10:35 pm

      Thanks Dan. I went to your link. Very clever and interesting stuff. Glad my post helped you out.

Leave a Reply Cancel reply

This site uses Akismet to reduce spam. Learn how your comment data is processed.

Recent Posts

  • AES-256 GCM + Golang
  • EPOS – ESC/P Printing graphics to receipt printers
  • Run Android JellyBean 4.2 on Windows
  • Software Development tools

Archives

  • February 2023
  • October 2013
  • August 2013
  • August 2012

Categories

  • "How To" Guides
  • Articles
  • Coders Corner
  • Delphi
  • Misc
  • Snippets
© Copyright 2014. Theme by BloomPixel.