Solved

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

Posted on 2012-03-27
5
1,830 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

Highfive + Dolby Voice = No More Audio Complaints!

Poor audio quality is one of the top reasons people don’t use video conferencing. Get the crispest, clearest audio powered by Dolby Voice in every meeting. Highfive and Dolby Voice deliver the best video conferencing and audio experience for every meeting and every room.

Join & Write a Comment

Suggested Solutions

In this tutorial I will show you how to use the Windows Speech API in Delphi. I will only cover basic functions such as text to speech and controlling the speed of the speech. SAPI Installation First you need to install the SAPI type library, th…
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…
It is a freely distributed piece of software for such tasks as photo retouching, image composition and image authoring. It works on many operating systems, in many languages.
This video explains how to create simple products associated to Magento configurable product and offers fast way of their generation with Store Manager for Magento tool.

744 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

Need Help in Real-Time?

Connect with top rated Experts

15 Experts available now in Live!

Get 1:1 Help Now