Ignore:
Timestamp:
Apr 9, 2015, 9:58:36 PM (9 years ago)
Author:
chronos
Message:
  • Fixed: Use csOpaque control style also to Image, PaintBox and OpenGLControl.
  • Modified: Change size of test frame with SpinEdits as delayed using timer.
  • Updated: BRGABitmap package to version 8.1.
File:
1 edited

Legend:

Unmodified
Added
Removed
  • GraphicTest/Packages/bgrabitmap/bgratypewriter.pas

    r452 r472  
    1919  protected
    2020    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;
    2127  public
    2228    Width,Height: single;
    2329    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;
    2532    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);
    2738
    2839  { TBGRAPolygonalGlyph }
     
    3445    FQuadraticCurves: boolean;
    3546    Points: array of TPointF;
     47    CurveMode: array of TGlyphPointCurveMode;
    3648    Curves: array of record
    3749      isCurvedToNext,isCurvedToPrevious: boolean;
     
    4052    function MaybeCurve(start1,end1,start2,end2: integer): boolean;
    4153    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;
    4259  public
    4360    Offset: TPointF;
     61    Closed: boolean;
     62    MinimumDotProduct: single;
    4463    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;
    4768    property QuadraticCurves: boolean read FQuadraticCurves write SetQuadraticCurves;
     69  end;
     70
     71  TBGRACustomTypeWriterHeader = record
     72    HeaderName: String;
     73    NbGlyphs: integer;
    4874  end;
    4975
     
    5985    function GetGlyph(AIdentifier: string): TBGRAGlyph; virtual;
    6086    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);
    6288    procedure GlyphPath(ADest: TBGRACanvas2D; AIdentifier: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft);
    6389    procedure DrawLastPath(ADest: TBGRACanvas2D);
     
    6692    procedure AddGlyph(AGlyph: TBGRAGlyph);
    6793    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;
    6995    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;
    70101  public
    71102    OutlineMode: TBGRATypeWriterOutlineMode;
     103    DrawGlyphsSimultaneously : boolean;
    72104    constructor Create;
     105    procedure SaveGlyphsToFile(AFilenameUTF8: string);
     106    procedure SaveGlyphsToStream(AStream: TStream);
     107    procedure LoadGlyphsFromFile(AFilenameUTF8: string);
     108    procedure LoadGlyphsFromStream(AStream: TStream);
    73109    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;
    75112    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;
    78117    destructor Destroy; override;
    79118  end;
    80119
     120function ComputeEasyBezier(APoints: array of TPointF; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF; overload;
     121function ComputeEasyBezier(APoints: array of TPointF; ACurveMode: array of TGlyphPointCurveMode; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF; overload;
     122
    81123implementation
    82124
    83 uses LCLProc;
     125uses LCLProc, lazutf8classes;
     126
     127{$i winstream.inc}
     128
     129function ComputeEasyBezier(APoints: array of TPointF; AClosed: boolean; AMinimumDotProduct: single = 0.707): ArrayOfTPointF;
     130var
     131  glyph: TBGRAPolygonalGlyph;
     132  canvas2D: TBGRACanvas2D;
     133  i: integer;
     134begin
     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;
     153end;
     154
     155function ComputeEasyBezier(APoints: array of TPointF;
     156  ACurveMode: array of TGlyphPointCurveMode; AClosed: boolean;
     157  AMinimumDotProduct: single): ArrayOfTPointF;
     158var
     159  glyph: TBGRAPolygonalGlyph;
     160  canvas2D: TBGRACanvas2D;
     161  i: integer;
     162begin
     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;
     181end;
    84182
    85183{ TBGRAPolygonalGlyph }
     
    109207  if lv <> 0 then v *= 1/lv;
    110208
    111   result := u*v > 0.707;
     209  result := u*v > MinimumDotProduct;
    112210end;
    113211
     
    119217  FirstPointIndex := 0;
    120218  for i := 0 to high(points) do
     219    Curves[i].isCurvedToPrevious := false;
     220  for i := 0 to high(points) do
    121221  begin
    122222    Curves[i].isCurvedToNext := false;
    123     Curves[i].isCurvedToPrevious := false;
    124223    Curves[i].Center := EmptyPointF;
    125224    Curves[i].ControlPoint := EmptyPointF;
     
    138237      Curves[i].Center := (points[i]+points[NextPt])*0.5;
    139238      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;
    143239      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;
    144250    end;
    145251  end;
     252end;
     253
     254function TBGRAPolygonalGlyph.ContentSize: integer;
     255begin
     256  Result:= (inherited ContentSize) + sizeof(single)*2 + 4 + sizeof(single)*2*length(Points);
     257end;
     258
     259function TBGRAPolygonalGlyph.HeaderName: string;
     260begin
     261  Result:='TBGRAPolygonalGlyph';
     262end;
     263
     264procedure TBGRAPolygonalGlyph.WriteContent(AStream: TStream);
     265var i: integer;
     266begin
     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]);
     272end;
     273
     274procedure TBGRAPolygonalGlyph.ReadContent(AStream: TStream);
     275var i: integer;
     276  tempPts: array of TPointF;
     277begin
     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);
     284end;
     285
     286procedure TBGRAPolygonalGlyph.Init;
     287begin
     288  Closed := True;
     289  MinimumDotProduct := 0.707;
    146290end;
    147291
     
    150294  inherited Create(AIdentifier);
    151295  Offset := PointF(0,0);
     296  Init;
     297end;
     298
     299constructor TBGRAPolygonalGlyph.Create(AStream: TStream);
     300begin
     301  inherited Create(AStream);
     302  Init;
    152303end;
    153304
     
    158309  for i := 0 to high(points) do
    159310    points[i] := APoints[i];
     311  setlength(CurveMode, length(APoints));
     312  for i := 0 to high(CurveMode) do
     313    CurveMode[i] := cmAuto;
    160314  Curves := nil;
    161315end;
    162316
    163 procedure TBGRAPolygonalGlyph.Path(ADest: TBGRACanvas2D; AMatrix: TAffineMatrix);
     317procedure TBGRAPolygonalGlyph.SetPoints(const APoints: array of TPointF;
     318  const ACurveMode: array of TGlyphPointCurveMode);
     319var i: integer;
     320begin
     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;
     330end;
     331
     332procedure TBGRAPolygonalGlyph.Path(ADest: IBGRAPath; AMatrix: TAffineMatrix);
    164333var i: integer;
    165334  nextMove: boolean;
    166335  startCoord: TPointF;
     336
    167337begin
    168338  if Points = nil then exit;
     
    171341  nextMove := true;
    172342  AMatrix := AMatrix*AffineMatrixTranslation(Offset.X,Offset.Y);
     343
    173344  for i := 0 to high(Points) do
    174345    if isEmptyPointF(Points[i]) then
     
    206377        nextMove := false;
    207378      end else
     379      begin
    208380        ADest.lineTo(AMatrix*Points[i]);
     381      end;
    209382    end;
    210   if not nextmove then ADest.closePath;
     383  if not nextmove then
     384    ADest.closePath;
    211385end;
    212386
    213387{ TBGRAGlyph }
    214388
     389procedure TBGRAGlyph.WriteHeader(AStream: TStream; AName: string;
     390  AContentSize: longint);
     391begin
     392  WinWriteByte(AStream, length(AName));
     393  AStream.Write(AName[1],length(AName));
     394  WinWriteLongint(AStream, AContentSize);
     395end;
     396
     397class procedure TBGRAGlyph.ReadHeader(AStream: TStream; out AName: string; out
     398  AContentSize: longint);
     399var NameLength: integer;
     400begin
     401  NameLength := WinReadByte(AStream);
     402  setlength(AName,NameLength);
     403  AStream.Read(AName[1],length(AName));
     404  AContentSize := WinReadLongint(AStream);
     405end;
     406
     407function TBGRAGlyph.ContentSize: integer;
     408begin
     409  result := 4+length(FIdentifier)+sizeof(single)*2;
     410end;
     411
     412function TBGRAGlyph.HeaderName: string;
     413begin
     414  result := 'TBGRAGlyph';
     415end;
     416
     417procedure TBGRAGlyph.WriteContent(AStream: TStream);
     418begin
     419  WinWriteLongint(AStream,length(FIdentifier));
     420  AStream.Write(FIdentifier[1],length(FIdentifier));
     421  WinWriteSingle(AStream,Width);
     422  WinWriteSingle(AStream,Height);
     423end;
     424
     425procedure TBGRAGlyph.ReadContent(AStream: TStream);
     426var lIdentifierLength: integer;
     427begin
     428  lIdentifierLength:= WinReadLongint(AStream);
     429  setlength(FIdentifier, lIdentifierLength);
     430  AStream.Read(FIdentifier[1],length(FIdentifier));
     431  Width := WinReadSingle(AStream);
     432  Height := WinReadSingle(AStream);
     433end;
     434
    215435constructor TBGRAGlyph.Create(AIdentifier: string);
    216436begin
    217437  FIdentifier:= AIdentifier;
     438end;
     439
     440constructor TBGRAGlyph.Create(AStream: TStream);
     441begin
     442  ReadContent(AStream);
     443end;
     444
     445procedure TBGRAGlyph.Path(ADest: IBGRAPath; AMatrix: TAffineMatrix);
     446begin
     447  //nothing
     448end;
     449
     450procedure TBGRAGlyph.SaveToStream(AStream: TStream);
     451begin
     452  WriteHeader(AStream, HeaderName, ContentSize);
     453  WriteContent(AStream);
     454end;
     455
     456class function TBGRAGlyph.LoadFromStream(AStream: TStream) : TBGRAGlyph;
     457var lName: string;
     458  lContentSize: integer;
     459  EndPosition: Int64;
     460begin
     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;
    218470end;
    219471
     
    272524  TypeWriterMatrix := AffineMatrixIdentity;
    273525  OutlineMode:= twoFill;
     526  DrawGlyphsSimultaneously := false;
    274527end;
    275528
     
    281534end;
    282535
    283 procedure TBGRACustomTypeWriter.DrawText(ADest: TBGRACanvas2D; AText: string;
     536procedure TBGRACustomTypeWriter.DrawText(ADest: TBGRACanvas2D; ATextUTF8: string;
    284537  X, Y: Single; AAlign: TBGRATypeWriterAlignment);
    285538begin
    286   TextPath(ADest, AText, X,Y, AAlign);
    287   DrawLastPath(ADest);
     539  TextPath(ADest, ATextUTF8, X,Y, AAlign, (OutlineMode <> twoPath) and not DrawGlyphsSimultaneously);
     540end;
     541
     542procedure TBGRACustomTypeWriter.CopyTextPathTo(ADest: IBGRAPath; ATextUTF8: string; X,Y: Single; AAlign: TBGRATypeWriterAlignment = twaTopLeft);
     543var
     544  pstr: pchar;
     545  left,charlen: integer;
     546  nextchar: string;
     547  g: TBGRAGlyph;
     548  m,m2: TAffineMatrix;
     549begin
     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;
    288577end;
    289578
     
    301590end;
    302591
    303 function TBGRACustomTypeWriter.GetTextBox(AText: string; X, Y: Single;
     592function TBGRACustomTypeWriter.GetTextBox(ATextUTF8: string; X, Y: Single;
    304593  AAlign: TBGRATypeWriterAlignment): TAffineBox;
    305594var
     
    313602
    314603begin
    315   if AText = '' then result := TAffineBox.EmptyBox else
    316   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);
    318607    minY := 0;
    319608    maxY := 0;
    320609    totalWidth := 0;
    321610
    322     pstr := @AText[1];
    323     left := length(AText);
     611    pstr := @ATextUTF8[1];
     612    left := length(ATextUTF8);
    324613    while left > 0 do
    325614    begin
     
    359648end;
    360649
    361 function TBGRACustomTypeWriter.GetTextGlyphBoxes(AText: string; X, Y: Single;
     650function TBGRACustomTypeWriter.GetTextGlyphBoxes(ATextUTF8: string; X, Y: Single;
    362651  AAlign: TBGRATypeWriterAlignment): TGlyphBoxes;
    363652var
     
    372661
    373662begin
    374   if AText = '' then result := nil else
    375   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);
    382671    numChar := 0;
    383672    while left > 0 do
     
    418707end;
    419708
    420 procedure TBGRACustomTypeWriter.TextPath(ADest: TBGRACanvas2D; AText: string; X,
    421   Y: Single; AAlign: TBGRATypeWriterAlignment);
     709procedure TBGRACustomTypeWriter.NeedGlyphRange(AUnicodeFrom, AUnicodeTo: Cardinal);
     710var c: cardinal;
     711begin
     712  for c := AUnicodeFrom to AUnicodeTo do
     713    GetGlyph(UnicodeToUTF8(c));
     714end;
     715
     716procedure TBGRACustomTypeWriter.NeedGlyphAnsiRange;
     717var i: integer;
     718begin
     719  for i := 0 to 255 do
     720    GetGlyph(AnsiToUtf8(chr(i)));
     721end;
     722
     723procedure TBGRACustomTypeWriter.TextPath(ADest: TBGRACanvas2D; ATextUTF8: string; X,
     724  Y: Single; AAlign: TBGRATypeWriterAlignment; ADrawEachChar: boolean);
    422725var
    423726  pstr: pchar;
     
    427730  m,m2: TAffineMatrix;
    428731begin
    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);
    432735  m2 := m;
    433736
    434   pstr := @AText[1];
    435   left := length(AText);
     737  pstr := @ATextUTF8[1];
     738  left := length(ATextUTF8);
    436739  while left > 0 do
    437740  begin
     
    451754      else
    452755        m2 := m;
     756      if ADrawEachChar then ADest.beginPath;
    453757      g.Path(ADest, m2);
     758      if ADrawEachChar then DrawLastPath(ADest);
    454759      m := m*AffineMatrixTranslation(g.Width,0);
    455760    end;
     
    497802end;
    498803
     804procedure TBGRACustomTypeWriter.SaveGlyphsToStream(AStream: TStream);
     805var Enumerator: TAvgLvlTreeNodeEnumerator;
     806begin
     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;
     814end;
     815
     816procedure TBGRACustomTypeWriter.LoadGlyphsFromFile(AFilenameUTF8: string);
     817var Stream: TFileStreamUTF8;
     818begin
     819  Stream := nil;
     820  try
     821    Stream := TFileStreamUTF8.Create(AFilenameUTF8, fmOpenRead);
     822    LoadGlyphsFromStream(Stream);
     823  finally
     824    Stream.Free;
     825  end;
     826end;
     827
     828procedure TBGRACustomTypeWriter.LoadGlyphsFromStream(AStream: TStream);
     829var Header: TBGRACustomTypeWriterHeader;
     830  i: integer;
     831  g: TBGRAGlyph;
     832  HeaderSize: integer;
     833  GlyphStartPosition: Int64;
     834begin
     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;
     847end;
     848
     849procedure TBGRACustomTypeWriter.SaveGlyphsToFile(AFilenameUTF8: string);
     850var Stream: TFileStreamUTF8;
     851begin
     852  Stream := nil;
     853  try
     854    Stream := TFileStreamUTF8.Create(AFilenameUTF8, fmCreate or fmOpenWrite);
     855    SaveGlyphsToStream(Stream);
     856  finally
     857    Stream.Free;
     858  end;
     859end;
     860
    499861function TBGRACustomTypeWriter.GetGlyphMatrix(AGlyph: TBGRAGlyph; X, Y: Single;
    500862  AAlign: TBGRATypeWriterAlignment): TAffineMatrix;
     
    514876end;
    515877
    516 function TBGRACustomTypeWriter.GetTextMatrix(AText: string; X, Y: Single;
     878function TBGRACustomTypeWriter.GetTextMatrix(ATextUTF8: string; X, Y: Single;
    517879  AAlign: TBGRATypeWriterAlignment): TAffineMatrix;
    518880var
     
    528890  begin
    529891    totalWidth := 0;
    530     pstr := @AText[1];
    531     left := length(AText);
     892    pstr := @ATextUTF8[1];
     893    left := length(ATextUTF8);
    532894    while left > 0 do
    533895    begin
     
    548910end;
    549911
     912function TBGRACustomTypeWriter.CustomHeaderSize: integer;
     913begin
     914  result := 1+length(HeaderName)+4;
     915end;
     916
     917procedure TBGRACustomTypeWriter.WriteCustomHeader(AStream: TStream);
     918var lHeaderName: string;
     919begin
     920  lHeaderName:= HeaderName;
     921  WinWriteByte(AStream,length(lHeaderName));
     922  AStream.Write(lHeaderName[1],length(lHeaderName));
     923  WinWriteLongint(AStream,FGlyphs.Count);
     924end;
     925
     926function TBGRACustomTypeWriter.ReadCustomTypeWriterHeader(AStream: TStream
     927  ): TBGRACustomTypeWriterHeader;
     928begin
     929  setlength(result.HeaderName, WinReadByte(AStream));
     930  AStream.Read(result.HeaderName[1],length(result.HeaderName));
     931  result.NbGlyphs:= WinReadLongint(AStream);
     932end;
     933
     934procedure TBGRACustomTypeWriter.ReadAdditionalHeader(AStream: TStream);
     935begin
     936  //nothing
     937end;
     938
     939function TBGRACustomTypeWriter.HeaderName: string;
     940begin
     941  result := 'TBGRACustomTypeWriter';
     942end;
     943
    550944destructor TBGRACustomTypeWriter.Destroy;
    551945begin
Note: See TracChangeset for help on using the changeset viewer.