You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

610 regels
22 KiB

  1. unit utsFontCreatorGDI;
  2. {$IFDEF FPC}
  3. {$mode delphi}{$H+}
  4. {$ENDIF}
  5. interface
  6. uses
  7. Classes, SysUtils,
  8. utsTextSuite, utsTypes, utsGDI;
  9. type
  10. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  11. TtsFontGDI = class(TtsFont)
  12. private
  13. fHandle: THandle;
  14. fMat2: TMat2;
  15. protected
  16. constructor Create(const aRenderer: TtsRenderer; const aCreator: TtsFontGenerator; const aProperties: TtsFontProperties; const aHandle: THandle);
  17. public
  18. destructor Destroy; override;
  19. end;
  20. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  21. TtsFontRegistration = class(TObject)
  22. protected
  23. fIsRegistered: Boolean;
  24. fFontname: String;
  25. procedure UnregisterFont; virtual; abstract;
  26. public
  27. property IsRegistered: Boolean read fIsRegistered;
  28. property Fontname: String read fFontname;
  29. destructor Destroy; override;
  30. end;
  31. TtsFontRegistrationFile = class(TtsFontRegistration)
  32. private
  33. fFilename: String;
  34. protected
  35. procedure UnregisterFont; override;
  36. public
  37. constructor Create(const aFilename: String);
  38. end;
  39. TtsFontRegistrationStream = class(TtsFontRegistration)
  40. private
  41. fHandle: THandle;
  42. protected
  43. procedure UnregisterFont; override;
  44. public
  45. constructor Create(const aStream: TStream);
  46. end;
  47. TtsRegistredFontGDI = class(TtsFontGDI)
  48. private
  49. fRegistration: TtsFontRegistration;
  50. public
  51. constructor Create(const aRenderer: TtsRenderer; const aCreator: TtsFontGenerator;
  52. const aRegistration: TtsFontRegistration; const aProperties: TtsFontProperties; const aHandle: THandle);
  53. destructor Destroy; override;
  54. end;
  55. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  56. TtsFontGeneratorGDI = class(TtsFontGenerator)
  57. private
  58. function ConvertFont(const aFont: TtsFont): TtsFontGDI;
  59. function GetGlyphIndex(const aFont: TtsFontGDI; const aCharCode: WideChar): Integer;
  60. procedure GetCharImageAANone(const aDC: HDC; const aFont: TtsFontGDI; const aCharCode: WideChar; const aImage: TtsImage);
  61. procedure GetCharImageAANormal(const aDC: HDC; const aFont: TtsFontGDI; const aCharCode: WideChar; const aImage: TtsImage);
  62. function CreateFont(const aFontname: String; const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing; out aProperties: TtsFontProperties): THandle;
  63. protected
  64. function GetGlyphMetrics(const aFont: TtsFont; const aCharCode: WideChar; out aGlyphOrigin, aGlyphSize: TtsPosition; out aAdvance: Integer): Boolean; override;
  65. procedure GetCharImage(const aFont: TtsFont; const aCharCode: WideChar; const aCharImage: TtsImage); override;
  66. public
  67. function GetFontByName(const aFontname: String; const aRenderer: TtsRenderer; const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont; overload;
  68. function GetFontByFile(const aFilename: String; const aRenderer: TtsRenderer; const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont; overload;
  69. function GetFontByStream(const aStream: TStream; const aRenderer: TtsRenderer; const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont; overload;
  70. constructor Create(const aContext: TtsContext);
  71. destructor Destroy; override;
  72. end;
  73. implementation
  74. uses
  75. math, utsTtfUtils;
  76. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  77. //TtsFontGDI////////////////////////////////////////////////////////////////////////////////////////////////////////////
  78. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  79. constructor TtsFontGDI.Create(const aRenderer: TtsRenderer; const aCreator: TtsFontGenerator; const aProperties: TtsFontProperties; const aHandle: THandle);
  80. begin
  81. inherited Create(aRenderer, aCreator, aProperties);
  82. FillChar(fMat2, SizeOf(fMat2), #0);
  83. fMat2.eM11.value := 1;
  84. fMat2.eM22.value := 1;
  85. fHandle := aHandle;
  86. end;
  87. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  88. destructor TtsFontGDI.Destroy;
  89. begin
  90. DeleteObject(fHandle);
  91. inherited Destroy;
  92. end;
  93. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  94. //TtsFontRegistration///////////////////////////////////////////////////////////////////////////////////////////////////
  95. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  96. destructor TtsFontRegistration.Destroy;
  97. begin
  98. if fIsRegistered then
  99. UnregisterFont;
  100. inherited Destroy;
  101. end;
  102. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  103. //TtsFontRegistrationFile///////////////////////////////////////////////////////////////////////////////////////////////
  104. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  105. procedure TtsFontRegistrationFile.UnregisterFont;
  106. begin
  107. if Assigned(RemoveFontResourceExA) then
  108. RemoveFontResourceExA(PAnsiChar(fFilename), 0, nil)
  109. else if Assigned(RemoveFontResourceA) then
  110. RemoveFontResourceA(PAnsiChar(fFilename));
  111. end;
  112. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  113. constructor TtsFontRegistrationFile.Create(const aFilename: String);
  114. var
  115. lang: AnsiString;
  116. begin
  117. inherited Create;
  118. fFilename := aFilename;
  119. // get Fontname
  120. SetLength(lang, 4);
  121. GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, @lang[1], 4);
  122. fFontname := GetTTFontFullNameFromFile(aFilename, StrToInt('$' + String(lang)));
  123. // register font
  124. if Assigned(AddFontResourceExA) then
  125. fIsRegistered := (AddFontResourceExA(PAnsiChar(fFilename), 0, nil) > 0)
  126. else if Assigned(AddFontResourceA) then
  127. fIsRegistered := (AddFontResourceA(PAnsiChar(fFilename)) > 0)
  128. else
  129. fIsRegistered := false;
  130. end;
  131. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  132. //TtsFontRegistrationStream/////////////////////////////////////////////////////////////////////////////////////////////
  133. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  134. procedure TtsFontRegistrationStream.UnregisterFont;
  135. begin
  136. if Assigned(RemoveFontMemResourceEx) then
  137. RemoveFontMemResourceEx(fHandle);
  138. end;
  139. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  140. constructor TtsFontRegistrationStream.Create(const aStream: TStream);
  141. var
  142. lang: AnsiString;
  143. ms: TMemoryStream;
  144. cnt: DWORD;
  145. begin
  146. inherited Create;
  147. fHandle := 0;
  148. fIsRegistered := false;
  149. // get Fontname
  150. SetLength(Lang, 4);
  151. GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, @lang[1], 4);
  152. fFontname := GetTTFontFullNameFromStream(aStream, StrToInt('$' + String(Lang)));
  153. // register font
  154. ms := TMemoryStream.Create;
  155. try
  156. ms.CopyFrom(aStream, 0);
  157. if Assigned(AddFontMemResourceEx) then
  158. fHandle := AddFontMemResourceEx(ms.Memory, ms.Size, nil, @cnt);
  159. fIsRegistered := (fHandle > 0);
  160. finally
  161. FreeAndNil(ms);
  162. end;
  163. end;
  164. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  165. //TtsRegistredFontGDI///////////////////////////////////////////////////////////////////////////////////////////////////
  166. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  167. constructor TtsRegistredFontGDI.Create(const aRenderer: TtsRenderer; const aCreator: TtsFontGenerator;
  168. const aRegistration: TtsFontRegistration; const aProperties: TtsFontProperties; const aHandle: THandle);
  169. begin
  170. inherited Create(aRenderer, aCreator, aProperties, aHandle);
  171. fRegistration := aRegistration;
  172. end;
  173. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  174. destructor TtsRegistredFontGDI.Destroy;
  175. begin
  176. FreeAndNil(fRegistration);
  177. inherited Destroy;
  178. end;
  179. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  180. //TtsFontCreatorGDIFontFace/////////////////////////////////////////////////////////////////////////////////////////////
  181. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  182. function TtsFontGeneratorGDI.ConvertFont(const aFont: TtsFont): TtsFontGDI;
  183. begin
  184. if not (aFont is TtsFontGDI) then
  185. raise EtsException.Create('aFont need to be a TtsFontGDI object');
  186. result := (aFont as TtsFontGDI);
  187. end;
  188. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  189. function TtsFontGeneratorGDI.GetGlyphIndex(const aFont: TtsFontGDI; const aCharCode: WideChar): Integer;
  190. var
  191. DC: HDC;
  192. GCPRes: TGCPResultsW;
  193. begin
  194. result := -1;
  195. DC := CreateCompatibleDC(0);
  196. try
  197. SelectObject(DC, aFont.fHandle);
  198. if Assigned(GetCharacterPlacementW) then begin
  199. FillChar(GCPRes, SizeOf(GCPRes), #0);
  200. GetMem(GCPRes.lpGlyphs, SizeOf(Cardinal));
  201. try
  202. GCPRes.lStructSize := SizeOf(GCPRes);
  203. GCPRes.lpGlyphs^ := 0;
  204. GCPRes.nGlyphs := 1;
  205. if (GetCharacterPlacementW(DC, @aCharCode, 1, GCP_MAXEXTENT, @GCPRes, 0) <> GDI_ERROR) and
  206. (GCPRes.nGlyphs = 1) and
  207. (GCPRes.lpGlyphs <> nil) then
  208. begin
  209. result := GCPRes.lpGlyphs^;
  210. end;
  211. finally
  212. FreeMem(GCPRes.lpGlyphs);
  213. end;
  214. end;
  215. finally
  216. DeleteDC(DC);
  217. end;
  218. end;
  219. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  220. procedure TtsFontGeneratorGDI.GetCharImageAANone(const aDC: HDC; const aFont: TtsFontGDI; const aCharCode: WideChar; const aImage: TtsImage);
  221. var
  222. Metric: TGlyphMetrics;
  223. GlyphIndex, srcW, srcX, w, h, x, y: Integer;
  224. Size, OutlineRes: Cardinal;
  225. Buffer, pSrc, pDst: PByte;
  226. procedure ExpandByte;
  227. var
  228. i, cnt, srcCnt: Integer;
  229. c: TtsColor4f;
  230. begin
  231. srcCnt := min(8, srcX);
  232. cnt := min(8, x);
  233. for i := 1 to cnt do begin
  234. c := tsColor4f(1, 1, 1, 1);
  235. if ((pSrc^ and $80) > 0) then
  236. c.a := 1.0
  237. else
  238. c.a := 0.0;
  239. pSrc^ := (pSrc^ and not $80) shl 1;
  240. tsFormatMap(aFont.Renderer.Format, pDst, c);
  241. end;
  242. dec(srcX, srcCnt);
  243. dec(x, cnt);
  244. inc(pSrc);
  245. end;
  246. begin
  247. if (aFont.fMat2.eM11.value <> 1) then
  248. raise EtsException.Create('invalid value');
  249. FillChar(Metric, SizeOf(Metric), #0);
  250. GlyphIndex := GetGlyphIndex(aFont, aCharCode);
  251. if (GlyphIndex < 0) then
  252. exit;
  253. Size := GetGlyphOutlineA(aDC, GlyphIndex, GGO_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @aFont.fMat2);
  254. if (Size = GDI_ERROR) or (Size = 0) then
  255. exit;
  256. GetMem(Buffer, Size);
  257. try
  258. OutlineRes := GetGlyphOutlineA(aDC, GlyphIndex, GGO_BITMAP or GGO_GLYPH_INDEX, @Metric, Size, Buffer, @aFont.fMat2);
  259. if (OutlineRes = GDI_ERROR) then
  260. exit;
  261. w := Metric.gmBlackBoxX;
  262. h := Metric.gmBlackBoxY;
  263. srcW := (Size div h) * 8;
  264. if (w <= 0) or (h <= 0) then
  265. exit;
  266. aImage.CreateEmpty(aFont.Renderer.Format, w, h);
  267. pSrc := Buffer;
  268. for y := 0 to h-1 do begin
  269. pDst := aImage.Scanline[y];
  270. srcX := srcW;
  271. x := w;
  272. while (srcX > 0) do
  273. ExpandByte;
  274. end;
  275. finally
  276. Freemem(Buffer);
  277. end;
  278. end;
  279. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  280. procedure TtsFontGeneratorGDI.GetCharImageAANormal(const aDC: HDC; const aFont: TtsFontGDI; const aCharCode: WideChar; const aImage: TtsImage);
  281. var
  282. Metric: TGlyphMetrics;
  283. GlyphIndex, OutlineRes, tmp, Spacer, x, y, w, h: Integer;
  284. Size: Cardinal;
  285. Buffer, pSrc, pDst: PByte;
  286. procedure CopyPixel;
  287. var
  288. i: Integer;
  289. tmp, cnt: Cardinal;
  290. c: TtsColor4f;
  291. begin
  292. cnt := min(x, aFont.fMat2.eM11.value);
  293. tmp := 0;
  294. for i := 0 to cnt-1 do begin
  295. tmp := tmp + pSrc^;
  296. inc(pSrc, 1);
  297. end;
  298. dec(x, cnt);
  299. c := tsColor4f(1, 1, 1, tmp / $40);
  300. tsFormatMap(aFont.Renderer.Format, pDst, c);
  301. end;
  302. begin
  303. FillChar(Metric, SizeOf(Metric), #0);
  304. GlyphIndex := GetGlyphIndex(aFont, aCharCode);
  305. if (GlyphIndex < 0) then
  306. exit;
  307. Size := GetGlyphOutlineA(aDC, GlyphIndex, GGO_GRAY8_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @aFont.fMat2);
  308. if (Size = GDI_ERROR) or (Size = 0) then
  309. exit;
  310. GetMem(Buffer, Size);
  311. try
  312. OutlineRes := GetGlyphOutlineA(aDC, GlyphIndex, GGO_GRAY8_BITMAP or GGO_GLYPH_INDEX, @Metric, Size, Buffer, @aFont.fMat2);
  313. if (OutlineRes = GDI_ERROR) then
  314. exit;
  315. w := Integer(Metric.gmBlackBoxX) div aFont.fMat2.eM11.value;
  316. h := Metric.gmBlackBoxY;
  317. tmp := Integer(Metric.gmBlackBoxX) mod aFont.fMat2.eM11.value;
  318. if (tmp <> 0) then
  319. w := w + aFont.fMat2.eM11.value - tmp;
  320. if (w <= 0) or (h <= 0) then
  321. exit;
  322. // spacer
  323. Spacer := Metric.gmBlackBoxX mod 4;
  324. if (Spacer <> 0) then
  325. Spacer := 4 - Spacer;
  326. // copy image
  327. aImage.CreateEmpty(aFont.Renderer.Format, w, h);
  328. pSrc := Buffer;
  329. for y := 0 to h-1 do begin
  330. pDst := aImage.Scanline[y];
  331. x := Metric.gmBlackBoxX;
  332. while (x > 0) do
  333. CopyPixel;
  334. inc(pSrc, Spacer);
  335. end;
  336. finally
  337. FreeMem(Buffer);
  338. end;
  339. end;
  340. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  341. function TtsFontGeneratorGDI.CreateFont(const aFontname: String; const aSize: Integer; const aStyle: TtsFontStyles;
  342. const aAntiAliasing: TtsAntiAliasing; out aProperties: TtsFontProperties): THandle;
  343. var
  344. LogFont: TLogFontA;
  345. i: Integer;
  346. DC: HDC;
  347. TableName, BufSize: Cardinal;
  348. Buffer: PByte;
  349. Lang: AnsiString;
  350. TextMetric: TTextMetricW;
  351. OutlineMetric: TOutlineTextmetricW;
  352. function _(e: Boolean; a, b: Integer): Integer;
  353. begin
  354. if e then
  355. result := a
  356. else
  357. result := b;
  358. end;
  359. begin
  360. result := 0;
  361. FillChar(aProperties, SizeOf(aProperties), #0);
  362. aProperties.Size := aSize;
  363. aProperties.Style := aStyle;
  364. aProperties.AntiAliasing := aAntiAliasing;
  365. aProperties.Fontname := aFontname;
  366. // prepare font attribs
  367. FillChar(LogFont, SizeOf(LogFont), #0);
  368. for i := 1 to min(Length(aFontname), Length(LogFont.lfFaceName)) do
  369. LogFont.lfFaceName[i-1] := aFontname[i];
  370. LogFont.lfCharSet := DEFAULT_CHARSET;
  371. LogFont.lfHeight := -aSize;
  372. LogFont.lfWeight := _(tsStyleBold in aStyle, FW_BOLD, FW_NORMAL);
  373. LogFont.lfItalic := _(tsStyleItalic in aStyle, 1, 0);
  374. LogFont.lfUnderline := _(tsStyleUnderline in aStyle, 1, 0);
  375. LogFont.lfQuality := _(aAntiAliasing = tsAANormal, ANTIALIASED_QUALITY, NONANTIALIASED_QUALITY);
  376. result := CreateFontIndirectA(LogFont);
  377. DC := CreateCompatibleDC(0);
  378. try try
  379. SelectObject(DC, result);
  380. TableName := MakeTTTableName('n', 'a', 'm', 'e');
  381. BufSize := GetFontData(DC, TableName, 0, nil, 0);
  382. if (BufSize <> GDI_ERROR) then begin
  383. GetMem(Buffer, BufSize);
  384. try
  385. if (GetFontData(DC, TableName, 0, Buffer, BufSize) <> GDI_ERROR) then begin
  386. SetLength(Lang, 4);
  387. GetLocaleInfoA(LOCALE_USER_DEFAULT, LOCALE_ILANGUAGE, @Lang[1], 4);
  388. GetTTString(Buffer, BufSize, NAME_ID_COPYRIGHT, StrToInt('$' + String(Lang)), aProperties.Copyright);
  389. GetTTString(Buffer, BufSize, NAME_ID_FACE_NAME, StrToInt('$' + String(Lang)), aProperties.FaceName);
  390. GetTTString(Buffer, BufSize, NAME_ID_STYLE_NAME, StrToInt('$' + String(Lang)), aProperties.StyleName);
  391. GetTTString(Buffer, BufSize, NAME_ID_FULL_NAME, StrToInt('$' + String(Lang)), aProperties.FullName);
  392. end;
  393. finally
  394. FreeMem(Buffer);
  395. end;
  396. end;
  397. if GetTextMetricsW(DC, TextMetric) then begin
  398. aProperties.Ascent := TextMetric.tmAscent;
  399. aProperties.Descent := TextMetric.tmDescent;
  400. aProperties.ExternalLeading := TextMetric.tmExternalLeading;
  401. aProperties.DefaultChar := TextMetric.tmDefaultChar;
  402. end;
  403. if (GetOutlineTextMetricsW(DC, SizeOf(OutlineMetric), OutlineMetric) > 0) then begin
  404. aProperties.UnderlinePos := OutlineMetric.otmsUnderscorePosition;
  405. aProperties.UnderlineSize := Min(1, OutlineMetric.otmsUnderscoreSize);
  406. aProperties.StrikeoutPos := OutlineMetric.otmsStrikeoutPosition;
  407. aProperties.StrikeoutSize := Min(1, OutlineMetric.otmsStrikeoutSize);
  408. end;
  409. except
  410. DeleteObject(result);
  411. result := 0;
  412. end;
  413. finally
  414. DeleteDC(DC);
  415. end;
  416. end;
  417. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  418. function TtsFontGeneratorGDI.GetGlyphMetrics(const aFont: TtsFont; const aCharCode: WideChar; out aGlyphOrigin, aGlyphSize: TtsPosition; out aAdvance: Integer): Boolean;
  419. var
  420. GlyphIndex: Integer;
  421. font: TtsFontGDI;
  422. DC: HDC;
  423. Metric: TGlyphMetrics;
  424. Size: Cardinal;
  425. begin
  426. result := false;
  427. aGlyphOrigin.x := 0;
  428. aGlyphOrigin.x := 0;
  429. aGlyphSize.x := 0;
  430. aGlyphSize.y := 0;
  431. aAdvance := 0;
  432. font := ConvertFont(aFont);
  433. GlyphIndex := GetGlyphIndex(font, aCharCode);
  434. if (GlyphIndex < 0) then
  435. exit;
  436. DC := CreateCompatibleDC(0);
  437. try
  438. SelectObject(DC, font.fHandle);
  439. case font.Properties.AntiAliasing of
  440. tsAANone: begin
  441. Size := GetGlyphOutlineA(DC, GlyphIndex, GGO_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @font.fMat2);
  442. end;
  443. tsAANormal: begin
  444. Size := GetGlyphOutlineA(DC, GlyphIndex, GGO_GRAY8_BITMAP or GGO_GLYPH_INDEX, @Metric, 0, nil, @font.fMat2);
  445. end;
  446. else
  447. Size := GDI_ERROR;
  448. end;
  449. if (Size = GDI_ERROR) then
  450. Size := GetGlyphOutlineA(DC, GlyphIndex, GGO_METRICS or GGO_GLYPH_INDEX, @Metric, 0, nil, @font.fMat2);
  451. if (Size <> GDI_ERROR) then begin
  452. aGlyphOrigin.x := Metric.gmptGlyphOrigin.x;
  453. aGlyphOrigin.y := Metric.gmptGlyphOrigin.y;
  454. aGlyphSize.x := Metric.gmBlackBoxX;
  455. aGlyphSize.y := Metric.gmBlackBoxY;
  456. aAdvance := Metric.gmCellIncX;
  457. result := true;
  458. end;
  459. finally
  460. DeleteDC(DC);
  461. end;
  462. end;
  463. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  464. procedure TtsFontGeneratorGDI.GetCharImage(const aFont: TtsFont; const aCharCode: WideChar; const aCharImage: TtsImage);
  465. var
  466. DC: HDC;
  467. font: TtsFontGDI;
  468. begin
  469. font := ConvertFont(aFont);
  470. DC := CreateCompatibleDC(0);
  471. try
  472. SelectObject(DC, font.fHandle);
  473. case font.Properties.AntiAliasing of
  474. tsAANone:
  475. GetCharImageAANone(DC, font, aCharCode, aCharImage);
  476. tsAANormal:
  477. GetCharImageAANormal(DC, font, aCharCode, aCharImage);
  478. end;
  479. finally
  480. DeleteDC(DC);
  481. end;
  482. end;
  483. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  484. function TtsFontGeneratorGDI.GetFontByName(const aFontname: String; const aRenderer: TtsRenderer;
  485. const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont;
  486. var
  487. handle: THandle;
  488. prop: TtsFontProperties;
  489. begin
  490. handle := CreateFont(aFontname, aSize, aStyle, aAntiAliasing, prop);
  491. if (handle = 0) then
  492. raise EtsException.Create('unable to create font from name: ' + aFontname);
  493. result := TtsFontGDI.Create(aRenderer, self, prop, handle);
  494. end;
  495. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  496. function TtsFontGeneratorGDI.GetFontByFile(const aFilename: String; const aRenderer: TtsRenderer;
  497. const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont;
  498. var
  499. reg: TtsFontRegistrationFile;
  500. handle: THandle;
  501. prop: TtsFontProperties;
  502. begin
  503. reg := TtsFontRegistrationFile.Create(aFilename);
  504. try
  505. if not reg.IsRegistered then
  506. raise EtsException.Create('unable to register font file: ' + aFilename);
  507. handle := CreateFont(reg.Fontname, aSize, aStyle, aAntiAliasing, prop);
  508. if (handle = 0) then
  509. raise EtsException.Create('unable to create font from file: ' + aFilename);
  510. except
  511. FreeAndNil(reg);
  512. raise;
  513. end;
  514. result := TtsRegistredFontGDI.Create(aRenderer, self, reg, prop, handle);
  515. end;
  516. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  517. function TtsFontGeneratorGDI.GetFontByStream(const aStream: TStream; const aRenderer: TtsRenderer;
  518. const aSize: Integer; const aStyle: TtsFontStyles; const aAntiAliasing: TtsAntiAliasing): TtsFont;
  519. var
  520. reg: TtsFontRegistrationStream;
  521. handle: THandle;
  522. prop: TtsFontProperties;
  523. begin
  524. reg := TtsFontRegistrationStream.Create(aStream);
  525. if not reg.IsRegistered then
  526. raise EtsException.Create('unable to register font from stream');
  527. handle := CreateFont(reg.Fontname, aSize, aStyle, aAntiAliasing, prop);
  528. if (handle = 0) then
  529. raise EtsException.Create('unable to create font from stream: ' + reg.Fontname);
  530. result := TtsRegistredFontGDI.Create(aRenderer, self, reg, prop, handle);
  531. end;
  532. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  533. constructor TtsFontGeneratorGDI.Create(const aContext: TtsContext);
  534. begin
  535. inherited Create(aContext);
  536. InitGDI;
  537. end;
  538. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  539. destructor TtsFontGeneratorGDI.Destroy;
  540. begin
  541. inherited Destroy; // first free all fonts (managed by parent class)
  542. QuitGDI;
  543. end;
  544. end.