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.

275 lines
9.5 KiB

  1. unit utsPostProcess;
  2. {$mode objfpc}{$H+}
  3. interface
  4. uses
  5. Classes, SysUtils, utsTextSuite, utsTypes;
  6. type
  7. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  8. TtsPostProcessFillColor = class(TtsPostProcessStep)
  9. private
  10. fColor: TtsColor4f;
  11. fModes: TtsImageModes;
  12. fChannels: TtsColorChannels;
  13. protected
  14. procedure Execute(const aChar: TtsChar; const aCharImage: TtsImage); override;
  15. public
  16. constructor Create(const aColor: TtsColor4f;
  17. const aModes: TtsImageModes; const aChannels: TtsColorChannels);
  18. end;
  19. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  20. TtsPostProcessFillPattern = class(TtsPostProcessStep)
  21. private
  22. fPattern: TtsImage;
  23. fOwnsPattern: Boolean;
  24. fX, fY: Integer;
  25. fModes: TtsImageModes;
  26. fChannels: TtsColorChannels;
  27. protected
  28. procedure Execute(const aChar: TtsChar; const aCharImage: TtsImage); override;
  29. public
  30. constructor Create(const aPattern: TtsImage; const aOwnsPattern: Boolean; const X, Y: Integer;
  31. const aModes: TtsImageModes; const aChannels: TtsColorChannels);
  32. destructor Destroy; override;
  33. end;
  34. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  35. TtsPostProcessBorder = class(TtsPostProcessStep)
  36. private
  37. fKernel: TtsKernel2D;
  38. fColor: TtsColor4f;
  39. fKeepCharSize: Boolean;
  40. public
  41. procedure Execute(const aChar: TtsChar; const aCharImage: TtsImage); override;
  42. public
  43. constructor Create(const aWidth, aStrength: Single; const aColor: TtsColor4f;
  44. const aKeepCharSize: Boolean = false);
  45. destructor Destroy; override;
  46. end;
  47. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  48. TtsPostProcessShadow = class(TtsPostProcessStep)
  49. private
  50. fKernel: TtsKernel1D;
  51. fColor: TtsColor4f;
  52. fX, fY: Integer;
  53. protected
  54. procedure Execute(const aChar: TtsChar; const aCharImage: TtsImage); override;
  55. public
  56. constructor Create(const aRadius, aStrength: Single; const X, Y: Integer; const aColor: TtsColor4f);
  57. destructor Destroy; override;
  58. end;
  59. implementation
  60. uses
  61. Math;
  62. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  63. //TtsPostProcessFillColor///////////////////////////////////////////////////////////////////////////////////////////////
  64. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  65. procedure TtsPostProcessFillColor.Execute(const aChar: TtsChar; const aCharImage: TtsImage);
  66. begin
  67. if Assigned(aCharImage) then
  68. aCharImage.FillColor(fColor, fChannels, fModes);
  69. end;
  70. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  71. constructor TtsPostProcessFillColor.Create(const aColor: TtsColor4f; const aModes: TtsImageModes; const aChannels: TtsColorChannels);
  72. begin
  73. inherited Create;
  74. fColor := aColor;
  75. fModes := aModes;
  76. fChannels := aChannels;
  77. end;
  78. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  79. //TtsPostProcessFillPattern/////////////////////////////////////////////////////////////////////////////////////////////
  80. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  81. procedure TtsPostProcessFillPattern.Execute(const aChar: TtsChar; const aCharImage: TtsImage);
  82. begin
  83. if Assigned(aCharImage) then
  84. aCharImage.FillPattern(fPattern, fX, fY, fChannels, fModes);
  85. end;
  86. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  87. constructor TtsPostProcessFillPattern.Create(const aPattern: TtsImage; const aOwnsPattern: Boolean; const X,
  88. Y: Integer; const aModes: TtsImageModes; const aChannels: TtsColorChannels);
  89. begin
  90. inherited Create;
  91. fPattern := aPattern;
  92. fOwnsPattern := aOwnsPattern;
  93. fX := X;
  94. fY := Y;
  95. fModes := aModes;
  96. fChannels := aChannels;
  97. end;
  98. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  99. destructor TtsPostProcessFillPattern.Destroy;
  100. begin
  101. if fOwnsPattern then
  102. FreeAndNil(fPattern);
  103. inherited Destroy;
  104. end;
  105. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  106. //TtsPostProcessBorder//////////////////////////////////////////////////////////////////////////////////////////////////
  107. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  108. procedure TtsPostProcessBorder.Execute(const aChar: TtsChar; const aCharImage: TtsImage);
  109. var
  110. orig: TtsImage;
  111. x, y: Integer;
  112. dst: PByte;
  113. function BorderLookup: TtsColor4f;
  114. var
  115. i: Integer;
  116. c: TtsColor4f;
  117. s: Single;
  118. chan: TtsColorChannel;
  119. mask: TtsColorChannels;
  120. tmpX, tmpY: Integer;
  121. begin
  122. mask := TS_CHANNELS_RGBA;
  123. result := tsColor4f(0, 0, 0, 0);
  124. for i := 0 to fKernel.ItemCount-1 do begin
  125. tmpX := x + fKernel.Items[i].OffsetX;
  126. tmpY := y + fKernel.Items[i].OffsetY;
  127. if (tmpX >= 0) and (tmpX < orig.Width) and
  128. (tmpY >= 0) and (tmpY < orig.Height) and
  129. orig.GetPixelAt(tmpX, tmpY, c) then
  130. begin
  131. for chan in mask do begin
  132. s := c.arr[Integer(chan)] * fColor.arr[Integer(chan)] * fKernel.Items[i].Value;
  133. if (s > result.arr[Integer(chan)]) then begin
  134. result.arr[Integer(chan)] := s;
  135. if (s >= 1.0) then begin
  136. Exclude(mask, chan);
  137. if (mask = []) then
  138. exit;
  139. end;
  140. end;
  141. end;
  142. end;
  143. end;
  144. end;
  145. begin
  146. if not Assigned(aCharImage) then
  147. exit;
  148. aCharImage.Resize(
  149. aCharImage.Width + 2 * fKernel.SizeX,
  150. aCharImage.Height + 2 * fKernel.SizeY,
  151. fKernel.SizeX, fKernel.SizeY);
  152. orig := TtsImage.Create;
  153. try
  154. orig.Assign(aCharImage);
  155. aCharImage.FillColor(fColor, TS_CHANNELS_RGBA, TS_MODES_REPLACE_ALL);
  156. for y := 0 to orig.Height-1 do begin
  157. dst := aCharImage.Scanline[y];
  158. for x := 0 to orig.Width-1 do
  159. tsFormatMap(aCharImage.Format, dst, BorderLookup);
  160. end;
  161. aCharImage.Blend(orig, 0, 0, @tsBlendFundAdditiveAlpha);
  162. finally
  163. FreeAndNil(orig);
  164. end;
  165. aChar.GlyphRect := tsRect(
  166. aChar.GlyphRect.Left,
  167. aChar.GlyphRect.Top,
  168. aChar.GlyphRect.Right + 2 * fKernel.SizeX,
  169. aChar.GlyphRect.Bottom + 2 * fKernel.SizeY);
  170. if fKeepCharSize then begin
  171. aChar.GlyphOrigin := tsPosition(
  172. aChar.GlyphOrigin.x - fKernel.SizeX,
  173. aChar.GlyphOrigin.y + fKernel.SizeY);
  174. end else begin
  175. aChar.Advance := aChar.Advance + 2 * fKernel.SizeX;
  176. aChar.GlyphOrigin := tsPosition(
  177. aChar.GlyphOrigin.x,
  178. aChar.GlyphOrigin.y + fKernel.SizeY);
  179. end;
  180. end;
  181. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  182. constructor TtsPostProcessBorder.Create(const aWidth, aStrength: Single; const aColor: TtsColor4f; const aKeepCharSize: Boolean);
  183. begin
  184. inherited Create;
  185. fKernel := TtsKernel2D.Create(aWidth, aStrength);
  186. fColor := aColor;
  187. fKeepCharSize := aKeepCharSize;
  188. end;
  189. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  190. destructor TtsPostProcessBorder.Destroy;
  191. begin
  192. FreeAndNil(fKernel);
  193. inherited Destroy;
  194. end;
  195. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  196. //TtsPostProcessShadow//////////////////////////////////////////////////////////////////////////////////////////////////
  197. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  198. procedure TtsPostProcessShadow.Execute(const aChar: TtsChar; const aCharImage: TtsImage);
  199. var
  200. orig: TtsImage;
  201. tmpX, tmpY: Integer;
  202. begin
  203. orig := TtsImage.Create;
  204. try
  205. orig.Assign(aCharImage);
  206. aCharImage.Resize(
  207. aCharImage.Width + 2 * fKernel.Size,
  208. aCharImage.Height + 2 * fKernel.Size,
  209. fKernel.Size, fKernel.Size);
  210. aCharImage.FillColor(fColor, TS_CHANNELS_RGBA, TS_MODES_MODULATE_ALPHA);
  211. aCharImage.Blur(fKernel, fKernel, [tsChannelAlpha]);
  212. tmpX := fKernel.Size - fX;
  213. tmpY := fKernel.Size - fY;
  214. aCharImage.Blend(orig, tmpX, tmpY, @tsBlendFundAlpha);
  215. aChar.GlyphRect := tsRect(
  216. aChar.GlyphRect.Left,
  217. aChar.GlyphRect.Top,
  218. aChar.GlyphRect.Right + 2 * fKernel.Size,
  219. aChar.GlyphRect.Bottom + 2 * fKernel.Size);
  220. aChar.GlyphOrigin := tsPosition(
  221. aChar.GlyphOrigin.x - tmpX,
  222. aChar.GlyphOrigin.y + tmpX);
  223. finally
  224. FreeAndNil(orig);
  225. end;
  226. end;
  227. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  228. constructor TtsPostProcessShadow.Create(const aRadius, aStrength: Single; const X, Y: Integer; const aColor: TtsColor4f);
  229. begin
  230. inherited Create;
  231. fKernel := TtsKernel1D.Create(aRadius, aStrength);
  232. fX := X;
  233. fY := Y;
  234. fColor := aColor;
  235. end;
  236. ////////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
  237. destructor TtsPostProcessShadow.Destroy;
  238. begin
  239. FreeAndNil(fKernel);
  240. inherited Destroy;
  241. end;
  242. end.