Du kan inte välja fler än 25 ämnen Ämnen måste starta med en bokstav eller siffra, kan innehålla bindestreck ('-') och vara max 35 tecken långa.

614 rader
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. Math,
  149. utsConstants;
  150. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  151. //TtsPostProcessor//////////////////////////////////////////////////////////////////////////////////////////////////////
  152. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  153. procedure TtsPostProcessor.ClearList(const aList: TList);
  154. var
  155. i: Integer;
  156. p: PtsCharRange;
  157. begin
  158. for i := 0 to aList.Count-1 do begin
  159. p := aList[i];
  160. Dispose(p);
  161. end;
  162. aList.Clear;
  163. end;
  164. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  165. function TtsPostProcessor.IsInRange(const aCharCode: WideChar): Boolean;
  166. var
  167. i: Integer;
  168. p: PtsCharRange;
  169. begin
  170. result := (fIncludeCharRanges.Count = 0);
  171. if not result then for i := 0 to fIncludeCharRanges.Count-1 do begin
  172. p := fIncludeCharRanges[i];
  173. if (aCharCode >= p^.Start) and (aCharCode <= p^.Stop) then begin
  174. result := true;
  175. break;
  176. end;
  177. end;
  178. if result then for i := 0 to fExcludeCharRanges.Count-1 do begin
  179. p := fExcludeCharRanges[i];
  180. if (aCharCode >= p^.Start) and (aCharCode <= p^.Stop) then begin
  181. result := false;
  182. break;
  183. end;
  184. end;
  185. end;
  186. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  187. procedure TtsPostProcessor.AddRange(const aUsage: TtsCharRangeUsage; const aStart, aStop: WideChar);
  188. var
  189. p: PtsCharRange;
  190. begin
  191. new(p);
  192. p^.Start := aStart;
  193. p^.Stop := aStop;
  194. case aUsage of
  195. tsUsageInclude: fIncludeCharRanges.Add(p);
  196. tsUsageExclude: fExcludeCharRanges.Add(p);
  197. end;
  198. end;
  199. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  200. procedure TtsPostProcessor.AddChars(const aUsage: TtsCharRangeUsage; aChars: PWideChar);
  201. begin
  202. if not Assigned(aChars) then
  203. exit;
  204. while (aChars^ <> #0) do begin
  205. AddRange(aUsage, aChars^, aChars^);
  206. inc(aChars);
  207. end;
  208. end;
  209. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  210. procedure TtsPostProcessor.ClearRanges;
  211. begin
  212. ClearList(fIncludeCharRanges);
  213. ClearList(fExcludeCharRanges);
  214. end;
  215. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  216. function TtsPostProcessor.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  217. begin
  218. result := IsInRange(aChar.CharCode);
  219. end;
  220. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  221. constructor TtsPostProcessor.Create(const aContext: TtsContext);
  222. begin
  223. inherited Create(aContext);
  224. fIncludeCharRanges := TList.Create;
  225. fExcludeCharRanges := TList.Create;
  226. end;
  227. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  228. destructor TtsPostProcessor.Destroy;
  229. begin
  230. ClearRanges;
  231. FreeAndNil(fIncludeCharRanges);
  232. FreeAndNil(fExcludeCharRanges);
  233. inherited Destroy;
  234. end;
  235. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  236. //TtsPostProcessorList//////////////////////////////////////////////////////////////////////////////////////////////////
  237. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  238. function TtsPostProcessorList.GetCount: Integer;
  239. begin
  240. result := fItems.Count;
  241. end;
  242. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  243. function TtsPostProcessorList.GetItem(const aIndex: Integer): TtsPostProcessor;
  244. begin
  245. result := TtsPostProcessor(fItems[aIndex]);
  246. end;
  247. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  248. function TtsPostProcessorList.GetOwnsObjects: Boolean;
  249. begin
  250. result := fItems.OwnsObjects;
  251. end;
  252. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  253. procedure TtsPostProcessorList.SetOwnsObjects(const aValue: Boolean);
  254. begin
  255. fItems.OwnsObjects := aValue;
  256. end;
  257. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  258. procedure TtsPostProcessorList.Add(const aPostProcessor: TtsPostProcessor);
  259. begin
  260. fItems.Add(aPostProcessor);
  261. end;
  262. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  263. procedure TtsPostProcessorList.Delete(const aIndex: Integer);
  264. begin
  265. fItems.Delete(aIndex);
  266. end;
  267. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  268. procedure TtsPostProcessorList.Clear;
  269. begin
  270. fItems.Clear;
  271. end;
  272. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  273. function TtsPostProcessorList.Remove(const aPostProcessor: TtsPostProcessor): Integer;
  274. begin
  275. result := fItems.IndexOf(aPostProcessor);
  276. if (result >= 0) then
  277. fItems.Delete(result);
  278. end;
  279. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  280. function TtsPostProcessorList.IndexOf(const aPostProcessor: TtsPostProcessor): Integer;
  281. begin
  282. result := fItems.IndexOf(aPostProcessor);
  283. end;
  284. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  285. function TtsPostProcessorList.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  286. var
  287. i: Integer;
  288. begin
  289. result := inherited Execute(aChar, aImage);
  290. if result then
  291. for i := 0 to fItems.Count-1 do
  292. (fItems[i] as TtsPostProcessor).Execute(aChar, aImage);
  293. end;
  294. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  295. constructor TtsPostProcessorList.Create(const aContext: TtsContext; const aOwnsObjects: Boolean);
  296. begin
  297. inherited Create(aContext);
  298. fItems := TObjectList.Create(aOwnsObjects);
  299. end;
  300. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  301. destructor TtsPostProcessorList.Destroy;
  302. begin
  303. FreeAndNil(fItems);
  304. inherited Destroy;
  305. end;
  306. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  307. //TtsPostProcessorFillColor/////////////////////////////////////////////////////////////////////////////////////////////
  308. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  309. function TtsPostProcessorFillColor.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  310. begin
  311. result := inherited Execute(aChar, aImage);
  312. if result and Assigned(aImage) then
  313. aImage.FillColor(fColor, fChannels, fModes);
  314. end;
  315. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  316. constructor TtsPostProcessorFillColor.Create(const aContext: TtsContext; const aColor: TtsColor4f;
  317. const aModes: TtsImageModes; const aChannels: TtsColorChannels);
  318. begin
  319. inherited Create(aContext);
  320. fColor := aColor;
  321. fModes := aModes;
  322. fChannels := aChannels;
  323. end;
  324. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  325. //TtsPostProcessorFillPattern///////////////////////////////////////////////////////////////////////////////////////////
  326. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  327. procedure TtsPostProcessorFillPattern.SetPattern(aValue: TtsImage);
  328. begin
  329. if (fPattern = aValue) then
  330. exit;
  331. if fOwnsPattern then
  332. FreeAndNil(fPattern);
  333. fPattern := aValue;
  334. end;
  335. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  336. function TtsPostProcessorFillPattern.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  337. begin
  338. result := inherited Execute(aChar, aImage);
  339. if result and Assigned(aImage) then
  340. aImage.FillPattern(fPattern, fPosition.x, fPosition.y, fChannels, fModes);
  341. end;
  342. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  343. constructor TtsPostProcessorFillPattern.Create(const aContext: TtsContext; const aPattern: TtsImage;
  344. const aOwnsPattern: Boolean; const aPosition: TtsPosition; const aModes: TtsImageModes; const aChannels: TtsColorChannels);
  345. begin
  346. inherited Create(aContext);
  347. fPattern := aPattern;
  348. fOwnsPattern := aOwnsPattern;
  349. fPosition := aPosition;
  350. fModes := aModes;
  351. fChannels := aChannels;
  352. end;
  353. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  354. destructor TtsPostProcessorFillPattern.Destroy;
  355. begin
  356. if fOwnsPattern then
  357. FreeAndNil(fPattern);
  358. inherited Destroy;
  359. end;
  360. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  361. //TtsPostProcessorBorder////////////////////////////////////////////////////////////////////////////////////////////////
  362. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  363. procedure TtsPostProcessorBorder.SetStrength(const aValue: Single);
  364. begin
  365. fStrength := aValue;
  366. FreeAndNil(fKernel);
  367. fKernel := TtsKernel2D.Create(fWidth, fStrength);
  368. end;
  369. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  370. procedure TtsPostProcessorBorder.SetWidth(const aValue: Single);
  371. begin
  372. fWidth := aValue;
  373. FreeAndNil(fKernel);
  374. fKernel := TtsKernel2D.Create(fWidth, fStrength);
  375. end;
  376. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  377. function TtsPostProcessorBorder.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  378. var
  379. orig: TtsImage;
  380. x, y: Integer;
  381. dst: PByte;
  382. m: TtsGlyphMetric;
  383. function BorderLookup: TtsColor4f;
  384. var
  385. i: Integer;
  386. c: TtsColor4f;
  387. s: Single;
  388. chan: TtsColorChannel;
  389. mask: TtsColorChannels;
  390. tmpX, tmpY: Integer;
  391. begin
  392. mask := TS_COLOR_CHANNELS_RGBA;
  393. result := tsColor4f(0, 0, 0, 0);
  394. for i := 0 to fKernel.ItemCount-1 do begin
  395. tmpX := x + fKernel.Items[i].OffsetX;
  396. tmpY := y + fKernel.Items[i].OffsetY;
  397. if (tmpX >= 0) and (tmpX < orig.Width) and
  398. (tmpY >= 0) and (tmpY < orig.Height) and
  399. orig.GetPixelAt(tmpX, tmpY, c) then
  400. begin
  401. {$IFDEF FPC}
  402. for chan in mask do begin
  403. {$ELSE}
  404. for chan := low(TtsColorChannel) to high(TtsColorChannel) do if (chan in mask) then begin
  405. {$ENDIF}
  406. s := c.arr[Integer(chan)] * fColor.arr[Integer(chan)] * fKernel.Items[i].Value;
  407. if (s > result.arr[Integer(chan)]) then begin
  408. result.arr[Integer(chan)] := s;
  409. if (s >= 1.0) then begin
  410. Exclude(mask, chan);
  411. if (mask = []) then
  412. exit;
  413. end;
  414. end;
  415. end;
  416. end;
  417. end;
  418. end;
  419. begin
  420. result := inherited Execute(aChar, aImage);
  421. if not result or not Assigned(aImage) then
  422. exit;
  423. aImage.Resize(
  424. aImage.Width + 2 * fKernel.SizeX,
  425. aImage.Height + 2 * fKernel.SizeY,
  426. fKernel.SizeX, fKernel.SizeY);
  427. orig := TtsImage.Create(fContext);
  428. try
  429. orig.Assign(aImage);
  430. aImage.FillColor(fColor, TS_COLOR_CHANNELS_RGBA, TS_IMAGE_MODES_REPLACE_ALL);
  431. for y := 0 to orig.Height-1 do begin
  432. dst := aImage.Scanline[y];
  433. for x := 0 to orig.Width-1 do
  434. tsFormatMap(aImage.Format, dst, BorderLookup);
  435. end;
  436. aImage.Blend(orig, 0, 0, @tsBlendColorAdditiveAlpha);
  437. finally
  438. FreeAndNil(orig);
  439. end;
  440. m := aChar.GlyphMetric;
  441. m.GlyphRect.Right := m.GlyphRect.Right + 2 * fKernel.SizeX;
  442. m.GlyphRect.Bottom := m.GlyphRect.Bottom + 2 * fKernel.SizeY;
  443. if fKeepSize then begin
  444. m.GlyphOrigin.x := m.GlyphOrigin.x - fKernel.SizeX;
  445. m.GlyphOrigin.y := m.GlyphOrigin.y + fKernel.SizeY;
  446. end else begin
  447. m.Advance := m.Advance + 2 * fKernel.SizeX;
  448. m.GlyphOrigin.y := m.GlyphOrigin.y + fKernel.SizeY;
  449. end;
  450. aChar.GlyphMetric := m;
  451. end;
  452. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  453. constructor TtsPostProcessorBorder.Create(const aContext: TtsContext;
  454. const aWidth, aStrength: Single; const aColor: TtsColor4f; const aKeepSize: Boolean);
  455. begin
  456. inherited Create(aContext);
  457. fWidth := aWidth;
  458. fStrength := aStrength;
  459. fColor := aColor;
  460. fKeepSize := aKeepSize;
  461. fKernel := TtsKernel2D.Create(fWidth, fStrength);
  462. end;
  463. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  464. destructor TtsPostProcessorBorder.Destroy;
  465. begin
  466. FreeAndNil(fKernel);
  467. inherited Destroy;
  468. end;
  469. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  470. //TtsPostProcessorShadow////////////////////////////////////////////////////////////////////////////////////////////////
  471. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  472. procedure TtsPostProcessorShadow.SetRadius(const aValue: Single);
  473. begin
  474. fRadius := aValue;
  475. FreeAndNil(fKernel);
  476. fKernel := TtsKernel1D.Create(fRadius, fStrength);
  477. end;
  478. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  479. procedure TtsPostProcessorShadow.SetStrength(const aValue: Single);
  480. begin
  481. fStrength := aValue;
  482. FreeAndNil(fKernel);
  483. fKernel := TtsKernel1D.Create(fRadius, fStrength);
  484. end;
  485. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  486. function TtsPostProcessorShadow.Execute(const aChar: TtsChar; const aImage: TtsImage): Boolean;
  487. var
  488. orig: TtsImage;
  489. tmpX, tmpY, w, h: Integer;
  490. m: TtsGlyphMetric;
  491. begin
  492. result := inherited Execute(aChar, aImage);
  493. if not result or not Assigned(aImage) then
  494. exit;
  495. orig := TtsImage.Create(fContext);
  496. try
  497. orig.Assign(aImage);
  498. aImage.Resize(
  499. aImage.Width + 2 * fKernel.Size + abs(fOffset.x),
  500. aImage.Height + 2 * fKernel.Size + abs(fOffset.y),
  501. fKernel.Size + max(0, fOffset.x),
  502. fKernel.Size + max(0, fOffset.y));
  503. aImage.FillColor(fColor, TS_COLOR_CHANNELS_RGBA, TS_IMAGE_MODES_MODULATE_ALPHA);
  504. aImage.Blur(fKernel, fKernel, [tsChannelAlpha]);
  505. tmpX := fKernel.Size + max(0, -fOffset.x); //fKernel.Size - fOffset.x;
  506. tmpY := fKernel.Size + max(0, -fOffset.y); //fKernel.Size - fOffset.y;
  507. aImage.Blend(orig, tmpX, tmpY, @tsBlendColorAlpha);
  508. m := aChar.GlyphMetric;
  509. m.GlyphRect.Right := m.GlyphRect.Right + 2 * fKernel.Size + abs(fOffset.x);
  510. m.GlyphRect.Bottom := m.GlyphRect.Bottom + 2 * fKernel.Size + abs(fOffset.y);
  511. m.GlyphOrigin.x := m.GlyphOrigin.x - tmpX;
  512. m.GlyphOrigin.y := m.GlyphOrigin.y + tmpX;
  513. aChar.GlyphMetric := m;
  514. finally
  515. FreeAndNil(orig);
  516. end;
  517. end;
  518. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  519. constructor TtsPostProcessorShadow.Create(const aContext: TtsContext; const aRadius, aStrength: Single;
  520. const aOffset: TtsPosition; const aColor: TtsColor4f);
  521. begin
  522. inherited Create(aContext);
  523. fRadius := aRadius;
  524. fStrength := aStrength;
  525. fOffset := aOffset;
  526. fColor := aColor;
  527. fKernel := TtsKernel1D.Create(fRadius, fStrength);
  528. end;
  529. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  530. destructor TtsPostProcessorShadow.Destroy;
  531. begin
  532. FreeAndNil(fKernel);
  533. inherited Destroy;
  534. end;
  535. end.