+ FreeType font and freetype font library calls

+ test program for fonts
This commit is contained in:
luk 2003-09-21 22:06:55 +00:00
parent 07504a9e93
commit 8d26c4604b
3 changed files with 1493 additions and 0 deletions

850
fcl/image/freetype.pp Normal file
View 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
View 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
View 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.