Sending Bitmap to ESC/POS lazarus / 39-Graphics ---------------------------------------------------------------------- lainz · 2019-12-26 22:50 Hi, this is the code website https://bitbucket.org/bernd_summerswell/delphi_escpos_bitmap/src/maste r/ This is the source for the class https://bitbucket.org/bernd_summerswell/delphi_escpos_bitmap/src/maste r/ssESCPosPrintBitmap.pas And this is the demo Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i uses  synaser,  ssESCPOSPrintBitmap; var  LDevice : TBlockDevice;  LBuffer : string;begin  LBuffer := #27'@'; // Initialise the printer  LBuffer := LBuffer + _ESCPosPrintBitmap().RenderBitmap( 'path\to\bitmapfile' );  LBuffer := #29'V'#1 // Paper cut full   // Send LBuffer to Printer  LDevice := TBlockSerial.Create();    try      LDevice.Config( 115200, 8, 'N', 1, False, False );      LDevice.Connect( 'COM7' );      LDevice.SendString( LBuffer  );    finally      LDevice.Free();    end;end. Anyone can confirm this works with Lazarus fine? Unfortunatelly I don't have an ESC/POS printer... There's a way I can "emulate" any ESC/POS printer to test this? ---------------------------------------------------------------------- trev · 2019-12-26 23:06 Quote from: lainz on December 26, 2019, 11:50:21 pmThere's a way I can "emulate" any ESC/POS printer to test this? Have a look at https://github.com/receipt-print-hq/escpos-tools ---------------------------------------------------------------------- winni · 2019-12-26 23:39 Hi! And if you don't want to emulate: (Brand!)new China trash available for $ 18.99 at Ebay ("Free international shipping!"). https://www.ebay.com/sch/i.html?_from=R40&_nkw=ESC%2FPOS&_sacat=0&_sop =15 No, I don't get any payment from them ... Winni ---------------------------------------------------------------------- lainz · 2019-12-26 23:49 Quote from: winni on December 27, 2019, 12:39:19 amHi! And if you don't want to emulate: (Brand!)new China trash available for $ 18.99 at Ebay ("Free international shipping!"). https://www.ebay.com/sch/i.html?_from=R40&_nkw=ESC%2FPOS&_sacat=0&_sop =15 No, I don't get any payment from them ... Winni Thanks. I imagined these was more expensive, but I get the emulator running on my system, so it will be cheaper I think  Quote from: trev on December 27, 2019, 12:06:05 amQuote from: lainz on December 26, 2019, 11:50:21 pmThere's a way I can "emulate" any ESC/POS printer to test this? Have a look at https://github.com/receipt-print-hq/escpos-tools Thanks. It works. I need a bit more of help, how I can save properly the binary file? To send it to the php program? Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i LBuffer : string;begin  LBuffer := #27'@'; // Initialise the printer  LBuffer := LBuffer + _ESCPosPrintBitmap().RenderBitmap( 'path\to\bitmapfile' );  LBuffer := #29'V'#1 // Paper cut full // Save to .bin file here---  I'm new to binary stuff... always working with high level stuff... Thanks. ---------------------------------------------------------------------- wp · 2019-12-26 23:57 Assuming that you want to save the string LBuffer to file do this: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i var  stream: TFileStream;...  stream := TFileStream.Create(FILE_NAME, fmCreate);  try    stream.Write(LBuffer[1], Length(LBuffer));  finally    stream.Free;  end; ---------------------------------------------------------------------- winni · 2019-12-27 00:17 Hi! The function TssESCPosPrintBitmap.RenderBitmap( const ABitmapFilename: string): string; converts everything into the format for the lineprinter: Put the bmp header in the beginning. Makes stripes of 24 pix height for a "24 needle printer" - old standard. And converts the bitmap.data into printer format. So there are definitly unprintable and illegal utf8-signs in the string. So take care that this bytes are not stripped or masked by some routines. I don't knoew if it happes with a FileStream. If it does I would copy the string into an array of byte and save it als a file of byte. And have a look in the Delphi code in the function TssESCPosPrintBitmap.RenderBitmap - there you can see in some lines of code how he is converting the bitmap into the line printer format. Winni ---------------------------------------------------------------------- lainz · 2019-12-27 13:29 On Delphi it works changing string with rawbytestring, but the resulting image has some artifacts, anyways it works. With the same code on Lazarus, it displays only the first say 20% of the image from left to right. On Lazarus I get these warnings ssESCPosPrintBitmap.pas(137,22) Warning: Symbol "ScanLine" is not portable ssESCPosPrintBitmap.pas(183,30) Warning: lo/hi(dword/qword) returns the upper/lower word/dword ssESCPosPrintBitmap.pas(184,30) Warning: lo/hi(dword/qword) returns the upper/lower word/dword Of course ScanLine works only on Windows. What about Lo / Hi ? It works different from Delphi or is just a warning that I can forget? ---------------------------------------------------------------------- winni · 2019-12-27 13:50 Hi! The warings about Hi/Lo leads to those two lines: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Result := Result + Char( Lo( FBitmapData.Width ) );Result := Result + Char( Hi( FBitmapData.Width ) ); They only make sense if he is using 16 bit integers - smallint. So change your integers to smallint! Winni ---------------------------------------------------------------------- lainz · 2019-12-27 13:57 Quote from: winni on December 27, 2019, 02:50:57 pmHi! The warings about Hi/Lo leads to those two lines: Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i Result := Result + Char( Lo( FBitmapData.Width ) );Result := Result + Char( Hi( FBitmapData.Width ) ); They only make sense if he is using 16 bit integers - smallint. So change your integers to smallint! Winni Thanks, it works =)    TBitmapData = record      Dots      : array of Boolean; -    Height    : Integer; -    Width     : Integer; +    Height    : smallint; +    Width     : smallint;    end; ---------------------------------------------------------------------- lainz · 2019-12-27 15:43 This is the fixed unit, using BGRABitmap to allow to load any kind of image. Transparency by default is converted to White. Tested only on Windows with the php tools of the second comment. Code: Pascal  [Select][+][-]window.onload = function(){var x1 = document.getElementById("main_content_section"); if (x1) { var x = document.getElementsByClassName("geshi");for (var i = 0; i {********** ********************************************************************}{                                                                            }{  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------------ -------------------------------------------------------------------}de structor TssESCPosPrintBitmap.Destroy;begin  FBitmap.Free();  inherite d;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:    stri ng-------------------------------------------------------------------- -----------}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.