Solved

I need a Delphi function to convert .BMP pixel data to dot matrix APA graphics.

Posted on 2012-03-27
5
1,880 Views
Last Modified: 2012-03-30
Hello...

For reference, we are using Delphi 7 for this project.

I need help with printing graphics to a 9 pin POS printer. Actually I am looking for a universal function to read in a bitmap from a file and return a stream of data in
APA(All-Points-Addressible) format so we can use it with all of our 9 pin POS printers.  
The only info I could find on the net about APA graphics format was in an old ESC/P
manual.  APA format is a vertical slice of bitmap data printed as the head moves
across the paper which is much different than the way the bitmap data is stored
in a .bmp file.  All of the bitmaps we will be sending to the printer are 1 bit black and white.  We also need the function to scale the bitmap using  x0, y0, x1, y1 arguments.

My current test printer is a Cognitive TPG-A760.
Programming Doc can be found here...
A760 Programmers Manual

If I can get it working with the A760, I can
get it working on our others.

The A760 programmers manual has a command:
      ESC (+*.BMP file)
but we can't use this since its not offered in our other printers.

We prefer to use Command:
      ESC * m n1 n2 d1...dn

Where m = 0
and n1 + (256 * n2) bytes of data
 

Here is my function so far:


function BMPtoAPA(bmp:TBitmap; x0, y0, x1, y1:Integer ): String;
var iRow,iCol:Integer;
    byteArray: array of array of byte; 
    Row:  PByteArray;
    pixel: byte;
begin
  result := '';
  
  if Not Assigned(bmp) then exit;
  
  SetLength(byteArray, bmp.Height, bmp.Width);
  
  for iRow := 0 to bmp.Height-1 do
      begin
        Row := bmp.Scanline[iRow];

        for iCol := 0 to bmp.Width - 1 do
          begin
            byteArray[iRow,iCol] := Row[iCol];

            
                
          end;

      end;

  end;
	

  
  byteArray := nil;
end;	

Open in new window

0
Comment
Question by:cmcclenny
  • 4
5 Comments
 

Author Comment

by:cmcclenny
ID: 37773730
I just came across this question that is very similar:
http://www.experts-exchange.com/Programming/Languages/C/Q_10100995.html
0
 
LVL 19

Accepted Solution

by:
Thommy earned 500 total points
ID: 37775267
This technical white paper describes principles of bitmap dot matrix printing and also the procedure of converting a bitmap to directly send it to the printer.
Sending a bit image to an Epson TM-T88III receipt printer using C# and ESC/POS

Description is for an EPSON printer and C# as programming language, but I think it will help you with your problem anyhow...
0
 

Author Comment

by:cmcclenny
ID: 37784129
Thanks for the info Thommy. That was a huge help.  I used that blog to translate it into delphi but I seem to be getting gibberish instead of a bitmap printed out.  I think maybe I am missing something in my translation?   If anyone knows, I would appreciate the help.



Code Translation:


function BitmapToAPAGraphics(const bmp:TBitmap;
                              const RowHeightEscapeStr:String;
                              const SliceEscapeStr:String;
                              const PrintHeadPinCount:byte = 9):String;

const threshhold = 127;
      CRLF = #13#10;
TYPE
    TRGB32 = packed record
        B, G, R, A: Byte;
     end;

    TRGB32Array = packed array[0..MaxInt div SizeOf(TRGB32)-1] of TRGB32;
    PRGB32Array = ^TRGB32Array;
    TBitArray = array of boolean;
var
    iCol,iRow,index, sliceIndex, bytePos, bitPos, offset,luminance: integer;
    Line: PRGB32Array;
    Pixel: TRGB32;
    tmpFile: TextFile;

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

begin
  result := '';


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



  try

    bmp.PixelFormat := pf1bit;

    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.R * 0.3) + (Pixel.G * 0.59) + (Pixel.B * 0.11));
            dots[index] := (luminance < threshhold);

            inc(index);
          end;
      end;


    offset := 0;

    //Convert pin count to Count of bytes in each slice
    bytesPerSlice := (PrintHeadPinCount div 8);

    //if there is a remainder, we need another byte added (9 pin is 2 bytes, etc...)
    if PrintHeadPinCount 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; //end for bit := 0 to 7 do

                result := result + chr(slice);
             
             end; //end for sliceIndex := 0 to bytesPerSlice -1 do 
          end; //end for iCol := 0 to bmp.Width-1 do

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

        result := result + CRLF;
     
     end;  //end while offset < bmp.Height do

  finally
     dots := nil;
  end;


end;

Open in new window



Useage:
    function PrintBitmap: Boolean
    var prnBuffer, RowHeightEscapeStr, SliceEscapeStr :String; 
          nL, nH: byte;  
          myBMP :TBitmap;
    begin
         myBMP := TBitmap.create;
         
         try
             myBMP.LoadFromFile('someBitmap.bmp');
 
             RowHeightEscapeStr := #27+#51+#9; // 1b 3 <n>   Line Height

             nL := (myBMP.Width + 1) div 256;
             nH := (myBMP.Width + 1) mod 256;
             SliceEscapeStr := #27+#42+#48 + chr(nL)+ chr(nH);   // 1b * 0 nL nH 

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

        finally
            myBMP.Free;
        end;

       //***** send prnBuffer to printer here...

      end;

Open in new window

0
 

Author Comment

by:cmcclenny
ID: 37789413
Its been a long time since I have dug through hardware code. I finally got it working thanks to Thommy.  i am posting my final code below. Hope this helps others out there.

Thanks Thommy!!


Final Translation:
function TGlobals.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;

Open in new window

0
 

Author Closing Comment

by:cmcclenny
ID: 37789415
Thanks Thommy!!!!
0

Featured Post

Live: Real-Time Solutions, Start Here

Receive instant 1:1 support from technology experts, using our real-time conversation and whiteboard interface. Your first 5 minutes are always free.

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Hello everybody This Article will show you how to validate number with TEdit control, What's the TEdit control? TEdit is a standard Windows edit control on a form, it allows to user to write, read and copy/paste single line of text. Usua…
Article by: Nadia
Suppose you use Uber application as a rider and you request a ride to go from one place to another. Your driver just arrived at the parking lot of your place. The only thing you know about the ride is the license plate number. How do you find your U…
Along with being a a promotional video for my three-day Annielytics Dashboard Seminor, this Micro Tutorial is an intro to Google Analytics API data.
Microsoft Active Directory, the widely used IT infrastructure, is known for its high risk of credential theft. The best way to test your Active Directory’s vulnerabilities to pass-the-ticket, pass-the-hash, privilege escalation, and malware attacks …

776 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question