Changeset 472 for GraphicTest/Packages/bgrabitmap/bgratypewriter.pas
- Timestamp:
- Apr 9, 2015, 9:58:36 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
GraphicTest/Packages/bgrabitmap/bgratypewriter.pas
r452 r472 19 19 protected 20 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; 21 27 public 22 28 Width,Height: single; 23 29 constructor Create(AIdentifier: string); virtual; 24 procedure Path(ADest: TBGRACanvas2D; AMatrix: TAffineMatrix); virtual; abstract; 30 constructor Create(AStream: TStream); virtual; 31 procedure Path({%H-}ADest: IBGRAPath; {%H-}AMatrix: TAffineMatrix); virtual; 25 32 property Identifier: string read FIdentifier; 26 end; 33 procedure SaveToStream(AStream: TStream); 34 class function LoadFromStream(AStream: TStream): TBGRAGlyph; 35 end; 36 37 TGlyphPointCurveMode= (cmAuto, cmCurve, cmAngle); 27 38 28 39 { TBGRAPolygonalGlyph } … … 34 45 FQuadraticCurves: boolean; 35 46 Points: array of TPointF; 47 CurveMode: array of TGlyphPointCurveMode; 36 48 Curves: array of record 37 49 isCurvedToNext,isCurvedToPrevious: boolean; … … 40 52 function MaybeCurve(start1,end1,start2,end2: integer): boolean; 41 53 procedure ComputeQuadraticCurves; 54 function ContentSize: integer; override; 55 function HeaderName: string; override; 56 procedure WriteContent(AStream: TStream); override; 57 procedure ReadContent(AStream: TStream); override; 58 procedure Init; 42 59 public 43 60 Offset: TPointF; 61 Closed: boolean; 62 MinimumDotProduct: single; 44 63 constructor Create(AIdentifier: string); override; 45 procedure SetPoints(const APoints: array of TPointF); 46 procedure Path(ADest: TBGRACanvas2D; AMatrix: TAffineMatrix); override; 64 constructor Create(AStream: TStream); override; 65 procedure SetPoints(const APoints: array of TPointF); overload; 66 procedure SetPoints(const APoints: array of TPointF; const ACurveMode: array of TGlyphPointCurveMode); overload; 67 procedure Path(ADest: IBGRAPath; AMatrix: TAffineMatrix); override; 47 68 property QuadraticCurves: boolean read FQuadraticCurves write SetQuadraticCurves; 69 end; 70 71 TBGRACustomTypeWriterHeader = record 72 HeaderName: String; 73 NbGlyphs: integer; 48 74 end; 49 75 … … 59 85 function GetGlyph(AIdentifier: string): TBGRAGlyph; virtual; 60 86 procedure SetGlyph(AIdentifier: string; AValue: TBGRAGlyph); 61 procedure TextPath(ADest: TBGRACanvas2D; AText : string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft);87 procedure TextPath(ADest: TBGRACanvas2D; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment; ADrawEachChar: boolean); 62 88 procedure GlyphPath(ADest: TBGRACanvas2D; AIdentifier: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); 63 89 procedure DrawLastPath(ADest: TBGRACanvas2D); … … 66 92 procedure AddGlyph(AGlyph: TBGRAGlyph); 67 93 function GetGlyphMatrix(AGlyph: TBGRAGlyph; X,Y: Single; AAlign: TBGRATypeWriterAlignment): TAffineMatrix; 68 function GetTextMatrix(AText : string; X,Y: Single; AAlign: TBGRATypeWriterAlignment): TAffineMatrix;94 function GetTextMatrix(ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment): TAffineMatrix; 69 95 property Glyph[AIdentifier: string]: TBGRAGlyph read GetGlyph write SetGlyph; 96 function CustomHeaderSize: integer; virtual; 97 procedure WriteCustomHeader(AStream: TStream); virtual; 98 function ReadCustomTypeWriterHeader(AStream: TStream): TBGRACustomTypeWriterHeader; 99 procedure ReadAdditionalHeader({%H-}AStream: TStream); virtual; 100 function HeaderName: string; virtual; 70 101 public 71 102 OutlineMode: TBGRATypeWriterOutlineMode; 103 DrawGlyphsSimultaneously : boolean; 72 104 constructor Create; 105 procedure SaveGlyphsToFile(AFilenameUTF8: string); 106 procedure SaveGlyphsToStream(AStream: TStream); 107 procedure LoadGlyphsFromFile(AFilenameUTF8: string); 108 procedure LoadGlyphsFromStream(AStream: TStream); 73 109 procedure DrawGlyph(ADest: TBGRACanvas2D; AIdentifier: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); 74 procedure DrawText(ADest: TBGRACanvas2D; AText: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); 110 procedure DrawText(ADest: TBGRACanvas2D; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); virtual; 111 procedure CopyTextPathTo(ADest: IBGRAPath; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); virtual; 75 112 function GetGlyphBox(AIdentifier: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TAffineBox; 76 function GetTextBox(AText: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TAffineBox; 77 function GetTextGlyphBoxes(AText: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TGlyphBoxes; 113 function GetTextBox(ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TAffineBox; 114 function GetTextGlyphBoxes(ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft): TGlyphBoxes; 115 procedure NeedGlyphRange(AUnicodeFrom, AUnicodeTo: Cardinal); 116 procedure NeedGlyphAnsiRange; 78 117 destructor Destroy; override; 79 118 end; 80 119 120 function ComputeEasyBezier(APoints: array of TPointF; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF; overload; 121 function ComputeEasyBezier(APoints: array of TPointF; ACurveMode: array of TGlyphPointCurveMode; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF; overload; 122 81 123 implementation 82 124 83 uses LCLProc; 125 uses LCLProc, lazutf8classes; 126 127 {$i winstream.inc} 128 129 function ComputeEasyBezier(APoints: array of TPointF; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF; 130 var 131 glyph: TBGRAPolygonalGlyph; 132 canvas2D: TBGRACanvas2D; 133 i: integer; 134 begin 135 if length(APoints) <= 2 then 136 begin 137 setlength(result, length(APoints)); 138 for i := 0 to high(result) do 139 result[i] := APoints[i]; 140 exit; 141 end; 142 glyph := TBGRAPolygonalGlyph.Create(''); 143 glyph.QuadraticCurves := true; 144 glyph.Closed:= AClosed; 145 glyph.MinimumDotProduct := AMinimumDotProduct; 146 glyph.SetPoints(APoints); 147 canvas2D := TBGRACanvas2D.Create(nil); 148 canvas2D.pixelCenteredCoordinates := true; 149 glyph.Path(canvas2D,AffineMatrixIdentity); 150 glyph.Free; 151 result := canvas2D.currentPath; 152 canvas2D.free; 153 end; 154 155 function ComputeEasyBezier(APoints: array of TPointF; 156 ACurveMode: array of TGlyphPointCurveMode; AClosed: boolean; 157 AMinimumDotProduct: single): ArrayOfTPointF; 158 var 159 glyph: TBGRAPolygonalGlyph; 160 canvas2D: TBGRACanvas2D; 161 i: integer; 162 begin 163 if length(APoints) <= 2 then 164 begin 165 setlength(result, length(APoints)); 166 for i := 0 to high(result) do 167 result[i] := APoints[i]; 168 exit; 169 end; 170 glyph := TBGRAPolygonalGlyph.Create(''); 171 glyph.QuadraticCurves := true; 172 glyph.Closed:= AClosed; 173 glyph.MinimumDotProduct := AMinimumDotProduct; 174 glyph.SetPoints(APoints, ACurveMode); 175 canvas2D := TBGRACanvas2D.Create(nil); 176 canvas2D.pixelCenteredCoordinates := true; 177 glyph.Path(canvas2D,AffineMatrixIdentity); 178 glyph.Free; 179 result := canvas2D.currentPath; 180 canvas2D.free; 181 end; 84 182 85 183 { TBGRAPolygonalGlyph } … … 109 207 if lv <> 0 then v *= 1/lv; 110 208 111 result := u*v > 0.707;209 result := u*v > MinimumDotProduct; 112 210 end; 113 211 … … 119 217 FirstPointIndex := 0; 120 218 for i := 0 to high(points) do 219 Curves[i].isCurvedToPrevious := false; 220 for i := 0 to high(points) do 121 221 begin 122 222 Curves[i].isCurvedToNext := false; 123 Curves[i].isCurvedToPrevious := false;124 223 Curves[i].Center := EmptyPointF; 125 224 Curves[i].ControlPoint := EmptyPointF; … … 138 237 Curves[i].Center := (points[i]+points[NextPt])*0.5; 139 238 Curves[i].NextCenter := (points[NextPt]+points[NextPt2])*0.5; 140 141 Curves[i].isCurvedToNext:= MaybeCurve(i,NextPt,NextPt,NextPt2);142 Curves[NextPt].isCurvedToPrevious := Curves[i].isCurvedToNext;143 239 Curves[i].ControlPoint := points[NextPt]; 240 241 if (i < high(points)-1) or Closed then 242 begin 243 case CurveMode[nextPt] of 244 cmAuto: Curves[i].isCurvedToNext:= MaybeCurve(i,NextPt,NextPt,NextPt2); 245 cmCurve: Curves[i].isCurvedToNext:= true; 246 else Curves[i].isCurvedToNext:= false; 247 end; 248 Curves[NextPt].isCurvedToPrevious := Curves[i].isCurvedToNext; 249 end; 144 250 end; 145 251 end; 252 end; 253 254 function TBGRAPolygonalGlyph.ContentSize: integer; 255 begin 256 Result:= (inherited ContentSize) + sizeof(single)*2 + 4 + sizeof(single)*2*length(Points); 257 end; 258 259 function TBGRAPolygonalGlyph.HeaderName: string; 260 begin 261 Result:='TBGRAPolygonalGlyph'; 262 end; 263 264 procedure TBGRAPolygonalGlyph.WriteContent(AStream: TStream); 265 var i: integer; 266 begin 267 inherited WriteContent(AStream); 268 WinWritePointF(AStream, Offset); 269 WinWriteLongint(AStream,length(Points)); 270 for i := 0 to high(Points) do 271 WinWritePointF(AStream, Points[i]); 272 end; 273 274 procedure TBGRAPolygonalGlyph.ReadContent(AStream: TStream); 275 var i: integer; 276 tempPts: array of TPointF; 277 begin 278 inherited ReadContent(AStream); 279 Offset := WinReadPointF(AStream); 280 SetLength(tempPts, WinReadLongint(AStream)); 281 for i := 0 to high(tempPts) do 282 tempPts[i] := WinReadPointF(AStream); 283 SetPoints(tempPts); 284 end; 285 286 procedure TBGRAPolygonalGlyph.Init; 287 begin 288 Closed := True; 289 MinimumDotProduct := 0.707; 146 290 end; 147 291 … … 150 294 inherited Create(AIdentifier); 151 295 Offset := PointF(0,0); 296 Init; 297 end; 298 299 constructor TBGRAPolygonalGlyph.Create(AStream: TStream); 300 begin 301 inherited Create(AStream); 302 Init; 152 303 end; 153 304 … … 158 309 for i := 0 to high(points) do 159 310 points[i] := APoints[i]; 311 setlength(CurveMode, length(APoints)); 312 for i := 0 to high(CurveMode) do 313 CurveMode[i] := cmAuto; 160 314 Curves := nil; 161 315 end; 162 316 163 procedure TBGRAPolygonalGlyph.Path(ADest: TBGRACanvas2D; AMatrix: TAffineMatrix); 317 procedure TBGRAPolygonalGlyph.SetPoints(const APoints: array of TPointF; 318 const ACurveMode: array of TGlyphPointCurveMode); 319 var i: integer; 320 begin 321 if length(APoints) <> length(ACurveMode) then 322 raise exception.Create('Dimension mismatch'); 323 SetLength(Points,length(APoints)); 324 for i := 0 to high(points) do 325 points[i] := APoints[i]; 326 setlength(CurveMode, length(ACurveMode)); 327 for i := 0 to high(CurveMode) do 328 CurveMode[i] := ACurveMode[i]; 329 Curves := nil; 330 end; 331 332 procedure TBGRAPolygonalGlyph.Path(ADest: IBGRAPath; AMatrix: TAffineMatrix); 164 333 var i: integer; 165 334 nextMove: boolean; 166 335 startCoord: TPointF; 336 167 337 begin 168 338 if Points = nil then exit; … … 171 341 nextMove := true; 172 342 AMatrix := AMatrix*AffineMatrixTranslation(Offset.X,Offset.Y); 343 173 344 for i := 0 to high(Points) do 174 345 if isEmptyPointF(Points[i]) then … … 206 377 nextMove := false; 207 378 end else 379 begin 208 380 ADest.lineTo(AMatrix*Points[i]); 381 end; 209 382 end; 210 if not nextmove then ADest.closePath; 383 if not nextmove then 384 ADest.closePath; 211 385 end; 212 386 213 387 { TBGRAGlyph } 214 388 389 procedure TBGRAGlyph.WriteHeader(AStream: TStream; AName: string; 390 AContentSize: longint); 391 begin 392 WinWriteByte(AStream, length(AName)); 393 AStream.Write(AName[1],length(AName)); 394 WinWriteLongint(AStream, AContentSize); 395 end; 396 397 class procedure TBGRAGlyph.ReadHeader(AStream: TStream; out AName: string; out 398 AContentSize: longint); 399 var NameLength: integer; 400 begin 401 NameLength := WinReadByte(AStream); 402 setlength(AName,NameLength); 403 AStream.Read(AName[1],length(AName)); 404 AContentSize := WinReadLongint(AStream); 405 end; 406 407 function TBGRAGlyph.ContentSize: integer; 408 begin 409 result := 4+length(FIdentifier)+sizeof(single)*2; 410 end; 411 412 function TBGRAGlyph.HeaderName: string; 413 begin 414 result := 'TBGRAGlyph'; 415 end; 416 417 procedure TBGRAGlyph.WriteContent(AStream: TStream); 418 begin 419 WinWriteLongint(AStream,length(FIdentifier)); 420 AStream.Write(FIdentifier[1],length(FIdentifier)); 421 WinWriteSingle(AStream,Width); 422 WinWriteSingle(AStream,Height); 423 end; 424 425 procedure TBGRAGlyph.ReadContent(AStream: TStream); 426 var lIdentifierLength: integer; 427 begin 428 lIdentifierLength:= WinReadLongint(AStream); 429 setlength(FIdentifier, lIdentifierLength); 430 AStream.Read(FIdentifier[1],length(FIdentifier)); 431 Width := WinReadSingle(AStream); 432 Height := WinReadSingle(AStream); 433 end; 434 215 435 constructor TBGRAGlyph.Create(AIdentifier: string); 216 436 begin 217 437 FIdentifier:= AIdentifier; 438 end; 439 440 constructor TBGRAGlyph.Create(AStream: TStream); 441 begin 442 ReadContent(AStream); 443 end; 444 445 procedure TBGRAGlyph.Path(ADest: IBGRAPath; AMatrix: TAffineMatrix); 446 begin 447 //nothing 448 end; 449 450 procedure TBGRAGlyph.SaveToStream(AStream: TStream); 451 begin 452 WriteHeader(AStream, HeaderName, ContentSize); 453 WriteContent(AStream); 454 end; 455 456 class function TBGRAGlyph.LoadFromStream(AStream: TStream) : TBGRAGlyph; 457 var lName: string; 458 lContentSize: integer; 459 EndPosition: Int64; 460 begin 461 ReadHeader(AStream,lName,lContentSize); 462 EndPosition := AStream.Position + lContentSize; 463 if lName = 'TBGRAPolygonalGlyph' then 464 result := TBGRAPolygonalGlyph.Create(AStream) 465 else if lName = 'TBGRAGlyph' then 466 result := TBGRAGlyph.Create(AStream) 467 else 468 raise exception.Create('Unknown glyph type (' + lName + ')'); 469 AStream.Position:= EndPosition; 218 470 end; 219 471 … … 272 524 TypeWriterMatrix := AffineMatrixIdentity; 273 525 OutlineMode:= twoFill; 526 DrawGlyphsSimultaneously := false; 274 527 end; 275 528 … … 281 534 end; 282 535 283 procedure TBGRACustomTypeWriter.DrawText(ADest: TBGRACanvas2D; AText : string;536 procedure TBGRACustomTypeWriter.DrawText(ADest: TBGRACanvas2D; ATextUTF8: string; 284 537 X, Y: Single; AAlign: TBGRATypeWriterAlignment); 285 538 begin 286 TextPath(ADest, AText, X,Y, AAlign); 287 DrawLastPath(ADest); 539 TextPath(ADest, ATextUTF8, X,Y, AAlign, (OutlineMode <> twoPath) and not DrawGlyphsSimultaneously); 540 end; 541 542 procedure TBGRACustomTypeWriter.CopyTextPathTo(ADest: IBGRAPath; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft); 543 var 544 pstr: pchar; 545 left,charlen: integer; 546 nextchar: string; 547 g: TBGRAGlyph; 548 m,m2: TAffineMatrix; 549 begin 550 if ATextUTF8 = '' then exit; 551 m := GetTextMatrix(ATextUTF8, X,Y,AAlign); 552 m2 := m; 553 554 pstr := @ATextUTF8[1]; 555 left := length(ATextUTF8); 556 while left > 0 do 557 begin 558 charlen := UTF8CharacterLength(pstr); 559 setlength(nextchar, charlen); 560 move(pstr^, nextchar[1], charlen); 561 inc(pstr,charlen); 562 dec(left,charlen); 563 564 g := GetGlyph(nextchar); 565 if g <> nil then 566 begin 567 if AAlign in [twaLeft,twaMiddle,twaRight] then 568 m2 := m*AffineMatrixTranslation(0,-g.Height/2) else 569 if AAlign in [twaBottomLeft,twaBottom,twaBottomRight] then 570 m2 := m*AffineMatrixTranslation(0,-g.Height) 571 else 572 m2 := m; 573 g.Path(ADest, m2); 574 m := m*AffineMatrixTranslation(g.Width,0); 575 end; 576 end; 288 577 end; 289 578 … … 301 590 end; 302 591 303 function TBGRACustomTypeWriter.GetTextBox(AText : string; X, Y: Single;592 function TBGRACustomTypeWriter.GetTextBox(ATextUTF8: string; X, Y: Single; 304 593 AAlign: TBGRATypeWriterAlignment): TAffineBox; 305 594 var … … 313 602 314 603 begin 315 if AText = '' then result := TAffineBox.EmptyBox else316 begin 317 m := GetTextMatrix(AText ,X,Y,AAlign);604 if ATextUTF8 = '' then result := TAffineBox.EmptyBox else 605 begin 606 m := GetTextMatrix(ATextUTF8,X,Y,AAlign); 318 607 minY := 0; 319 608 maxY := 0; 320 609 totalWidth := 0; 321 610 322 pstr := @AText [1];323 left := length(AText );611 pstr := @ATextUTF8[1]; 612 left := length(ATextUTF8); 324 613 while left > 0 do 325 614 begin … … 359 648 end; 360 649 361 function TBGRACustomTypeWriter.GetTextGlyphBoxes(AText : string; X, Y: Single;650 function TBGRACustomTypeWriter.GetTextGlyphBoxes(ATextUTF8: string; X, Y: Single; 362 651 AAlign: TBGRATypeWriterAlignment): TGlyphBoxes; 363 652 var … … 372 661 373 662 begin 374 if AText = '' then result := nil else375 begin 376 setlength(result, UTF8Length(AText ));377 378 m := GetTextMatrix(AText ,X,Y,AAlign);379 380 pstr := @AText [1];381 left := length(AText );663 if ATextUTF8 = '' then result := nil else 664 begin 665 setlength(result, UTF8Length(ATextUTF8)); 666 667 m := GetTextMatrix(ATextUTF8,X,Y,AAlign); 668 669 pstr := @ATextUTF8[1]; 670 left := length(ATextUTF8); 382 671 numChar := 0; 383 672 while left > 0 do … … 418 707 end; 419 708 420 procedure TBGRACustomTypeWriter.TextPath(ADest: TBGRACanvas2D; AText: string; X, 421 Y: Single; AAlign: TBGRATypeWriterAlignment); 709 procedure TBGRACustomTypeWriter.NeedGlyphRange(AUnicodeFrom, AUnicodeTo: Cardinal); 710 var c: cardinal; 711 begin 712 for c := AUnicodeFrom to AUnicodeTo do 713 GetGlyph(UnicodeToUTF8(c)); 714 end; 715 716 procedure TBGRACustomTypeWriter.NeedGlyphAnsiRange; 717 var i: integer; 718 begin 719 for i := 0 to 255 do 720 GetGlyph(AnsiToUtf8(chr(i))); 721 end; 722 723 procedure TBGRACustomTypeWriter.TextPath(ADest: TBGRACanvas2D; ATextUTF8: string; X, 724 Y: Single; AAlign: TBGRATypeWriterAlignment; ADrawEachChar: boolean); 422 725 var 423 726 pstr: pchar; … … 427 730 m,m2: TAffineMatrix; 428 731 begin 429 ADest.beginPath;430 if AText = '' then exit;431 m := GetTextMatrix(AText , X,Y,AAlign);732 if not ADrawEachChar then ADest.beginPath; 733 if ATextUTF8 = '' then exit; 734 m := GetTextMatrix(ATextUTF8, X,Y,AAlign); 432 735 m2 := m; 433 736 434 pstr := @AText [1];435 left := length(AText );737 pstr := @ATextUTF8[1]; 738 left := length(ATextUTF8); 436 739 while left > 0 do 437 740 begin … … 451 754 else 452 755 m2 := m; 756 if ADrawEachChar then ADest.beginPath; 453 757 g.Path(ADest, m2); 758 if ADrawEachChar then DrawLastPath(ADest); 454 759 m := m*AffineMatrixTranslation(g.Width,0); 455 760 end; … … 497 802 end; 498 803 804 procedure TBGRACustomTypeWriter.SaveGlyphsToStream(AStream: TStream); 805 var Enumerator: TAvgLvlTreeNodeEnumerator; 806 begin 807 WinWriteLongint(AStream,CustomHeaderSize); 808 WriteCustomHeader(AStream); 809 810 Enumerator := FGlyphs.GetEnumerator; 811 while Enumerator.MoveNext do 812 TBGRAGlyph(Enumerator.Current.Data).SaveToStream(AStream); 813 Enumerator.Free; 814 end; 815 816 procedure TBGRACustomTypeWriter.LoadGlyphsFromFile(AFilenameUTF8: string); 817 var Stream: TFileStreamUTF8; 818 begin 819 Stream := nil; 820 try 821 Stream := TFileStreamUTF8.Create(AFilenameUTF8, fmOpenRead); 822 LoadGlyphsFromStream(Stream); 823 finally 824 Stream.Free; 825 end; 826 end; 827 828 procedure TBGRACustomTypeWriter.LoadGlyphsFromStream(AStream: TStream); 829 var Header: TBGRACustomTypeWriterHeader; 830 i: integer; 831 g: TBGRAGlyph; 832 HeaderSize: integer; 833 GlyphStartPosition: Int64; 834 begin 835 HeaderSize := WinReadLongint(AStream); 836 GlyphStartPosition:= AStream.Position+HeaderSize; 837 Header := ReadCustomTypeWriterHeader(AStream); 838 if header.HeaderName <> HeaderName then 839 raise exception.Create('Invalid file format ("'+header.HeaderName+'" should be "'+HeaderName+'")'); 840 ReadAdditionalHeader(AStream); 841 AStream.Position:= GlyphStartPosition; 842 for i := 0 to Header.NbGlyphs-1 do 843 begin 844 g := TBGRAGlyph.LoadFromStream(AStream); 845 AddGlyph(g); 846 end; 847 end; 848 849 procedure TBGRACustomTypeWriter.SaveGlyphsToFile(AFilenameUTF8: string); 850 var Stream: TFileStreamUTF8; 851 begin 852 Stream := nil; 853 try 854 Stream := TFileStreamUTF8.Create(AFilenameUTF8, fmCreate or fmOpenWrite); 855 SaveGlyphsToStream(Stream); 856 finally 857 Stream.Free; 858 end; 859 end; 860 499 861 function TBGRACustomTypeWriter.GetGlyphMatrix(AGlyph: TBGRAGlyph; X, Y: Single; 500 862 AAlign: TBGRATypeWriterAlignment): TAffineMatrix; … … 514 876 end; 515 877 516 function TBGRACustomTypeWriter.GetTextMatrix(AText : string; X, Y: Single;878 function TBGRACustomTypeWriter.GetTextMatrix(ATextUTF8: string; X, Y: Single; 517 879 AAlign: TBGRATypeWriterAlignment): TAffineMatrix; 518 880 var … … 528 890 begin 529 891 totalWidth := 0; 530 pstr := @AText [1];531 left := length(AText );892 pstr := @ATextUTF8[1]; 893 left := length(ATextUTF8); 532 894 while left > 0 do 533 895 begin … … 548 910 end; 549 911 912 function TBGRACustomTypeWriter.CustomHeaderSize: integer; 913 begin 914 result := 1+length(HeaderName)+4; 915 end; 916 917 procedure TBGRACustomTypeWriter.WriteCustomHeader(AStream: TStream); 918 var lHeaderName: string; 919 begin 920 lHeaderName:= HeaderName; 921 WinWriteByte(AStream,length(lHeaderName)); 922 AStream.Write(lHeaderName[1],length(lHeaderName)); 923 WinWriteLongint(AStream,FGlyphs.Count); 924 end; 925 926 function TBGRACustomTypeWriter.ReadCustomTypeWriterHeader(AStream: TStream 927 ): TBGRACustomTypeWriterHeader; 928 begin 929 setlength(result.HeaderName, WinReadByte(AStream)); 930 AStream.Read(result.HeaderName[1],length(result.HeaderName)); 931 result.NbGlyphs:= WinReadLongint(AStream); 932 end; 933 934 procedure TBGRACustomTypeWriter.ReadAdditionalHeader(AStream: TStream); 935 begin 936 //nothing 937 end; 938 939 function TBGRACustomTypeWriter.HeaderName: string; 940 begin 941 result := 'TBGRACustomTypeWriter'; 942 end; 943 550 944 destructor TBGRACustomTypeWriter.Destroy; 551 945 begin
Note:
See TracChangeset
for help on using the changeset viewer.