1 | unit BGRATypewriter;
|
---|
2 |
|
---|
3 | {$mode objfpc}{$H+}
|
---|
4 |
|
---|
5 | interface
|
---|
6 |
|
---|
7 | uses
|
---|
8 | Classes, SysUtils, AvgLvlTree, BGRABitmapTypes, BGRACanvas2D, BGRATransform;
|
---|
9 |
|
---|
10 | type
|
---|
11 | TGlyphBoxes = array of record
|
---|
12 | Glyph: string;
|
---|
13 | Box: TAffineBox;
|
---|
14 | end;
|
---|
15 |
|
---|
16 | { TBGRAGlyph }
|
---|
17 |
|
---|
18 | TBGRAGlyph = class
|
---|
19 | protected
|
---|
20 | FIdentifier: string;
|
---|
21 | procedure WriteHeader(AStream: TStream; AName: string; AContentSize: longint);
|
---|
22 | class procedure ReadHeader(AStream: TStream; out AName: string; out AContentSize: longint);
|
---|
23 | function ContentSize: integer; virtual;
|
---|
24 | function HeaderName: string; virtual;
|
---|
25 | procedure WriteContent(AStream: TStream); virtual;
|
---|
26 | procedure ReadContent(AStream: TStream); virtual;
|
---|
27 | public
|
---|
28 | Width,Height: single;
|
---|
29 | constructor Create(AIdentifier: string); virtual;
|
---|
30 | constructor Create(AStream: TStream); virtual;
|
---|
31 | procedure Path({%H-}ADest: IBGRAPath; {%H-}AMatrix: TAffineMatrix); virtual;
|
---|
32 | property Identifier: string read FIdentifier;
|
---|
33 | procedure SaveToStream(AStream: TStream);
|
---|
34 | class function LoadFromStream(AStream: TStream): TBGRAGlyph;
|
---|
35 | end;
|
---|
36 |
|
---|
37 | TGlyphPointCurveMode= TEasyBezierCurveMode;
|
---|
38 |
|
---|
39 | const
|
---|
40 | cmAuto = TEasyBezierCurveMode.cmAuto;
|
---|
41 | cmCurve = TEasyBezierCurveMode.cmCurve;
|
---|
42 | cmAngle = TEasyBezierCurveMode.cmAngle;
|
---|
43 |
|
---|
44 | type
|
---|
45 | { TBGRAPolygonalGlyph }
|
---|
46 |
|
---|
47 | TBGRAPolygonalGlyph = class(TBGRAGlyph)
|
---|
48 | private
|
---|
49 | function GetClosed: boolean;
|
---|
50 | function GetMinimumDotProduct: single;
|
---|
51 | function GetPoint(AIndex: integer): TPointF;
|
---|
52 | function GetPointCount: integer;
|
---|
53 | procedure SetClosed(AValue: boolean);
|
---|
54 | procedure SetMinimumDotProduct(AValue: single);
|
---|
55 | procedure SetPoint(AIndex: integer; AValue: TPointF);
|
---|
56 | procedure SetQuadraticCurves(AValue: boolean);
|
---|
57 | protected
|
---|
58 | FQuadraticCurves: boolean;
|
---|
59 | FEasyBezier: TEasyBezierCurve;
|
---|
60 | function ContentSize: integer; override;
|
---|
61 | function HeaderName: string; override;
|
---|
62 | procedure WriteContent(AStream: TStream); override;
|
---|
63 | procedure ReadContent(AStream: TStream); override;
|
---|
64 | function PointTransformMatrix(APoint: PPointF; AData: pointer): TPointF;
|
---|
65 | procedure Init;
|
---|
66 | public
|
---|
67 | Offset: TPointF;
|
---|
68 | constructor Create(AIdentifier: string); override;
|
---|
69 | constructor Create(AStream: TStream); override;
|
---|
70 | constructor Create(AStream: TStream; AQuadratic: boolean);
|
---|
71 | procedure SetPoints(const APoints: array of TPointF); overload;
|
---|
72 | procedure SetPoints(const APoints: array of TPointF; const ACurveMode: array of TGlyphPointCurveMode); overload;
|
---|
73 | procedure Path(ADest: IBGRAPath; AMatrix: TAffineMatrix); override;
|
---|
74 | property QuadraticCurves: boolean read FQuadraticCurves write SetQuadraticCurves;
|
---|
75 | property Closed: boolean read GetClosed write SetClosed;
|
---|
76 | property MinimumDotProduct: single read GetMinimumDotProduct write SetMinimumDotProduct;
|
---|
77 | property Point[AIndex: integer]: TPointF read GetPoint write SetPoint;
|
---|
78 | property PointCount: integer read GetPointCount;
|
---|
79 | end;
|
---|
80 |
|
---|
81 | TBGRACustomTypeWriterHeader = record
|
---|
82 | HeaderName: String;
|
---|
83 | NbGlyphs: integer;
|
---|
84 | end;
|
---|
85 |
|
---|
86 | { TBGRACustomTypeWriter }
|
---|
87 |
|
---|
88 | TBGRACustomTypeWriter = class
|
---|
89 | private
|
---|
90 | FGlyphs: TAvgLvlTree;
|
---|
91 | protected
|
---|
92 | TypeWriterMatrix: TAffineMatrix;
|
---|
93 | function CompareGlyph({%H-}Tree: TAvgLvlTree; Data1, Data2: Pointer): integer;
|
---|
94 | function FindGlyph(AIdentifier: string): TAvgLvlTreeNode;
|
---|
95 | function GetGlyph(AIdentifier: string): TBGRAGlyph; virtual;
|
---|
96 | procedure SetGlyph(AIdentifier: string; AValue: TBGRAGlyph);
|
---|
97 | procedure TextPath(ADest: TBGRACanvas2D; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment; ADrawEachChar: boolean);
|
---|
98 | procedure GlyphPath(ADest: TBGRACanvas2D; AIdentifier: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft);
|
---|
99 | procedure DrawLastPath(ADest: TBGRACanvas2D);
|
---|
100 | procedure ClearGlyphs;
|
---|
101 | procedure RemoveGlyph(AIdentifier: string);
|
---|
102 | procedure AddGlyph(AGlyph: TBGRAGlyph);
|
---|
103 | function GetGlyphMatrix(AGlyph: TBGRAGlyph; X,Y: Single; AAlign: TBGRATypeWriterAlignment): TAffineMatrix;
|
---|
104 | function GetTextMatrix(ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment): TAffineMatrix;
|
---|
105 | property Glyph[AIdentifier: string]: TBGRAGlyph read GetGlyph write SetGlyph;
|
---|
106 | function CustomHeaderSize: integer; virtual;
|
---|
107 | procedure WriteCustomHeader(AStream: TStream); virtual;
|
---|
108 | function ReadCustomTypeWriterHeader(AStream: TStream): TBGRACustomTypeWriterHeader;
|
---|
109 | procedure ReadAdditionalHeader({%H-}AStream: TStream); virtual;
|
---|
110 | function HeaderName: string; virtual;
|
---|
111 | public
|
---|
112 | OutlineMode: TBGRATypeWriterOutlineMode;
|
---|
113 | DrawGlyphsSimultaneously : boolean;
|
---|
114 | constructor Create;
|
---|
115 | procedure SaveGlyphsToFile(AFilenameUTF8: string);
|
---|
116 | procedure SaveGlyphsToStream(AStream: TStream);
|
---|
117 | procedure LoadGlyphsFromFile(AFilenameUTF8: string);
|
---|
118 | procedure LoadGlyphsFromStream(AStream: TStream);
|
---|
119 | procedure DrawGlyph(ADest: TBGRACanvas2D; AIdentifier: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft);
|
---|
120 | procedure DrawText(ADest: TBGRACanvas2D; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); virtual;
|
---|
121 | procedure CopyTextPathTo(ADest: IBGRAPath; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); virtual;
|
---|
122 | function GetGlyphBox(AIdentifier: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TAffineBox;
|
---|
123 | function GetTextBox(ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TAffineBox;
|
---|
124 | function GetTextGlyphBoxes(ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TGlyphBoxes;
|
---|
125 | procedure NeedGlyphRange(AUnicodeFrom, AUnicodeTo: Cardinal);
|
---|
126 | procedure NeedGlyphAnsiRange;
|
---|
127 | destructor Destroy; override;
|
---|
128 | end;
|
---|
129 |
|
---|
130 | function ComputeEasyBezier(APoints: array of TPointF; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF; overload;
|
---|
131 | function ComputeEasyBezier(APoints: array of TPointF; ACurveMode: array of TGlyphPointCurveMode; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF; overload;
|
---|
132 |
|
---|
133 | implementation
|
---|
134 |
|
---|
135 | uses BGRAUTF8;
|
---|
136 |
|
---|
137 | procedure LEWritePointF(Stream: TStream; AValue: TPointF);
|
---|
138 | begin
|
---|
139 | LEWriteSingle(Stream,AValue.x);
|
---|
140 | LEWriteSingle(Stream,AValue.y);
|
---|
141 | end;
|
---|
142 |
|
---|
143 | function LEReadPointF(Stream: TStream): TPointF;
|
---|
144 | begin
|
---|
145 | result.x := LEReadSingle(Stream);
|
---|
146 | result.y := LEReadSingle(Stream);
|
---|
147 | end;
|
---|
148 |
|
---|
149 | function ComputeEasyBezier(APoints: array of TPointF; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF;
|
---|
150 | var
|
---|
151 | glyph: TBGRAPolygonalGlyph;
|
---|
152 | canvas2D: TBGRACanvas2D;
|
---|
153 | i: integer;
|
---|
154 | begin
|
---|
155 | if length(APoints) <= 2 then
|
---|
156 | begin
|
---|
157 | setlength(result, length(APoints));
|
---|
158 | for i := 0 to high(result) do
|
---|
159 | result[i] := APoints[i];
|
---|
160 | exit;
|
---|
161 | end;
|
---|
162 | glyph := TBGRAPolygonalGlyph.Create('');
|
---|
163 | glyph.QuadraticCurves := true;
|
---|
164 | glyph.Closed:= AClosed;
|
---|
165 | glyph.MinimumDotProduct := AMinimumDotProduct;
|
---|
166 | glyph.SetPoints(APoints);
|
---|
167 | canvas2D := TBGRACanvas2D.Create(nil);
|
---|
168 | canvas2D.pixelCenteredCoordinates := true;
|
---|
169 | glyph.Path(canvas2D,AffineMatrixIdentity);
|
---|
170 | glyph.Free;
|
---|
171 | result := canvas2D.currentPath;
|
---|
172 | canvas2D.free;
|
---|
173 | end;
|
---|
174 |
|
---|
175 | function ComputeEasyBezier(APoints: array of TPointF;
|
---|
176 | ACurveMode: array of TGlyphPointCurveMode; AClosed: boolean;
|
---|
177 | AMinimumDotProduct: single): ArrayOfTPointF;
|
---|
178 | var
|
---|
179 | glyph: TBGRAPolygonalGlyph;
|
---|
180 | canvas2D: TBGRACanvas2D;
|
---|
181 | i: integer;
|
---|
182 | begin
|
---|
183 | if length(APoints) <= 2 then
|
---|
184 | begin
|
---|
185 | setlength(result, length(APoints));
|
---|
186 | for i := 0 to high(result) do
|
---|
187 | result[i] := APoints[i];
|
---|
188 | exit;
|
---|
189 | end;
|
---|
190 | glyph := TBGRAPolygonalGlyph.Create('');
|
---|
191 | glyph.QuadraticCurves := true;
|
---|
192 | glyph.Closed:= AClosed;
|
---|
193 | glyph.MinimumDotProduct := AMinimumDotProduct;
|
---|
194 | glyph.SetPoints(APoints, ACurveMode);
|
---|
195 | canvas2D := TBGRACanvas2D.Create(nil);
|
---|
196 | canvas2D.pixelCenteredCoordinates := true;
|
---|
197 | glyph.Path(canvas2D,AffineMatrixIdentity);
|
---|
198 | glyph.Free;
|
---|
199 | result := canvas2D.currentPath;
|
---|
200 | canvas2D.free;
|
---|
201 | end;
|
---|
202 |
|
---|
203 | { TBGRAPolygonalGlyph }
|
---|
204 |
|
---|
205 | function TBGRAPolygonalGlyph.GetClosed: boolean;
|
---|
206 | begin
|
---|
207 | result := FEasyBezier.Closed;
|
---|
208 | end;
|
---|
209 |
|
---|
210 | function TBGRAPolygonalGlyph.GetMinimumDotProduct: single;
|
---|
211 | begin
|
---|
212 | result := FEasyBezier.MinimumDotProduct;
|
---|
213 | end;
|
---|
214 |
|
---|
215 | function TBGRAPolygonalGlyph.GetPoint(AIndex: integer): TPointF;
|
---|
216 | begin
|
---|
217 | result := FEasyBezier.Point[AIndex];
|
---|
218 | end;
|
---|
219 |
|
---|
220 | function TBGRAPolygonalGlyph.GetPointCount: integer;
|
---|
221 | begin
|
---|
222 | result := FEasyBezier.PointCount;
|
---|
223 | end;
|
---|
224 |
|
---|
225 | procedure TBGRAPolygonalGlyph.SetClosed(AValue: boolean);
|
---|
226 | begin
|
---|
227 | FEasyBezier.Closed := AValue;
|
---|
228 | end;
|
---|
229 |
|
---|
230 | procedure TBGRAPolygonalGlyph.SetMinimumDotProduct(AValue: single);
|
---|
231 | begin
|
---|
232 | FEasyBezier.MinimumDotProduct := AValue;
|
---|
233 | end;
|
---|
234 |
|
---|
235 | procedure TBGRAPolygonalGlyph.SetPoint(AIndex: integer; AValue: TPointF);
|
---|
236 | begin
|
---|
237 | FEasyBezier.Point[AIndex] := AValue;
|
---|
238 | end;
|
---|
239 |
|
---|
240 | procedure TBGRAPolygonalGlyph.SetQuadraticCurves(AValue: boolean);
|
---|
241 | begin
|
---|
242 | if FQuadraticCurves=AValue then Exit;
|
---|
243 | FQuadraticCurves:=AValue;
|
---|
244 | end;
|
---|
245 |
|
---|
246 | function TBGRAPolygonalGlyph.ContentSize: integer;
|
---|
247 | begin
|
---|
248 | Result:= (inherited ContentSize) + sizeof(single)*2 + 4 + sizeof(single)*2*PointCount;
|
---|
249 | end;
|
---|
250 |
|
---|
251 | function TBGRAPolygonalGlyph.HeaderName: string;
|
---|
252 | begin
|
---|
253 | if FQuadraticCurves then
|
---|
254 | Result:='TBGRAEasyBezierGlyph'
|
---|
255 | else
|
---|
256 | Result:='TBGRAPolygonalGlyph'
|
---|
257 | end;
|
---|
258 |
|
---|
259 | procedure TBGRAPolygonalGlyph.WriteContent(AStream: TStream);
|
---|
260 | var i: integer;
|
---|
261 | begin
|
---|
262 | inherited WriteContent(AStream);
|
---|
263 | LEWritePointF(AStream, Offset);
|
---|
264 | LEWriteLongint(AStream,PointCount);
|
---|
265 | for i := 0 to PointCount-1 do
|
---|
266 | LEWritePointF(AStream, FEasyBezier.Point[i]);
|
---|
267 | if FQuadraticCurves then
|
---|
268 | for i := 0 to PointCount-1 do
|
---|
269 | LEWriteLongint(AStream, ord(FEasyBezier.CurveMode[i]));
|
---|
270 | end;
|
---|
271 |
|
---|
272 | procedure TBGRAPolygonalGlyph.ReadContent(AStream: TStream);
|
---|
273 | var i: integer;
|
---|
274 | tempPts: array of TPointF;
|
---|
275 | flags: LongInt;
|
---|
276 | begin
|
---|
277 | inherited ReadContent(AStream);
|
---|
278 | Offset := LEReadPointF(AStream);
|
---|
279 | SetLength(tempPts, LEReadLongint(AStream));
|
---|
280 | for i := 0 to high(tempPts) do
|
---|
281 | tempPts[i] := LEReadPointF(AStream);
|
---|
282 | SetPoints(tempPts);
|
---|
283 | if FQuadraticCurves then
|
---|
284 | begin
|
---|
285 | for i := 0 to high(tempPts) do
|
---|
286 | begin
|
---|
287 | flags := LEReadLongint(AStream);
|
---|
288 | FEasyBezier.CurveMode[i] := TEasyBezierCurveMode(flags and 255);
|
---|
289 | end;
|
---|
290 | end;
|
---|
291 | end;
|
---|
292 |
|
---|
293 | function TBGRAPolygonalGlyph.PointTransformMatrix(APoint: PPointF;
|
---|
294 | AData: pointer): TPointF;
|
---|
295 | begin
|
---|
296 | result := TAffineMatrix(AData^) * APoint^;
|
---|
297 | end;
|
---|
298 |
|
---|
299 | procedure TBGRAPolygonalGlyph.Init;
|
---|
300 | begin
|
---|
301 | FEasyBezier.Init;
|
---|
302 | Closed := True;
|
---|
303 | Offset := PointF(0,0);
|
---|
304 | FQuadraticCurves:= False;
|
---|
305 | end;
|
---|
306 |
|
---|
307 | constructor TBGRAPolygonalGlyph.Create(AIdentifier: string);
|
---|
308 | begin
|
---|
309 | Init;
|
---|
310 | inherited Create(AIdentifier);
|
---|
311 | end;
|
---|
312 |
|
---|
313 | constructor TBGRAPolygonalGlyph.Create(AStream: TStream);
|
---|
314 | begin
|
---|
315 | Init;
|
---|
316 | inherited Create(AStream);
|
---|
317 | end;
|
---|
318 |
|
---|
319 | constructor TBGRAPolygonalGlyph.Create(AStream: TStream; AQuadratic: boolean);
|
---|
320 | begin
|
---|
321 | Init;
|
---|
322 | FQuadraticCurves:= AQuadratic;
|
---|
323 | inherited Create(AStream);
|
---|
324 | end;
|
---|
325 |
|
---|
326 | procedure TBGRAPolygonalGlyph.SetPoints(const APoints: array of TPointF);
|
---|
327 | begin
|
---|
328 | FEasyBezier.SetPoints(APoints, cmAuto);
|
---|
329 | end;
|
---|
330 |
|
---|
331 | procedure TBGRAPolygonalGlyph.SetPoints(const APoints: array of TPointF;
|
---|
332 | const ACurveMode: array of TGlyphPointCurveMode);
|
---|
333 | begin
|
---|
334 | if length(APoints) <> length(ACurveMode) then
|
---|
335 | raise exception.Create('Dimension mismatch');
|
---|
336 | FEasyBezier.SetPoints(APoints, ACurveMode);
|
---|
337 | end;
|
---|
338 |
|
---|
339 | procedure TBGRAPolygonalGlyph.Path(ADest: IBGRAPath; AMatrix: TAffineMatrix);
|
---|
340 | var i: integer;
|
---|
341 | nextMove: boolean;
|
---|
342 | begin
|
---|
343 | AMatrix := AMatrix*AffineMatrixTranslation(Offset.X,Offset.Y);
|
---|
344 | if not FQuadraticCurves then
|
---|
345 | begin
|
---|
346 | nextMove := true;
|
---|
347 | for i := 0 to PointCount-1 do
|
---|
348 | if isEmptyPointF(Point[i]) then
|
---|
349 | begin
|
---|
350 | if not nextMove and Closed then ADest.closePath;
|
---|
351 | nextMove := true;
|
---|
352 | end else
|
---|
353 | begin
|
---|
354 | if nextMove then
|
---|
355 | begin
|
---|
356 | ADest.moveTo(AMatrix*Point[i]);
|
---|
357 | nextMove := false;
|
---|
358 | end else
|
---|
359 | ADest.lineTo(AMatrix*Point[i]);
|
---|
360 | end;
|
---|
361 | if not nextmove and Closed then ADest.closePath;
|
---|
362 | end else
|
---|
363 | FEasyBezier.CopyToPath(ADest, @PointTransformMatrix, @AMatrix);
|
---|
364 | end;
|
---|
365 |
|
---|
366 | { TBGRAGlyph }
|
---|
367 |
|
---|
368 | procedure TBGRAGlyph.WriteHeader(AStream: TStream; AName: string;
|
---|
369 | AContentSize: longint);
|
---|
370 | begin
|
---|
371 | LEWriteByte(AStream, length(AName));
|
---|
372 | AStream.Write(AName[1],length(AName));
|
---|
373 | LEWriteLongint(AStream, AContentSize);
|
---|
374 | end;
|
---|
375 |
|
---|
376 | class procedure TBGRAGlyph.ReadHeader(AStream: TStream; out AName: string; out
|
---|
377 | AContentSize: longint);
|
---|
378 | var NameLength: integer;
|
---|
379 | begin
|
---|
380 | NameLength := LEReadByte(AStream);
|
---|
381 | setlength(AName,NameLength);
|
---|
382 | AStream.Read(AName[1],length(AName));
|
---|
383 | AContentSize := LEReadLongint(AStream);
|
---|
384 | end;
|
---|
385 |
|
---|
386 | function TBGRAGlyph.ContentSize: integer;
|
---|
387 | begin
|
---|
388 | result := 4+length(FIdentifier)+sizeof(single)*2;
|
---|
389 | end;
|
---|
390 |
|
---|
391 | function TBGRAGlyph.HeaderName: string;
|
---|
392 | begin
|
---|
393 | result := 'TBGRAGlyph';
|
---|
394 | end;
|
---|
395 |
|
---|
396 | procedure TBGRAGlyph.WriteContent(AStream: TStream);
|
---|
397 | begin
|
---|
398 | LEWriteLongint(AStream,length(FIdentifier));
|
---|
399 | AStream.Write(FIdentifier[1],length(FIdentifier));
|
---|
400 | LEWriteSingle(AStream,Width);
|
---|
401 | LEWriteSingle(AStream,Height);
|
---|
402 | end;
|
---|
403 |
|
---|
404 | procedure TBGRAGlyph.ReadContent(AStream: TStream);
|
---|
405 | var lIdentifierLength: integer;
|
---|
406 | begin
|
---|
407 | lIdentifierLength:= LEReadLongint(AStream);
|
---|
408 | setlength(FIdentifier, lIdentifierLength);
|
---|
409 | AStream.Read(FIdentifier[1],length(FIdentifier));
|
---|
410 | Width := LEReadSingle(AStream);
|
---|
411 | Height := LEReadSingle(AStream);
|
---|
412 | end;
|
---|
413 |
|
---|
414 | constructor TBGRAGlyph.Create(AIdentifier: string);
|
---|
415 | begin
|
---|
416 | FIdentifier:= AIdentifier;
|
---|
417 | end;
|
---|
418 |
|
---|
419 | constructor TBGRAGlyph.Create(AStream: TStream);
|
---|
420 | begin
|
---|
421 | ReadContent(AStream);
|
---|
422 | end;
|
---|
423 |
|
---|
424 | procedure TBGRAGlyph.Path(ADest: IBGRAPath; AMatrix: TAffineMatrix);
|
---|
425 | begin
|
---|
426 | //nothing
|
---|
427 | end;
|
---|
428 |
|
---|
429 | procedure TBGRAGlyph.SaveToStream(AStream: TStream);
|
---|
430 | begin
|
---|
431 | WriteHeader(AStream, HeaderName, ContentSize);
|
---|
432 | WriteContent(AStream);
|
---|
433 | end;
|
---|
434 |
|
---|
435 | class function TBGRAGlyph.LoadFromStream(AStream: TStream) : TBGRAGlyph;
|
---|
436 | var lName: string;
|
---|
437 | lContentSize: integer;
|
---|
438 | EndPosition: Int64;
|
---|
439 | begin
|
---|
440 | ReadHeader(AStream,lName,lContentSize);
|
---|
441 | EndPosition := AStream.Position + lContentSize;
|
---|
442 | if lName = 'TBGRAPolygonalGlyph' then
|
---|
443 | result := TBGRAPolygonalGlyph.Create(AStream)
|
---|
444 | else if lName = 'TBGRAEasyBezierGlyph' then
|
---|
445 | result := TBGRAPolygonalGlyph.Create(AStream, true)
|
---|
446 | else if lName = 'TBGRAGlyph' then
|
---|
447 | result := TBGRAGlyph.Create(AStream)
|
---|
448 | else
|
---|
449 | raise exception.Create('Unknown glyph type (' + lName + ')');
|
---|
450 | AStream.Position:= EndPosition;
|
---|
451 | end;
|
---|
452 |
|
---|
453 | { TBGRACustomTypeWriter }
|
---|
454 |
|
---|
455 | function TBGRACustomTypeWriter.GetGlyph(AIdentifier: string): TBGRAGlyph;
|
---|
456 | var Node: TAvgLvlTreeNode;
|
---|
457 | begin
|
---|
458 | Node := FindGlyph(AIdentifier);
|
---|
459 | if Node = nil then
|
---|
460 | result := nil
|
---|
461 | else
|
---|
462 | result := TBGRAGlyph(Node.Data);
|
---|
463 | end;
|
---|
464 |
|
---|
465 | procedure TBGRACustomTypeWriter.SetGlyph(AIdentifier: string; AValue: TBGRAGlyph);
|
---|
466 | var Node: TAvgLvlTreeNode;
|
---|
467 | begin
|
---|
468 | if AValue.Identifier <> AIdentifier then
|
---|
469 | raise exception.Create('Identifier mismatch');
|
---|
470 | Node := FindGlyph(AIdentifier);
|
---|
471 | if Node <> nil then
|
---|
472 | begin
|
---|
473 | if pointer(AValue) <> Node.Data then
|
---|
474 | TBGRAGlyph(Node.Data).Free;
|
---|
475 | Node.Data := AValue;
|
---|
476 | end else
|
---|
477 | FGlyphs.Add(pointer(AValue));
|
---|
478 | end;
|
---|
479 |
|
---|
480 | function TBGRACustomTypeWriter.CompareGlyph(Tree: TAvgLvlTree; Data1, Data2: Pointer): integer;
|
---|
481 | begin
|
---|
482 | result := CompareStr(TBGRAGlyph(Data1).Identifier,TBGRAGlyph(Data2).Identifier);
|
---|
483 | end;
|
---|
484 |
|
---|
485 | function TBGRACustomTypeWriter.FindGlyph(AIdentifier: string): TAvgLvlTreeNode;
|
---|
486 | var Comp: integer;
|
---|
487 | Node: TAvgLvlTreeNode;
|
---|
488 | begin
|
---|
489 | Node:=FGlyphs.Root;
|
---|
490 | while (Node<>nil) do begin
|
---|
491 | Comp:=CompareStr(AIdentifier,TBGRAGlyph(Node.Data).Identifier);
|
---|
492 | if Comp=0 then break;
|
---|
493 | if Comp<0 then begin
|
---|
494 | Node:=Node.Left
|
---|
495 | end else begin
|
---|
496 | Node:=Node.Right
|
---|
497 | end;
|
---|
498 | end;
|
---|
499 | result := Node;
|
---|
500 | end;
|
---|
501 |
|
---|
502 | constructor TBGRACustomTypeWriter.Create;
|
---|
503 | begin
|
---|
504 | FGlyphs := TAvgLvlTree.CreateObjectCompare(@CompareGlyph);
|
---|
505 | TypeWriterMatrix := AffineMatrixIdentity;
|
---|
506 | OutlineMode:= twoFill;
|
---|
507 | DrawGlyphsSimultaneously := false;
|
---|
508 | end;
|
---|
509 |
|
---|
510 | procedure TBGRACustomTypeWriter.DrawGlyph(ADest: TBGRACanvas2D;
|
---|
511 | AIdentifier: string; X, Y: Single; AAlign: TBGRATypeWriterAlignment);
|
---|
512 | begin
|
---|
513 | GlyphPath(ADest, AIdentifier, X,Y, AAlign);
|
---|
514 | DrawLastPath(ADest);
|
---|
515 | end;
|
---|
516 |
|
---|
517 | procedure TBGRACustomTypeWriter.DrawText(ADest: TBGRACanvas2D; ATextUTF8: string;
|
---|
518 | X, Y: Single; AAlign: TBGRATypeWriterAlignment);
|
---|
519 | begin
|
---|
520 | TextPath(ADest, ATextUTF8, X,Y, AAlign, (OutlineMode <> twoPath) and not DrawGlyphsSimultaneously);
|
---|
521 | end;
|
---|
522 |
|
---|
523 | procedure TBGRACustomTypeWriter.CopyTextPathTo(ADest: IBGRAPath; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft);
|
---|
524 | var
|
---|
525 | pstr: pchar;
|
---|
526 | left,charlen: integer;
|
---|
527 | nextchar: string;
|
---|
528 | g: TBGRAGlyph;
|
---|
529 | m,m2: TAffineMatrix;
|
---|
530 | begin
|
---|
531 | if ATextUTF8 = '' then exit;
|
---|
532 | m := GetTextMatrix(ATextUTF8, X,Y,AAlign);
|
---|
533 | m2 := m;
|
---|
534 |
|
---|
535 | pstr := @ATextUTF8[1];
|
---|
536 | left := length(ATextUTF8);
|
---|
537 | while left > 0 do
|
---|
538 | begin
|
---|
539 | charlen := UTF8CharacterLength(pstr);
|
---|
540 | setlength(nextchar, charlen);
|
---|
541 | move(pstr^, nextchar[1], charlen);
|
---|
542 | inc(pstr,charlen);
|
---|
543 | dec(left,charlen);
|
---|
544 |
|
---|
545 | g := GetGlyph(nextchar);
|
---|
546 | if g <> nil then
|
---|
547 | begin
|
---|
548 | if AAlign in [twaLeft,twaMiddle,twaRight] then
|
---|
549 | m2 := m*AffineMatrixTranslation(0,-g.Height/2) else
|
---|
550 | if AAlign in [twaBottomLeft,twaBottom,twaBottomRight] then
|
---|
551 | m2 := m*AffineMatrixTranslation(0,-g.Height)
|
---|
552 | else
|
---|
553 | m2 := m;
|
---|
554 | g.Path(ADest, m2);
|
---|
555 | m := m*AffineMatrixTranslation(g.Width,0);
|
---|
556 | end;
|
---|
557 | end;
|
---|
558 | end;
|
---|
559 |
|
---|
560 | function TBGRACustomTypeWriter.GetGlyphBox(AIdentifier: string; X, Y: Single;
|
---|
561 | AAlign: TBGRATypeWriterAlignment): TAffineBox;
|
---|
562 | var g: TBGRAGlyph;
|
---|
563 | m: TAffineMatrix;
|
---|
564 | begin
|
---|
565 | g := GetGlyph(AIdentifier);
|
---|
566 | if g = nil then result := TAffineBox.EmptyBox else
|
---|
567 | begin
|
---|
568 | m := GetGlyphMatrix(g,X,Y,AAlign);
|
---|
569 | result := TAffineBox.AffineBox(m*PointF(0,0),m*PointF(g.Width,0),m*PointF(0,g.Height));
|
---|
570 | end;
|
---|
571 | end;
|
---|
572 |
|
---|
573 | function TBGRACustomTypeWriter.GetTextBox(ATextUTF8: string; X, Y: Single;
|
---|
574 | AAlign: TBGRATypeWriterAlignment): TAffineBox;
|
---|
575 | var
|
---|
576 | m: TAffineMatrix;
|
---|
577 | totalWidth,minY,maxY,gMinY,gMaxY: single;
|
---|
578 |
|
---|
579 | pstr: pchar;
|
---|
580 | left,charlen: integer;
|
---|
581 | nextchar: string;
|
---|
582 | g: TBGRAGlyph;
|
---|
583 |
|
---|
584 | begin
|
---|
585 | if ATextUTF8 = '' then result := TAffineBox.EmptyBox else
|
---|
586 | begin
|
---|
587 | m := GetTextMatrix(ATextUTF8,X,Y,AAlign);
|
---|
588 | minY := 0;
|
---|
589 | maxY := 0;
|
---|
590 | totalWidth := 0;
|
---|
591 |
|
---|
592 | pstr := @ATextUTF8[1];
|
---|
593 | left := length(ATextUTF8);
|
---|
594 | while left > 0 do
|
---|
595 | begin
|
---|
596 | charlen := UTF8CharacterLength(pstr);
|
---|
597 | setlength(nextchar, charlen);
|
---|
598 | move(pstr^, nextchar[1], charlen);
|
---|
599 | inc(pstr,charlen);
|
---|
600 | dec(left,charlen);
|
---|
601 |
|
---|
602 | g := GetGlyph(nextchar);
|
---|
603 | if g <> nil then
|
---|
604 | begin
|
---|
605 | totalWidth += g.Width;
|
---|
606 |
|
---|
607 | if AAlign in [twaLeft,twaMiddle,twaRight] then
|
---|
608 | begin
|
---|
609 | gMinY := -g.Height/2;
|
---|
610 | gMaxY := g.Height/2;
|
---|
611 | end else
|
---|
612 | if AAlign in [twaBottomLeft,twaBottom,twaBottomRight] then
|
---|
613 | begin
|
---|
614 | gMinY := -g.Height;
|
---|
615 | gMaxY := 0;
|
---|
616 | end
|
---|
617 | else
|
---|
618 | begin
|
---|
619 | gMinY := 0;
|
---|
620 | gMaxY := g.Height;
|
---|
621 | end;
|
---|
622 | if gMinY < minY then minY := gMinY;
|
---|
623 | if gMaxY > maxY then maxY := gMaxY;
|
---|
624 | end;
|
---|
625 | end;
|
---|
626 |
|
---|
627 | result := TAffineBox.AffineBox(m*PointF(0,minY),m*PointF(totalWidth,minY),m*PointF(0,maxY));
|
---|
628 | end;
|
---|
629 | end;
|
---|
630 |
|
---|
631 | function TBGRACustomTypeWriter.GetTextGlyphBoxes(ATextUTF8: string; X, Y: Single;
|
---|
632 | AAlign: TBGRATypeWriterAlignment): TGlyphBoxes;
|
---|
633 | var
|
---|
634 | m: TAffineMatrix;
|
---|
635 | gMinY,gMaxY: single;
|
---|
636 |
|
---|
637 | pstr: pchar;
|
---|
638 | left,charlen: integer;
|
---|
639 | nextchar: string;
|
---|
640 | g: TBGRAGlyph;
|
---|
641 | numChar: integer;
|
---|
642 |
|
---|
643 | begin
|
---|
644 | if ATextUTF8 = '' then result := nil else
|
---|
645 | begin
|
---|
646 | setlength(result, UTF8Length(ATextUTF8));
|
---|
647 |
|
---|
648 | m := GetTextMatrix(ATextUTF8,X,Y,AAlign);
|
---|
649 |
|
---|
650 | pstr := @ATextUTF8[1];
|
---|
651 | left := length(ATextUTF8);
|
---|
652 | numChar := 0;
|
---|
653 | while left > 0 do
|
---|
654 | begin
|
---|
655 | charlen := UTF8CharacterLength(pstr);
|
---|
656 | setlength(nextchar, charlen);
|
---|
657 | move(pstr^, nextchar[1], charlen);
|
---|
658 | inc(pstr,charlen);
|
---|
659 | dec(left,charlen);
|
---|
660 |
|
---|
661 | result[numChar].Glyph := nextchar;
|
---|
662 | g := GetGlyph(nextchar);
|
---|
663 | if g <> nil then
|
---|
664 | begin
|
---|
665 | if AAlign in [twaLeft,twaMiddle,twaRight] then
|
---|
666 | begin
|
---|
667 | gMinY := -g.Height/2;
|
---|
668 | gMaxY := g.Height/2;
|
---|
669 | end else
|
---|
670 | if AAlign in [twaBottomLeft,twaBottom,twaBottomRight] then
|
---|
671 | begin
|
---|
672 | gMinY := -g.Height;
|
---|
673 | gMaxY := 0;
|
---|
674 | end
|
---|
675 | else
|
---|
676 | begin
|
---|
677 | gMinY := 0;
|
---|
678 | gMaxY := g.Height;
|
---|
679 | end;
|
---|
680 | result[numChar].Box := TAffineBox.AffineBox(m*PointF(0,gMinY),m*PointF(g.Width,gMinY),m*PointF(0,gMaxY));
|
---|
681 | m := m*AffineMatrixTranslation(g.Width,0);
|
---|
682 | end else
|
---|
683 | result[numChar].Box := TAffineBox.EmptyBox;
|
---|
684 |
|
---|
685 | inc(numChar);
|
---|
686 | end;
|
---|
687 | end;
|
---|
688 | end;
|
---|
689 |
|
---|
690 | procedure TBGRACustomTypeWriter.NeedGlyphRange(AUnicodeFrom, AUnicodeTo: Cardinal);
|
---|
691 | var c: cardinal;
|
---|
692 | begin
|
---|
693 | for c := AUnicodeFrom to AUnicodeTo do
|
---|
694 | GetGlyph(UnicodeCharToUTF8(c));
|
---|
695 | end;
|
---|
696 |
|
---|
697 | procedure TBGRACustomTypeWriter.NeedGlyphAnsiRange;
|
---|
698 | var i: integer;
|
---|
699 | begin
|
---|
700 | for i := 0 to 255 do
|
---|
701 | GetGlyph(AnsiToUtf8(chr(i)));
|
---|
702 | end;
|
---|
703 |
|
---|
704 | procedure TBGRACustomTypeWriter.TextPath(ADest: TBGRACanvas2D; ATextUTF8: string; X,
|
---|
705 | Y: Single; AAlign: TBGRATypeWriterAlignment; ADrawEachChar: boolean);
|
---|
706 | var
|
---|
707 | pstr: pchar;
|
---|
708 | left,charlen: integer;
|
---|
709 | nextchar: string;
|
---|
710 | g: TBGRAGlyph;
|
---|
711 | m,m2: TAffineMatrix;
|
---|
712 | begin
|
---|
713 | if not ADrawEachChar then ADest.beginPath;
|
---|
714 | if ATextUTF8 = '' then exit;
|
---|
715 | m := GetTextMatrix(ATextUTF8, X,Y,AAlign);
|
---|
716 | m2 := m;
|
---|
717 |
|
---|
718 | pstr := @ATextUTF8[1];
|
---|
719 | left := length(ATextUTF8);
|
---|
720 | while left > 0 do
|
---|
721 | begin
|
---|
722 | charlen := UTF8CharacterLength(pstr);
|
---|
723 | setlength(nextchar, charlen);
|
---|
724 | move(pstr^, nextchar[1], charlen);
|
---|
725 | inc(pstr,charlen);
|
---|
726 | dec(left,charlen);
|
---|
727 |
|
---|
728 | g := GetGlyph(nextchar);
|
---|
729 | if g <> nil then
|
---|
730 | begin
|
---|
731 | if AAlign in [twaLeft,twaMiddle,twaRight] then
|
---|
732 | m2 := m*AffineMatrixTranslation(0,-g.Height/2) else
|
---|
733 | if AAlign in [twaBottomLeft,twaBottom,twaBottomRight] then
|
---|
734 | m2 := m*AffineMatrixTranslation(0,-g.Height)
|
---|
735 | else
|
---|
736 | m2 := m;
|
---|
737 | if ADrawEachChar then ADest.beginPath;
|
---|
738 | g.Path(ADest, m2);
|
---|
739 | if ADrawEachChar then DrawLastPath(ADest);
|
---|
740 | m := m*AffineMatrixTranslation(g.Width,0);
|
---|
741 | end;
|
---|
742 | end;
|
---|
743 | end;
|
---|
744 |
|
---|
745 | procedure TBGRACustomTypeWriter.GlyphPath(ADest: TBGRACanvas2D; AIdentifier: string;
|
---|
746 | X, Y: Single; AAlign: TBGRATypeWriterAlignment);
|
---|
747 | var g: TBGRAGlyph;
|
---|
748 | begin
|
---|
749 | ADest.beginPath;
|
---|
750 | g := GetGlyph(AIdentifier);
|
---|
751 | if g = nil then exit;
|
---|
752 | g.Path(ADest, GetGlyphMatrix(g,X,Y,AAlign));
|
---|
753 | end;
|
---|
754 |
|
---|
755 | procedure TBGRACustomTypeWriter.DrawLastPath(ADest: TBGRACanvas2D);
|
---|
756 | begin
|
---|
757 | case OutlineMode of
|
---|
758 | twoPath: ;
|
---|
759 | twoFill: ADest.fill;
|
---|
760 | twoStroke: ADest.stroke;
|
---|
761 | twoFillOverStroke: ADest.fillOverStroke;
|
---|
762 | twoStrokeOverFill: ADest.strokeOverFill;
|
---|
763 | twoFillThenStroke: begin ADest.fill; ADest.stroke; end;
|
---|
764 | twoStrokeThenFill: begin ADest.stroke; ADest.fill; end;
|
---|
765 | end;
|
---|
766 | end;
|
---|
767 |
|
---|
768 | procedure TBGRACustomTypeWriter.ClearGlyphs;
|
---|
769 | begin
|
---|
770 | FGlyphs.FreeAndClear;
|
---|
771 | end;
|
---|
772 |
|
---|
773 | procedure TBGRACustomTypeWriter.RemoveGlyph(AIdentifier: string);
|
---|
774 | var Node: TAvgLvlTreeNode;
|
---|
775 | begin
|
---|
776 | Node := FindGlyph(AIdentifier);
|
---|
777 | if Node <> nil then FGlyphs.Delete(Node);
|
---|
778 | end;
|
---|
779 |
|
---|
780 | procedure TBGRACustomTypeWriter.AddGlyph(AGlyph: TBGRAGlyph);
|
---|
781 | begin
|
---|
782 | Glyph[AGlyph.Identifier] := AGlyph;
|
---|
783 | end;
|
---|
784 |
|
---|
785 | procedure TBGRACustomTypeWriter.SaveGlyphsToStream(AStream: TStream);
|
---|
786 | var Enumerator: TAvgLvlTreeNodeEnumerator;
|
---|
787 | begin
|
---|
788 | LEWriteLongint(AStream,CustomHeaderSize);
|
---|
789 | WriteCustomHeader(AStream);
|
---|
790 |
|
---|
791 | Enumerator := FGlyphs.GetEnumerator;
|
---|
792 | while Enumerator.MoveNext do
|
---|
793 | TBGRAGlyph(Enumerator.Current.Data).SaveToStream(AStream);
|
---|
794 | Enumerator.Free;
|
---|
795 | end;
|
---|
796 |
|
---|
797 | procedure TBGRACustomTypeWriter.LoadGlyphsFromFile(AFilenameUTF8: string);
|
---|
798 | var Stream: TFileStreamUTF8;
|
---|
799 | begin
|
---|
800 | Stream := nil;
|
---|
801 | try
|
---|
802 | Stream := TFileStreamUTF8.Create(AFilenameUTF8, fmOpenRead);
|
---|
803 | LoadGlyphsFromStream(Stream);
|
---|
804 | finally
|
---|
805 | Stream.Free;
|
---|
806 | end;
|
---|
807 | end;
|
---|
808 |
|
---|
809 | procedure TBGRACustomTypeWriter.LoadGlyphsFromStream(AStream: TStream);
|
---|
810 | var Header: TBGRACustomTypeWriterHeader;
|
---|
811 | i: integer;
|
---|
812 | g: TBGRAGlyph;
|
---|
813 | HeaderSize: integer;
|
---|
814 | GlyphStartPosition: Int64;
|
---|
815 | begin
|
---|
816 | HeaderSize := LEReadLongint(AStream);
|
---|
817 | GlyphStartPosition:= AStream.Position+HeaderSize;
|
---|
818 | Header := ReadCustomTypeWriterHeader(AStream);
|
---|
819 | if header.HeaderName <> HeaderName then
|
---|
820 | raise exception.Create('Invalid file format ("'+header.HeaderName+'" should be "'+HeaderName+'")');
|
---|
821 | ReadAdditionalHeader(AStream);
|
---|
822 | AStream.Position:= GlyphStartPosition;
|
---|
823 | for i := 0 to Header.NbGlyphs-1 do
|
---|
824 | begin
|
---|
825 | g := TBGRAGlyph.LoadFromStream(AStream);
|
---|
826 | AddGlyph(g);
|
---|
827 | end;
|
---|
828 | end;
|
---|
829 |
|
---|
830 | procedure TBGRACustomTypeWriter.SaveGlyphsToFile(AFilenameUTF8: string);
|
---|
831 | var Stream: TFileStreamUTF8;
|
---|
832 | begin
|
---|
833 | Stream := nil;
|
---|
834 | try
|
---|
835 | Stream := TFileStreamUTF8.Create(AFilenameUTF8, fmCreate or fmOpenWrite);
|
---|
836 | SaveGlyphsToStream(Stream);
|
---|
837 | finally
|
---|
838 | Stream.Free;
|
---|
839 | end;
|
---|
840 | end;
|
---|
841 |
|
---|
842 | function TBGRACustomTypeWriter.GetGlyphMatrix(AGlyph: TBGRAGlyph; X, Y: Single;
|
---|
843 | AAlign: TBGRATypeWriterAlignment): TAffineMatrix;
|
---|
844 | var tGlyph: TPointF;
|
---|
845 | begin
|
---|
846 | if AGlyph = nil then
|
---|
847 | begin
|
---|
848 | result := AffineMatrixIdentity;
|
---|
849 | exit;
|
---|
850 | end;
|
---|
851 | tGlyph := PointF(0,0);
|
---|
852 | if AAlign in [twaTop,twaMiddle,twaBottom] then tGlyph.X -= AGlyph.Width/2;
|
---|
853 | if AAlign in [twaTopRight,twaRight,twaBottomRight] then tGlyph.X -= AGlyph.Width;
|
---|
854 | if AAlign in [twaLeft,twaMiddle,twaRight] then tGlyph.Y -= AGlyph.Height/2;
|
---|
855 | if AAlign in [twaBottomLeft,twaBottom,twaBottomRight] then tGlyph.Y -= AGlyph.Height;
|
---|
856 | result := AffineMatrixTranslation(X,Y)*TypeWriterMatrix*AffineMatrixTranslation(tGlyph.X,tGlyph.Y);
|
---|
857 | end;
|
---|
858 |
|
---|
859 | function TBGRACustomTypeWriter.GetTextMatrix(ATextUTF8: string; X, Y: Single;
|
---|
860 | AAlign: TBGRATypeWriterAlignment): TAffineMatrix;
|
---|
861 | var
|
---|
862 | tGlyph: TPointF;
|
---|
863 | totalWidth: single;
|
---|
864 | pstr: pchar;
|
---|
865 | left,charlen: integer;
|
---|
866 | nextchar: string;
|
---|
867 | g: TBGRAGlyph;
|
---|
868 | begin
|
---|
869 | tGlyph := PointF(0,0);
|
---|
870 | if not (AAlign in [twaLeft,twaTopLeft,twaBottomLeft]) then
|
---|
871 | begin
|
---|
872 | totalWidth := 0;
|
---|
873 | pstr := @ATextUTF8[1];
|
---|
874 | left := length(ATextUTF8);
|
---|
875 | while left > 0 do
|
---|
876 | begin
|
---|
877 | charlen := UTF8CharacterLength(pstr);
|
---|
878 | setlength(nextchar, charlen);
|
---|
879 | move(pstr^, nextchar[1], charlen);
|
---|
880 | inc(pstr,charlen);
|
---|
881 | dec(left,charlen);
|
---|
882 |
|
---|
883 | g := GetGlyph(nextchar);
|
---|
884 | if g <> nil then totalWidth += g.Width;
|
---|
885 | end;
|
---|
886 |
|
---|
887 | if AAlign in[twaTop,twaMiddle,twaBottom] then tGlyph.X -= totalWidth/2 else
|
---|
888 | if AAlign in[twaTopRight, twaRight, twaBottomRight] then tGlyph.X -= totalWidth;
|
---|
889 | end;
|
---|
890 | result := AffineMatrixTranslation(X,Y)*TypeWriterMatrix*AffineMatrixTranslation(tGlyph.X,tGlyph.Y);
|
---|
891 | end;
|
---|
892 |
|
---|
893 | function TBGRACustomTypeWriter.CustomHeaderSize: integer;
|
---|
894 | begin
|
---|
895 | result := 1+length(HeaderName)+4;
|
---|
896 | end;
|
---|
897 |
|
---|
898 | procedure TBGRACustomTypeWriter.WriteCustomHeader(AStream: TStream);
|
---|
899 | var lHeaderName: string;
|
---|
900 | begin
|
---|
901 | lHeaderName:= HeaderName;
|
---|
902 | LEWriteByte(AStream,length(lHeaderName));
|
---|
903 | AStream.Write(lHeaderName[1],length(lHeaderName));
|
---|
904 | LEWriteLongint(AStream,FGlyphs.Count);
|
---|
905 | end;
|
---|
906 |
|
---|
907 | function TBGRACustomTypeWriter.ReadCustomTypeWriterHeader(AStream: TStream
|
---|
908 | ): TBGRACustomTypeWriterHeader;
|
---|
909 | begin
|
---|
910 | setlength(result.HeaderName, LEReadByte(AStream));
|
---|
911 | AStream.Read(result.HeaderName[1],length(result.HeaderName));
|
---|
912 | result.NbGlyphs:= LEReadLongint(AStream);
|
---|
913 | end;
|
---|
914 |
|
---|
915 | procedure TBGRACustomTypeWriter.ReadAdditionalHeader(AStream: TStream);
|
---|
916 | begin
|
---|
917 | //nothing
|
---|
918 | end;
|
---|
919 |
|
---|
920 | function TBGRACustomTypeWriter.HeaderName: string;
|
---|
921 | begin
|
---|
922 | result := 'TBGRACustomTypeWriter';
|
---|
923 | end;
|
---|
924 |
|
---|
925 | destructor TBGRACustomTypeWriter.Destroy;
|
---|
926 | begin
|
---|
927 | FGlyphs.FreeAndClear;
|
---|
928 | FGlyphs.Free;
|
---|
929 | inherited Destroy;
|
---|
930 | end;
|
---|
931 |
|
---|
932 | end.
|
---|
933 |
|
---|