{******************************************************************************}
{ }
{ Unit: ssESCPosPrintBitmap.pas }
{ Summerswell Core }
{ }
{ Copyright (C) 2015 Summerswell, 2019 Lainz }
{ }
{ Author : bvonfintel }
{ Original : 2015/01/06 11:12:30 AM }
{ Modified : 2019/12/27 12:38:00 AM }
{ }
{******************************************************************************}
{
This is based on the class provided by:
http://nicholas.piasecki.name/blog/2009/12/sending-a-bit-image-to-an-epson-tm-t88iii-receipt-printer-using-c-and-escpos/
The Delphi translation provided (http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/Delphi-Version.txt.txt)
did not print to the Epson TM T70
Updated to use BGRABitmap Library and working with Lazarus by Lainz
}
unit ssESCPosPrintBitmap;
{$MODE Delphi}
interface
type
// *** -------------------------------------------------------------------------
// *** INTERFACE: IssESCPosPrintBitmap
// *** -------------------------------------------------------------------------
{ IssESCPosPrintBitmap }
IssESCPosPrintBitmap = interface( IInterface )
['{3F279585-6D2E-451F-AF97-76F0E07A70DF}']
function RenderBitmap( const ABitmapFilename: string ): rawbytestring;
function RenderBitmapBase64(const base64data: string): rawbytestring;
end;
function _ESCPosPrintBitmap(): IssESCPosPrintBitmap;
implementation
uses
LCLIntf, LCLType, {LMessages,}
Graphics,
Math,
BGRABitmap, BGRABitmapTypes, base64, Classes, SysUtils, Dialogs;
function Base64ToStream(const ABase64: String; var AStream: TMemoryStream): Boolean;
var
Str: TStringStream;
begin
Result := False;
if Length(Trim(ABase64)) = 0 then
Exit;
try
Str := TStringStream.Create(DecodeStringBase64(ABase64));
try
AStream.CopyFrom(Str, Str.Size);
AStream.Position := 0;
finally
Str.Free;
end;
Result := True;
except
on E: Exception do
ShowMessage(E.Message);
end;
end;
function StreamToBase64(const AStream: TMemoryStream; out Base64: String): Boolean;
var
Str: String = '';
begin
Result := False;
if AStream.Size = 0 then
Exit;
AStream.Position := 0;
try
SetLength(Str, AStream.Size div SizeOf(Char));
AStream.ReadBuffer(Pointer(Str)^, AStream.Size div SizeOf(Char));
Base64 := EncodeStringBase64(Str);
Result := True;
except
{on E: Exception do
ShowMessage(E.Message);}
end;
end;
type
// *** -------------------------------------------------------------------------
// *** RECORD: TBitmapData
// *** -------------------------------------------------------------------------
TBitmapData = record
Dots : array of Boolean;
Height : smallint;
Width : smallint;
end;
// *** -------------------------------------------------------------------------
// *** CLASS: TssESCPosPrintBitmap
// *** -------------------------------------------------------------------------
{ TssESCPosPrintBitmap }
TssESCPosPrintBitmap = class( TInterfacedObject, IssESCPosPrintBitmap )
private
FLumThreshold : Integer;
FBitmap : TBGRABitmap;
FBitmapData : TBitmapData;
procedure LoadBitmapData();
public
constructor Create();
destructor Destroy; override;
function RenderBitmap( const ABitmapFilename: string ): rawbytestring;
function RenderBitmapBase64(const base64data: string): rawbytestring;
end;
const
C_DEFAULT_THRESHOLD = 127;
function _ESCPosPrintBitmap(): IssESCPosPrintBitmap;
begin
Result := TssESCPosPrintBitmap.Create();
end;
{ TssESCPosPrintBitmap }
{-------------------------------------------------------------------------------
Procedure: TssESCPosPrintBitmap.Create
Author: bvonfintel - lainz
DateTime: 2015.01.06 - 2019.12.27
Arguments: None
Result: None
-------------------------------------------------------------------------------}
constructor TssESCPosPrintBitmap.Create();
begin
inherited;
FBitmap := TBGRABitmap.Create();
FLumThreshold := C_DEFAULT_THRESHOLD;
end;
{-------------------------------------------------------------------------------
Procedure: TssESCPosPrintBitmap.Destroy
Author: bvonfintel - lainz
DateTime: 2015.01.06 - 2019.12.27
Arguments: None
Result: None
-------------------------------------------------------------------------------}
destructor TssESCPosPrintBitmap.Destroy;
begin
FBitmap.Free();
inherited;
end;
{-------------------------------------------------------------------------------
Procedure: TssESCPosPrintBitmap.LoadBitmapData
Author: bvonfintel - lainz
DateTime: 2015.01.06 - 2019.12.27
Arguments: None
Result: None
-------------------------------------------------------------------------------}
procedure TssESCPosPrintBitmap.LoadBitmapData();
var
i: integer;
p: PBGRAPixel;
LIndex : Integer;
LLum : Integer;
begin
LIndex := 0;
FBitmapData.Height := FBitmap.Height;
FBitmapData.Width := FBitmap.Width;
SetLength( FBitmapData.Dots, FBitmap.Width * FBitmap.Height );
FBitmap.VerticalFlip;
FBitmap.ReplaceTransparent(BGRAWhite);
p := FBitmap.Data;
for i := 0 to FBitmap.NBPixels - 1 do
begin
LLum := Trunc( ( p^.red * 0.3 ) + ( p^.green * 0.59 ) + ( p^.blue * 0.11 ) );
FBitmapData.Dots[LIndex] := ( LLum < FLumThreshold );
Inc(LIndex);
Inc(p);
end;
end;
{-------------------------------------------------------------------------------
Procedure: TssESCPosPrintBitmap.RenderBitmap
Author: bvonfintel
DateTime: 2015.01.06
Arguments: const ABitmapFilename: string
Result: string
-------------------------------------------------------------------------------}
function TssESCPosPrintBitmap.RenderBitmap( const ABitmapFilename: string): rawbytestring;
var
LOffset : Integer;
LX : Integer;
LSlice : Byte;
LB : Integer;
LK : Integer;
LY : Integer;
LI : Integer;
LV : Boolean;
LVI : Integer;
begin
// *** load the Bitmap from the file
FBitmap.LoadFromFile( ABitmapFilename );
// *** Convert the bitmap to an array of B/W pixels
LoadBitmapData();
// *** Set the line spacing to 24 dots, the height of each "stripe" of the
// *** image that we're drawing
Result := #27'3'#24;
LOffset := 0;
while ( LOffset < FBitmapData.Height ) do begin
Result := Result + #27;
Result := Result + '*'; // Bit image mode
Result := Result + #33; // 24-dot double density
Result := Result + Char( Lo( FBitmapData.Width ) );
Result := Result + Char( Hi( FBitmapData.Width ) );
for LX := 0 to FBitmapData.Width -1 do begin
for LK := 0 to 2 do begin
LSlice := 0;
for LB := 0 to 7 do begin
LY := ( ( ( LOffset div 8 ) + LK ) * 8 ) + LB;
LI := ( LY * FBitmapData.Width ) + LX;
LV := False;
if ( LI < Length( FBitmapData.Dots ) ) then
LV := FBitmapData.Dots[LI];
LVI := IfThen( LV, 1, 0 );
LSlice := LSlice or ( LVI shl ( 7 - LB ) );
end;
Result := Result + Chr( LSlice );
end;
end;
LOffset := LOffset + 24;
Result := Result + sLineBreak;
end;
// *** Restore the line spacing to the default of 30 dots
Result := Result + #27'3'#30 + sLineBreak + sLineBreak + sLineBreak;
end;
function TssESCPosPrintBitmap.RenderBitmapBase64(const base64data: string
): rawbytestring;
var
LOffset : Integer;
LX : Integer;
LSlice : Byte;
LB : Integer;
LK : Integer;
LY : Integer;
LI : Integer;
LV : Boolean;
LVI : Integer;
var
Stream: TMemoryStream;
begin
// *** load the Bitmap from the base64
Stream := TMemoryStream.Create;
try
if Base64ToStream(base64data.Replace('data:image/png;base64,', ''), Stream) then
FBitmap.LoadFromStream(Stream);
finally
Stream.Free;
end;
// *** Convert the bitmap to an array of B/W pixels
LoadBitmapData();
// *** Set the line spacing to 24 dots, the height of each "stripe" of the
// *** image that we're drawing
Result := #27'3'#24;
LOffset := 0;
while ( LOffset < FBitmapData.Height ) do begin
Result := Result + #27;
Result := Result + '*'; // Bit image mode
Result := Result + #33; // 24-dot double density
Result := Result + Char( Lo( FBitmapData.Width ) );
Result := Result + Char( Hi( FBitmapData.Width ) );
for LX := 0 to FBitmapData.Width -1 do begin
for LK := 0 to 2 do begin
LSlice := 0;
for LB := 0 to 7 do begin
LY := ( ( ( LOffset div 8 ) + LK ) * 8 ) + LB;
LI := ( LY * FBitmapData.Width ) + LX;
LV := False;
if ( LI < Length( FBitmapData.Dots ) ) then
LV := FBitmapData.Dots[LI];
LVI := IfThen( LV, 1, 0 );
LSlice := LSlice or ( LVI shl ( 7 - LB ) );
end;
Result := Result + Chr( LSlice );
end;
end;
LOffset := LOffset + 24;
Result := Result + sLineBreak;
end;
// *** Restore the line spacing to the default of 30 dots
Result := Result + #27'3'#30 + sLineBreak + sLineBreak + sLineBreak;
end;
end.