### Bookstore

 Computer Math and Games in Pascal (preview) Lazarus Handbook

### Author Topic: (Solved) Difference between FPC and Delphi  (Read 501 times)

#### lainz

• Hero Member
• Posts: 3991
• Leandro Diaz
##### (Solved) Difference between FPC and Delphi
« on: March 05, 2021, 01:43:07 pm »
Hi, with FPC I generate the attached bitmap_string1.txt and with Delphi I generate bitmap_string2.txt.

The right output is the FPC one (bitmap_string1.txt) and the problem is in Delphi.

This is the faulty part:

I'm thinking it must be the data types or the Chr(). Any ideas on differences on Char between FPC and Delphi?

Code: Pascal  [Select][+][-]
1. function TssESCPosPrintBitmap.RenderBitmap( const ABitmapFilename: string): string;
2. var
3.   LOffset     : Integer;
4.   LX          : Integer;
5.   LSlice      : Byte;
6.   LB          : Integer;
7.   LK          : Integer;
8.   LY          : Integer;
9.   LI          : Integer;
10.   LV          : Boolean;
11.   LVI         : Integer;
12. begin
13.   // *** load the Bitmap from the file
15.   FBitmap.PixelFormat := pf24bit;
16.   // *** Convert the bitmap to an array of B/W pixels
18.   // *** Set the line spacing to 24 dots, the height of each "stripe" of the
19.   // *** image that we're drawing
20.   Result := #27'3'#24;
21.   LOffset := 0;
22.   while ( LOffset < FBitmapData.Height ) do
23.    begin
24.     Result := Result + #27;
25.     Result := Result + '*'; // Bit image mode
26.     Result := Result + #33; // 24-dot double density
27.     Result := Result + Char( Lo( FBitmapData.Width ) );
28.     Result := Result + Char( Hi( FBitmapData.Width ) );
29.     for LX := 0 to FBitmapData.Width -1 do begin
30.       for LK := 0 to 2 do begin
31.         LSlice := 0;
32.         for LB := 0 to 7 do begin
33.           LY := ( ( ( LOffset div 8 ) + LK ) * 8 ) + LB;
34.           LI := ( LY * FBitmapData.Width ) + LX;
35.           LV := False;
36.           if ( LI < Length( FBitmapData.Dots ) ) then
37.             LV := FBitmapData.Dots[LI];
38.           LVI := IfThen( LV, 1, 0 );
39.           LSlice := LSlice or ( LVI shl ( 7 - LB ) );
40.         end;
41.         Result := Result + Chr( LSlice );
42.       end;
43.     end;
44.     LOffset := LOffset + 24;
45.     Result := Result + sLineBreak;
46.    end;
47.   // *** Restore the line spacing to the default of 30 dots
48.   Result := Result + #27'3'#30 + sLineBreak + sLineBreak + sLineBreak;
49. end;

This is the full code (for Delphi):

Code: Pascal  [Select][+][-]
1. {******************************************************************************}
2. {                                                                              }
3. {  Unit: ssESCPosPrintBitmap.pas                                               }
4. {  Summerswell Core                                                            }
5. {                                                                              }
6. {  Copyright (C) 2015 Summerswell                                              }
7. {                                                                              }
8. {  Author     : bvonfintel                                                     }
9. {  Original   : 2015/01/06 11:12:30 AM                                         }
10. {                                                                              }
11. {******************************************************************************}
12. {
13.   This is based on the class provided by:
14.   http://nicholas.piasecki.name/blog/2009/12/sending-a-bit-image-to-an-epson-tm-t88iii-receipt-printer-using-c-and-escpos/
15.   The Delphi translation provided (http://nicholas.piasecki.name/blog/wp-content/uploads/2009/12/Delphi-Version.txt.txt)
16.   did not print to the Epson TM T70
17. {}
18. unit ssESCPosPrintBitmap;
19. interface
20. uses
21.  Soap.EncdDecd;
22. type
23.   // *** -------------------------------------------------------------------------
24.   // *** INTERFACE: IssESCPosPrintBitmap
25.   // *** -------------------------------------------------------------------------
26.   IssESCPosPrintBitmap = interface( IInterface )
27.     ['{3F279585-6D2E-451F-AF97-76F0E07A70DF}']
28.     function RenderBitmap( const ABitmapFilename: string ): string;
29.     function RenderBitmapBase64(const base64data: string): string;
30.   end;
31.   function _ESCPosPrintBitmap(): IssESCPosPrintBitmap;
32. implementation
33. uses
34.   Windows,
35.   Math,Classes,Graphics, SysUtils, Dialogs,System.NetEncoding;
36. type
37.   TRGBTripleArray = ARRAY[Word] of TRGBTriple;
38.   pRGBTripleArray = ^TRGBTripleArray; // Use a PByteArray for pf8bit color.
39.   // *** -------------------------------------------------------------------------
40.   // *** RECORD:  TBitmapData
41.   // *** -------------------------------------------------------------------------
42.   TBitmapData = record
43.     Dots      : array of Boolean;
44.     Height    : Integer;
45.     Width     : Integer;
46.   end;
47.   // *** -------------------------------------------------------------------------
48.   // *** CLASS: TssESCPosPrintBitmap
49.   // *** -------------------------------------------------------------------------
50.   TssESCPosPrintBitmap = class( TInterfacedObject, IssESCPosPrintBitmap )
51.     private
52.       FLumThreshold : Integer;
53.       FBitmap       : TBitmap;
54.       FBitmapData   : TBitmapData;
56.     public
57.       constructor Create();
58.       destructor Destroy; override;
59.       function RenderBitmap( const ABitmapFilename: string ): string;
60.       function RenderBitmapBase64(const base64data: string): string;
61.   end;
62. const
63.   C_DEFAULT_THRESHOLD = 127;
64. function _ESCPosPrintBitmap(): IssESCPosPrintBitmap;
65. begin
66.   Result := TssESCPosPrintBitmap.Create();
67. end;
68. { TssESCPosPrintBitmap }
69. {-------------------------------------------------------------------------------
70.   Procedure: TssESCPosPrintBitmap.Create
71.   Author:    bvonfintel
72.   DateTime:  2015.01.06
73.   Arguments: None
74.   Result:    None
75. -------------------------------------------------------------------------------}
76. constructor TssESCPosPrintBitmap.Create;
77. begin
78.   inherited;
79.   FBitmap       := TBitmap.Create();
80.   FLumThreshold := C_DEFAULT_THRESHOLD;
81. end;
82. function BitmapFromBase64(const base64: string): TBitmap;
83. var
84.   Input: TStringStream;
85.   Output: TBytesStream;
86. begin
87.   Input := TStringStream.Create(base64, TEncoding.ASCII);
88.   try
89.     Output := TBytesStream.Create;
90.     try
91.       Soap.EncdDecd.DecodeStream(Input, Output);
92.       Output.Position := 0;
93.       Result := TBitmap.Create;
94.       try
96.       except
97.         Result.Free;
98.         raise;
99.       end;
100.     finally
101.       Output.Free;
102.     end;
103.   finally
104.     Input.Free;
105.   end;
106. end;
107. {-------------------------------------------------------------------------------
108.   Procedure: TssESCPosPrintBitmap.Destroy
109.   Author:    bvonfintel
110.   DateTime:  2015.01.06
111.   Arguments: None
112.   Result:    None
113. -------------------------------------------------------------------------------}
114. destructor TssESCPosPrintBitmap.Destroy;
115. begin
116.   FBitmap.Free();
117.   inherited;
118. end;
119. {-------------------------------------------------------------------------------
121.   Author:    bvonfintel
122.   DateTime:  2015.01.06
123.   Arguments: None
124.   Result:    None
125. -------------------------------------------------------------------------------}
127. var
128.   LIndex : Integer;
129.   LX     : Integer;
130.   LY     : Integer;
131.   LLine  : pRGBTripleArray;
132.   LPixel : TRGBTriple;
133.   LLum   : Integer;
134. begin
135.   LIndex := 0;
136.   FBitmapData.Height := FBitmap.Height;
137.   FBitmapData.Width  := FBitmap.Width;
138.   SetLength( FBitmapData.Dots, FBitmap.Width * FBitmap.Height );
139.   for LY := 0 to FBitmap.Height - 1 do
140.   begin
141.     LLine := FBitmap.ScanLine[LY];
142.     for LX := 0 to FBitmap.Width - 1 do
143.     begin
144.       LPixel := LLine[LX];
145.       LLum   := Trunc( ( LPixel.rgbtRed * 0.3 ) + ( LPixel.rgbtGreen  * 0.59 ) + ( LPixel.rgbtBlue * 0.11 ) );
146.       FBitmapData.Dots[LIndex] := ( LLum < FLumThreshold );
147.       Inc( LIndex );
148.     end;
149.   end;
150. end;
151. function TssESCPosPrintBitmap.RenderBitmapBase64(const base64data: string): string;
152. var
153.   LOffset     : Integer;
154.   LX          : Integer;
155.   LSlice      : Byte;
156.   LB          : Integer;
157.   LK          : Integer;
158.   LY          : Integer;
159.   LI          : Integer;
160.   LV          : Boolean;
161.   LVI         : Integer;
162.   bmp: TBitmap;
163. begin
164.   bmp := TBitmap.Create;
165.   bmp := BitmapFromBase64(base64data);
166.   //bmp.SaveToFile('D:\PosBASE64.bmp');
167.   FBitmap:=bmp;
168.   //FBitmap.SaveToFile('D:\Pos2BASE64.bmp');
170.   Result := #27'3'#24;
171.   LOffset := 0;
172.   while ( LOffset < FBitmapData.Height ) do begin
173.     Result := Result + #27;
174.     Result := Result + '*'; // Bit image mode
175.     Result := Result + #33; // 24-dot double density
176.     Result := Result + Char( Lo( FBitmapData.Width ) );
177.     Result := Result + Char( Hi( FBitmapData.Width ) );
178.     for LX := 0 to FBitmapData.Width -1 do begin
179.       for LK := 0 to 2 do begin
180.         LSlice := 0;
181.         for LB := 0 to 7 do begin
182.           LY := ( ( ( LOffset div 8 ) + LK ) * 8 ) + LB;
183.           LI := ( LY * FBitmapData.Width ) + LX;
184.           LV := False;
185.           if ( LI < Length( FBitmapData.Dots ) ) then
186.             LV := FBitmapData.Dots[LI];
187.           LVI := IfThen( LV, 1, 0 );
188.           LSlice := LSlice or ( LVI shl ( 7 - LB ) );
189.         end;
190.         Result := Result + Chr( LSlice );
191.       end;
192.     end;
193.     LOffset := LOffset + 24;
194.     Result := Result + sLineBreak;
195.   end;
196.   // *** Restore the line spacing to the default of 30 dots
197.   Result := Result + #27'3'#30 + sLineBreak + sLineBreak + sLineBreak;
198. end;
199. {-------------------------------------------------------------------------------
200.   Procedure: TssESCPosPrintBitmap.RenderBitmap
201.   Author:    bvonfintel
202.   DateTime:  2015.01.06
203.   Arguments: const ABitmapFilename: string
204.   Result:    string
205. -------------------------------------------------------------------------------}
206. function TssESCPosPrintBitmap.RenderBitmap( const ABitmapFilename: string): string;
207. var
208.   LOffset     : Integer;
209.   LX          : Integer;
210.   LSlice      : Byte;
211.   LB          : Integer;
212.   LK          : Integer;
213.   LY          : Integer;
214.   LI          : Integer;
215.   LV          : Boolean;
216.   LVI         : Integer;
217. begin
218.   // *** load the Bitmap from the file
220.   FBitmap.PixelFormat := pf24bit;
221.   // *** Convert the bitmap to an array of B/W pixels
223.   // *** Set the line spacing to 24 dots, the height of each "stripe" of the
224.   // *** image that we're drawing
225.   Result := #27'3'#24;
226.   LOffset := 0;
227.   while ( LOffset < FBitmapData.Height ) do
228.    begin
229.     Result := Result + #27;
230.     Result := Result + '*'; // Bit image mode
231.     Result := Result + #33; // 24-dot double density
232.     Result := Result + Char( Lo( FBitmapData.Width ) );
233.     Result := Result + Char( Hi( FBitmapData.Width ) );
234.     for LX := 0 to FBitmapData.Width -1 do begin
235.       for LK := 0 to 2 do begin
236.         LSlice := 0;
237.         for LB := 0 to 7 do begin
238.           LY := ( ( ( LOffset div 8 ) + LK ) * 8 ) + LB;
239.           LI := ( LY * FBitmapData.Width ) + LX;
240.           LV := False;
241.           if ( LI < Length( FBitmapData.Dots ) ) then
242.             LV := FBitmapData.Dots[LI];
243.           LVI := IfThen( LV, 1, 0 );
244.           LSlice := LSlice or ( LVI shl ( 7 - LB ) );
245.         end;
246.         Result := Result + Chr( LSlice );
247.       end;
248.     end;
249.     LOffset := LOffset + 24;
250.     Result := Result + sLineBreak;
251.    end;
252.   // *** Restore the line spacing to the default of 30 dots
253.   Result := Result + #27'3'#30 + sLineBreak + sLineBreak + sLineBreak;
254. end;
255. end.
« Last Edit: March 05, 2021, 02:56:40 pm by lainz »
https://lainz.github.io/ - My Website

#### Bart

• Hero Member
• Posts: 4217
##### Re: Difference between FPC and Delphi
« Reply #1 on: March 05, 2021, 01:53:19 pm »
In Delphi Char = WideChar?

Bart

#### marcov

• Global Moderator
• Hero Member
• Posts: 9175
• FPC developer.
##### Re: Difference between FPC and Delphi
« Reply #2 on: March 05, 2021, 01:57:10 pm »
In D2009 char=widechar in D2007- char=ansichar.

If you mean a bytesized char, always use ansichar.

#### lainz

• Hero Member
• Posts: 3991
• Leandro Diaz
##### Re: Difference between FPC and Delphi
« Reply #3 on: March 05, 2021, 02:32:53 pm »
Thanks =)
https://lainz.github.io/ - My Website

• Hero Member
• Posts: 10716
##### Re: Difference between FPC and Delphi
« Reply #4 on: March 05, 2021, 02:35:55 pm »
In D2009 char=widechar in D2007- char=ansichar.

If you mean a bytesized char, always use ansichar.
In D2009 or higher. And D2007 or lower.
In this case there are two solutions:
1: replace the char casts to AnsiChar casts
2: use byte as you correctly remark.
This code is sloppy and needs byte....
Probably due to C'ism complex.
« Last Edit: March 05, 2021, 02:37:54 pm by Thaddy »

#### lainz

• Hero Member
• Posts: 3991
• Leandro Diaz
##### Re: Difference between FPC and Delphi
« Reply #5 on: March 05, 2021, 02:56:30 pm »
Code: Pascal  [Select][+][-]
1. Result := Result + ansichar(chr(LSlice));

Using that solves the problem.

Many thanks =)
https://lainz.github.io/ - My Website