系统应该是矢量的否则字体变化时字会变化很大
矢量字体好象dos的时候考虑比较多,windows很少有人讨论

解决方案 »

  1.   

    大富翁看来的
    ----------------------------
    问题的标题是: 如何用GetGlyphOutline函数获得汉字字符的矢量 (100分 )
    来自:delfan 时间:1998-12-1 17:22:54 ID:93756 GetGlyphOutline函数可以获得一个字符的矢量, 但是只能用于Char类型, 对
    WideChar/UniCode等不可用, 有没有变通办法? 我遍查了Windows SDK, 就是
    找不到答案。那位大虾感兴趣我可以再追加分数。来自:tqz 时间:1998-12-2 22:25:40 ID:93848 当然可以用,我就用过。:)下面是一个从TTF转向Vector的控件源代码。注意:不要理它的UniCode:)其中,CharCode是字符代码,对于双字节的文字,用以下代码生成;function CharCode(value:string):UINT;
    begin
      if Length(value)=1 then
      begin
        CharCode:=Ord(Value[1]);
      end
      else if (Length(value)=2) and(Value[1] in LeadBytes)  then
      begin
        CharCode:=(Ord(Value[1]) shl 8 )or Ord(Value[2]);
      end
      else
      begin
        Raise(Exception.Create(value+'不是合法的中西文字符!'));
        Exit;
      end;
    {
      UTTF2Vct.pas       (was UTTFToVector.pas; changed for 8.3 compatibility )  TTF to Vector converter
      Copyright (c) 1996-97 by Marco Cocco. All rights reseved.
      Copyright (c) 1996-97 by D3K Artisan Of Ware. All rights reseved.  Please send comments to [email protected]
                              [email protected]  URL: http://free.websight.com/Cocco2/  Do you need additional features ? Feel free to ask for it!  ******************************************************************************
      *   Permission to use, copy,  modify, and distribute this software and its   *
      * documentation without fee for any non-commerical purpose is hereby granted,*
      *   provided that the above copyright notice appears on all copies and that  *
      *     both that copyright notice and this permission notice appear in all    *
      *                         supporting documentation.                          *
      *                                                                            *
      * NO REPRESENTATIONS ARE MADE ABOUT THE SUITABILITY OF THIS SOFTWARE FOR ANY *
      *    PURPOSE.  IT IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY.   *
      *   NEITHER MARCO COCCO OR D3K SHALL BE LIABLE FOR ANY DAMAGES SUFFERED BY   *
      *                          THE USE OF THIS SOFTWARE.                         *
      ******************************************************************************
      * D3K - Artisan Of Ware - A Marco Cocco's Company                            *
      * Casella Postale 99 - 09047 Selargius (CA) - ITALY                          *
      ******************************************************************************  History
      ------------------------------------------------------------------
      17/Dec/1996  v1.00 Start of implementation
      19/Dec/1996  v1.01 Added some sparse comments
      20/Dec/1996  v1.02 Added support for Delphi 1.0/Win3.x
      20/Dec/1996  v2.00 Converterd from pure class to component
      20/Dec/1996  v2.01 Added support for UNICODE (Delphi 2.0 only)
      03/Jan/1997  v2.02 Coordinate scaling causing runtime errors has been fixed.
                         Bug in memory allocation has been fixed (Delphi 1.0).
                         Now works even with R+, Q+
      04/Jan/1997  v2.03 Added automatic conversion of glyphs to a GDI region
                         (useful for clipping & special effects)
      14/Jan/1997  v2.04 Some minor changes
      15/Jan/1997  v2.05 Some minor changes  To do:
        - Test for new routines added in v2.03
        - Glyph scaling to caller defined dimensions (!)
        - Baseline coordinate retrieval (!)
        - UNICODE tests (need WinNT to do this) (!)
        - Increase performance and spline precision (?)
        - Triangle subdivision for texture mapping (?)
        - Char to char morphing (?)
        - 3D Extrusion (?)    (!) = to do as soon as possible
        (?) = may be
    }
      

  2.   


    unit UTTF2Vct;interfaceuses
      {$IFDEF WIN32}
      Windows,
      {$ELSE}
      WinTypes, WinProcs,
      {$ENDIF}
      Classes, Graphics, SysUtils;type
      { Font stroke: a Font Stroke is the "basic" element of a character glyph,
                    that is a glyph is a sequence of connected strokes (lines).
                    First point of first stroke connects to last point of last stroke.
                    All strokes with equal GlyphNumber value come from the same glyph.
                    Strokes of the same glyph are stored sequentially, i.e. stroke 0,
                    stroke 1, ... stoke n-1. }
      PFontStroke = ^TFontStroke;
      TFontStroke = record
                      GlyphNumber: integer;
                      Pt1, Pt2: TPoint;          { Note: Strokes[i].Pt2=Strokes[i+1].Pt1
                                                         (also Strokes[i].Pt1=Strokes[i-1].Pt2)
                                                          when Strokes[i].GlyphNumber = Strokes[i+1].GlyphNumber }
                    end;  TEnumStrokesCallback = function( Idx: integer; const Stroke: TFontStroke ): boolean of object;  TStrokeCollection = class( TList )
        private
        protected
          function GetNumGlyphs: integer;
          function GetFontStroke( Idx: integer ): TFontStroke;
          procedure FreeStrokes;
          function GetBounds: TRect;
        public
          constructor Create; virtual;
          destructor Destroy; override;      { Returns the index of the first stroke for the glyph number GlyphNumber }
          function StartOfGlyph( GlyphNumber: integer ): integer;
          { Returns the count of strokes for the glyph number GlyphNumber. }
          function GlyphNumStrokes( GlyphNumber: integer ): integer;
          { Enumerates all strokes of all glyphs }
          procedure EnumStrokes( Callback: TEnumStrokesCallback );      { Returns the number of glyphs }
          property NumGlyphs: integer read GetNumGlyphs;
          { Returns the stroke number Idx. Use StrartOfGlyph to determine
            the index of the first stroke for a given glyph.
            Use GlyphNumStrokes to determine the number of strokes a glyph is. }
          property Stroke[Idx:integer]: TFontStroke read GetFontStroke;
          { Returns the smallest rectangle that completely bounds all glyphs }
          property Bounds: TRect read GetBounds;
      end;  TTTFToVectorConverter = class( TComponent )
        private
          FFont: TFont;
          FSplinePrecision: integer;
          FUNICODE: boolean;
        protected
          procedure SetFont( Value: TFont ); virtual;
          procedure SetSplinePrecision( Value: integer );
        public
          constructor Create( Owner: TComponent ); override;
          destructor Destroy; override;      function GetCharacterGlyphs( CharCode: integer ): TStrokeCollection;
          function StrokesToRegion(Strokes:TStrokeCollection;SizeX, SizeY, OfsX, OfsY: integer ): HRGN;
          function GetCharacterRegion( CharCode, SizeX, SizeY, OfsX, OfsY: integer ): HRGN;    published
          property Font: TFont read FFont write SetFont;
          property Precision: integer read FSplinePrecision write SetSplinePrecision default 5;
          {$IFDEF WIN32}
          { Set to TRUE if you wish retrieve outlines for UNICODE fonts
            NEVER TESTED!!! }
          property UNICODE: boolean read FUNICODE write FUNICODE default false;
          {$ENDIF}
      end;procedure Register;implementation{$IFNDEF WIN32}
    type
      DWORD = longint;  PTTPolygonHeader = ^TTTPolygonHeader;
      TTTPolygonHeader = packed record
        cb: DWORD;
        dwType: DWORD;
        pfxStart: TPointFX;
      end;const
      GDI_ERROR = -1;
    {$ENDIF}{ *** TStrokeCollection ****************** }constructor TStrokeCollection.Create;
    begin
      inherited Create;
    end;destructor TStrokeCollection.Destroy;
    begin
      FreeStrokes;
      inherited Destroy;
    end;procedure TStrokeCollection.FreeStrokes;
    var i: integer;
    begin
      for i := 0 to Count-1 do
      begin
        {$IFDEF WIN32}
        FreeMem( Items[i] );
        {$ELSE}
        FreeMem( Items[i], sizeof(TFontStroke) );
        {$ENDIF}
        Items[i] := nil;
      end;
      Pack;
    end;function TStrokeCollection.GetNumGlyphs: integer;
    begin
      if Count = 0 then
        Result := 0
      else
        Result := PFontStroke(Items[Count-1])^.GlyphNumber+1;
    end;function TStrokeCollection.StartOfGlyph( GlyphNumber: integer ): integer;
    var ng, i: integer;
    begin
      ng := GetNumGlyphs;
      if (GlyphNumber<0) or (GlyphNumber>=ng) then
        Result := -1
      else
      begin
        for i := 0 to Count-1 do
          if PFontStroke(Items[i])^.GlyphNumber = GlyphNumber then
            break;
        Result := i;
      end;
    end;function TStrokeCollection.GlyphNumStrokes( GlyphNumber: integer ): integer;
    var sog, eog: integer;
    begin
      sog := StartOfGlyph( GlyphNumber );
      if sog < 0 then
        Result := -1
      else
      begin
        eog := StartOfGlyph( GlyphNumber+1 );
        if eog < 0 then
          eog := Count;
        Result := eog - sog;
      end;
    end;function TStrokeCollection.GetFontStroke( Idx: integer ): TFontStroke;
    begin
      if (Idx>=0) and (Idx<Count) then
        Result := PFontStroke(Items[Idx])^
      else
        Error('List out of bounds.',0);
    end;procedure TStrokeCollection.EnumStrokes( Callback: TEnumStrokesCallback );
    var i: integer;
    begin
      if not Assigned( Callback ) then
        exit;
      for i := 0 to Count-1 do
        if not Callback( i, PFontStroke(Items[i])^ ) then
          break;
    end;function TStrokeCollection.GetBounds: TRect;
    var i: integer;
        fs: PFontStroke;
    begin
      if Count = 0 then
      begin
        Result := Rect( 0, 0, 0, 0 );
        exit;
      end;
      Result := Rect( MaxInt, MaxInt, -MaxInt, -MaxInt );
      for i := 0 to Count-1 do
      begin
        fs := Items[i];
        if fs^.Pt1.X < Result.Left then
          Result.Left := fs^.Pt1.X;
        if fs^.Pt1.X > Result.Right then
          Result.Right := fs^.Pt1.X;
        if fs^.Pt2.X < Result.Left then
          Result.Left := fs^.Pt2.X;
        if fs^.Pt2.X > Result.Right then
          Result.Right := fs^.Pt2.X;
        if fs^.Pt1.Y < Result.Top then
          Result.Top := fs^.Pt1.Y;
        if fs^.Pt1.Y > Result.Bottom then
          Result.Bottom := fs^.Pt1.Y;
        if fs^.Pt2.Y < Result.Top then
          Result.Top := fs^.Pt2.Y;
        if fs^.Pt2.Y > Result.Bottom then
          Result.Bottom := fs^.Pt2.Y;
      end;
    end;
      

  3.   

    { *** TTTFToVectorConverter ************** }constructor TTTFToVectorConverter.Create( Owner: TComponent );
    begin
      inherited Create( Owner );
      FFont := TFont.Create;
      FFont.Name := 'Arial';
      FFont.Size := 28;
      FSplinePrecision := 8;
      FUNICODE := false;
    end;destructor TTTFToVectorConverter.Destroy;
    begin
      FFont.Free;
      inherited Destroy;
    end;procedure TTTFToVectorConverter.SetFont( Value: TFont );
    begin
      FFont.Assign( Value );
    end;procedure TTTFToVectorConverter.SetSplinePrecision( Value: integer );
    begin
      if (Value<1) or (Value>100) then
        exit;
      FSplinePrecision := Value;
    end;type
      TFXPArray = array[0..MaxInt div sizeof(TPOINTFX)-1] of TPOINTFX;
      PFXPArray = ^TFXPArray;function TTTFToVectorConverter.GetCharacterGlyphs( CharCode: integer ): TStrokeCollection;
    const EMSIZE = 1024; SIZEX = 1024; SIZEY = 1024;
    type TDPoint = record x,y: double end;
    var res, bufSize : integer;
        bufPtr, buf: PTTPolygonHeader;
        pc: PTTPolyCurve;
        dc, mdc: HDC;
        ofont: HFONT;
        gm: TGLYPHMETRICS;
        m2: TMAT2;
        ps, p1, p2 : TDPoint;
        ofs, ofs2, pcSize: integer;
        done: boolean;
        i: integer;
        pfxA, pfxB, pfXC: TDPoint;
        lpAPFX: PFXPArray;
        polyN: integer;
        pcType: integer;
        first: boolean;  function Fix2Double( AFix: TFixed ): double;
      begin
        Result := AFix.fract/65536.0 + AFix.value;
      end;  function EqualPoints( var p1, p2: TDPoint ): boolean;
      begin
        Result := (p1.X = p2.X) and
                  (p1.Y = p2.Y);
      end;  procedure NewStroke( GlyphNumber: integer; var Pt1, Pt2: TDPoint );
      var ps: PFontStroke;
      begin
        ps := AllocMem( sizeof(TFontStroke) );
        ps^.GlyphNumber := GlyphNumber;
        ps^.Pt1.X := round(Pt1.X/EMSIZE*SIZEX);
        ps^.Pt1.Y := round(Pt1.Y/EMSIZE*SIZEY);
        ps^.Pt2.X := round(Pt2.X/EMSIZE*SIZEX);
        ps^.Pt2.Y := round(Pt2.Y/EMSIZE*SIZEY);
        Result.Add( ps );
      end;  procedure DrawQSpline( APolyN: integer; var pa, pb, pc: TDPoint );
      var di, i: double;
          p1,p2: TDPoint;
      begin
        di := 1.0 / FSplinePrecision;
        i := di;
        p2 := pa;
        while i<=1.0 do
        begin
          if i-di/2 > 1.0-di then
            i := 1.0;
          p1 := p2;
          p2.X := (pa.X-2*pb.X+pc.X)*sqr(i) + (2*pb.X-2*pa.X)*i + pa.X;
          p2.Y := (pa.Y-2*pb.Y+pc.Y)*sqr(i) + (2*pb.Y-2*pa.Y)*i + pa.Y;
          if not EqualPoints( p1, p2 ) then
            NewStroke( APolyN, p1, p2 );
          i := i + di;
        end;
        pc := p2;
      end;begin
      Result := nil;
      if Font.Handle = 0 then
        exit;  dc := GetDC( 0 );
      mdc := CreateCompatibleDC( dc );
      ReleaseDC( 0, dc );  FFont.Size := EMSIZE;
      ofont := SelectObject( mdc, FFont.Handle );  m2.eM11.value := 1; m2.eM11.fract := 1; { Identity matrix }
      m2.eM12.value := 0; m2.eM12.fract := 1; { |1,0|           }
      m2.eM21.value := 0; m2.eM21.fract := 1; { |0,1|           }
      m2.eM22.value := 1; m2.eM22.fract := 1;
      

  4.   

    //faint  连续回复不能超过3次 :(
    //------------------------------------------------
    {$IFDEF WIN32}
      if not FUNICODE then
        bufSize := GetGlyphOutline( mdc,
                                    CharCode,
                                    GGO_NATIVE,
                                    gm,
                                    0, nil,
                                    m2 )
      else
        bufSize := GetGlyphOutlineW( mdc,
                                     CharCode,
                                     GGO_NATIVE,
                                     gm,
                                     0, nil,
                                     m2 );
      {$ELSE}
      bufSize := GetGlyphOutline( mdc,
                                  CharCode,
                                  GGO_NATIVE,
                                  gm,
                                  0, nil,
                                  m2 );
      {$ENDIF}
      if (bufSize = GDI_ERROR) or (bufSize=0) then
      begin
        SelectObject( mdc, ofont );
        DeleteDC( mdc );
        exit;
      end;  bufPtr := AllocMem( bufSize );
      buf := bufPtr;  {$IFDEF WIN32}
      if not FUNICODE then
        res := GetGlyphOutline( mdc,
                                CharCode,
                                GGO_NATIVE,
                                gm,
                                bufSize, pchar(buf),
                                m2 )
      else
        res := GetGlyphOutlineW( mdc,
                                 CharCode,
                                 GGO_NATIVE,
                                 gm,
                                 bufSize, pchar(buf),
                                 m2 );
      {$ELSE}
      res := GetGlyphOutline( mdc,
                              CharCode,
                              GGO_NATIVE,
                              gm,
                              bufSize, pchar(buf),
                              m2 );
      {$ENDIF}
      SelectObject( mdc, ofont );
      DeleteDC( mdc );
      if (res = GDI_ERROR) or (buf^.dwType <> TT_POLYGON_TYPE) then
      begin
        {$IFDEF WIN32}
        FreeMem( bufPtr );
        {$ELSE}
        FreeMem( bufPtr, bufSize );
        {$ENDIF}
        exit;
      end;  Result := TStrokeCollection.Create;  done := false;
      ofs := 0;
      polyN := 0;
      while not done do
      begin
        ps.X := Fix2Double( buf^.pfxStart.X );
        ps.Y := Fix2Double( buf^.pfxStart.Y );
        pcSize := buf^.cb - sizeof(TTTPOLYGONHEADER);
        pchar(pc) := pchar(buf) + sizeof(TTTPOLYGONHEADER);
        ofs2 := 0;
        p2 := ps;
        while not done and (ofs2 < pcSize) do
        begin
          pcType := pc^.wType;
          case pcType of
            TT_PRIM_LINE:
              begin
                lpAPFX := @pc^.apfx[0];
                for i := 0 to pc^.cpfx-1 do
                begin
                  p1 := p2;
                  p2.X := Fix2Double(lpAPFX^[i].X);
                  p2.Y := Fix2Double(lpAPFX^[i].Y);
                  if not EqualPoints( p1, p2 ) then
                    NewStroke( polyN, p1, p2 );
                end;
              end;
            TT_PRIM_QSPLINE:
              begin
                lpAPFX := @pc^.apfx[0];
                pfxA := p2;
                for i := 0 to pc^.cpfx-2 do
                begin
                  pfxB.X := Fix2Double(lpAPFX^[i].X);
                  pfxB.Y := Fix2Double(lpAPFX^[i].Y);
                  if i < pc^.cpfx-2 then
                  begin
                    pfxC.X := Fix2Double(lpAPFX^[i+1].X);
                    pfxC.Y := Fix2Double(lpAPFX^[i+1].Y);
                    pfxC.X := (pfxC.X + pfxB.X) / 2;
                    pfxC.Y := (pfxC.Y + pfxB.Y) / 2;
                  end
                  else
                  begin
                    pfxC.X := Fix2Double(lpAPFX^[i+1].X);
                    pfxC.Y := Fix2Double(lpAPFX^[i+1].Y);
                  end;
                  DrawQSpline( polyN, pfxA, pfxB, pfxC );
                  pfxA := pfxC;
                end;
                p2 := pfxC;
              end;
          end;
          ofs2 := ofs2 + sizeof(TTTPOLYCURVE) + (pc^.cpfx-1)*sizeof(TPOINTFX);
          pchar(pc) := pchar(pc) + sizeof(TTTPOLYCURVE) + (pc^.cpfx-1)*sizeof(TPOINTFX);
        end;
        if not done then
        begin
          p1 := p2;
          p2 := ps;
          if not EqualPoints( p1, p2 ) then
            NewStroke( polyN, p1, p2 );
          ofs := ofs + pcSize + sizeof(TTTPOLYGONHEADER);
          done := ofs >= bufSize-sizeof(TTTPolygonHeader);
          pchar(buf) := pchar(pc);
          inc( polyN );
        end;
      end;
      {$IFDEF WIN32}
      FreeMem( bufPtr );
      {$ELSE}
      FreeMem( bufPtr, bufSize );
      {$ENDIF}
    end;
      

  5.   

    function TTTFToVectorConverter.GetCharacterRegion( CharCode, SizeX, SizeY, OfsX, OfsY: integer ): HRGN;
    var strokes: TStrokeCollection;
        cbounds: TRect;
        i, j, k, sog: integer;
        polys, pps: ^TPoint;
        {$ifdef WIN32}
        polyCounts, ppc: ^UINT;
        {$else}
        polyCounts, ppc: ^word;
        {$endif}
        stroke: TFontStroke;
        sx, sy: double; { Scaling factors }
    begin
      { ************************************** }
      {  Convert to polilines                  }
      { ************************************** }
      strokes := GetCharacterGlyphs( CharCode );
      if strokes = nil then
      begin
        Result := 0;
        exit;
      end;
      { ************************************** }
      {  Compose the GDI region                }
      { ************************************** }
      {  Get character bounds }
      cbounds := strokes.Bounds;
      {  Scaling factors }
      sx := SizeX/(cbounds.Right-cbounds.Left+1);
      sy := SizeY/(cbounds.Bottom-cbounds.Top+1);
      {  Allocate memory for (all) the points }
      polys := AllocMem( sizeof(TPoint) * strokes.Count );
      {  Allocate memory for the "points per polygon" counters }
      {$IFDEF WIN32}
      polyCounts := AllocMem( sizeof(UINT) * strokes.NumGlyphs );
      {$ELSE}
      polyCounts := AllocMem( sizeof(word) * strokes.NumGlyphs );
      {$ENDIF}
      {  Copy glyphs' points to the allocated buffers }
      pps := polys;
      ppc := polyCounts;
      for i := 0 to strokes.NumGlyphs-1 do
      begin
        ppc^ := strokes.GlyphNumStrokes( i );
        sog := strokes.StartOfGlyph( i );
        for j := 0 to ppc^-1 do
        begin
          {  Get a stroke }
          stroke := strokes.Stroke[sog+j];
          {  Store it }
          pps^.x := OfsX + round( (stroke.Pt1.X-cbounds.Left) * sx );
          pps^.y := OfsY + round( (cbounds.Bottom-stroke.Pt1.Y) * sy ); {  Flip vertically! }
          {  Next }
          pps := pointer( pchar(pps) + sizeof(TPoint) );
        end;
        ppc := pointer( pchar(ppc) + sizeof(ppc^) );
      end;
      Result := CreatePolyPolygonRgn( polys^,
                                      polyCounts^,
                                      strokes.NumGlyphs,
                                      WINDING );
      {  Release buffers }
      {$IFDEF WIN32}
      FreeMem( polys );
      FreeMem( polyCounts );
      {$ELSE}
      FreeMem( polys, sizeof(TPoint) * strokes.Count );
      FreeMem( polyCounts, sizeof(word) * strokes.NumGlyphs );
      {$ENDIF}
      {  Release the strokes }
      strokes.Free;
    end;function TTTFToVectorConverter.StrokesToRegion(Strokes:TStrokeCollection;SizeX, SizeY, OfsX, OfsY: integer ): HRGN;
    var
        cbounds: TRect;
        i, j, k, sog: integer;
        polys, pps: ^TPoint;
        {$ifdef WIN32}
        polyCounts, ppc: ^UINT;
        {$else}
        polyCounts, ppc: ^word;
        {$endif}
        stroke: TFontStroke;
        sx, sy: double; { Scaling factors }
    begin
      { ************************************** }
      {  Convert to polilines                  }
      { ************************************** }
      if strokes = nil then
      begin
        Result := 0;
        exit;
      end;
      { ************************************** }
      {  Compose the GDI region                }
      { ************************************** }
      {  Get character bounds }
      cbounds := strokes.Bounds;
      {  Scaling factors }
      sx := SizeX/(cbounds.Right-cbounds.Left+1);
      sy := SizeY/(cbounds.Bottom-cbounds.Top+1);
      {  Allocate memory for (all) the points }
      polys := AllocMem( sizeof(TPoint) * strokes.Count );
      {  Allocate memory for the "points per polygon" counters }
      {$IFDEF WIN32}
      polyCounts := AllocMem( sizeof(UINT) * strokes.NumGlyphs );
      {$ELSE}
      polyCounts := AllocMem( sizeof(word) * strokes.NumGlyphs );
      {$ENDIF}
      {  Copy glyphs' points to the allocated buffers }
      pps := polys;
      ppc := polyCounts;
      for i := 0 to strokes.NumGlyphs-1 do
      begin
        ppc^ := strokes.GlyphNumStrokes( i );
        sog := strokes.StartOfGlyph( i );
        for j := 0 to ppc^-1 do
        begin
          {  Get a stroke }
          stroke := strokes.Stroke[sog+j];
          {  Store it }
          pps^.x := OfsX + round( (stroke.Pt1.X-cbounds.Left) * sx );
          pps^.y := OfsY + round( (cbounds.Bottom-stroke.Pt1.Y) * sy ); {  Flip vertically! }
          {  Next }
          pps := pointer( pchar(pps) + sizeof(TPoint) );
        end;
        ppc := pointer( pchar(ppc) + sizeof(ppc^) );
      end;
      Result := CreatePolyPolygonRgn( polys^,
                                      polyCounts^,
                                      strokes.NumGlyphs,
                                      WINDING );
      {  Release buffers }
      {$IFDEF WIN32}
      FreeMem( polys );
      FreeMem( polyCounts );
      {$ELSE}
      FreeMem( polys, sizeof(TPoint) * strokes.Count );
      FreeMem( polyCounts, sizeof(word) * strokes.NumGlyphs );
      {$ENDIF}
      {  Release the strokes }
      strokes.Free;
    end;
    procedure Register;
    begin
      RegisterComponents( 'D3K', [TTTFToVectorConverter]);
    end;end.
      

  6.   

    to 竹子:
        你有for D6的版本吗?
      

  7.   

    这个只能装上看看了看他的  History
      ------------------------------------------------------------------
      15/Jan/1997  v2.05 Some minor changes