Você não pode selecionar mais de 25 tópicos Os tópicos devem começar com uma letra ou um número, podem incluir traços ('-') e podem ter até 35 caracteres.

612 linhas
22 KiB

  1. unit utsPostProcessor;
  2. {$IFDEF FPC}
  3. {$mode objfpc}{$H+}
  4. {$ENDIF}
  5. interface
  6. uses
  7. Classes, SysUtils, contnrs,
  8. utsUtils, utsChar, utsImage, utsContext, utsTypes;
  9. type
  10. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  11. TtsCharRange = record
  12. Start: WideChar;
  13. Stop: WideChar;
  14. end;
  15. PtsCharRange = ^TtsCharRange;
  16. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  17. TtsCharRangeUsage = (
  18. tsUsageInclude,
  19. tsUsageExclude);
  20. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  21. TtsPostProcessor = class(TtsRefManager)
  22. private
  23. fContext: TtsContext;
  24. fIncludeCharRanges: TList;
  25. fExcludeCharRanges: TList;
  26. procedure ClearList(const aList: TList);
  27. public
  28. property Context: TtsContext read fContext;
  29. function IsInRange(const aCharCode: WideChar): Boolean;
  30. procedure AddRange(const aUsage: TtsCharRangeUsage; const aStart, aStop: WideChar);
  31. procedure AddChars(const aUsage: TtsCharRangeUsage; aChars: PWideChar);
  32. procedure ClearRanges;
  33. function Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean; virtual;
  34. constructor Create(const aContext: TtsContext);
  35. destructor Destroy; override;
  36. end;
  37. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  38. TtsPostProcessorList = class(TtsPostProcessor)
  39. private
  40. fItems: TObjectList;
  41. function GetCount: Integer;
  42. function GetItem(const aIndex: Integer): TtsPostProcessor;
  43. function GetOwnsObjects: Boolean;
  44. procedure SetOwnsObjects(const aValue: Boolean);
  45. public
  46. property Count: Integer read GetCount;
  47. property OwnsObjects: Boolean read GetOwnsObjects write SetOwnsObjects;
  48. property Items[const aIndex: Integer]: TtsPostProcessor read GetItem;
  49. procedure Add(const aPostProcessor: TtsPostProcessor);
  50. procedure Delete(const aIndex: Integer);
  51. procedure Clear;
  52. function Remove(const aPostProcessor: TtsPostProcessor): Integer;
  53. function IndexOf(const aPostProcessor: TtsPostProcessor): Integer;
  54. function Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean; override;
  55. constructor Create(const aContext: TtsContext; const aOwnsObjects: Boolean);
  56. destructor Destroy; override;
  57. end;
  58. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  59. TtsPostProcessorFillColor = class(TtsPostProcessor)
  60. private
  61. fColor: TtsColor4f;
  62. fModes: TtsImageModes;
  63. fChannels: TtsColorChannels;
  64. public
  65. property Color: TtsColor4f read fColor write fColor;
  66. property Modes: TtsImageModes read fModes write fModes;
  67. property Channels: TtsColorChannels read fChannels write fChannels;
  68. function Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean; override;
  69. constructor Create(
  70. const aContext: TtsContext;
  71. const aColor: TtsColor4f;
  72. const aModes: TtsImageModes;
  73. const aChannels: TtsColorChannels);
  74. end;
  75. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  76. TtsPostProcessorFillPattern = class(TtsPostProcessor)
  77. private
  78. fPattern: TtsImage;
  79. fOwnsPattern: Boolean;
  80. fPosition: TtsPosition;
  81. fModes: TtsImageModes;
  82. fChannels: TtsColorChannels;
  83. procedure SetPattern(aValue: TtsImage);
  84. public
  85. property Pattern: TtsImage read fPattern write SetPattern;
  86. property OwnsPattern: Boolean read fOwnsPattern write fOwnsPattern;
  87. property Position: TtsPosition read fPosition write fPosition;
  88. property Modes: TtsImageModes read fModes write fModes;
  89. property Channels: TtsColorChannels read fChannels write fChannels;
  90. function Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean; override;
  91. constructor Create(
  92. const aContext: TtsContext;
  93. const aPattern: TtsImage;
  94. const aOwnsPattern: Boolean;
  95. const aPosition: TtsPosition;
  96. const aModes: TtsImageModes;
  97. const aChannels: TtsColorChannels);
  98. destructor Destroy; override;
  99. end;
  100. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  101. TtsPostProcessorBorder = class(TtsPostProcessor)
  102. private
  103. fKernel: TtsKernel2D;
  104. fKeepSize: Boolean;
  105. fColor: TtsColor4f;
  106. fStrength: Single;
  107. fWidth: Single;
  108. procedure SetStrength(const aValue: Single);
  109. procedure SetWidth(const aValue: Single);
  110. public
  111. property Width: Single read fWidth write SetWidth;
  112. property Strength: Single read fStrength write SetStrength;
  113. property Color: TtsColor4f read fColor write fColor;
  114. property KeepSize: Boolean read fKeepSize write fKeepSize;
  115. function Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean; override;
  116. constructor Create(
  117. const aContext: TtsContext;
  118. const aWidth, aStrength: Single;
  119. const aColor: TtsColor4f;
  120. const aKeepSize: Boolean);
  121. destructor Destroy; override;
  122. end;
  123. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  124. TtsPostProcessorShadow = class(TtsPostProcessor)
  125. private
  126. fKernel: TtsKernel1D;
  127. fColor: TtsColor4f;
  128. fOffset: TtsPosition;
  129. fRadius: Single;
  130. fStrength: Single;
  131. procedure SetRadius(const aValue: Single);
  132. procedure SetStrength(const aValue: Single);
  133. public
  134. property Radius: Single read fRadius write SetRadius;
  135. property Strength: Single read fStrength write SetStrength;
  136. property Offset: TtsPosition read fOffset write fOffset;
  137. property Color: TtsColor4f read fColor write fColor;
  138. function Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean; override;
  139. constructor Create(
  140. const aContext: TtsContext;
  141. const aRadius, aStrength: Single;
  142. const aOffset: TtsPosition;
  143. const aColor: TtsColor4f);
  144. destructor Destroy; override;
  145. end;
  146. implementation
  147. uses
  148. utsConstants;
  149. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  150. //TtsPostProcessor//////////////////////////////////////////////////////////////////////////////////////////////////////
  151. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  152. procedure TtsPostProcessor.ClearList(const aList: TList);
  153. var
  154. i: Integer;
  155. p: PtsCharRange;
  156. begin
  157. for i := 0 to aList.Count-1 do begin
  158. p := aList[i];
  159. Dispose(p);
  160. end;
  161. aList.Clear;
  162. end;
  163. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  164. function TtsPostProcessor.IsInRange(const aCharCode: WideChar): Boolean;
  165. var
  166. i: Integer;
  167. p: PtsCharRange;
  168. begin
  169. result := (fIncludeCharRanges.Count = 0);
  170. if not result then for i := 0 to fIncludeCharRanges.Count-1 do begin
  171. p := fIncludeCharRanges[i];
  172. if (aCharCode >= p^.Start) and (aCharCode <= p^.Stop) then begin
  173. result := true;
  174. break;
  175. end;
  176. end;
  177. if result then for i := 0 to fExcludeCharRanges.Count-1 do begin
  178. p := fExcludeCharRanges[i];
  179. if (aCharCode >= p^.Start) and (aCharCode <= p^.Stop) then begin
  180. result := false;
  181. break;
  182. end;
  183. end;
  184. end;
  185. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  186. procedure TtsPostProcessor.AddRange(const aUsage: TtsCharRangeUsage; const aStart, aStop: WideChar);
  187. var
  188. p: PtsCharRange;
  189. begin
  190. new(p);
  191. p^.Start := aStart;
  192. p^.Stop := aStop;
  193. case aUsage of
  194. tsUsageInclude: fIncludeCharRanges.Add(p);
  195. tsUsageExclude: fExcludeCharRanges.Add(p);
  196. end;
  197. end;
  198. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  199. procedure TtsPostProcessor.AddChars(const aUsage: TtsCharRangeUsage; aChars: PWideChar);
  200. begin
  201. if not Assigned(aChars) then
  202. exit;
  203. while (aChars^ <> #0) do begin
  204. AddRange(aUsage, aChars^, aChars^);
  205. inc(aChars);
  206. end;
  207. end;
  208. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  209. procedure TtsPostProcessor.ClearRanges;
  210. begin
  211. ClearList(fIncludeCharRanges);
  212. ClearList(fExcludeCharRanges);
  213. end;
  214. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  215. function TtsPostProcessor.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  216. begin
  217. result := IsInRange(aChar.CharCode);
  218. end;
  219. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  220. constructor TtsPostProcessor.Create(const aContext: TtsContext);
  221. begin
  222. inherited Create(aContext);
  223. fIncludeCharRanges := TList.Create;
  224. fExcludeCharRanges := TList.Create;
  225. end;
  226. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  227. destructor TtsPostProcessor.Destroy;
  228. begin
  229. ClearRanges;
  230. FreeAndNil(fIncludeCharRanges);
  231. FreeAndNil(fExcludeCharRanges);
  232. inherited Destroy;
  233. end;
  234. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  235. //TtsPostProcessorList//////////////////////////////////////////////////////////////////////////////////////////////////
  236. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  237. function TtsPostProcessorList.GetCount: Integer;
  238. begin
  239. result := fItems.Count;
  240. end;
  241. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  242. function TtsPostProcessorList.GetItem(const aIndex: Integer): TtsPostProcessor;
  243. begin
  244. result := TtsPostProcessor(fItems[aIndex]);
  245. end;
  246. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  247. function TtsPostProcessorList.GetOwnsObjects: Boolean;
  248. begin
  249. result := fItems.OwnsObjects;
  250. end;
  251. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  252. procedure TtsPostProcessorList.SetOwnsObjects(const aValue: Boolean);
  253. begin
  254. fItems.OwnsObjects := aValue;
  255. end;
  256. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  257. procedure TtsPostProcessorList.Add(const aPostProcessor: TtsPostProcessor);
  258. begin
  259. fItems.Add(aPostProcessor);
  260. end;
  261. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  262. procedure TtsPostProcessorList.Delete(const aIndex: Integer);
  263. begin
  264. fItems.Delete(aIndex);
  265. end;
  266. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  267. procedure TtsPostProcessorList.Clear;
  268. begin
  269. fItems.Clear;
  270. end;
  271. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  272. function TtsPostProcessorList.Remove(const aPostProcessor: TtsPostProcessor): Integer;
  273. begin
  274. result := fItems.IndexOf(aPostProcessor);
  275. if (result >= 0) then
  276. fItems.Delete(result);
  277. end;
  278. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  279. function TtsPostProcessorList.IndexOf(const aPostProcessor: TtsPostProcessor): Integer;
  280. begin
  281. result := fItems.IndexOf(aPostProcessor);
  282. end;
  283. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  284. function TtsPostProcessorList.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  285. var
  286. i: Integer;
  287. begin
  288. result := inherited Execute(aChar, aImage);
  289. if result then
  290. for i := 0 to fItems.Count-1 do
  291. (fItems[i] as TtsPostProcessor).Execute(aChar, aImage);
  292. end;
  293. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  294. constructor TtsPostProcessorList.Create(const aContext: TtsContext; const aOwnsObjects: Boolean);
  295. begin
  296. inherited Create(aContext);
  297. fItems := TObjectList.Create(aOwnsObjects);
  298. end;
  299. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  300. destructor TtsPostProcessorList.Destroy;
  301. begin
  302. FreeAndNil(fItems);
  303. inherited Destroy;
  304. end;
  305. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  306. //TtsPostProcessorFillColor/////////////////////////////////////////////////////////////////////////////////////////////
  307. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  308. function TtsPostProcessorFillColor.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  309. begin
  310. result := inherited Execute(aChar, aImage);
  311. if result and Assigned(aImage) then
  312. aImage.FillColor(fColor, fChannels, fModes);
  313. end;
  314. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  315. constructor TtsPostProcessorFillColor.Create(const aContext: TtsContext; const aColor: TtsColor4f;
  316. const aModes: TtsImageModes; const aChannels: TtsColorChannels);
  317. begin
  318. inherited Create(aContext);
  319. fColor := aColor;
  320. fModes := aModes;
  321. fChannels := aChannels;
  322. end;
  323. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  324. //TtsPostProcessorFillPattern///////////////////////////////////////////////////////////////////////////////////////////
  325. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  326. procedure TtsPostProcessorFillPattern.SetPattern(aValue: TtsImage);
  327. begin
  328. if (fPattern = aValue) then
  329. exit;
  330. if fOwnsPattern then
  331. FreeAndNil(fPattern);
  332. fPattern := aValue;
  333. end;
  334. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  335. function TtsPostProcessorFillPattern.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  336. begin
  337. result := inherited Execute(aChar, aImage);
  338. if result and Assigned(aImage) then
  339. aImage.FillPattern(fPattern, fPosition.x, fPosition.y, fChannels, fModes);
  340. end;
  341. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  342. constructor TtsPostProcessorFillPattern.Create(const aContext: TtsContext; const aPattern: TtsImage;
  343. const aOwnsPattern: Boolean; const aPosition: TtsPosition; const aModes: TtsImageModes; const aChannels: TtsColorChannels);
  344. begin
  345. inherited Create(aContext);
  346. fPattern := aPattern;
  347. fOwnsPattern := aOwnsPattern;
  348. fPosition := aPosition;
  349. fModes := aModes;
  350. fChannels := aChannels;
  351. end;
  352. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  353. destructor TtsPostProcessorFillPattern.Destroy;
  354. begin
  355. if fOwnsPattern then
  356. FreeAndNil(fPattern);
  357. inherited Destroy;
  358. end;
  359. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  360. //TtsPostProcessorBorder////////////////////////////////////////////////////////////////////////////////////////////////
  361. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  362. procedure TtsPostProcessorBorder.SetStrength(const aValue: Single);
  363. begin
  364. fStrength := aValue;
  365. FreeAndNil(fKernel);
  366. fKernel := TtsKernel2D.Create(fWidth, fStrength);
  367. end;
  368. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  369. procedure TtsPostProcessorBorder.SetWidth(const aValue: Single);
  370. begin
  371. fWidth := aValue;
  372. FreeAndNil(fKernel);
  373. fKernel := TtsKernel2D.Create(fWidth, fStrength);
  374. end;
  375. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  376. function TtsPostProcessorBorder.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  377. var
  378. orig: TtsImage;
  379. x, y: Integer;
  380. dst: PByte;
  381. m: TtsGlyphMetric;
  382. function BorderLookup: TtsColor4f;
  383. var
  384. i: Integer;
  385. c: TtsColor4f;
  386. s: Single;
  387. chan: TtsColorChannel;
  388. mask: TtsColorChannels;
  389. tmpX, tmpY: Integer;
  390. begin
  391. mask := TS_COLOR_CHANNELS_RGBA;
  392. result := tsColor4f(0, 0, 0, 0);
  393. for i := 0 to fKernel.ItemCount-1 do begin
  394. tmpX := x + fKernel.Items[i].OffsetX;
  395. tmpY := y + fKernel.Items[i].OffsetY;
  396. if (tmpX >= 0) and (tmpX < orig.Width) and
  397. (tmpY >= 0) and (tmpY < orig.Height) and
  398. orig.GetPixelAt(tmpX, tmpY, c) then
  399. begin
  400. {$IFDEF FPC}
  401. for chan in mask do begin
  402. {$ELSE}
  403. for chan := low(TtsColorChannel) to high(TtsColorChannel) do if (chan in mask) then begin
  404. {$ENDIF}
  405. s := c.arr[Integer(chan)] * fColor.arr[Integer(chan)] * fKernel.Items[i].Value;
  406. if (s > result.arr[Integer(chan)]) then begin
  407. result.arr[Integer(chan)] := s;
  408. if (s >= 1.0) then begin
  409. Exclude(mask, chan);
  410. if (mask = []) then
  411. exit;
  412. end;
  413. end;
  414. end;
  415. end;
  416. end;
  417. end;
  418. begin
  419. result := inherited Execute(aChar, aImage);
  420. if not result or not Assigned(aImage) then
  421. exit;
  422. aImage.Resize(
  423. aImage.Width + 2 * fKernel.SizeX,
  424. aImage.Height + 2 * fKernel.SizeY,
  425. fKernel.SizeX, fKernel.SizeY);
  426. orig := TtsImage.Create(fContext);
  427. try
  428. orig.Assign(aImage);
  429. aImage.FillColor(fColor, TS_COLOR_CHANNELS_RGBA, TS_IMAGE_MODES_REPLACE_ALL);
  430. for y := 0 to orig.Height-1 do begin
  431. dst := aImage.Scanline[y];
  432. for x := 0 to orig.Width-1 do
  433. tsFormatMap(aImage.Format, dst, BorderLookup);
  434. end;
  435. aImage.Blend(orig, 0, 0, @tsBlendColorAdditiveAlpha);
  436. finally
  437. FreeAndNil(orig);
  438. end;
  439. m := aChar.GlyphMetric;
  440. m.GlyphRect.Right := m.GlyphRect.Right + 2 * fKernel.SizeX;
  441. m.GlyphRect.Bottom := m.GlyphRect.Bottom + 2 * fKernel.SizeY;
  442. if fKeepSize then begin
  443. m.GlyphOrigin.x := m.GlyphOrigin.x - fKernel.SizeX;
  444. m.GlyphOrigin.y := m.GlyphOrigin.y + fKernel.SizeY;
  445. end else begin
  446. m.Advance := m.Advance + 2 * fKernel.SizeX;
  447. m.GlyphOrigin.y := m.GlyphOrigin.y + fKernel.SizeY;
  448. end;
  449. aChar.GlyphMetric := m;
  450. end;
  451. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  452. constructor TtsPostProcessorBorder.Create(const aContext: TtsContext;
  453. const aWidth, aStrength: Single; const aColor: TtsColor4f; const aKeepSize: Boolean);
  454. begin
  455. inherited Create(aContext);
  456. fWidth := aWidth;
  457. fStrength := aStrength;
  458. fColor := aColor;
  459. fKeepSize := aKeepSize;
  460. fKernel := TtsKernel2D.Create(fWidth, fStrength);
  461. end;
  462. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  463. destructor TtsPostProcessorBorder.Destroy;
  464. begin
  465. FreeAndNil(fKernel);
  466. inherited Destroy;
  467. end;
  468. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  469. //TtsPostProcessorShadow////////////////////////////////////////////////////////////////////////////////////////////////
  470. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  471. procedure TtsPostProcessorShadow.SetRadius(const aValue: Single);
  472. begin
  473. fRadius := aValue;
  474. FreeAndNil(fKernel);
  475. fKernel := TtsKernel1D.Create(fRadius, fStrength);
  476. end;
  477. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  478. procedure TtsPostProcessorShadow.SetStrength(const aValue: Single);
  479. begin
  480. fStrength := aValue;
  481. FreeAndNil(fKernel);
  482. fKernel := TtsKernel1D.Create(fRadius, fStrength);
  483. end;
  484. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  485. function TtsPostProcessorShadow.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  486. var
  487. orig: TtsImage;
  488. tmpX, tmpY: Integer;
  489. m: TtsGlyphMetric;
  490. begin
  491. result := inherited Execute(aChar, aImage);
  492. if not result or not Assigned(aImage) then
  493. exit;
  494. orig := TtsImage.Create(fContext);
  495. try
  496. orig.Assign(aImage);
  497. aImage.Resize(
  498. aImage.Width + 2 * fKernel.Size,
  499. aImage.Height + 2 * fKernel.Size,
  500. fKernel.Size, fKernel.Size);
  501. aImage.FillColor(fColor, TS_COLOR_CHANNELS_RGBA, TS_IMAGE_MODES_MODULATE_ALPHA);
  502. aImage.Blur(fKernel, fKernel, [tsChannelAlpha]);
  503. tmpX := fKernel.Size - fOffset.x;
  504. tmpY := fKernel.Size - fOffset.y;
  505. aImage.Blend(orig, tmpX, tmpY, @tsBlendColorAlpha);
  506. m := aChar.GlyphMetric;
  507. m.GlyphRect.Right := m.GlyphRect.Right + 2 * fKernel.Size;
  508. m.GlyphRect.Bottom := m.GlyphRect.Bottom + 2 * fKernel.Size;
  509. m.GlyphOrigin.x := m.GlyphOrigin.x - tmpX;
  510. m.GlyphOrigin.y := m.GlyphOrigin.y + tmpX;
  511. aChar.GlyphMetric := m;
  512. finally
  513. FreeAndNil(orig);
  514. end;
  515. end;
  516. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  517. constructor TtsPostProcessorShadow.Create(const aContext: TtsContext; const aRadius, aStrength: Single;
  518. const aOffset: TtsPosition; const aColor: TtsColor4f);
  519. begin
  520. inherited Create(aContext);
  521. fRadius := aRadius;
  522. fStrength := aStrength;
  523. fOffset := aOffset;
  524. fColor := aColor;
  525. fKernel := TtsKernel1D.Create(fRadius, fStrength);
  526. end;
  527. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  528. destructor TtsPostProcessorShadow.Destroy;
  529. begin
  530. FreeAndNil(fKernel);
  531. inherited Destroy;
  532. end;
  533. end.