Chris McClenny
asked on
I need a Delphi function to convert .BMP pixel data to dot matrix APA graphics.
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:
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
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;
ASKER CERTIFIED SOLUTION
membership
This solution is only available to members.
To access this solution, you must be a member of Experts Exchange.
ASKER
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:
Useage:
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;
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;
ASKER
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:
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;
ASKER
Thanks Thommy!!!!
ASKER
https://www.experts-exchange.com/questions/10100995/Printing-graphics.html