SVGFilters.Mod 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588
  1. MODULE SVGFilters;
  2. IMPORT SVG, SVGColors, SVGUtilities, XML, XMLObjects, Raster, Math;
  3. (* Constants that determine the input, the blend-mode and the type of color-matrix *)
  4. CONST
  5. InSourceGraphic*=0;
  6. InFilterElement*=1;
  7. BlendModeNormal=0;
  8. BlendModeMultiply=1;
  9. BlendModeScreen=2;
  10. BlendModeDarken=3;
  11. BlendModeLighten=4;
  12. ColorMatrixTypeMatrix=0;
  13. ColorMatrixTypeSaturate=1;
  14. ColorMatrixTypeHueRotate=2;
  15. ColorMatrixTypeLuminanceToAlpha=3;
  16. TYPE
  17. Buffer*=SVG.Document;
  18. FilterWindow*=POINTER TO FilterWindowDesc;
  19. FilterWindowDesc*=RECORD
  20. x*, y*, width*, height*: SVG.Length;
  21. modeBlend, modeCopy: Raster.Mode;
  22. sourceGraphic: Buffer;
  23. END;
  24. In*=POINTER TO InDesc;
  25. InDesc*=RECORD
  26. type*: SHORTINT;
  27. fe*: FilterElement;
  28. END;
  29. FilterElement*=OBJECT
  30. VAR
  31. in*: In;
  32. x*,y*,width*,height*: SVG.Length;
  33. (* Apply this filter element to a new target *)
  34. PROCEDURE Apply*(window: FilterWindow): Buffer;
  35. VAR target: Buffer;
  36. BEGIN
  37. target := SVG.NewDocument(ENTIER(width),ENTIER(height));
  38. ApplyFilter(window, target);
  39. RETURN target;
  40. END Apply;
  41. (* Apply this filter element to the specifies target *)
  42. PROCEDURE ApplyFilter*(window: FilterWindow; target: Buffer);
  43. BEGIN
  44. HALT(99)
  45. END ApplyFilter;
  46. (* Get the buffer of the processed input *)
  47. PROCEDURE GetInBuffer(in: In; window: FilterWindow): Buffer;
  48. VAR b:Buffer; fe: FilterElement;
  49. BEGIN
  50. CASE in.type OF
  51. InSourceGraphic: RETURN window.sourceGraphic;
  52. | InFilterElement: fe:=in.fe; b:=fe.Apply(window); RETURN b;
  53. END
  54. END GetInBuffer;
  55. (* Get a pixel from the source buffer*)
  56. PROCEDURE GetInPixel(x,y, tx0,ty0: LONGINT; window: FilterWindow; in: In; source: Buffer; VAR pix: Raster.Pixel);
  57. BEGIN
  58. IF in.type#InFilterElement THEN
  59. x:=x+tx0-ENTIER(window.x);
  60. y:=y+ty0-ENTIER(window.y);
  61. END;
  62. IF (0 <= x) & (x < source.width) & (0 <= y) & (y < source.height) THEN
  63. Raster.Get(source,x,y, pix, window.modeCopy);
  64. ELSE
  65. Raster.SetRGBA(pix,0,0,0,0)
  66. END
  67. END GetInPixel;
  68. END FilterElement;
  69. feBlend*=OBJECT(FilterElement)
  70. VAR
  71. in2*: In;
  72. mode*: SHORTINT;
  73. (* Apply this filter element *)
  74. PROCEDURE ApplyFilter*(window: FilterWindow; target: Buffer);
  75. VAR tx,ty: LONGINT;
  76. source,source2: Buffer;
  77. pix,pix2: Raster.Pixel;
  78. BEGIN
  79. source := GetInBuffer(in,window);
  80. source2 := GetInBuffer(in2,window);
  81. FOR ty:=0 TO target.height-1 DO
  82. FOR tx:=0 TO target.width-1 DO
  83. GetInPixel(tx,ty, ENTIER(x),ENTIER(y), window, in,source, pix);
  84. GetInPixel(tx,ty, ENTIER(x),ENTIER(y), window, in2,source2, pix2);
  85. Blend(pix,pix2);
  86. Raster.Put(target, tx,ty, pix, window.modeCopy)
  87. END; END;
  88. END ApplyFilter;
  89. (* Blend two pixels *)
  90. PROCEDURE Blend(VAR a, b: Raster.Pixel);
  91. VAR fa, fb, ta, tb, i: LONGINT;
  92. BEGIN
  93. CASE mode OF
  94. | BlendModeNormal: (* (1-qa)*cb+ca *)
  95. fa := 255;
  96. fb := 255-ORD(a[3]);
  97. FOR i := 0 TO 2 DO
  98. a[i] := Raster.Clamp[200H + (fa * ORD(a[i]) + fb * ORD(b[i])) DIV 255]
  99. END
  100. | BlendModeMultiply: (* (1-qa)*cb+(1-qb)*ca+ca*cb *)
  101. fb := 255-ORD(a[3]);
  102. FOR i := 0 TO 2 DO
  103. fa := 255-ORD(b[3])+ORD(b[i]);
  104. a[i] := Raster.Clamp[200H + (fa * ORD(a[i]) + fb * ORD(b[i])) DIV 255]
  105. END
  106. | BlendModeScreen: (* cb+ca-ca*cb *)
  107. fb := 255;
  108. FOR i := 0 TO 2 DO
  109. fa := 255-ORD(b[i]);
  110. a[i] := Raster.Clamp[200H + (fa * ORD(a[i]) + fb * ORD(b[i])) DIV 255]
  111. END
  112. | BlendModeDarken: (* Min((1-qa)*cb+ca,(1-qb)*ca+cb) *)
  113. fa := 255-ORD(b[3]);
  114. fb := 255-ORD(a[3]);
  115. FOR i := 0 TO 2 DO
  116. ta := fa * ORD(a[i]) + 255 * LONG(ORD(b[i]));
  117. tb := 255 * LONG(ORD(a[i])) + fb * ORD(b[i]);
  118. IF ta<tb THEN
  119. a[i] := Raster.Clamp[200H + ta DIV 255]
  120. ELSE
  121. a[i] := Raster.Clamp[200H + tb DIV 255]
  122. END
  123. END
  124. | BlendModeLighten: (* Max((1-qa)*cb+ca,(1-qb)*ca+cb) *)
  125. fa := 255-ORD(b[3]);
  126. fb := 255-ORD(a[3]);
  127. FOR i := 0 TO 2 DO
  128. ta := fa * ORD(a[i]) + 255 * LONG(ORD(b[i]));
  129. tb := 255 * LONG(ORD(a[i])) + fb * ORD(b[i]);
  130. IF ta>tb THEN
  131. a[i] := Raster.Clamp[200H + ta DIV 255]
  132. ELSE
  133. a[i] := Raster.Clamp[200H + tb DIV 255]
  134. END
  135. END
  136. END;
  137. (* 1- (1-qa)*(1-qb) *)
  138. fa := 255-ORD(a[3]);
  139. fb := 255-ORD(b[3]);
  140. a[3] := Raster.Clamp[200H + 255 - (fa*fb) DIV 255]
  141. END Blend;
  142. END feBlend;
  143. feOffset*=OBJECT(FilterElement)
  144. VAR
  145. dx*,dy*: SVG.Length;
  146. (* Apply this filter element *)
  147. PROCEDURE ApplyFilter*(window: FilterWindow; target: Buffer);
  148. VAR tx,ty, sx,sy: LONGINT;
  149. source: Buffer;
  150. pix: Raster.Pixel;
  151. BEGIN
  152. source := GetInBuffer(in,window);
  153. FOR ty:=0 TO target.height-1 DO
  154. FOR tx:=0 TO target.width-1 DO
  155. sx := ENTIER(tx-dx);
  156. sy := ENTIER(ty-dy);
  157. GetInPixel(sx,sy, ENTIER(x),ENTIER(y), window, in,source, pix);
  158. Raster.Put(target, tx,ty, pix, window.modeCopy)
  159. END; END;
  160. END ApplyFilter;
  161. END feOffset;
  162. ColorMatrix*=RECORD
  163. a: ARRAY 5,4 OF LONGREAL;
  164. END;
  165. feColorMatrix*=OBJECT(FilterElement)
  166. VAR
  167. type*: SHORTINT;
  168. matrix*: ColorMatrix;
  169. (* Apply this filter element *)
  170. PROCEDURE ApplyFilter*(window: FilterWindow; target: Buffer);
  171. VAR tx,ty: LONGINT;
  172. source: Buffer;
  173. pix: Raster.Pixel;
  174. BEGIN
  175. source := GetInBuffer(in,window);
  176. FOR ty:=0 TO target.height-1 DO
  177. FOR tx:=0 TO target.width-1 DO
  178. GetInPixel(tx,ty, ENTIER(x),ENTIER(y), window, in,source, pix);
  179. TransformByColorMatrix(pix,matrix);
  180. Raster.Put(target, tx,ty, pix, window.modeCopy)
  181. END; END;
  182. END ApplyFilter;
  183. END feColorMatrix;
  184. feGaussianBlur*=OBJECT(FilterElement)
  185. VAR
  186. stdDeviationX*, stdDeviationY*: SVG.Length;
  187. (* Apply this filter element *)
  188. PROCEDURE ApplyFilter*(window: FilterWindow; target: Buffer);
  189. VAR tx,ty, k: LONGINT;
  190. source: Buffer;
  191. pix: Raster.Pixel;
  192. temp: Buffer;
  193. kernel: POINTER TO ARRAY OF LONGREAL;
  194. kernelSizeX, kernelSizeY, kernelHalfX, kernelHalfY: LONGINT;
  195. norm, sSquared2: LONGREAL;
  196. sum: SVGColors.ColorSum;
  197. BEGIN
  198. (* Gaussian Kernel is seperable into a vertical part and a horizontal part. *)
  199. (* Prepare the buffers for both parts using the larger stdDeviation. *)
  200. kernelHalfX := 3*ENTIER(stdDeviationX);
  201. kernelHalfY := 3*ENTIER(stdDeviationY);
  202. kernelSizeX := 2*kernelHalfX+1;
  203. kernelSizeY := 2*kernelHalfY+1;
  204. IF stdDeviationX>stdDeviationY THEN NEW(kernel,kernelSizeX)
  205. ELSE NEW(kernel,kernelSizeY);
  206. END;
  207. source := GetInBuffer(in,window);
  208. temp := SVG.NewDocument(source.width, source.height);
  209. (* horizontal part *)
  210. sSquared2 := 2*stdDeviationX*stdDeviationX;
  211. norm := Math.sqrt(SHORT(sSquared2)*Math.pi);
  212. FOR k :=-kernelHalfX TO kernelHalfX DO
  213. kernel[kernelHalfX+k] := Math.exp(SHORT(-k*k/sSquared2)) / norm;
  214. END;
  215. FOR ty:=0 TO temp.height-1 DO
  216. FOR tx:=0 TO temp.width-1 DO
  217. sum[0] := 0; sum[1] := 0; sum[2] := 0; sum[3] := 0;
  218. FOR k:=-kernelHalfX TO kernelHalfX DO
  219. GetInPixel(tx+k,ty, ENTIER(x),ENTIER(y), window, in,source, pix);
  220. SVGColors.WeightedAdd(sum, kernel[kernelHalfX+k], pix);
  221. END;
  222. SVGColors.ColorSumToPixel(sum, pix);
  223. Raster.Put(temp, tx,ty, pix, window.modeCopy)
  224. END; END;
  225. (* vertical part *)
  226. sSquared2 := 2*stdDeviationY*stdDeviationY;
  227. norm := Math.sqrt(SHORT(sSquared2)*Math.pi);
  228. FOR k :=-kernelHalfY TO kernelHalfY DO
  229. kernel[kernelHalfY+k] := Math.exp(SHORT(-k*k/sSquared2)) / norm;
  230. END;
  231. FOR ty:=0 TO target.height-1 DO
  232. FOR tx:=0 TO target.width-1 DO
  233. sum[0] := 0; sum[1] := 0; sum[2] := 0; sum[3] := 0;
  234. FOR k:=-kernelHalfY TO kernelHalfY DO
  235. GetInPixel(tx,ty+k, ENTIER(x),ENTIER(y), window, in,temp, pix);
  236. SVGColors.WeightedAdd(sum, kernel[kernelHalfY+k], pix);
  237. END;
  238. SVGColors.ColorSumToPixel(sum, pix);
  239. Raster.Put(target, tx,ty, pix, window.modeCopy)
  240. END; END
  241. END ApplyFilter;
  242. END feGaussianBlur;
  243. feMerge*=OBJECT(FilterElement)
  244. VAR in2: XMLObjects.List;
  245. (* Apply this filter element *)
  246. PROCEDURE ApplyFilter*(window: FilterWindow; target: Buffer);
  247. VAR tx,ty: LONGINT;
  248. source: Buffer;
  249. pix: Raster.Pixel;
  250. enum: XMLObjects.Enumerator;
  251. next: In;
  252. nextPtr: ANY;
  253. BEGIN
  254. IF in#NIL THEN
  255. source := GetInBuffer(in,window);
  256. FOR ty:=0 TO target.height-1 DO
  257. FOR tx:=0 TO target.width-1 DO
  258. GetInPixel(tx,ty, ENTIER(x),ENTIER(y), window, in,source, pix);
  259. Raster.Put(target, tx,ty, pix, window.modeCopy)
  260. END; END;
  261. IF in2#NIL THEN
  262. enum := in2.GetEnumerator();
  263. WHILE enum.HasMoreElements() DO
  264. nextPtr := enum.GetNext();
  265. next := nextPtr(In);
  266. source := GetInBuffer(next,window);
  267. FOR ty:=0 TO target.height-1 DO
  268. FOR tx:=0 TO target.width-1 DO
  269. GetInPixel(tx,ty, ENTIER(x),ENTIER(y), window, in,source, pix);
  270. Raster.Put(target, tx,ty, pix, window.modeBlend)
  271. END; END;
  272. END
  273. END
  274. END
  275. END ApplyFilter;
  276. (* Add a mergeNode *)
  277. PROCEDURE AddNode*(in: In);
  278. BEGIN
  279. IF in2=NIL THEN NEW(in2) END;
  280. in2.Add(in);
  281. END AddNode;
  282. END feMerge;
  283. feFlood*=OBJECT(FilterElement)
  284. VAR
  285. pix*: Raster.Pixel;
  286. (* Apply this filter element *)
  287. PROCEDURE ApplyFilter*(window: FilterWindow; target: Buffer);
  288. VAR tx,ty: LONGINT;
  289. BEGIN
  290. FOR ty:=0 TO target.height-1 DO
  291. FOR tx:=0 TO target.width-1 DO
  292. Raster.Put(target, tx,ty, pix, window.modeCopy)
  293. END; END;
  294. END ApplyFilter;
  295. END feFlood;
  296. feImage*=OBJECT(FilterElement)
  297. VAR image*: Buffer;
  298. (* Apply this filter element *)
  299. PROCEDURE ApplyFilter*(window: FilterWindow; target: Buffer);
  300. VAR tx,ty, sx,sy: LONGINT;
  301. pix: Raster.Pixel;
  302. BEGIN
  303. FOR ty:=0 TO target.height-1 DO
  304. FOR tx:=0 TO target.width-1 DO
  305. sx := ENTIER(tx*image.width/width);
  306. sy := ENTIER(ty*image.height/height);
  307. IF (sx <image.width) & (sy < image.height) THEN
  308. Raster.Get(image, sx,sy, pix, window.modeCopy);
  309. ELSE
  310. Raster.SetRGBA(pix,0,0,0,0)
  311. END;
  312. Raster.Put(target, tx,ty, pix, window.modeCopy)
  313. END; END;
  314. END ApplyFilter;
  315. END feImage;
  316. feTile*=OBJECT(FilterElement)
  317. (* Apply this filter element *)
  318. PROCEDURE ApplyFilter*(window: FilterWindow; target: Buffer);
  319. VAR tx,ty, sx,sy: LONGINT;
  320. source: Buffer;
  321. pix: Raster.Pixel;
  322. BEGIN
  323. source := GetInBuffer(in,window);
  324. FOR ty:=0 TO target.height-1 DO
  325. FOR tx:=0 TO target.width-1 DO
  326. sx := tx MOD source.width;
  327. sy := ty MOD source.height;
  328. GetInPixel(sx,sy, ENTIER(x),ENTIER(y), window, in,source, pix);
  329. Raster.Put(target, tx,ty, pix, window.modeCopy)
  330. END; END;
  331. END ApplyFilter;
  332. END feTile;
  333. Filter*=OBJECT
  334. VAR fElements: XMLObjects.ArrayDict;
  335. rootElement*: FilterElement;
  336. window*: FilterWindow;
  337. PROCEDURE &New*;
  338. BEGIN
  339. NEW(fElements);
  340. NEW(window);
  341. Raster.InitMode(window.modeBlend, Raster.srcOverDst);
  342. Raster.InitMode(window.modeCopy, Raster.srcCopy);
  343. END New;
  344. (* Add a filter element *)
  345. PROCEDURE AddFilterElement*(fElement: FilterElement; id: SVG.String);
  346. BEGIN
  347. fElements.Remove(id^);
  348. fElements.Add(id^, fElement);
  349. END AddFilterElement;
  350. (* Get a filter element with some specified id *)
  351. PROCEDURE GetFilterElement*(id: SVG.String):FilterElement;
  352. VAR p: ANY;
  353. BEGIN
  354. p := fElements.Get(id^);
  355. IF p = NIL THEN RETURN NIL
  356. ELSE RETURN p(FilterElement) END
  357. END GetFilterElement;
  358. (* Apply this filter *)
  359. PROCEDURE Apply*(source, target: Buffer);
  360. VAR result: Buffer;
  361. minx, miny, maxx, maxy: LONGINT;
  362. BEGIN
  363. IF rootElement#NIL THEN
  364. window.sourceGraphic := SVG.NewDocument(window.width,window.height);
  365. Raster.Copy(source, window.sourceGraphic,
  366. ENTIER(window.x), ENTIER(window.y), ENTIER(window.x+window.width), ENTIER(window.y+window.height),
  367. 0, 0, window.modeCopy);
  368. result := rootElement.Apply(window);
  369. minx := ENTIER(rootElement.x);
  370. miny := ENTIER(rootElement.y);
  371. maxx := ENTIER(rootElement.x+result.width);
  372. maxy := ENTIER(rootElement.y+result.height);
  373. IF minx<0 THEN minx := 0 END;
  374. IF miny<0 THEN miny := 0 END;
  375. IF maxx>target.width THEN maxx := target.width END;
  376. IF maxy>target.height THEN maxy := target.height END;
  377. IF (minx<=maxx) & (miny<=maxy) THEN
  378. Raster.Copy(result, target,
  379. minx-ENTIER(rootElement.x), miny-ENTIER(rootElement.y), maxx-ENTIER(rootElement.x), maxy-ENTIER(rootElement.y),
  380. minx, miny, window.modeBlend)
  381. END
  382. ELSE
  383. SVG.Log("Filter has no elements");
  384. END
  385. END Apply;
  386. END Filter;
  387. FilterDict*=OBJECT
  388. VAR filters: XMLObjects.ArrayDict;
  389. PROCEDURE &New*;
  390. BEGIN
  391. NEW(filters)
  392. END New;
  393. (* Add a filter *)
  394. PROCEDURE AddFilter*(filter: Filter; id: SVG.String);
  395. BEGIN
  396. filters.Add(id^, filter)
  397. END AddFilter;
  398. (* Get a filter with some specified id *)
  399. PROCEDURE GetFilter*(id: SVG.String):Filter;
  400. VAR p: ANY;
  401. BEGIN
  402. p := filters.Get(id^);
  403. IF p = NIL THEN RETURN NIL
  404. ELSE RETURN p(Filter) END
  405. END GetFilter;
  406. END FilterDict;
  407. FilterStack*=OBJECT
  408. VAR
  409. topFilter: Filter;
  410. next: FilterStack;
  411. (* Push a new filter onto the stack *)
  412. PROCEDURE Push*(filter: Filter);
  413. VAR pushed: FilterStack;
  414. BEGIN
  415. NEW(pushed);
  416. pushed^ := SELF^;
  417. next := pushed;
  418. topFilter:=filter;
  419. END Push;
  420. (* Pop the top filter from the stack *)
  421. PROCEDURE Pop*(VAR filter: Filter);
  422. BEGIN
  423. filter := topFilter;
  424. SELF^ := next^;
  425. END Pop;
  426. END FilterStack;
  427. (* Parse some in attribute of a filter element *)
  428. PROCEDURE ParseIn*(value: SVG.String; VAR in: SHORTINT);
  429. BEGIN
  430. IF value^ = "SourceGraphic" THEN in := InSourceGraphic
  431. ELSE
  432. in := InFilterElement
  433. END
  434. END ParseIn;
  435. (* Parse the blendMode attribute of some feBlend element *)
  436. PROCEDURE ParseBlendMode*(value: SVG.String; VAR mode: SHORTINT);
  437. BEGIN
  438. IF value^ = "normal" THEN mode := BlendModeNormal
  439. ELSIF value^ = "multiply" THEN mode := BlendModeMultiply
  440. ELSIF value^ = "screen" THEN mode := BlendModeScreen
  441. ELSIF value^ = "darken" THEN mode := BlendModeDarken
  442. ELSIF value^ = "lighten" THEN mode := BlendModeLighten
  443. ELSE
  444. SVG.Error("mode attribute feBlend must be 'normal', 'multiply', 'screen', 'darken' or 'lighten'");
  445. mode := BlendModeNormal
  446. END
  447. END ParseBlendMode;
  448. (* Parse some type attribute of some feColorMatrix element *)
  449. PROCEDURE ParseColorMatrixType*(value: XML.String; VAR type: SHORTINT);
  450. BEGIN
  451. IF value^ = "matrix" THEN type := ColorMatrixTypeMatrix
  452. ELSIF value^ = "saturate" THEN type := ColorMatrixTypeSaturate
  453. ELSIF value^ = "hueRotate" THEN type := ColorMatrixTypeHueRotate
  454. ELSIF value^ = "luminanceToAlpha" THEN type := ColorMatrixTypeLuminanceToAlpha
  455. ELSE
  456. SVG.Error("type attribute feColorMatrix must be 'matrix', 'saturate', 'hueRotate' or 'luminanceToAlpha'");
  457. type := ColorMatrixTypeMatrix
  458. END
  459. END ParseColorMatrixType;
  460. (* Parse some values attribute of some feColorMatrix element *)
  461. PROCEDURE ParseColorMatrixValues*(values: XML.String; type: SHORTINT; VAR matrix: ColorMatrix):BOOLEAN;
  462. VAR pos: SIZE; i,j: LONGINT;
  463. angle, s,c: LONGREAL;
  464. BEGIN
  465. (* Init to the zero matrix *)
  466. FOR i := 0 TO 4 DO
  467. FOR j := 0 TO 3 DO
  468. matrix.a[i,j] := 0;
  469. END; END;
  470. IF type=ColorMatrixTypeLuminanceToAlpha THEN
  471. (* In this case the 'values' attribute is not applicable as the matrix is predefined: *)
  472. matrix.a[0,3] := 0.2125;
  473. matrix.a[1,3] := 0.7154;
  474. matrix.a[2,3] := 0.0721;
  475. RETURN TRUE
  476. END;
  477. (* Otherwise the default is the identity matrix *)
  478. matrix.a[0,0] := 1;
  479. matrix.a[1,1] := 1;
  480. matrix.a[2,2] := 1;
  481. matrix.a[3,3] := 1;
  482. IF values=NIL THEN RETURN TRUE END;
  483. pos :=0;
  484. CASE type OF
  485. | ColorMatrixTypeMatrix:
  486. FOR j := 0 TO 3 DO
  487. FOR i := 0 TO 4 DO
  488. SVGUtilities.SkipCommaWhiteSpace(pos, values);
  489. SVGUtilities.StrToFloatPos(values^, matrix.a[i,j], pos);
  490. END;END;
  491. RETURN TRUE
  492. | ColorMatrixTypeSaturate:
  493. SVGUtilities.SkipCommaWhiteSpace(pos, values);
  494. SVGUtilities.StrToFloatPos(values^, s, pos);
  495. matrix.a[0,0] := 0.213+0.787*s; matrix.a[1,0] := 0.715-0.715*s; matrix.a[2,0] := 0.072-0.072*s;
  496. matrix.a[0,1] := 0.213-0.213*s; matrix.a[1,1] := 0.715+0.285*s; matrix.a[2,1] := 0.072-0.072*s;
  497. matrix.a[0,2] := 0.213-0.213*s; matrix.a[1,2] := 0.715-0.715*s; matrix.a[2,2] := 0.072+0.928*s;
  498. RETURN TRUE
  499. | ColorMatrixTypeHueRotate:
  500. SVGUtilities.SkipCommaWhiteSpace(pos, values);
  501. SVGUtilities.StrToFloatPos(values^, angle, pos);
  502. s := Math.sin(-SHORT(angle)/180.0*Math.pi);
  503. c := Math.cos(-SHORT(angle)/180.0*Math.pi);
  504. matrix.a[0,0] := 0.213+0.787*c-0.213*s; matrix.a[1,0] := 0.715-0.715*c-0.715*s; matrix.a[2,0] := 0.072-0.072*c+0.928*s;
  505. matrix.a[0,1] := 0.213-0.213*c+0.143*s; matrix.a[1,1] := 0.715+0.285*c+0.140*s; matrix.a[2,1] := 0.072-0.072*c-0.283*s;
  506. matrix.a[0,2] := 0.213-0.213*c-0.787*s; matrix.a[1,2] := 0.715-0.715*c+0.715*s; matrix.a[2,2] := 0.072+0.928*c+0.072*s;
  507. RETURN TRUE
  508. END;
  509. RETURN FALSE
  510. END ParseColorMatrixValues;
  511. (* Transform a pixel by a matrix *)
  512. PROCEDURE TransformByColorMatrix(VAR pix: Raster.Pixel; VAR matrix: ColorMatrix);
  513. VAR p, result: ARRAY 4 OF LONGREAL;
  514. BEGIN
  515. p[0] := ORD(pix[0])/255.0;
  516. p[1] := ORD(pix[1])/255.0;
  517. p[2] := ORD(pix[2])/255.0;
  518. p[3] := ORD(pix[3])/255.0;
  519. result[0] := matrix.a[0,0]*p[0] + matrix.a[1,0]*p[1] + matrix.a[2,0]*p[2] + matrix.a[3,0]*p[3] + matrix.a[4,0];
  520. result[1] := matrix.a[0,1]*p[0] + matrix.a[1,1]*p[1] + matrix.a[2,1]*p[2] + matrix.a[3,1]*p[3] + matrix.a[4,1];
  521. result[2] := matrix.a[0,2]*p[0] + matrix.a[1,2]*p[1] + matrix.a[2,2]*p[2] + matrix.a[3,2]*p[3] + matrix.a[4,2];
  522. result[3] := matrix.a[0,3]*p[0] + matrix.a[1,3]*p[1] + matrix.a[2,3]*p[2] + matrix.a[3,3]*p[3] + matrix.a[4,3];
  523. pix[0] := Raster.Clamp[200H+ENTIER(result[0]*255)];
  524. pix[1] := Raster.Clamp[200H+ENTIER(result[1]*255)];
  525. pix[2] := Raster.Clamp[200H+ENTIER(result[2]*255)];
  526. pix[3] := Raster.Clamp[200H+ENTIER(result[3]*255)];
  527. END TransformByColorMatrix;
  528. END SVGFilters.