Ви не можете вибрати більше 25 тем Теми мають розпочинатися з літери або цифри, можуть містити дефіси (-) і не повинні перевищувати 35 символів.

608 рядки
22 KiB

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