mirror of
https://gitlab.com/freepascal.org/fpc/source.git
synced 2025-04-16 15:59:30 +02:00
+ FreeType font and freetype font library calls
+ test program for fonts
This commit is contained in:
parent
07504a9e93
commit
8d26c4604b
850
fcl/image/freetype.pp
Normal file
850
fcl/image/freetype.pp
Normal file
@ -0,0 +1,850 @@
|
||||
{
|
||||
$Id$
|
||||
This file is part of the Free Pascal run time library.
|
||||
Copyright (c) 2003 by the Free Pascal development team
|
||||
|
||||
Basic canvas definitions.
|
||||
|
||||
See the file COPYING.FPC, included in this distribution,
|
||||
for details about the copyright.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
**********************************************************************}
|
||||
{$mode objfpc}{$h+}
|
||||
unit freetype;
|
||||
|
||||
interface
|
||||
|
||||
uses sysutils, classes, freetypeh, FPImgCmn;
|
||||
|
||||
{ TODO : take resolution in account to find the size }
|
||||
{ TODO : speed optimization: search glyphs with a hash-function/tree/binary search/... }
|
||||
{ TODO : memory optimization: TStringBitmaps keeps for each differnet character
|
||||
only 1 bitmap }
|
||||
{ TODO : load other files depending on the extention }
|
||||
{ possible TODO : different sizes/resolutions for x and y }
|
||||
{ possible TODO : TFontmanager can fill a list of all the fonts he can find
|
||||
fontfiles and faces available in a fontfile }
|
||||
|
||||
// determine if file comparison need to be case sensitive or not
|
||||
{$ifdef WIN32}
|
||||
{$undef CaseSense}
|
||||
{$else}
|
||||
{$define CaseSense}
|
||||
{$endif}
|
||||
|
||||
type
|
||||
|
||||
FreeTypeException = class (exception);
|
||||
|
||||
TBitmapType = (btBlackWhite, bt256Gray);
|
||||
TFontBitmap = record
|
||||
height, width, pitch,
|
||||
x,y, advanceX, advanceY : integer;
|
||||
data : PByteArray;
|
||||
end;
|
||||
PFontBitmap = ^TFontBitmap;
|
||||
|
||||
|
||||
TStringBitMaps = class
|
||||
private
|
||||
FList : TList;
|
||||
FBounds : TRect;
|
||||
FText : string;
|
||||
FMode : TBitmapType;
|
||||
function GetCount : integer;
|
||||
function GetBitmap (index:integer) : PFontBitmap;
|
||||
procedure CalculateGlobals;
|
||||
public
|
||||
constructor Create (ACount : integer);
|
||||
destructor destroy; override;
|
||||
procedure GetBoundRect (var aRect : TRect);
|
||||
property Text : string read FText;
|
||||
property Mode : TBitmapType read FMode;
|
||||
property Count : integer read GetCount;
|
||||
property Bitmaps[index:integer] : PFontBitmap read GetBitmap;
|
||||
end;
|
||||
|
||||
TFontManager = class;
|
||||
|
||||
PMgrGlyph = ^TMgrGlyph;
|
||||
TMgrGlyph = record
|
||||
Character : char;
|
||||
GlyphIndex : FT_UInt;
|
||||
Glyph : PFT_Glyph;
|
||||
end;
|
||||
|
||||
PMgrSize = ^TMgrSize;
|
||||
TMgrSize = record
|
||||
Resolution, Size : integer;
|
||||
Glyphs : TList;
|
||||
end;
|
||||
|
||||
TMgrFont = class
|
||||
private
|
||||
Mgr : TFontManager;
|
||||
Font : PFT_Face;
|
||||
FSizes : TList;
|
||||
Filename : string;
|
||||
LastSize : PMgrSize;
|
||||
procedure FreeGlyphs;
|
||||
public
|
||||
constructor Create (aMgr:TFontManager; afilename:string; anindex:integer);
|
||||
destructor destroy; override;
|
||||
end;
|
||||
|
||||
TFontManager = class
|
||||
private
|
||||
FTLib : PFT_Library;
|
||||
FList : TList;
|
||||
FPaths : TStringList;
|
||||
FExtention : string;
|
||||
FResolution : integer;
|
||||
CurFont : TMgrFont;
|
||||
CurSize : PMgrSize;
|
||||
CurRenderMode : FT_Render_Mode;
|
||||
CurTransform : FT_Matrix;
|
||||
UseKerning : boolean;
|
||||
function GetSearchPath : string;
|
||||
procedure SetSearchPath (AValue : string);
|
||||
procedure SetExtention (AValue : string);
|
||||
protected
|
||||
function GetFontId (afilename:string; anindex:integer) : integer;
|
||||
function CreateFont (afilename:string; anindex:integer) : integer;
|
||||
function SearchFont (afilename:string) : string;
|
||||
function GetFont (FontID:integer) : TMgrFont;
|
||||
procedure GetSize (aSize, aResolution : integer);
|
||||
function CreateSize (aSize, aResolution : integer) : PMgrSize;
|
||||
procedure SetPixelSize (aSize, aResolution : integer);
|
||||
function GetGlyph (c : char) : PMgrGlyph;
|
||||
function CreateGlyph (c : char) : PMgrGlyph;
|
||||
procedure MakeTransformation (angle:real; var Transformation:FT_Matrix);
|
||||
procedure InitMakeString (FontID, Size:integer);
|
||||
function MakeString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
|
||||
function MakeString (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
|
||||
public
|
||||
constructor Create;
|
||||
destructor destroy; override;
|
||||
function RequestFont (afilename:string) : integer;
|
||||
function RequestFont (afilename:string; anindex:integer) : integer;
|
||||
function GetFreeTypeFont (aFontID:integer) : PFT_Face;
|
||||
function GetString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
|
||||
// Black and white
|
||||
function GetStringGray (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
|
||||
// Anti Aliased gray scale
|
||||
function GetString (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
|
||||
// Black and white, following the direction of the font (left to right, top to bottom, ...)
|
||||
function GetStringGray (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
|
||||
// Anti Aliased gray scale, following the direction of the font (left to right, top to bottom, ...)
|
||||
property SearchPath : string read GetSearchPath write SetSearchPath;
|
||||
property DefaultExtention : string read FExtention write SetExtention;
|
||||
property Resolution : integer read Fresolution write FResolution;
|
||||
end;
|
||||
|
||||
const
|
||||
sErrErrorsInCleanup : string = '%d errors detected while freeing a Font Manager object';
|
||||
sErrFontFileNotFound : string = 'Font file "%s" not found';
|
||||
sErrFreeType : string = 'Error %d while %s';
|
||||
sInitializing : string = 'initializing font engine';
|
||||
sDestroying : string = 'destroying font engine';
|
||||
sErrErrorInCleanup : string = 'freeing Font Manager object';
|
||||
sErrSetPixelSize : string = 'setting pixel size %d (resolution %d)';
|
||||
sErrSetCharSize : string = 'setting char size %d (resolution %d)';
|
||||
sErrLoadingGlyph : string = 'loading glyph';
|
||||
sErrKerning : string = 'determining kerning distance';
|
||||
sErrMakingString : string = 'making string bitmaps';
|
||||
sErrLoadFont : string = 'loading font %d from file %s';
|
||||
sErrInitializing : string = 'initializing FreeType';
|
||||
sErrDestroying : string = 'finalizing FreeType';
|
||||
|
||||
DefaultFontExtention : string = '.ttf';
|
||||
DefaultSearchPath : string = '';
|
||||
{$IFDEF MAC}
|
||||
DefaultResolution : integer = 72;
|
||||
{$ELSE}
|
||||
DefaultResolution : integer = 97;
|
||||
{$ENDIF}
|
||||
|
||||
implementation
|
||||
|
||||
{$IFDEF win32}uses dos;{$ENDIF}
|
||||
|
||||
procedure FTError (Event:string; Err:integer);
|
||||
begin
|
||||
raise FreeTypeException.CreateFmt (sErrFreeType, [Event,Err]);
|
||||
end;
|
||||
|
||||
{ TMgrFont }
|
||||
|
||||
constructor TMgrFont.Create (aMgr:TFontManager; afilename:string; anindex:integer);
|
||||
var e : integer;
|
||||
begin
|
||||
inherited create;
|
||||
Filename := afilename;
|
||||
Mgr := aMgr;
|
||||
FSizes := TList.create;
|
||||
LastSize := nil;
|
||||
e := FT_New_Face (aMgr.FTLib, pchar(afilename), anindex, font);
|
||||
if e <> 0 then
|
||||
begin
|
||||
Font := nil;
|
||||
FTError (format (sErrLoadFont,[afilename,anindex]), e);
|
||||
end;
|
||||
end;
|
||||
|
||||
destructor TMgrFont.destroy;
|
||||
begin
|
||||
try
|
||||
FreeGlyphs;
|
||||
finally
|
||||
FSizes.Free;
|
||||
inherited Destroy;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TMgrFont.FreeGlyphs;
|
||||
var r,t : integer;
|
||||
S : PMgrSize;
|
||||
G : PMgrGlyph;
|
||||
begin
|
||||
for r := FSizes.count-1 downto 0 do
|
||||
begin
|
||||
with PMgrSize(FSizes[r])^ do
|
||||
begin
|
||||
for t := Glyphs.count-1 downto 0 do
|
||||
begin
|
||||
with PMgrGlyph(Glyphs[t])^ do
|
||||
FT_Done_Glyph (Glyph);
|
||||
G := PMgrGlyph(Glyphs[t]);
|
||||
dispose (G);
|
||||
end;
|
||||
Glyphs.Free;
|
||||
end;
|
||||
S := PMgrSize(FSizes[r]);
|
||||
dispose (S);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
{ TFontManager }
|
||||
|
||||
constructor TFontManager.Create;
|
||||
var r : integer;
|
||||
begin
|
||||
inherited create;
|
||||
FList := Tlist.Create;
|
||||
FPaths := TStringList.Create;
|
||||
r := FT_Init_FreeType(FTLib);
|
||||
if r <> 0 then
|
||||
begin
|
||||
FTLib := nil;
|
||||
FTError (sErrInitializing, r);
|
||||
end;
|
||||
SearchPath := DefaultSearchPath;
|
||||
DefaultExtention := DefaultFontExtention;
|
||||
Resolution := DefaultResolution;
|
||||
end;
|
||||
|
||||
destructor TFontManager.Destroy;
|
||||
procedure FreeFontObjects;
|
||||
var r : integer;
|
||||
begin
|
||||
for r := FList.Count-1 downto 0 do
|
||||
begin
|
||||
GetFont(r).Free;
|
||||
end;
|
||||
end;
|
||||
procedure FreeLibrary;
|
||||
var r : integer;
|
||||
begin
|
||||
r := FT_Done_FreeType (FTlib);
|
||||
if r <> 0 then
|
||||
FTError (sErrDestroying, r);
|
||||
end;
|
||||
begin
|
||||
FreeFontObjects;
|
||||
FList.Free;
|
||||
FPaths.Free;
|
||||
try
|
||||
if assigned(FTLib) then
|
||||
FreeLibrary;
|
||||
finally
|
||||
inherited Destroy;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFontManager.GetSearchPath : string;
|
||||
var r : integer;
|
||||
begin
|
||||
if FPaths.count > 0 then
|
||||
begin
|
||||
result := FPaths[0];
|
||||
for r := 1 to FPaths.count-1 do
|
||||
result := result + ';' + FPaths[r];
|
||||
end
|
||||
else
|
||||
result := '';
|
||||
end;
|
||||
|
||||
procedure TFontManager.SetSearchPath (AValue : string);
|
||||
procedure AddPath (apath : string);
|
||||
begin
|
||||
FPaths.Add (IncludeTrailingBackslash(Apath));
|
||||
end;
|
||||
var p : integer;
|
||||
begin
|
||||
while (AValue <> '') do
|
||||
begin
|
||||
p := pos (';', AValue);
|
||||
if p = 0 then
|
||||
begin
|
||||
AddPath (AValue);
|
||||
AValue := '';
|
||||
end
|
||||
else
|
||||
begin
|
||||
AddPath (copy(AValue,1,p-1));
|
||||
delete (AVAlue,1,p);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFontManager.SetExtention (AValue : string);
|
||||
begin
|
||||
if AValue <> '' then
|
||||
if AValue[1] <> '.' then
|
||||
FExtention := '.' + AValue
|
||||
else
|
||||
FExtention := AValue
|
||||
else
|
||||
AValue := '';
|
||||
end;
|
||||
|
||||
function TFontManager.SearchFont (afilename:string) : string;
|
||||
// returns full filename of font, taking SearchPath in account
|
||||
var p,fn : string;
|
||||
r : integer;
|
||||
begin
|
||||
if (pos('.', afilename)=0) and (DefaultFontExtention<>'') then
|
||||
fn := afilename + DefaultFontExtention
|
||||
else
|
||||
fn := aFilename;
|
||||
if FileExists(fn) then
|
||||
result := ExpandFilename(fn)
|
||||
else
|
||||
begin
|
||||
p := ExtractFilepath(fn);
|
||||
if p = '' then
|
||||
begin // no path given, look in SearchPaths
|
||||
r := FPaths.Count;
|
||||
repeat
|
||||
dec (r);
|
||||
until (r < 0) or FileExists(FPaths[r]+fn);
|
||||
if r < 0 then
|
||||
raise FreeTypeException.CreateFmt (sErrFontFileNotFound, [fn])
|
||||
else
|
||||
result := FPaths[r]+fn;
|
||||
end
|
||||
else
|
||||
raise FreeTypeException.CreateFmt (sErrFontFileNotFound, [afilename]);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFontManager.GetFontId (afilename:string; anindex:integer) : integer;
|
||||
begin
|
||||
result := FList.count-1;
|
||||
while (result >= 0) and
|
||||
( ({$ifdef CaseSense}CompareText{$else}CompareStr{$endif}
|
||||
(TMgrFont(FList[anIndex]).Filename, afilename) <> 0) or
|
||||
(anIndex <> TMgrFont(FList[anIndex]).font^.face_index)
|
||||
) do
|
||||
dec (result);
|
||||
end;
|
||||
|
||||
function TFontManager.CreateFont (afilename:string; anindex:integer) : integer;
|
||||
var f : TMgrFont;
|
||||
begin
|
||||
writeln ('creating font ',afilename,' (',anindex,')');
|
||||
f := TMgrFont.Create (self, afilename, anindex);
|
||||
result := FList.Count;
|
||||
Flist.Add (f);
|
||||
end;
|
||||
|
||||
function TFontManager.GetFont (FontID:integer) : TMgrFont;
|
||||
begin
|
||||
result := TMgrFont(FList[FontID]);
|
||||
if result <> CurFont then // set last used size of the font as current size
|
||||
begin
|
||||
CurSize := result.LastSize;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFontManager.GetSize (aSize, aResolution : integer);
|
||||
var r : integer;
|
||||
begin
|
||||
if not ( assigned(CurSize) and
|
||||
(CurSize^.Size = aSize) and (CurSize^.resolution = aResolution)) then
|
||||
begin
|
||||
r := CurFont.FSizes.count;
|
||||
repeat
|
||||
dec (r)
|
||||
until (r < 0) or ( (PMgrSize(CurFont.FSizes[r])^.size = aSize) and
|
||||
(PMgrSize(CurFont.FSizes[r])^.resolution = FResolution) );
|
||||
if r < 0 then
|
||||
CurSize := CreateSize (aSize,aResolution)
|
||||
else
|
||||
CurSize := PMgrSize(CurFont.FSizes[r]);
|
||||
CurFont.LastSize := CurSize;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFontManager.CreateSize (aSize, aResolution : integer) : PMgrSize;
|
||||
begin
|
||||
new (result);
|
||||
result^.Size := aSize;
|
||||
result^.Size := aResolution;
|
||||
result^.Glyphs := Tlist.Create;
|
||||
SetPixelSize (aSize,aResolution);
|
||||
CurFont.FSizes.Add (result);
|
||||
end;
|
||||
|
||||
procedure TFontManager.SetPixelSize (aSize, aResolution : integer);
|
||||
|
||||
procedure CheckSize;
|
||||
var r : integer;
|
||||
begin
|
||||
with Curfont.Font^ do
|
||||
begin
|
||||
r := Num_fixed_sizes;
|
||||
repeat
|
||||
dec (r);
|
||||
until (r < 0) or
|
||||
( (available_sizes^[r].height=asize) and
|
||||
(available_sizes^[r].width=asize) );
|
||||
if r >= 0 then
|
||||
raise FreeTypeException.CreateFmt ('Size %d not available for %s %s',
|
||||
[aSize, style_name, family_name]);
|
||||
end;
|
||||
end;
|
||||
|
||||
var s : longint;
|
||||
Err : integer;
|
||||
|
||||
begin
|
||||
with Curfont, Font^ do
|
||||
if (face_flags and FT_Face_Flag_Fixed_Sizes) <> 0 then
|
||||
begin
|
||||
CheckSize;
|
||||
Err := FT_Set_pixel_sizes (Font, aSize, aSize);
|
||||
if Err <> 0 then
|
||||
FTError (format(sErrSetPixelSize,[aSize,aResolution]), Err);
|
||||
end
|
||||
else
|
||||
begin
|
||||
s := aSize shl 6;
|
||||
Err := FT_Set_char_size (Font, s, s, aResolution, aResolution);
|
||||
if Err <> 0 then
|
||||
FTError (format(sErrSetCharSize,[aSize,aResolution]), Err);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFontManager.MakeTransformation (angle:real; var Transformation:FT_Matrix);
|
||||
begin
|
||||
with Transformation do
|
||||
begin
|
||||
xx := round( cos(angle)*$10000);
|
||||
xy := round(-sin(angle)*$10000);
|
||||
yx := round( sin(angle)*$10000);
|
||||
yy := round( cos(angle)*$10000);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFontManager.CreateGlyph (c : char) : PMgrGlyph;
|
||||
var e : integer;
|
||||
begin
|
||||
new (result);
|
||||
result^.character := c;
|
||||
result^.GlyphIndex := FT_Get_Char_Index (CurFont.font, ord(c));
|
||||
e := FT_Load_Glyph (CurFont.font, result^.GlyphIndex, FT_Load_Default);
|
||||
if e <> 0 then
|
||||
begin
|
||||
FTError (sErrLoadingGlyph, e);
|
||||
end;
|
||||
e := FT_Get_Glyph (Curfont.font^.glyph, result^.glyph);
|
||||
if e <> 0 then
|
||||
begin
|
||||
FTError (sErrLoadingGlyph, e);
|
||||
end;
|
||||
CurSize^.Glyphs.Add (result);
|
||||
end;
|
||||
|
||||
function TFontManager.GetGlyph (c : char) : PMgrGlyph;
|
||||
var r : integer;
|
||||
begin
|
||||
With CurSize^ do
|
||||
begin
|
||||
r := FList.Count;
|
||||
repeat
|
||||
dec (r)
|
||||
until (r < 0) or (PMgrGlyph(Flist[r])^.character = c);
|
||||
if r < 0 then
|
||||
result := CreateGlyph (c)
|
||||
else
|
||||
result := PMgrGlyph(Flist[r]);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFontManager.InitMakeString (FontID, Size:integer);
|
||||
begin
|
||||
GetSize (size,Resolution);
|
||||
UseKerning := ((Curfont.font^.face_flags and FT_FACE_FLAG_KERNING) <> 0);
|
||||
end;
|
||||
|
||||
function TFontManager.MakeString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
|
||||
var g : PMgrGlyph;
|
||||
bm : PFT_BitmapGlyph;
|
||||
gl : PFT_Glyph;
|
||||
e, prevIndex, prevx, c, r, rx : integer;
|
||||
pre, adv, pos, kern : FT_Vector;
|
||||
buf : PByteArray;
|
||||
reverse : boolean;
|
||||
trans : FT_Matrix;
|
||||
begin
|
||||
CurFont := GetFont(FontID);
|
||||
if (Angle = 0) or // no angle asked, or can't work with angles (not scalable)
|
||||
((CurFont.Font^.face_flags and FT_FACE_FLAG_SCALABLE)=0) then
|
||||
result := MakeString (FontID, Text, Size)
|
||||
else
|
||||
begin
|
||||
InitMakeString (FontID, Size);
|
||||
c := length(text);
|
||||
result := TStringBitmaps.Create(c);
|
||||
if (CurRenderMode = FT_RENDER_MODE_MONO) then
|
||||
result.FMode := btBlackWhite
|
||||
else
|
||||
result.FMode := bt256Gray;
|
||||
MakeTransformation (angle, trans);
|
||||
prevIndex := 0;
|
||||
prevx := 0;
|
||||
pos.x := 0;
|
||||
pos.y := 0;
|
||||
pre.x := 0;
|
||||
pre.y := 0;
|
||||
for r := 0 to c-1 do
|
||||
begin
|
||||
// retrieve loaded glyph
|
||||
g := GetGlyph (Text[r+1]);
|
||||
// check kerning
|
||||
if UseKerning and (g^.glyphindex <>0) and (PrevIndex <> 0) then
|
||||
begin
|
||||
prevx := pre.x;
|
||||
e := FT_Get_Kerning (Curfont.Font, prevIndex, g^.GlyphIndex, ft_kerning_default, kern);
|
||||
if e <> 0 then
|
||||
FTError (sErrKerning, e);
|
||||
pre.x := pre.x + kern.x;
|
||||
end;
|
||||
// render the glyph
|
||||
e := FT_Glyph_Copy (g^.glyph, gl);
|
||||
if e <> 0 then
|
||||
FTError (sErrMakingString, e);
|
||||
// placing the glyph
|
||||
e := FT_Glyph_Transform (gl, nil, @pre);
|
||||
if e <> 0 then
|
||||
FTError (sErrMakingString, e);
|
||||
adv := gl^.advance;
|
||||
// rotating the glyph
|
||||
e := FT_Glyph_Transform (gl, @trans, nil);
|
||||
if e <> 0 then
|
||||
FTError (sErrMakingString, e);
|
||||
// rendering the glyph
|
||||
e := FT_Glyph_To_Bitmap (gl, CurRenderMode, nil, true);
|
||||
if e <> 0 then
|
||||
FTError (sErrMakingString, e);
|
||||
// Copy what is needed to record
|
||||
bm := PFT_BitmapGlyph(gl);
|
||||
with result.Bitmaps[r]^ do
|
||||
begin
|
||||
with gl^.advance do
|
||||
begin
|
||||
advanceX := x div 64;
|
||||
advanceY := y div 64;
|
||||
end;
|
||||
with bm^ do
|
||||
begin
|
||||
height := bitmap.rows;
|
||||
width := bitmap.width;
|
||||
x := {(pos.x div 64)} + left; // transformed bitmap has correct x,y
|
||||
y := {(pos.y div 64)} - top; // not transformed has only a relative correction
|
||||
buf := PByteArray(bitmap.buffer);
|
||||
reverse := (bitmap.pitch < 0);
|
||||
if reverse then
|
||||
begin
|
||||
pitch := -bitmap.pitch;
|
||||
getmem (data, pitch*height);
|
||||
for rx := height-1 downto 0 do
|
||||
move (buf^[rx*pitch], data^[(height-rx-1)*pitch], pitch);
|
||||
end
|
||||
else
|
||||
begin
|
||||
pitch := bitmap.pitch;
|
||||
rx := pitch*height;
|
||||
getmem (data, rx);
|
||||
move (buf^[0], data^[0], rx);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
// place position for next glyph
|
||||
with gl^.advance do
|
||||
begin
|
||||
pos.x := pos.x + (x div 1024);
|
||||
pos.y := pos.y + (y div 1024);
|
||||
end;
|
||||
with adv do
|
||||
pre.x := pre.x + (x div 1024);
|
||||
if prevx > pre.x then
|
||||
pre.x := prevx;
|
||||
// finish rendered glyph
|
||||
FT_Done_Glyph (gl);
|
||||
end;
|
||||
result.FText := Text;
|
||||
result.CalculateGlobals;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFontManager.MakeString (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
|
||||
var g : PMgrGlyph;
|
||||
bm : PFT_BitmapGlyph;
|
||||
gl : PFT_Glyph;
|
||||
e, prevIndex, prevx, c, r, rx : integer;
|
||||
pos, kern : FT_Vector;
|
||||
buf : PByteArray;
|
||||
reverse : boolean;
|
||||
begin
|
||||
CurFont := GetFont(FontID);
|
||||
InitMakeString (FontID, Size);
|
||||
c := length(text);
|
||||
result := TStringBitmaps.Create(c);
|
||||
if (CurRenderMode = FT_RENDER_MODE_MONO) then
|
||||
result.FMode := btBlackWhite
|
||||
else
|
||||
result.FMode := bt256Gray;
|
||||
prevIndex := 0;
|
||||
prevx := 0;
|
||||
pos.x := 0;
|
||||
pos.y := 0;
|
||||
for r := 0 to c-1 do
|
||||
begin
|
||||
// retrieve loaded glyph
|
||||
g := GetGlyph (Text[r+1]);
|
||||
// check kerning
|
||||
if UseKerning and (g^.glyphindex <>0) and (PrevIndex <> 0) then
|
||||
begin
|
||||
prevx := pos.x;
|
||||
e := FT_Get_Kerning (Curfont.Font, prevIndex, g^.GlyphIndex, ft_kerning_default, kern);
|
||||
if e <> 0 then
|
||||
FTError (sErrKerning, e);
|
||||
pos.x := pos.x + kern.x;
|
||||
end;
|
||||
// render the glyph
|
||||
e := FT_Glyph_Copy (g^.glyph, gl);
|
||||
if e <> 0 then
|
||||
FTError (sErrMakingString, e);
|
||||
e := FT_Glyph_To_Bitmap (gl, CurRenderMode, @pos, true);
|
||||
if e <> 0 then
|
||||
FTError (sErrMakingString, e);
|
||||
// Copy what is needed to record
|
||||
bm := PFT_BitmapGlyph(gl);
|
||||
with result.Bitmaps[r]^ do
|
||||
begin
|
||||
with gl^.advance do
|
||||
begin
|
||||
advanceX := x shr 6;
|
||||
advanceY := y shr 6;
|
||||
end;
|
||||
with bm^ do
|
||||
begin
|
||||
height := bitmap.rows;
|
||||
width := bitmap.width;
|
||||
x := (pos.x shr 6) + left; // transformed bitmap has correct x,y
|
||||
y := (pos.y shr 6) - top; // not transformed has only a relative correction
|
||||
buf := PByteArray(bitmap.buffer);
|
||||
reverse := (bitmap.pitch < 0);
|
||||
if reverse then
|
||||
begin
|
||||
pitch := -bitmap.pitch;
|
||||
getmem (data, pitch*height);
|
||||
for rx := height-1 downto 0 do
|
||||
move (buf^[rx*pitch], data^[(height-rx-1)*pitch], pitch);
|
||||
end
|
||||
else
|
||||
begin
|
||||
pitch := bitmap.pitch;
|
||||
rx := pitch*height;
|
||||
getmem (data, rx);
|
||||
move (buf^[0], data^[0], rx);
|
||||
end;
|
||||
end;
|
||||
end;
|
||||
// place position for next glyph
|
||||
pos.x := pos.x + (gl^.advance.x shr 10);
|
||||
// pos.y := pos.y + (gl^.advance.y shr 6); // for angled texts also
|
||||
if prevx > pos.x then
|
||||
pos.x := prevx;
|
||||
// finish rendered glyph
|
||||
FT_Done_Glyph (gl);
|
||||
end;
|
||||
result.FText := Text;
|
||||
result.CalculateGlobals;
|
||||
end;
|
||||
|
||||
function TFontManager.GetString (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
|
||||
// Black and white
|
||||
begin
|
||||
CurRenderMode := FT_RENDER_MODE_MONO;
|
||||
result := MakeString (FontID, text, Size, angle);
|
||||
end;
|
||||
|
||||
function TFontManager.GetStringGray (FontId:integer; Text:string; size:integer; angle:real) : TStringBitmaps;
|
||||
// Anti Aliased gray scale
|
||||
begin
|
||||
CurRenderMode := FT_RENDER_MODE_NORMAL;
|
||||
result := MakeString (FontID, text, Size, angle);
|
||||
end;
|
||||
|
||||
{ Procedures without angle have own implementation to have better speed }
|
||||
|
||||
function TFontManager.GetString (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
|
||||
// Black and white, following the direction of the font (left to right, top to bottom, ...)
|
||||
begin
|
||||
CurRenderMode := FT_RENDER_MODE_MONO;
|
||||
result := MakeString (FontID, text, Size);
|
||||
end;
|
||||
|
||||
function TFontManager.GetStringGray (FontId:integer; Text:string; Size:integer) : TStringBitmaps;
|
||||
// Anti Aliased gray scale, following the direction of the font (left to right, top to bottom, ...)
|
||||
begin
|
||||
CurRenderMode := FT_RENDER_MODE_NORMAL;
|
||||
result := MakeString (FontID, text, Size);
|
||||
end;
|
||||
|
||||
function TFontManager.RequestFont (afilename:string) : integer;
|
||||
begin
|
||||
result := RequestFont (afilename,0);
|
||||
end;
|
||||
|
||||
function TFontManager.RequestFont (afilename:string; anindex:integer) : integer;
|
||||
var s : string;
|
||||
begin
|
||||
if afilename = '' then
|
||||
result := -1
|
||||
else
|
||||
begin
|
||||
s := SearchFont (afilename);
|
||||
result := GetFontID (s,anindex);
|
||||
if result < 0 then
|
||||
result := CreateFont (s,anindex);
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFontManager.GetFreeTypeFont (aFontID:integer) : PFT_Face;
|
||||
begin
|
||||
result := GetFont(aFontID).font;
|
||||
end;
|
||||
|
||||
{ TStringBitmaps }
|
||||
|
||||
function TStringBitmaps.GetCount : integer;
|
||||
begin
|
||||
result := FList.Count;
|
||||
end;
|
||||
|
||||
function TStringBitmaps.GetBitmap (index:integer) : PFontBitmap;
|
||||
begin
|
||||
result := PFontBitmap(FList[index]);
|
||||
end;
|
||||
|
||||
constructor TStringBitmaps.Create (ACount : integer);
|
||||
var r : integer;
|
||||
bm : PFontBitmap;
|
||||
begin
|
||||
inherited create;
|
||||
FList := Tlist.Create;
|
||||
FList.Capacity := ACount;
|
||||
for r := 0 to ACount-1 do
|
||||
begin
|
||||
new (bm);
|
||||
FList.Add (bm);
|
||||
end;
|
||||
end;
|
||||
|
||||
destructor TStringBitmaps.destroy;
|
||||
var r : integer;
|
||||
bm : PFontBitmap;
|
||||
begin
|
||||
for r := 0 to Flist.count-1 do
|
||||
begin
|
||||
bm := PFontBitmap(FList[r]);
|
||||
freemem (bm^.data);
|
||||
dispose (bm);
|
||||
end;
|
||||
FList.Free;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
procedure TStringBitmaps.CalculateGlobals;
|
||||
var r : integer;
|
||||
begin
|
||||
if count = 0 then
|
||||
Exit;
|
||||
// check first 2 bitmaps for left side
|
||||
// check last 2 bitmaps for right side
|
||||
with BitMaps[0]^ do
|
||||
begin
|
||||
FBounds.left := x;
|
||||
FBounds.top := y + height;
|
||||
FBounds.bottom := y;
|
||||
end;
|
||||
with Bitmaps[count-1]^ do
|
||||
FBounds.right := x + width;
|
||||
if count > 1 then
|
||||
begin
|
||||
with Bitmaps[1]^ do
|
||||
r := x;
|
||||
if r < FBounds.left then
|
||||
FBounds.left := r;
|
||||
with Bitmaps[count-2]^ do
|
||||
r := x + width;
|
||||
if r > FBounds.right then
|
||||
FBounds.right := r;
|
||||
end;
|
||||
// check top/bottom of other bitmaps
|
||||
for r := 1 to count-1 do
|
||||
with Bitmaps[r]^ do
|
||||
begin
|
||||
if FBounds.top < y + height then
|
||||
FBounds.top := y + height;
|
||||
if FBounds.bottom > y then
|
||||
FBounds.bottom := y;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TStringBitmaps.GetBoundRect (var aRect : TRect);
|
||||
begin
|
||||
aRect := FBounds;
|
||||
end;
|
||||
|
||||
{$ifdef win32}
|
||||
procedure SetWindowsFontPath;
|
||||
begin
|
||||
DefaultSearchPath := includetrailingbackslash(GetEnv('windir')) + 'fonts';
|
||||
end;
|
||||
{$endif}
|
||||
|
||||
initialization
|
||||
{$ifdef win32}
|
||||
SetWindowsFontPath;
|
||||
{$endif}
|
||||
end.
|
336
fcl/image/freetypeh.pp
Normal file
336
fcl/image/freetypeh.pp
Normal file
@ -0,0 +1,336 @@
|
||||
{
|
||||
$Id$
|
||||
This file is part of the Free Pascal run time library.
|
||||
Copyright (c) 2003 by the Free Pascal development team
|
||||
|
||||
Basic canvas definitions.
|
||||
|
||||
See the file COPYING.FPC, included in this distribution,
|
||||
for details about the copyright.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
**********************************************************************}
|
||||
{$mode objfpc}
|
||||
unit freetypeh;
|
||||
|
||||
{ These are not all the availlable calls from the dll, but only those
|
||||
I needed for the TStringBimaps }
|
||||
|
||||
interface
|
||||
|
||||
const
|
||||
{$ifdef win32}
|
||||
freetypedll = 'freetype-6.dll'; // version 2.1.4
|
||||
{$packrecords c}
|
||||
{$else}
|
||||
// I don't know what it will be ??
|
||||
freetypedll = 'freetype-6.dll';
|
||||
{$endif}
|
||||
|
||||
type
|
||||
FT_Encoding = array[0..3] of char;
|
||||
|
||||
const
|
||||
FT_FACE_FLAG_SCALABLE = 1 shl 0;
|
||||
FT_FACE_FLAG_FIXED_SIZES = 1 shl 1;
|
||||
FT_FACE_FLAG_FIXED_WIDTH = 1 shl 2;
|
||||
FT_FACE_FLAG_SFNT = 1 shl 3;
|
||||
FT_FACE_FLAG_HORIZONTAL = 1 shl 4;
|
||||
FT_FACE_FLAG_VERTICAL = 1 shl 5;
|
||||
FT_FACE_FLAG_KERNING = 1 shl 6;
|
||||
FT_FACE_FLAG_FAST_GLYPHS = 1 shl 7;
|
||||
FT_FACE_FLAG_MULTIPLE_MASTERS = 1 shl 8;
|
||||
FT_FACE_FLAG_GLYPH_NAMES = 1 shl 9;
|
||||
FT_FACE_FLAG_EXTERNAL_STREAM = 1 shl 10;
|
||||
|
||||
FT_STYLE_FLAG_ITALIC = 1 shl 0;
|
||||
FT_STYLE_FLAG_BOLD = 1 shl 1;
|
||||
|
||||
FT_LOAD_DEFAULT = $0000;
|
||||
FT_LOAD_NO_SCALE = $0001;
|
||||
FT_LOAD_NO_HINTING = $0002;
|
||||
FT_LOAD_RENDER = $0004;
|
||||
FT_LOAD_NO_BITMAP = $0008;
|
||||
FT_LOAD_VERTICAL_LAYOUT = $0010;
|
||||
FT_LOAD_FORCE_AUTOHINT = $0020;
|
||||
FT_LOAD_CROP_BITMAP = $0040;
|
||||
FT_LOAD_PEDANTIC = $0080;
|
||||
FT_LOAD_IGNORE_GLOBAL_ADVANCE_WIDTH = $0200;
|
||||
FT_LOAD_NO_RECURSE = $0400;
|
||||
FT_LOAD_IGNORE_TRANSFORM = $0800;
|
||||
FT_LOAD_MONOCHROME = $1000;
|
||||
FT_LOAD_LINEAR_DESIGN = $2000;
|
||||
|
||||
ft_glyph_format_none = $00000000;
|
||||
ft_glyph_format_composite = $636F6D70; //comp 099 111 109 112
|
||||
ft_glyph_format_bitmap = $62697473; //bits 098 105 116 115
|
||||
ft_glyph_format_outline = $6F75746C; //outl 111 117 116 108
|
||||
ft_glyph_format_plotter = $706C6F74; //plot 112 108 111 116
|
||||
|
||||
FT_ENCODING_MS_SYMBOL : FT_Encoding = 'symb';
|
||||
FT_ENCODING_UNICODE : FT_Encoding = 'unic';
|
||||
FT_ENCODING_MS_SJIS : FT_Encoding = 'sjis';
|
||||
FT_ENCODING_MS_GB2312 : FT_Encoding = 'gb ';
|
||||
FT_ENCODING_MS_BIG5 : FT_Encoding = 'big5';
|
||||
FT_ENCODING_MS_WANSUNG : FT_Encoding = 'wans';
|
||||
FT_ENCODING_MS_JOHAB : FT_Encoding = 'joha';
|
||||
FT_ENCODING_ADOBE_STANDARD : FT_Encoding = 'ADOB';
|
||||
FT_ENCODING_ADOBE_EXPERT : FT_Encoding = 'ADBE';
|
||||
FT_ENCODING_ADOBE_CUSTOM : FT_Encoding = 'ADBC';
|
||||
FT_ENCODING_ADOBE_LATIN_1 : FT_Encoding = 'lat1';
|
||||
FT_ENCODING_OLD_LATIN_2 : FT_Encoding = 'lat2';
|
||||
FT_ENCODING_APPLE_ROMAN : FT_Encoding = 'armn';
|
||||
|
||||
ft_glyph_bbox_unscaled = 0; //* return unscaled font units */
|
||||
ft_glyph_bbox_subpixels = 0; //* return unfitted 26.6 coordinates */
|
||||
ft_glyph_bbox_gridfit = 1; //* return grid-fitted 26.6 coordinates */
|
||||
ft_glyph_bbox_truncate = 2; //* return coordinates in integer pixels */
|
||||
ft_glyph_bbox_pixels = 3; //* return grid-fitted pixel coordinates */
|
||||
|
||||
FT_KERNING_DEFAULT = 0;
|
||||
FT_KERNING_UNFITTED = 1;
|
||||
FT_KERNING_UNSCALED = 2;
|
||||
|
||||
|
||||
type
|
||||
|
||||
FT_Bool = boolean;
|
||||
FT_FWord = smallint;
|
||||
FT_UFWord = word;
|
||||
FT_Char = char;
|
||||
FT_Byte = byte;
|
||||
FT_String = char;
|
||||
FT_Short = smallint;
|
||||
FT_UShort = word;
|
||||
FT_Int = longint;
|
||||
FT_UInt = longword;
|
||||
FT_Long = longint;
|
||||
FT_ULong = longword;
|
||||
FT_F2Dot14 = smallint;
|
||||
FT_F26Dot6 = longint;
|
||||
FT_Fixed = longint;
|
||||
FT_Error = longint;
|
||||
FT_Pointer = pointer;
|
||||
FT_Pos = longint;
|
||||
//FT_Offset = size_t;
|
||||
//FT_PtrDist = size_t;
|
||||
|
||||
FT_Render_Mode = (FT_RENDER_MODE_NORMAL, FT_RENDER_MODE_LIGHT,
|
||||
FT_RENDER_MODE_MONO, FT_RENDER_MODE_LCD, FT_RENDER_MODE_LCD_V,
|
||||
FT_RENDER_MODE_MAX);
|
||||
|
||||
FT_UnitVector_ = record
|
||||
x : FT_F2Dot14;
|
||||
y : FT_F2Dot14;
|
||||
end;
|
||||
FT_UnitVector = FT_UnitVector_;
|
||||
|
||||
FT_Matrix = record
|
||||
xx : FT_Fixed;
|
||||
xy : FT_Fixed;
|
||||
yx : FT_Fixed;
|
||||
yy : FT_Fixed;
|
||||
end;
|
||||
PFT_Matrix = ^FT_Matrix;
|
||||
|
||||
FT_Data = record
|
||||
pointer : ^FT_Byte;
|
||||
length : FT_Int;
|
||||
end;
|
||||
|
||||
FT_Generic_Finalizer = procedure (AnObject:pointer);cdecl;
|
||||
|
||||
FT_Generic = record
|
||||
data : pointer;
|
||||
finalizer : FT_Generic_Finalizer;
|
||||
end;
|
||||
|
||||
FT_Glyph_Metrics = record
|
||||
width : FT_Pos;
|
||||
height : FT_Pos;
|
||||
horiBearingX : FT_Pos;
|
||||
horiBearingY : FT_Pos;
|
||||
horiAdvance : FT_Pos;
|
||||
vertBearingX : FT_Pos;
|
||||
vertBearingY : FT_Pos;
|
||||
vertAdvance : FT_Pos;
|
||||
end;
|
||||
|
||||
FT_Bitmap_Size = record
|
||||
height : FT_Short;
|
||||
width : FT_Short;
|
||||
end;
|
||||
AFT_Bitmap_Size = array [0..1023] of FT_Bitmap_Size;
|
||||
PFT_Bitmap_Size = ^AFT_Bitmap_Size;
|
||||
|
||||
FT_Vector = record
|
||||
x : FT_Pos;
|
||||
y : FT_Pos;
|
||||
end;
|
||||
PFT_Vector = ^FT_Vector;
|
||||
|
||||
FT_BBox = record
|
||||
xMin, yMin : FT_Pos;
|
||||
xMax, yMax : FT_Pos;
|
||||
end;
|
||||
PFT_BBox = ^FT_BBox;
|
||||
|
||||
FT_Bitmap = record
|
||||
rows : integer;
|
||||
width : integer;
|
||||
pitch : integer;
|
||||
buffer : pointer;
|
||||
num_grays : shortint;
|
||||
pixel_mode : char;
|
||||
palette_mode : char;
|
||||
palette : pointer;
|
||||
end;
|
||||
|
||||
FT_Outline = record
|
||||
n_contours,
|
||||
n_points : smallint;
|
||||
points : PFT_Vector;
|
||||
tags : pchar;
|
||||
contours : ^smallint;
|
||||
flags : integer;
|
||||
end;
|
||||
|
||||
FT_Size_Metrics = record
|
||||
x_ppem : FT_UShort;
|
||||
y_ppem : FT_UShort;
|
||||
x_scale : FT_Fixed;
|
||||
y_scale : FT_Fixed;
|
||||
ascender : FT_Pos;
|
||||
descender : FT_Pos;
|
||||
height : FT_Pos;
|
||||
max_advance : FT_Pos;
|
||||
end;
|
||||
|
||||
|
||||
PFT_Library = ^TFT_Library;
|
||||
//PPFT_Library = ^PFT_Library;
|
||||
PFT_Face = ^TFT_Face;
|
||||
//PPFT_Face = ^PFT_Face;
|
||||
PFT_Charmap = ^TFT_Charmap;
|
||||
PPFT_Charmap = ^PFT_Charmap;
|
||||
PFT_GlyphSlot = ^TFT_GlyphSlot;
|
||||
PFT_Subglyph = ^TFT_Subglyph;
|
||||
PFT_Size = ^TFT_Size;
|
||||
|
||||
PFT_Glyph = ^TFT_Glyph;
|
||||
//PPFT_Glyph = ^PFT_Glyph;
|
||||
PFT_BitmapGlyph = ^TFT_BitmapGlyph;
|
||||
PFT_OutlineGlyph = ^TFT_OutlineGlyph;
|
||||
|
||||
|
||||
TFT_Library = record
|
||||
end;
|
||||
|
||||
TFT_Charmap = record
|
||||
face : PFT_Face;
|
||||
encoding : FT_Encoding;
|
||||
platform_id, encoding_id : FT_UShort;
|
||||
end;
|
||||
|
||||
TFT_Size = record
|
||||
face : PFT_Face;
|
||||
generic : FT_Generic;
|
||||
metrics : FT_Size_Metrics;
|
||||
//internal : FT_Size_Internal;
|
||||
end;
|
||||
|
||||
TFT_Subglyph = record // TODO
|
||||
end;
|
||||
|
||||
TFT_GlyphSlot = record
|
||||
alibrary : PFT_Library;
|
||||
face : PFT_Face;
|
||||
next : PFT_GlyphSlot;
|
||||
flags : FT_UInt;
|
||||
generic : FT_Generic;
|
||||
metrics : FT_Glyph_Metrics;
|
||||
linearHoriAdvance : FT_Fixed;
|
||||
linearVertAdvance : FT_Fixed;
|
||||
advance : FT_Vector;
|
||||
format : longword;
|
||||
bitmap : FT_Bitmap;
|
||||
bitmap_left : FT_Int;
|
||||
bitmap_top : FT_Int;
|
||||
outline : FT_Outline;
|
||||
num_subglyphs : FT_UInt;
|
||||
subglyphs : PFT_SubGlyph;
|
||||
control_data : pointer;
|
||||
control_len : longint;
|
||||
other : pointer;
|
||||
end;
|
||||
|
||||
TFT_Face = record
|
||||
num_faces : FT_Long;
|
||||
face_index : FT_Long;
|
||||
face_flags : FT_Long;
|
||||
style_flags : FT_Long;
|
||||
num_glyphs : FT_Long;
|
||||
family_name : pchar;
|
||||
style_name : pchar;
|
||||
num_fixed_sizes : FT_Int;
|
||||
available_sizes : PFT_Bitmap_Size; // is array
|
||||
num_charmaps : FT_Int;
|
||||
charmaps : PPFT_CharMap; // is array
|
||||
generic : FT_Generic;
|
||||
bbox : FT_BBox;
|
||||
units_per_EM : FT_UShort;
|
||||
ascender : FT_Short;
|
||||
descender : FT_Short;
|
||||
height : FT_Short;
|
||||
max_advance_width : FT_Short;
|
||||
max_advance_height : FT_Short;
|
||||
underline_position : FT_Short;
|
||||
underline_thickness : FT_Short;
|
||||
glyph : PFT_GlyphSlot;
|
||||
size : PFT_Size;
|
||||
charmap : PFT_CharMap;
|
||||
end;
|
||||
|
||||
TFT_Glyph = record
|
||||
FTlibrary : PFT_Library;
|
||||
clazz : pointer;
|
||||
aFormat : longword;
|
||||
advance : FT_Vector;
|
||||
end;
|
||||
|
||||
TFT_BitmapGlyph = record
|
||||
root : TFT_Glyph;
|
||||
left, top : FT_Int;
|
||||
bitmap : FT_Bitmap;
|
||||
end;
|
||||
|
||||
TFT_OutlineGlyph = record
|
||||
root : TFT_Glyph;
|
||||
outline : FT_Outline;
|
||||
end;
|
||||
|
||||
|
||||
function FT_Init_FreeType(var alibrary:PFT_Library) : integer; cdecl; external freetypedll name 'FT_Init_FreeType';
|
||||
function FT_Done_FreeType(alibrary:PFT_Library) : integer; cdecl; external freetypedll name 'FT_Done_FreeType';
|
||||
procedure FT_Library_Version(alibrary:PFT_Library; var amajor,aminor,apatch:integer); cdecl; external freetypedll name 'FT_Library_Version';
|
||||
|
||||
function FT_New_Face(alibrary:PFT_Library; filepathname:pchar; face_index:integer; var aface:PFT_Face):integer; cdecl; external freetypedll name 'FT_New_Face';
|
||||
function FT_Set_Pixel_Sizes(face:PFT_Face; pixel_width,pixel_height:FT_UInt) : integer; cdecl; external freetypedll name 'FT_Set_Pixel_Sizes';
|
||||
function FT_Set_Char_Size(face:PFT_Face; char_width,char_height:FT_F26dot6;horz_res, vert_res:FT_UInt) : integer; cdecl; external freetypedll name 'FT_Set_Char_Size';
|
||||
function FT_Get_Char_Index(face:PFT_Face; charcode:FT_ULong):FT_UInt; cdecl; external freetypedll name 'FT_Get_Char_Index';
|
||||
function FT_Load_Glyph(face:PFT_Face; glyph_index:FT_UInt ;load_flags:longint):integer; cdecl; external freetypedll name 'FT_Load_Glyph';
|
||||
function FT_Get_Kerning(face:PFT_Face; left_glyph, right_glyph, kern_mode:FT_UInt; var akerning:FT_Vector) : integer; cdecl; external freetypedll name 'FT_Get_Kerning';
|
||||
|
||||
function FT_Get_Glyph(slot:PFT_GlyphSlot; var aglyph:PFT_Glyph) : integer; cdecl; external freetypedll name 'FT_Get_Glyph';
|
||||
function FT_Glyph_Transform(glyph:PFT_Glyph; matrix:PFT_Matrix; delta:PFT_Vector) : integer; cdecl; external freetypedll name 'FT_Glyph_Transform';
|
||||
function FT_Glyph_Copy(source:PFT_Glyph; var target:PFT_Glyph): integer; cdecl; external freetypedll name 'FT_Glyph_Copy';
|
||||
procedure FT_Glyph_Get_CBox(glyph:PFT_Glyph;bbox_mode:FT_UInt;var acbox:FT_BBox); cdecl; external freetypedll name 'FT_Glyph_Get_CBox';
|
||||
function FT_Glyph_To_Bitmap(var the_glyph:PFT_Glyph;render_mode:FT_Render_Mode;origin:PFT_Vector; destroy:FT_Bool):integer; cdecl; external freetypedll name 'FT_Glyph_To_Bitmap';
|
||||
procedure FT_Done_Glyph (glyph:PFT_Glyph); cdecl; external freetypedll name 'FT_Done_Glyph';
|
||||
|
||||
implementation
|
||||
|
||||
end.
|
307
fcl/image/ftfont.pp
Normal file
307
fcl/image/ftfont.pp
Normal file
@ -0,0 +1,307 @@
|
||||
{
|
||||
$Id$
|
||||
This file is part of the Free Pascal run time library.
|
||||
Copyright (c) 2003 by the Free Pascal development team
|
||||
|
||||
Basic canvas definitions.
|
||||
|
||||
See the file COPYING.FPC, included in this distribution,
|
||||
for details about the copyright.
|
||||
|
||||
This program is distributed in the hope that it will be useful,
|
||||
but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
|
||||
|
||||
**********************************************************************}
|
||||
{$mode objfpc}{$h+}
|
||||
unit ftfont;
|
||||
|
||||
interface
|
||||
|
||||
uses classes, FPCanvas, fpimgcmn, freetype, freetypeh;
|
||||
|
||||
type
|
||||
|
||||
FreeTypeFontException = class (TFPFontException);
|
||||
|
||||
TFreeTypeFont = class (TFPCustomDrawFont)
|
||||
private
|
||||
FResolution : longword;
|
||||
FAntiAliased : boolean;
|
||||
FLastText : TStringBitmaps;
|
||||
FIndex, FFontID : integer;
|
||||
FFace : PFT_Face;
|
||||
FAngle : real;
|
||||
procedure DrawChar (x,y:integer; data:PByteArray; pitch, width, height:integer);
|
||||
procedure DrawCharBW (x,y:integer; data:PByteArray; pitch, width, height:integer);
|
||||
procedure ClearLastText;
|
||||
protected
|
||||
procedure SetName (AValue:string); override;
|
||||
procedure SetIndex (AValue : integer);
|
||||
procedure SetSize (AValue : integer); override;
|
||||
function GetFlags (index:integer) : boolean; override;
|
||||
procedure SetFlags (index:integer; AValue:boolean); override;
|
||||
procedure DoAllocateResources; override;
|
||||
procedure DoDeAllocateResources; override;
|
||||
procedure DoCopyProps (From:TFPCanvasHelper); override;
|
||||
procedure DoDrawText (atx,aty:integer; atext:string); override;
|
||||
procedure DoGetTextSize (text:string; var w,h:integer); override;
|
||||
function DoGetTextHeight (text:string) : integer; override;
|
||||
function DoGetTextWidth (text:string) : integer; override;
|
||||
procedure GetText (aText:string);
|
||||
procedure GetFace;
|
||||
public
|
||||
constructor create; override;
|
||||
property FontIndex : integer read FIndex write SetIndex;
|
||||
property Resolution : longword read FResolution write FResolution;
|
||||
property AntiAliased : boolean read FAntiAliased write FAntiAliased;
|
||||
property Angle : real read FAngle write FAngle;
|
||||
end;
|
||||
|
||||
implementation
|
||||
|
||||
uses sysutils, fpimage;
|
||||
|
||||
var
|
||||
FontMgr : TFontManager;
|
||||
|
||||
procedure InitEngine;
|
||||
begin
|
||||
if not assigned (FontMgr) then
|
||||
FontMgr := TFontManager.create;
|
||||
end;
|
||||
|
||||
procedure DoneEngine;
|
||||
begin
|
||||
if assigned (FontMgr) then
|
||||
FontMgr.Free;
|
||||
end;
|
||||
|
||||
constructor TFreeTypeFont.Create;
|
||||
begin
|
||||
inherited;
|
||||
FFontID := -1;
|
||||
FAntiAliased := True;
|
||||
FResolution := DefaultResolution;
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.DoCopyProps (From:TFPCanvasHelper);
|
||||
var f : TFreeTypeFont;
|
||||
begin
|
||||
inherited;
|
||||
if from is TFreeTypeFont then
|
||||
begin
|
||||
f := TFreeTypeFont(from);
|
||||
FIndex := F.Findex;
|
||||
FAntiAliased := f.FAntiAliased;
|
||||
FResolution := f.FResolution;
|
||||
FAngle := f.FAngle;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.SetName (AValue:string);
|
||||
begin
|
||||
inherited;
|
||||
ClearLastText;
|
||||
if allocated then
|
||||
FFontID := FontMgr.RequestFont(Name, FIndex);
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.SetIndex (AValue : integer);
|
||||
begin
|
||||
FIndex := AValue;
|
||||
ClearLastText;
|
||||
if allocated then
|
||||
FFontID := FontMgr.RequestFont(Name, FIndex);
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.SetSize (AValue : integer);
|
||||
begin
|
||||
ClearLastText;
|
||||
inherited;
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.ClearLastText;
|
||||
begin
|
||||
if assigned(FLastText) then
|
||||
begin
|
||||
FLastText.Free;
|
||||
FlastText := nil;
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.DoAllocateResources;
|
||||
begin
|
||||
InitEngine;
|
||||
FFontID := FontMgr.RequestFont(Name, FIndex);
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.DoDeAllocateResources;
|
||||
begin
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.DoGetTextSize (text:string; var w,h:integer);
|
||||
var r : TRect;
|
||||
begin
|
||||
GetText (text);
|
||||
FLastText.GetBoundRect (r);
|
||||
with r do
|
||||
begin
|
||||
w := right - left;
|
||||
h := top - bottom;
|
||||
end;
|
||||
end;
|
||||
|
||||
function TFreeTypeFont.DoGetTextHeight (text:string) : integer;
|
||||
var r : TRect;
|
||||
begin
|
||||
GetText (text);
|
||||
FLastText.GetBoundRect (r);
|
||||
with r do
|
||||
result := top - bottom;
|
||||
end;
|
||||
|
||||
function TFreeTypeFont.DoGetTextWidth (text:string) : integer;
|
||||
var r : TRect;
|
||||
begin
|
||||
GetText (text);
|
||||
FLastText.GetBoundRect (r);
|
||||
with r do
|
||||
result := right - left;
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.SetFlags (index:integer; AValue:boolean);
|
||||
begin
|
||||
if not (index in [5,6]) then // bold,italic
|
||||
inherited SetFlags (index, AValue);
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.GetFace;
|
||||
begin
|
||||
if not assigned(FFace) then
|
||||
FFace := FontMgr.GetFreeTypeFont (FFontID);
|
||||
end;
|
||||
|
||||
function TFreeTypeFont.GetFlags (index:integer) : boolean;
|
||||
begin
|
||||
if index = 5 then //bold
|
||||
begin
|
||||
GetFace;
|
||||
result := (FFace^.style_flags and FT_STYLE_FLAG_BOLD) <> 0;
|
||||
end
|
||||
else if index = 6 then //italic
|
||||
begin
|
||||
GetFace;
|
||||
result := (FFace^.style_flags and FT_STYLE_FLAG_ITALIC) <> 0;
|
||||
end
|
||||
else
|
||||
result := inherited GetFlags (index);
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.GetText (aText:string);
|
||||
var b : boolean;
|
||||
begin
|
||||
if assigned (FLastText) then
|
||||
begin
|
||||
if CompareStr(FLastText.Text,aText) <> 0 then
|
||||
begin
|
||||
FLastText.Free;
|
||||
b := true;
|
||||
end
|
||||
else
|
||||
begin
|
||||
if FAntiAliased then
|
||||
b := (FLastText.mode <> bt256Gray)
|
||||
else
|
||||
b := (FLastText.mode <> btBlackWhite);
|
||||
if b then
|
||||
FLastText.Free;
|
||||
end;
|
||||
end
|
||||
else
|
||||
b := true;
|
||||
if b then
|
||||
begin
|
||||
FontMgr.Resolution := FResolution;
|
||||
if FAntiAliased then
|
||||
FLastText := FontMgr.GetStringGray (FFontId, aText, Size, Angle)
|
||||
else
|
||||
FLastText := FontMgr.GetString (FFontId, aText, Size, Angle);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.DoDrawText (atX,atY:integer; atext:string);
|
||||
var r,i : integer;
|
||||
f : longint;
|
||||
begin
|
||||
GetText (atext);
|
||||
with FLastText do
|
||||
for r := 0 to count-1 do
|
||||
with Bitmaps[r]^ do
|
||||
begin
|
||||
if mode = btBlackWhite then
|
||||
DrawCharBW (atX+x, atY+y, data, pitch, width, height)
|
||||
else
|
||||
DrawChar (atX+x, atY+y, data, pitch, width, height);
|
||||
end;
|
||||
end;
|
||||
|
||||
const
|
||||
//bits : array[0..7] of byte = (1,2,4,8,16,32,64,128);
|
||||
bits : array[0..7] of byte = (128,64,32,16,8,4,2,1);
|
||||
|
||||
procedure TFreeTypeFont.DrawChar (x,y:integer; data:PByteArray; pitch, width, height:integer);
|
||||
|
||||
procedure Combine (canv:TFPCustomCanvas; x,y:integer; c : TFPColor; t:longword);
|
||||
var a,r,g,b:longword;
|
||||
begin
|
||||
if t = 255 then
|
||||
canv.colors[x,y] := c
|
||||
else if t <> 0 then
|
||||
begin
|
||||
with canv.colors[x,y] do
|
||||
begin
|
||||
a := 255-t;
|
||||
r := ((red * a) + (c.red * t)) div 255;
|
||||
g := ((green * a) + (c.green * t)) div 255;
|
||||
b := ((blue * a) + (c.blue * t)) div 255;
|
||||
end;
|
||||
canv.colors[x,y] := FPcolor(r,g,b,alphaOpaque);
|
||||
end;
|
||||
end;
|
||||
|
||||
var b,rx,ry : integer;
|
||||
begin
|
||||
b := 0;
|
||||
for ry := 0 to height-1 do
|
||||
begin
|
||||
for rx := 0 to width-1 do
|
||||
combine (canvas, x+rx, y+ry, color, data^[b+rx]);
|
||||
inc (b, pitch);
|
||||
end;
|
||||
end;
|
||||
|
||||
procedure TFreeTypeFont.DrawCharBW (x,y:integer; data:PByteArray; pitch, width, height:integer);
|
||||
var rb : byte;
|
||||
rx,ry,b,l : integer;
|
||||
begin
|
||||
b := 0;
|
||||
for ry := 0 to height-1 do
|
||||
begin
|
||||
l := 0;
|
||||
for rx := 0 to width-1 do
|
||||
begin
|
||||
rb := rx mod 8;
|
||||
if (data^[b+l] and bits[rb]) <> 0 then
|
||||
canvas.colors[x+rx,y+ry] := color;
|
||||
if rb = 7 then
|
||||
inc (l);
|
||||
end;
|
||||
inc (b, pitch);
|
||||
end;
|
||||
end;
|
||||
|
||||
|
||||
finalization
|
||||
DoneEngine;
|
||||
end.
|
Loading…
Reference in New Issue
Block a user