mathematical 1.4.2 → 1.5.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (149) hide show
  1. checksums.yaml +4 -4
  2. data/Rakefile +11 -21
  3. data/ext/mathematical/extconf.rb +21 -12
  4. data/ext/mathematical/lasem/Makefile +10 -10
  5. data/ext/mathematical/lasem/docs/Makefile +9 -9
  6. data/ext/mathematical/lasem/docs/reference/Makefile +9 -9
  7. data/ext/mathematical/lasem/docs/reference/lasem/Makefile +15 -9
  8. data/ext/mathematical/lasem/docs/reference/lasem/lasem-decl-list.txt +245 -0
  9. data/ext/mathematical/lasem/docs/reference/lasem/lasem-decl.txt +856 -0
  10. data/ext/mathematical/lasem/docs/reference/lasem/lasem-overrides.txt +0 -0
  11. data/ext/mathematical/lasem/itex2mml/Makefile +9 -9
  12. data/ext/mathematical/lasem/src/Makefile +34 -13
  13. data/ext/mathematical/lasem/src/lasemrender.c +13 -7
  14. data/ext/mathematical/lasem/src/lsmdomenumtypes.c +99 -0
  15. data/ext/mathematical/lasem/src/lsmdomenumtypes.h +26 -0
  16. data/ext/mathematical/lasem/src/lsmmathmlenums.c +24 -0
  17. data/ext/mathematical/lasem/src/lsmmathmlenums.h +12 -1
  18. data/ext/mathematical/lasem/src/lsmmathmlenumtypes.c +793 -0
  19. data/ext/mathematical/lasem/src/lsmmathmlenumtypes.h +96 -0
  20. data/ext/mathematical/lasem/src/lsmmathmlspaceelement.c +14 -0
  21. data/ext/mathematical/lasem/src/lsmmathmlspaceelement.h +1 -1
  22. data/ext/mathematical/lasem/src/lsmmathmltraits.c +24 -0
  23. data/ext/mathematical/lasem/src/lsmmathmltraits.h +1 -0
  24. data/ext/mathematical/lasem/src/lsmsvgattributes.h +50 -0
  25. data/ext/mathematical/lasem/src/lsmsvgdocument.c +18 -0
  26. data/ext/mathematical/lasem/src/lsmsvgenums.c +130 -0
  27. data/ext/mathematical/lasem/src/lsmsvgenums.h +59 -0
  28. data/ext/mathematical/lasem/src/lsmsvgenumtypes.c +1254 -0
  29. data/ext/mathematical/lasem/src/lsmsvgenumtypes.h +129 -0
  30. data/ext/mathematical/lasem/src/lsmsvgfiltercolormatrix.c +115 -0
  31. data/ext/mathematical/lasem/src/lsmsvgfiltercolormatrix.h +58 -0
  32. data/ext/mathematical/lasem/src/lsmsvgfilterconvolvematrix.c +206 -0
  33. data/ext/mathematical/lasem/src/lsmsvgfilterconvolvematrix.h +64 -0
  34. data/ext/mathematical/lasem/src/lsmsvgfilterdisplacementmap.c +124 -0
  35. data/ext/mathematical/lasem/src/lsmsvgfilterdisplacementmap.h +60 -0
  36. data/ext/mathematical/lasem/src/lsmsvgfilterimage.c +167 -0
  37. data/ext/mathematical/lasem/src/lsmsvgfilterimage.h +61 -0
  38. data/ext/mathematical/lasem/src/lsmsvgfiltermorphology.c +116 -0
  39. data/ext/mathematical/lasem/src/lsmsvgfiltermorphology.h +58 -0
  40. data/ext/mathematical/lasem/src/lsmsvgfilterspecularlighting.c +9 -2
  41. data/ext/mathematical/lasem/src/lsmsvgfiltersurface.c +1169 -87
  42. data/ext/mathematical/lasem/src/lsmsvgfiltersurface.h +28 -2
  43. data/ext/mathematical/lasem/src/lsmsvgfilterturbulence.c +142 -0
  44. data/ext/mathematical/lasem/src/lsmsvgfilterturbulence.h +61 -0
  45. data/ext/mathematical/lasem/src/lsmsvgtraits.c +249 -0
  46. data/ext/mathematical/lasem/src/lsmsvgtraits.h +18 -0
  47. data/ext/mathematical/lasem/src/lsmsvgtypes.h +6 -0
  48. data/ext/mathematical/lasem/src/lsmsvgview.c +267 -66
  49. data/ext/mathematical/lasem/src/lsmsvgview.h +23 -0
  50. data/ext/mathematical/lasem/src/lsmtraits.c +53 -1
  51. data/ext/mathematical/lasem/src/lsmtraits.h +2 -0
  52. data/ext/mathematical/lasem/tests/Makefile +26 -15
  53. data/ext/mathematical/lasem/tests/filter.c +152 -0
  54. data/ext/mathematical/lasem/tests/lsmtest.c +34 -30
  55. data/ext/mathematical/lasem/tests/suite.c +5 -2
  56. data/ext/mathematical/lib/libmtex2MML.a +0 -0
  57. data/ext/mathematical/mtex2MML/build/CMakeCache.txt +425 -0
  58. data/ext/mathematical/mtex2MML/build/CMakeFiles/2.8.10.1/CMakeCCompiler.cmake +55 -0
  59. data/ext/mathematical/mtex2MML/build/CMakeFiles/2.8.10.1/CMakeCXXCompiler.cmake +56 -0
  60. data/ext/mathematical/mtex2MML/build/CMakeFiles/2.8.10.1/CMakeSystem.cmake +15 -0
  61. data/ext/mathematical/mtex2MML/build/CMakeFiles/2.8.10.1/CompilerIdC/CMakeCCompilerId.c +393 -0
  62. data/ext/mathematical/mtex2MML/build/CMakeFiles/CMakeDirectoryInformation.cmake +16 -0
  63. data/ext/mathematical/mtex2MML/build/CMakeFiles/CMakeRuleHashes.txt +34 -0
  64. data/ext/mathematical/mtex2MML/build/CMakeFiles/Continuous.dir/DependInfo.cmake +27 -0
  65. data/ext/mathematical/mtex2MML/build/CMakeFiles/Continuous.dir/cmake_clean.cmake +8 -0
  66. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousBuild.dir/DependInfo.cmake +27 -0
  67. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousBuild.dir/cmake_clean.cmake +8 -0
  68. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousConfigure.dir/DependInfo.cmake +27 -0
  69. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousConfigure.dir/cmake_clean.cmake +8 -0
  70. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousCoverage.dir/DependInfo.cmake +27 -0
  71. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousCoverage.dir/cmake_clean.cmake +8 -0
  72. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousMemCheck.dir/DependInfo.cmake +27 -0
  73. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousMemCheck.dir/cmake_clean.cmake +8 -0
  74. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousStart.dir/DependInfo.cmake +27 -0
  75. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousStart.dir/cmake_clean.cmake +8 -0
  76. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousSubmit.dir/DependInfo.cmake +27 -0
  77. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousSubmit.dir/cmake_clean.cmake +8 -0
  78. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousTest.dir/DependInfo.cmake +27 -0
  79. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousTest.dir/cmake_clean.cmake +8 -0
  80. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousUpdate.dir/DependInfo.cmake +27 -0
  81. data/ext/mathematical/mtex2MML/build/CMakeFiles/ContinuousUpdate.dir/cmake_clean.cmake +8 -0
  82. data/ext/mathematical/mtex2MML/build/CMakeFiles/Experimental.dir/DependInfo.cmake +27 -0
  83. data/ext/mathematical/mtex2MML/build/CMakeFiles/Experimental.dir/cmake_clean.cmake +8 -0
  84. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalBuild.dir/DependInfo.cmake +27 -0
  85. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalBuild.dir/cmake_clean.cmake +8 -0
  86. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalConfigure.dir/DependInfo.cmake +27 -0
  87. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalConfigure.dir/cmake_clean.cmake +8 -0
  88. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalCoverage.dir/DependInfo.cmake +27 -0
  89. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalCoverage.dir/cmake_clean.cmake +8 -0
  90. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalMemCheck.dir/DependInfo.cmake +27 -0
  91. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalMemCheck.dir/cmake_clean.cmake +8 -0
  92. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalStart.dir/DependInfo.cmake +27 -0
  93. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalStart.dir/cmake_clean.cmake +8 -0
  94. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalSubmit.dir/DependInfo.cmake +27 -0
  95. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalSubmit.dir/cmake_clean.cmake +8 -0
  96. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalTest.dir/DependInfo.cmake +27 -0
  97. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalTest.dir/cmake_clean.cmake +8 -0
  98. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalUpdate.dir/DependInfo.cmake +27 -0
  99. data/ext/mathematical/mtex2MML/build/CMakeFiles/ExperimentalUpdate.dir/cmake_clean.cmake +8 -0
  100. data/ext/mathematical/mtex2MML/build/CMakeFiles/Makefile.cmake +95 -0
  101. data/ext/mathematical/mtex2MML/build/CMakeFiles/Nightly.dir/DependInfo.cmake +27 -0
  102. data/ext/mathematical/mtex2MML/build/CMakeFiles/Nightly.dir/cmake_clean.cmake +8 -0
  103. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyBuild.dir/DependInfo.cmake +27 -0
  104. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyBuild.dir/cmake_clean.cmake +8 -0
  105. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyConfigure.dir/DependInfo.cmake +27 -0
  106. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyConfigure.dir/cmake_clean.cmake +8 -0
  107. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyCoverage.dir/DependInfo.cmake +27 -0
  108. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyCoverage.dir/cmake_clean.cmake +8 -0
  109. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyMemCheck.dir/DependInfo.cmake +27 -0
  110. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyMemCheck.dir/cmake_clean.cmake +8 -0
  111. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyMemoryCheck.dir/DependInfo.cmake +27 -0
  112. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyMemoryCheck.dir/cmake_clean.cmake +8 -0
  113. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyStart.dir/DependInfo.cmake +27 -0
  114. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyStart.dir/cmake_clean.cmake +8 -0
  115. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlySubmit.dir/DependInfo.cmake +27 -0
  116. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlySubmit.dir/cmake_clean.cmake +8 -0
  117. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyTest.dir/DependInfo.cmake +27 -0
  118. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyTest.dir/cmake_clean.cmake +8 -0
  119. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyUpdate.dir/DependInfo.cmake +27 -0
  120. data/ext/mathematical/mtex2MML/build/CMakeFiles/NightlyUpdate.dir/cmake_clean.cmake +8 -0
  121. data/ext/mathematical/mtex2MML/build/CMakeFiles/TargetDirectories.txt +34 -0
  122. data/ext/mathematical/mtex2MML/build/CMakeFiles/format.dir/DependInfo.cmake +27 -0
  123. data/ext/mathematical/mtex2MML/build/CMakeFiles/format.dir/cmake_clean.cmake +8 -0
  124. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML.dir/DependInfo.cmake +44 -0
  125. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML.dir/cmake_clean.cmake +19 -0
  126. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML.dir/link.txt +1 -0
  127. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML_static.dir/DependInfo.cmake +43 -0
  128. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML_static.dir/cmake_clean.cmake +18 -0
  129. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML_static.dir/cmake_clean_target.cmake +3 -0
  130. data/ext/mathematical/mtex2MML/build/CMakeFiles/libmtex2MML_static.dir/link.txt +2 -0
  131. data/ext/mathematical/mtex2MML/build/CMakeFiles/memcheck.dir/DependInfo.cmake +27 -0
  132. data/ext/mathematical/mtex2MML/build/CMakeFiles/memcheck.dir/cmake_clean.cmake +8 -0
  133. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML.dir/DependInfo.cmake +44 -0
  134. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML.dir/cmake_clean.cmake +19 -0
  135. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML.dir/link.txt +1 -0
  136. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML_clar.dir/DependInfo.cmake +59 -0
  137. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML_clar.dir/cmake_clean.cmake +35 -0
  138. data/ext/mathematical/mtex2MML/build/CMakeFiles/mtex2MML_clar.dir/link.txt +1 -0
  139. data/ext/mathematical/mtex2MML/build/CTestTestfile.cmake +7 -0
  140. data/ext/mathematical/mtex2MML/build/Makefile +1332 -0
  141. data/ext/mathematical/mtex2MML/build/cmake_install.cmake +43 -0
  142. data/ext/mathematical/mtex2MML/build/lexer.c +8877 -0
  143. data/ext/mathematical/mtex2MML/build/libmtex2MML.a +0 -0
  144. data/ext/mathematical/mtex2MML/build/mtex2mml_export.h +35 -0
  145. data/ext/mathematical/mtex2MML/build/parser.c +10202 -0
  146. data/ext/mathematical/mtex2MML/build/parser.h +619 -0
  147. data/ext/mathematical/mtex2MML/src/mtex2MML.h +1 -1
  148. data/lib/mathematical/version.rb +1 -1
  149. metadata +115 -2
@@ -21,6 +21,10 @@
21
21
  * Authors:
22
22
  * Caleb Moore <c.moore@student.unsw.edu.au>
23
23
  * Emmanuel Pacaud <emmanuel@gnome.org>
24
+ * Mario Klingemann <mario@quasimondo.com>
25
+ *
26
+ * Image manipulation routines in this file are an adaptation of the code
27
+ * of librsvg: https://git.gnome.org/browse/librsvg
24
28
  */
25
29
 
26
30
  #include <lsmsvgfiltersurface.h>
@@ -29,6 +33,8 @@
29
33
  #include <math.h>
30
34
  #include <string.h>
31
35
 
36
+ static const int channelmap[4] = {2, 1, 0, 3};
37
+
32
38
  struct _LsmSvgFilterSurface {
33
39
  char *name;
34
40
  cairo_surface_t *surface;
@@ -141,93 +147,270 @@ lsm_svg_filter_surface_unref (LsmSvgFilterSurface *filter_surface)
141
147
 
142
148
  G_DEFINE_BOXED_TYPE (LsmSvgFilterSurface, lsm_svg_filter_surface, lsm_svg_filter_surface_ref, lsm_svg_filter_surface_unref)
143
149
 
150
+ /*
151
+ * The stack blur algorithm was invented by Mario Klingemann <mario@quasimondo.com>
152
+ * http://incubator.quasimondo.com/processing/fast_blur_deluxe.php
153
+ *
154
+ * Compared to Mario's original source code, the lookup table is removed as the benefit
155
+ * doesn't worth the memory usage in case of large radiuses. Also, the following code adds
156
+ * alpha channel support and different radius for vertical and horizontal directions.
157
+ */
158
+
144
159
  static void
145
- box_blur (cairo_surface_t *in,
146
- cairo_surface_t *output,
147
- int kw,
148
- int kh,
149
- int shiftx,
150
- int shifty,
151
- int x0,
152
- int y0,
153
- int x1,
154
- int y1)
160
+ stack_blur (cairo_surface_t *input, cairo_surface_t *output, int rx, int ry)
155
161
  {
156
- gint ch;
157
- gint x, y;
158
- gint offset;
159
- gint rowstride;
160
- guchar *intermediate;
161
- guchar *in_pixels;
162
- guchar *output_pixels;
163
- gint sum;
164
-
165
- in_pixels = cairo_image_surface_get_data (in);
166
- output_pixels = cairo_image_surface_get_data (output);
167
-
168
- rowstride = cairo_image_surface_get_stride (in);
169
-
170
- intermediate = g_new (guchar, MAX (kw, kh));
171
-
172
- if (kw > 1) {
173
- offset = shiftx - kw / 2;
174
- for (ch = 0; ch < 4; ch++) {
175
- for (y = y0; y < y1; y++) {
176
- sum = 0;
177
- for (x = x0; x < x0 + kw; x++) {
178
- sum += (intermediate[x % kw] = in_pixels[4 * x + y * rowstride + ch]);
179
- if (x + offset >= 0 && x + offset < x1)
180
- output_pixels[4 * (x + offset) + y * rowstride + ch] = sum / kw;
181
- }
182
- for (x = x0 + kw; x < x1; x++) {
183
- sum -= intermediate[x % kw];
184
- sum += (intermediate[x % kw] = in_pixels[4 * x + y * rowstride + ch]);
185
- if (x + offset >= 0 && x + offset < x1)
186
- output_pixels[4 * (x + offset) + y * rowstride + ch] = sum / kw;
187
- }
188
- for (x = x1; x < x1 + kw; x++) {
189
- sum -= intermediate[x % kw];
190
- if (x + offset >= 0 && x + offset < x1)
191
- output_pixels[4 * (x + offset) + y * rowstride + ch] = sum / kw;
192
- }
193
- }
194
- }
195
- in_pixels = output_pixels;
196
- }
197
-
198
- if (kh > 1) {
199
- offset = shifty - kh / 2;
200
- for (ch = 0; ch < 4; ch++) {
201
- for (x = x0; x < x1; x++) {
202
- sum = 0;
203
-
204
- for (y = y0; y < y0 + kh; y++) {
205
- sum += (intermediate[y % kh] = in_pixels[4 * x + y * rowstride + ch]);
206
- if (y + offset >= 0 && y + offset < y1)
207
- output_pixels[4 * x + (y + offset) * rowstride + ch] = sum / kh;
208
- }
209
- for (y = y0 + kh; y < y1; y++) {
210
- sum -= intermediate[y % kh];
211
- sum += (intermediate[y % kh] = in_pixels[4 * x + y * rowstride + ch]);
212
- if (y + offset >= 0 && y + offset < y1)
213
- output_pixels[4 * x + (y + offset) * rowstride + ch] = sum / kh;
214
- }
215
- for (y = y1; y < y1 + kh; y++) {
216
- sum -= intermediate[y % kh];
217
- if (y + offset >= 0 && y + offset < y1)
218
- output_pixels[4 * x + (y + offset) * rowstride + ch] = sum / kh;
219
- }
220
- }
221
- }
222
- }
223
-
224
- g_free (intermediate);
162
+ guint32 *input_pixels;
163
+ guint32 *output_pixels;
164
+ int w, h, wm, hm, wh, div;
165
+ int *r, *g, *b, *a;
166
+
167
+ int rsum,gsum,bsum,asum,x,y,i,p,yp,yi,yw;
168
+ int *vmin;
169
+ int divsum;
170
+
171
+ yw=yi=0;
172
+
173
+ int *stack;
174
+ int stackpointer;
175
+ int stackstart;
176
+ int *sir;
177
+ int rbs;
178
+ int r1;
179
+ int routsum,goutsum,boutsum, aoutsum;
180
+ int rinsum,ginsum,binsum, ainsum;
181
+ int rowstride;
182
+
183
+ g_return_if_fail (rx > 0 || ry > 0);
184
+
185
+ input_pixels = (guint32 *) cairo_image_surface_get_data (input);
186
+ output_pixels = (guint32 *) cairo_image_surface_get_data (output);
187
+ rowstride = cairo_image_surface_get_stride (input);
188
+ w = cairo_image_surface_get_width (input);
189
+ h = cairo_image_surface_get_height (input);
190
+
191
+ g_return_if_fail (cairo_image_surface_get_width (output) == w);
192
+ g_return_if_fail (cairo_image_surface_get_height (output) == h);
193
+ g_return_if_fail (cairo_image_surface_get_stride (output) == rowstride);
194
+
195
+ wm = w - 1;
196
+ hm = h - 1;
197
+ wh = w * h;
198
+
199
+ r = g_new (int, wh);
200
+ g = g_new (int, wh);
201
+ b = g_new (int, wh);
202
+ a = g_new (int, wh);
203
+
204
+ div = 2 * rx + 1;
205
+ divsum = (div + 1) >> 1;
206
+ divsum *= divsum;
207
+ stack = g_new (int, div * 4);
208
+ r1 = rx + 1;
209
+
210
+ vmin = g_new (int, w);
211
+ for (y =0; y < h; y++) {
212
+ rinsum=ginsum=binsum=ainsum=routsum=goutsum=boutsum=aoutsum=rsum=gsum=bsum=asum=0;
213
+ yi = y * rowstride / 4;
214
+
215
+ for (i = -rx; i <= rx; i++) {
216
+ p = input_pixels [yi + MIN (wm, MAX (i, 0))];
217
+ sir = &stack [4 * (i + rx)];
218
+ sir[0]=(p & 0x00ff0000)>>16;
219
+ sir[1]=(p & 0x0000ff00)>>8;
220
+ sir[2]=(p & 0x000000ff);
221
+ sir[3]=(p & 0xff0000ff)>>24;
222
+ rbs= r1 - ABS (i);
223
+ rsum+=sir[0]*rbs;
224
+ gsum+=sir[1]*rbs;
225
+ bsum+=sir[2]*rbs;
226
+ asum+=sir[3]*rbs;
227
+ if (i>0){
228
+ rinsum+=sir[0];
229
+ ginsum+=sir[1];
230
+ binsum+=sir[2];
231
+ ainsum+=sir[3];
232
+ } else {
233
+ routsum+=sir[0];
234
+ goutsum+=sir[1];
235
+ boutsum+=sir[2];
236
+ aoutsum+=sir[3];
237
+ }
238
+ }
239
+ stackpointer=rx;
240
+
241
+ for (x=0;x<w;x++){
242
+
243
+ r[yi] = rsum / divsum;
244
+ g[yi] = gsum / divsum;
245
+ b[yi] = bsum / divsum;
246
+ a[yi] = asum / divsum;
247
+ rsum-=routsum;
248
+ gsum-=goutsum;
249
+ bsum-=boutsum;
250
+ asum-=aoutsum;
251
+
252
+ stackstart=stackpointer-rx+div;
253
+ sir = &stack [4 * (stackstart % div)];
254
+
255
+ routsum-=sir[0];
256
+ goutsum-=sir[1];
257
+ boutsum-=sir[2];
258
+ aoutsum-=sir[3];
259
+
260
+ if(y==0){
261
+ vmin[x]=MIN (x + rx + 1, wm);
262
+ }
263
+ p = input_pixels [yw + vmin[x]];
264
+
265
+ sir[0]=(p & 0x00ff0000)>>16;
266
+ sir[1]=(p & 0x0000ff00)>>8;
267
+ sir[2]=(p & 0x000000ff);
268
+ sir[3]=(p & 0xff000000)>>24;
269
+
270
+ rinsum+=sir[0];
271
+ ginsum+=sir[1];
272
+ binsum+=sir[2];
273
+ ainsum+=sir[3];
274
+
275
+ rsum+=rinsum;
276
+ gsum+=ginsum;
277
+ bsum+=binsum;
278
+ asum+=ainsum;
279
+
280
+ stackpointer = (stackpointer + 1) % div;
281
+ sir = &stack [4 * ((stackpointer) % div)];
282
+
283
+ routsum+=sir[0];
284
+ goutsum+=sir[1];
285
+ boutsum+=sir[2];
286
+ aoutsum+=sir[3];
287
+
288
+ rinsum-=sir[0];
289
+ ginsum-=sir[1];
290
+ binsum-=sir[2];
291
+ ainsum-=sir[3];
292
+
293
+ yi++;
294
+ }
295
+ yw+=w;
296
+ }
297
+ g_free (vmin);
298
+ g_free (stack);
299
+
300
+ div = 2 * ry + 1;
301
+ divsum = (div + 1) >> 1;
302
+ divsum *= divsum;
303
+
304
+ stack = g_new0 (int, div * 4);
305
+ r1 = ry + 1;
306
+
307
+ vmin = g_new0 (int, h);
308
+ for (x=0;x<w;x++){
309
+ rinsum=ginsum=binsum=ainsum=routsum=goutsum=boutsum=aoutsum=rsum=gsum=bsum=asum=0;
310
+ yp=-ry*w;
311
+ for(i=-ry;i<=ry;i++){
312
+ yi= MAX(0,yp)+x;
313
+
314
+ sir = &stack [4 * (i + ry)];
315
+
316
+ sir[0]=r[yi];
317
+ sir[1]=g[yi];
318
+ sir[2]=b[yi];
319
+ sir[3]=a[yi];
320
+
321
+ rbs=r1 - ABS(i);
322
+
323
+ rsum+=r[yi]*rbs;
324
+ gsum+=g[yi]*rbs;
325
+ bsum+=b[yi]*rbs;
326
+ asum+=a[yi]*rbs;
327
+
328
+ if (i>0){
329
+ rinsum+=sir[0];
330
+ ginsum+=sir[1];
331
+ binsum+=sir[2];
332
+ ainsum+=sir[3];
333
+ } else {
334
+ routsum+=sir[0];
335
+ goutsum+=sir[1];
336
+ boutsum+=sir[2];
337
+ aoutsum+=sir[3];
338
+ }
339
+
340
+ if(i<hm){
341
+ yp+=w;
342
+ }
343
+ }
344
+ yi=x;
345
+ stackpointer=ry;
346
+ for (y=0;y<h;y++){
347
+ output_pixels [yi] =
348
+ ((asum / divsum) << 24) |
349
+ ((rsum / divsum) << 16) |
350
+ ((gsum / divsum) << 8) |
351
+ (bsum / divsum);
352
+ rsum-=routsum;
353
+ gsum-=goutsum;
354
+ bsum-=boutsum;
355
+ asum-=aoutsum;
356
+
357
+ stackstart=stackpointer-ry+div;
358
+ sir = &stack [4 * (stackstart % div)];
359
+
360
+ routsum-=sir[0];
361
+ goutsum-=sir[1];
362
+ boutsum-=sir[2];
363
+ aoutsum-=sir[3];
364
+
365
+ if(x==0) {
366
+ vmin[y] = MIN(y+r1,hm)*w;
367
+ }
368
+ p=x+vmin[y];
369
+
370
+ sir[0]=r[p];
371
+ sir[1]=g[p];
372
+ sir[2]=b[p];
373
+ sir[3]=a[p];
374
+
375
+ rinsum+=sir[0];
376
+ ginsum+=sir[1];
377
+ binsum+=sir[2];
378
+ ainsum+=sir[3];
379
+
380
+ rsum+=rinsum;
381
+ gsum+=ginsum;
382
+ bsum+=binsum;
383
+ asum+=ainsum;
384
+
385
+ stackpointer=(stackpointer+1)%div;
386
+ sir = &stack[4 * stackpointer];
387
+
388
+ routsum+=sir[0];
389
+ goutsum+=sir[1];
390
+ boutsum+=sir[2];
391
+ aoutsum+=sir[3];
392
+
393
+ rinsum-=sir[0];
394
+ ginsum-=sir[1];
395
+ binsum-=sir[2];
396
+ ainsum-=sir[3];
397
+
398
+ yi+= rowstride / 4;
399
+ }
400
+ }
401
+ g_free (vmin);
402
+ g_free (stack);
403
+
404
+ g_free (r);
405
+ g_free (g);
406
+ g_free (b);
407
+ g_free (a);
225
408
  }
226
409
 
227
410
  void
228
- lsm_svg_filter_surface_fast_blur (LsmSvgFilterSurface *input,
229
- LsmSvgFilterSurface *output,
230
- double sx, double sy)
411
+ lsm_svg_filter_surface_blur (LsmSvgFilterSurface *input,
412
+ LsmSvgFilterSurface *output,
413
+ double sx, double sy)
231
414
  {
232
415
  int kx, ky;
233
416
  int width, height;
@@ -247,6 +430,9 @@ lsm_svg_filter_surface_fast_blur (LsmSvgFilterSurface *input,
247
430
  height != cairo_image_surface_get_height (output->surface))
248
431
  return;
249
432
 
433
+ if (width < 1 || height < 1)
434
+ return;
435
+
250
436
  if (kx > 1 || ky > 1) {
251
437
  int x1, y1, x2, y2;
252
438
  cairo_surface_t *blur_surface;
@@ -271,9 +457,7 @@ lsm_svg_filter_surface_fast_blur (LsmSvgFilterSurface *input,
271
457
  } else
272
458
  blur_surface = output->surface;
273
459
 
274
- box_blur (input->surface, blur_surface, kx, ky, 0, 0, x1, y1, x2, y2);
275
- box_blur (blur_surface, blur_surface, kx, ky, (kx + 1) % 2, (ky + 1) % 2, x1, y1, x2, y2);
276
- box_blur (blur_surface, blur_surface, kx + (kx + 1) % 2, ky + (ky + 1) % 2, 0, 0, x1, y1, x2, y2);
460
+ stack_blur (input->surface, blur_surface, kx, ky);
277
461
 
278
462
  cairo_surface_mark_dirty (blur_surface);
279
463
 
@@ -424,14 +608,14 @@ lsm_svg_filter_surface_tile (LsmSvgFilterSurface *input, LsmSvgFilterSurface *ou
424
608
 
425
609
  surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, input->subregion.width, input->subregion.height);
426
610
  cairo = cairo_create (surface);
427
- cairo_set_source_surface (cairo, input->surface, input->subregion.x, input->subregion.y);
611
+ cairo_set_source_surface (cairo, input->surface, -input->subregion.x, -input->subregion.y);
428
612
  cairo_paint (cairo);
429
613
  cairo_destroy (cairo);
430
614
 
431
615
  cairo = cairo_create (output->surface);
432
616
  cairo_rectangle (cairo, output->subregion.x, output->subregion.y, output->subregion.width, output->subregion.height);
433
617
  cairo_clip (cairo);
434
- cairo_set_source_surface (cairo, surface, 0, 0);
618
+ cairo_set_source_surface (cairo, surface, input->subregion.x, input->subregion.y);
435
619
  pattern = cairo_get_source (cairo);
436
620
  cairo_pattern_set_extend (pattern, CAIRO_EXTEND_REPEAT);
437
621
  cairo_paint (cairo);
@@ -453,3 +637,901 @@ lsm_svg_filter_surface_alpha (LsmSvgFilterSurface *input, LsmSvgFilterSurface *o
453
637
 
454
638
  cairo_destroy (cairo);
455
639
  }
640
+
641
+ void
642
+ lsm_svg_filter_surface_color_matrix (LsmSvgFilterSurface *input, LsmSvgFilterSurface *output,
643
+ LsmSvgColorFilterType type, unsigned n_values, const double *values)
644
+ {
645
+ cairo_t *cairo;
646
+ unsigned i;
647
+ int matrix[20];
648
+ double cosval;
649
+ double sinval;
650
+ int ch;
651
+ gint x, y, x1, x2, y1, y2;
652
+ gint width, height;
653
+ gint rowstride;
654
+ gint sum;
655
+ guchar *in_pixels;
656
+ guchar *output_pixels;
657
+ double setting;
658
+
659
+ g_return_if_fail (input != NULL);
660
+ g_return_if_fail (output != NULL);
661
+ g_return_if_fail (values != NULL || n_values < 1);
662
+
663
+ width = cairo_image_surface_get_width (input->surface);
664
+ height = cairo_image_surface_get_height (input->surface);
665
+
666
+ if (width != cairo_image_surface_get_width (output->surface) ||
667
+ height != cairo_image_surface_get_height (output->surface))
668
+ return;
669
+
670
+ if (height < 1 || width < 1)
671
+ return;
672
+
673
+ memset (matrix, 0, sizeof (*matrix) * G_N_ELEMENTS (matrix));
674
+
675
+ switch (type) {
676
+ case LSM_SVG_COLOR_FILTER_TYPE_MATRIX:
677
+ for (i = 0; i < G_N_ELEMENTS (matrix) && i < n_values; i++)
678
+ matrix[i] = values[i] * 255.0;
679
+ break;
680
+ case LSM_SVG_COLOR_FILTER_TYPE_SATURATE:
681
+ if (n_values > 0)
682
+ setting = values[0];
683
+ else
684
+ setting = 1.0;
685
+
686
+ matrix[0] = 255.0 * (0.213 + 0.787 * setting);
687
+ matrix[1] = 255.0 * (0.715 - 0.715 * setting);
688
+ matrix[2] = 255.0 * (0.072 - 0.072 * setting);
689
+ matrix[5] = 255.0 * (0.213 - 0.213 * setting);
690
+ matrix[6] = 255.0 * (0.715 + 0.285 * setting);
691
+ matrix[7] = 255.0 * (0.072 - 0.072 * setting);
692
+ matrix[10] = 255.0 * (0.213 - 0.213 * setting);
693
+ matrix[11] = 255.0 * (0.715 - 0.715 * setting);
694
+ matrix[12] = 255.0 * (0.072 + 0.928 * setting);
695
+ matrix[18] = 255;
696
+ break;
697
+ case LSM_SVG_COLOR_FILTER_TYPE_HUE_ROTATE:
698
+ if (n_values > 0)
699
+ setting = values[0];
700
+ else
701
+ setting = 0.0;
702
+
703
+ cosval = cos (setting);
704
+ sinval = sin (setting);
705
+
706
+ matrix[0] = (0.213 + cosval * 0.787 + sinval * -0.213) * 255.;
707
+ matrix[1] = (0.715 + cosval * -0.715 + sinval * -0.715) * 255.;
708
+ matrix[2] = (0.072 + cosval * -0.072 + sinval * 0.928) * 255.;
709
+ matrix[5] = (0.213 + cosval * -0.213 + sinval * 0.143) * 255.;
710
+ matrix[6] = (0.715 + cosval * 0.285 + sinval * 0.140) * 255.;
711
+ matrix[7] = (0.072 + cosval * -0.072 + sinval * -0.283) * 255.;
712
+ matrix[10] = (0.213 + cosval * -0.213 + sinval * -0.787) * 255.;
713
+ matrix[11] = (0.715 + cosval * -0.715 + sinval * 0.715) * 255.;
714
+ matrix[12] = (0.072 + cosval * 0.928 + sinval * 0.072) * 255.;
715
+ matrix[18] = 255;
716
+ break;
717
+ case LSM_SVG_COLOR_FILTER_TYPE_LUMINANCE_TO_ALPHA:
718
+ matrix[15] = 0.2125 * 255.;
719
+ matrix[16] = 0.7154 * 255.;
720
+ matrix[17] = 0.0721 * 255.;
721
+ break;
722
+ default:
723
+ return;
724
+ }
725
+
726
+ cairo_surface_flush (input->surface);
727
+ cairo = cairo_create (output->surface);
728
+
729
+ in_pixels = cairo_image_surface_get_data (input->surface);
730
+ output_pixels = cairo_image_surface_get_data (output->surface);
731
+ rowstride = cairo_image_surface_get_stride (input->surface);
732
+
733
+ x1 = CLAMP (input->subregion.x, 0, width);
734
+ x2 = CLAMP (input->subregion.x + input->subregion.width, 0, width);
735
+ y1 = CLAMP (input->subregion.y, 0, height);
736
+ y2 = CLAMP (input->subregion.y + input->subregion.height, 0, height);
737
+
738
+ for (y = y1; y < y2; y++)
739
+ for (x = x1; x < x2; x++) {
740
+ int umch;
741
+ int alpha = in_pixels[4 * x + y * rowstride + channelmap[3]];
742
+ if (!alpha)
743
+ for (umch = 0; umch < 4; umch++) {
744
+ sum = matrix[umch * 5 + 4];
745
+ if (sum > 255)
746
+ sum = 255;
747
+ if (sum < 0)
748
+ sum = 0;
749
+ output_pixels[4 * x + y * rowstride + channelmap[umch]] = sum;
750
+ } else
751
+ for (umch = 0; umch < 4; umch++) {
752
+ int umi;
753
+ ch = channelmap[umch];
754
+ sum = 0;
755
+ for (umi = 0; umi < 4; umi++) {
756
+ i = channelmap[umi];
757
+ if (umi != 3)
758
+ sum += matrix[umch * 5 + umi] *
759
+ in_pixels[4 * x + y * rowstride + i] / alpha;
760
+ else
761
+ sum += matrix[umch * 5 + umi] *
762
+ in_pixels[4 * x + y * rowstride + i] / 255;
763
+ }
764
+ sum += matrix[umch * 5 + 4];
765
+
766
+
767
+
768
+ if (sum > 255)
769
+ sum = 255;
770
+ if (sum < 0)
771
+ sum = 0;
772
+
773
+ output_pixels[4 * x + y * rowstride + ch] = sum;
774
+ }
775
+ for (umch = 0; umch < 3; umch++) {
776
+ ch = channelmap[umch];
777
+ output_pixels[4 * x + y * rowstride + ch] =
778
+ output_pixels[4 * x + y * rowstride + ch] *
779
+ output_pixels[4 * x + y * rowstride + channelmap[3]] / 255;
780
+ }
781
+ }
782
+
783
+ cairo_surface_mark_dirty (output->surface);
784
+
785
+ cairo_destroy (cairo);
786
+ }
787
+
788
+ void
789
+ lsm_svg_filter_surface_convolve_matrix (LsmSvgFilterSurface *input, LsmSvgFilterSurface *output,
790
+ unsigned order_x, unsigned order_y, unsigned n_values, const double *values,
791
+ double divisor, double bias, unsigned target_x, unsigned target_y,
792
+ LsmSvgEdgeMode edge_mode, gboolean preserve_alpha)
793
+ {
794
+ cairo_t *cairo;
795
+ int ch;
796
+ gint x, y, x1, x2, y1, y2;
797
+ gint width, height;
798
+ gint rowstride;
799
+ guchar *in_pixels;
800
+ guchar *output_pixels;
801
+ double kval, sum;
802
+ guchar sval;
803
+ int sx, sy, kx, ky;
804
+ double dx = 1.0, dy = 1.0;
805
+ int umch, i, j;
806
+ gint tempresult;
807
+
808
+ g_return_if_fail (input != NULL);
809
+ g_return_if_fail (output != NULL);
810
+ g_return_if_fail (values != NULL || n_values < 1);
811
+
812
+ if (divisor <= 0.0)
813
+ return;
814
+
815
+ width = cairo_image_surface_get_width (input->surface);
816
+ height = cairo_image_surface_get_height (input->surface);
817
+
818
+ if (width != cairo_image_surface_get_width (output->surface) ||
819
+ height != cairo_image_surface_get_height (output->surface))
820
+ return;
821
+
822
+ if (height < 1 || width < 1)
823
+ return;
824
+
825
+ if (order_y * order_x != n_values)
826
+ return;
827
+
828
+ if (target_x > order_x || target_y > order_y)
829
+ return;
830
+
831
+ x1 = CLAMP (input->subregion.x, 0, width);
832
+ x2 = CLAMP (input->subregion.x + input->subregion.width, 0, width);
833
+ y1 = CLAMP (input->subregion.y, 0, height);
834
+ y2 = CLAMP (input->subregion.y + input->subregion.height, 0, height);
835
+
836
+ cairo_surface_flush (input->surface);
837
+ cairo = cairo_create (output->surface);
838
+
839
+ in_pixels = cairo_image_surface_get_data (input->surface);
840
+ output_pixels = cairo_image_surface_get_data (output->surface);
841
+ rowstride = cairo_image_surface_get_stride (input->surface);
842
+
843
+ for (y = y1; y < y2; y++)
844
+ for (x = x1; x < x2; x++) {
845
+ for (umch = 0; umch < 3 + !preserve_alpha; umch++) {
846
+ ch = channelmap[umch];
847
+ sum = 0;
848
+ for (i = 0; i < order_y; i++)
849
+ for (j = 0; j < order_x; j++) {
850
+ int alpha;
851
+ sx = x - target_x + j * dx;
852
+ sy = y - target_y + i * dy;
853
+ if (edge_mode == LSM_SVG_EDGE_MODE_DUPLICATE) {
854
+ if (sx < x1)
855
+ sx = x1;
856
+ if (sx >= x2)
857
+ sx = x2 - 1;
858
+ if (sy < y1)
859
+ sy = y1;
860
+ if (sy >= y2)
861
+ sy = y2 - 1;
862
+ } else if (edge_mode == LSM_SVG_EDGE_MODE_WRAP) {
863
+ if (sx < x1 || (sx >= x2))
864
+ sx = x1 + (sx - x1) % (x2 - x1);
865
+ if (sy < y1 || (sy >= y2))
866
+ sy = y1 + (sy - y1) % (y2 - y1);
867
+ } else if (edge_mode == LSM_SVG_EDGE_MODE_NONE)
868
+ if (sx < x1 || (sx >= x2) ||
869
+ sy < y1 || (sy >= y2))
870
+ continue;
871
+
872
+ kx = order_x - j - 1;
873
+ ky = order_y - i - 1;
874
+ alpha = in_pixels[4 * sx + sy * rowstride + 3];
875
+ if (ch == 3)
876
+ sval = alpha;
877
+ else if (alpha)
878
+ sval = in_pixels[4 * sx + sy * rowstride + ch] * 255 / alpha;
879
+ else
880
+ sval = 0;
881
+ kval = values[kx + ky * order_x];
882
+ sum += (double) sval *kval;
883
+ }
884
+ tempresult = sum / divisor + bias;
885
+
886
+ if (tempresult > 255)
887
+ tempresult = 255;
888
+ if (tempresult < 0)
889
+ tempresult = 0;
890
+
891
+ output_pixels[4 * x + y * rowstride + ch] = tempresult;
892
+ }
893
+ if (preserve_alpha)
894
+ output_pixels[4 * x + y * rowstride + channelmap[3]] =
895
+ in_pixels[4 * x + y * rowstride + channelmap[3]];
896
+ for (umch = 0; umch < 3; umch++) {
897
+ ch = channelmap[umch];
898
+ output_pixels[4 * x + y * rowstride + ch] =
899
+ output_pixels[4 * x + y * rowstride + ch] *
900
+ output_pixels[4 * x + y * rowstride + channelmap[3]] / 255;
901
+ }
902
+ }
903
+
904
+ cairo_surface_mark_dirty (output->surface);
905
+
906
+ cairo_destroy (cairo);
907
+ }
908
+
909
+ static guchar
910
+ _get_interp_pixel (guchar * src, gdouble ox, gdouble oy, guchar ch,
911
+ gint x1, gint x2, gint y1, gint y2,
912
+ guint rowstride)
913
+ {
914
+ double xmod, ymod;
915
+ double dist1, dist2, dist3, dist4;
916
+ double c, c1, c2, c3, c4;
917
+ double fox, foy, cox, coy;
918
+
919
+ xmod = fmod (ox, 1.0);
920
+ ymod = fmod (oy, 1.0);
921
+
922
+ dist1 = (1 - xmod) * (1 - ymod);
923
+ dist2 = (xmod) * (1 - ymod);
924
+ dist3 = (xmod) * (ymod);
925
+ dist4 = (1 - xmod) * (ymod);
926
+
927
+ fox = floor (ox);
928
+ foy = floor (oy);
929
+ cox = ceil (ox);
930
+ coy = ceil (oy);
931
+
932
+ if (fox <= x1 || fox >= x2 ||
933
+ foy <= y1 || foy >= y2)
934
+ c1 = 0;
935
+ else
936
+ c1 = src[(guint) foy * rowstride + (guint) fox * 4 + ch];
937
+
938
+ if (cox <= x1 || cox >= x2 ||
939
+ foy <= y1 || foy >= y2)
940
+ c2 = 0;
941
+ else
942
+ c2 = src[(guint) foy * rowstride + (guint) cox * 4 + ch];
943
+
944
+ if (cox <= x1 || cox >= x2 ||
945
+ coy <= y1 || coy >= y2)
946
+ c3 = 0;
947
+ else
948
+ c3 = src[(guint) coy * rowstride + (guint) cox * 4 + ch];
949
+
950
+ if (fox <= x1 || fox >= x2 ||
951
+ coy <= y1 || coy >= y2)
952
+ c4 = 0;
953
+ else
954
+ c4 = src[(guint) coy * rowstride + (guint) fox * 4 + ch];
955
+
956
+ c = (c1 * dist1 + c2 * dist2 + c3 * dist3 + c4 * dist4) / (dist1 + dist2 + dist3 + dist4);
957
+
958
+ return (guchar) c;
959
+ }
960
+
961
+ void
962
+ lsm_svg_filter_surface_displacement_map (LsmSvgFilterSurface *input_1,
963
+ LsmSvgFilterSurface *input_2,
964
+ LsmSvgFilterSurface *output,
965
+ double x_scale,
966
+ double y_scale,
967
+ LsmSvgChannelSelector x_channel_selector,
968
+ LsmSvgChannelSelector y_channel_selector)
969
+ {
970
+ guchar ch, xch, ych;
971
+ gint x, y, x1, x2, y1, y2;
972
+ double ox, oy;
973
+ gint rowstride, height, width;
974
+ guchar *in_pixels;
975
+ guchar *in2_pixels;
976
+ guchar *output_pixels;
977
+ cairo_t *cairo;
978
+
979
+ g_return_if_fail (input_1 != NULL);
980
+ g_return_if_fail (input_2 != NULL);
981
+ g_return_if_fail (output != NULL);
982
+
983
+ height = cairo_image_surface_get_height (input_1->surface);
984
+ width = cairo_image_surface_get_width (input_1->surface);
985
+
986
+ if (width != cairo_image_surface_get_width (input_2->surface) ||
987
+ height != cairo_image_surface_get_height (input_2->surface))
988
+ return;
989
+
990
+ if (width != cairo_image_surface_get_width (output->surface) ||
991
+ height != cairo_image_surface_get_height (output->surface))
992
+ return;
993
+
994
+ cairo_surface_flush (input_1->surface);
995
+ cairo_surface_flush (input_2->surface);
996
+
997
+ cairo = cairo_create (output->surface);
998
+
999
+ in_pixels = cairo_image_surface_get_data (input_1->surface);
1000
+ in2_pixels = cairo_image_surface_get_data (input_2->surface);
1001
+
1002
+ rowstride = cairo_image_surface_get_stride (input_1->surface);
1003
+
1004
+ output_pixels = cairo_image_surface_get_data (output->surface);
1005
+
1006
+ switch (x_channel_selector) {
1007
+ case LSM_SVG_CHANNEL_SELECTOR_RED:
1008
+ xch = 0;
1009
+ break;
1010
+ case LSM_SVG_CHANNEL_SELECTOR_GREEN:
1011
+ xch = 1;
1012
+ break;
1013
+ case LSM_SVG_CHANNEL_SELECTOR_BLUE:
1014
+ xch = 2;
1015
+ break;
1016
+ case LSM_SVG_CHANNEL_SELECTOR_ALPHA:
1017
+ xch = 3;
1018
+ break;
1019
+ default:
1020
+ xch = 4;
1021
+ };
1022
+
1023
+ switch (y_channel_selector) {
1024
+ case LSM_SVG_CHANNEL_SELECTOR_RED:
1025
+ ych = 0;
1026
+ break;
1027
+ case LSM_SVG_CHANNEL_SELECTOR_GREEN:
1028
+ ych = 1;
1029
+ break;
1030
+ case LSM_SVG_CHANNEL_SELECTOR_BLUE:
1031
+ ych = 2;
1032
+ break;
1033
+ case LSM_SVG_CHANNEL_SELECTOR_ALPHA:
1034
+ ych = 3;
1035
+ break;
1036
+ default:
1037
+ ych = 4;
1038
+ };
1039
+
1040
+ x1 = CLAMP (input_1->subregion.x, 0, width);
1041
+ x2 = CLAMP (input_1->subregion.x + input_1->subregion.width, 0, width);
1042
+ y1 = CLAMP (input_1->subregion.y, 0, height);
1043
+ y2 = CLAMP (input_1->subregion.y + input_1->subregion.height, 0, height);
1044
+
1045
+ xch = channelmap[xch];
1046
+ ych = channelmap[ych];
1047
+ for (y = y1; y < y2; y++)
1048
+ for (x = x1; x < x2; x++) {
1049
+ if (xch != 4)
1050
+ ox = x + x_scale *
1051
+ ((double) in2_pixels[y * rowstride + x * 4 + xch] / 255.0 - 0.5);
1052
+ else
1053
+ ox = x;
1054
+
1055
+ if (ych != 4)
1056
+ oy = y + y_scale *
1057
+ ((double) in2_pixels[y * rowstride + x * 4 + ych] / 255.0 - 0.5);
1058
+ else
1059
+ oy = y;
1060
+
1061
+ for (ch = 0; ch < 4; ch++) {
1062
+ output_pixels[y * rowstride + x * 4 + ch] =
1063
+ _get_interp_pixel (in_pixels, ox, oy, ch, x1, x2, y1, y2, rowstride);
1064
+ }
1065
+ }
1066
+
1067
+ cairo_surface_mark_dirty (output->surface);
1068
+
1069
+ cairo_destroy (cairo);
1070
+ }
1071
+
1072
+ void
1073
+ lsm_svg_filter_surface_specular_lighting (LsmSvgFilterSurface *output,
1074
+ double surface_scale, double specular_constant, double specular_exponent,
1075
+ double dx, double dy)
1076
+ {
1077
+ cairo_t *cairo;
1078
+ int width, height;
1079
+ #if 0
1080
+ guchar *output_pixels;
1081
+ gint rowstride;
1082
+ gint x1, x2, y1, y2;
1083
+ #endif
1084
+
1085
+ g_return_if_fail (output != NULL);
1086
+
1087
+ width = cairo_image_surface_get_width (output->surface);
1088
+ height = cairo_image_surface_get_height (output->surface);
1089
+
1090
+ if (height < 1 || width < 1)
1091
+ return;
1092
+
1093
+ cairo = cairo_create (output->surface);
1094
+
1095
+ #if 0
1096
+ output_pixels = cairo_image_surface_get_data (output->surface);
1097
+ rowstride = cairo_image_surface_get_stride (output->surface);
1098
+
1099
+ x1 = CLAMP (output->subregion.x, 0, width);
1100
+ x2 = CLAMP (output->subregion.x + output->subregion.width, 0, width);
1101
+ y1 = CLAMP (output->subregion.y, 0, height);
1102
+ y2 = CLAMP (output->subregion.y + output->subregion.height, 0, height);
1103
+ #endif
1104
+
1105
+ cairo_surface_mark_dirty (output->surface);
1106
+
1107
+ cairo_destroy (cairo);
1108
+ }
1109
+
1110
+ void
1111
+ lsm_svg_filter_surface_image (LsmSvgFilterSurface *output, GdkPixbuf *pixbuf,
1112
+ LsmSvgPreserveAspectRatio preserve_aspect_ratio)
1113
+ {
1114
+ cairo_t *cairo;
1115
+ int width, height;
1116
+ double zoom_x, zoom_y;
1117
+
1118
+ g_return_if_fail (output != NULL);
1119
+ g_return_if_fail (GDK_IS_PIXBUF (pixbuf));
1120
+
1121
+ if (output->subregion.width < 1 ||
1122
+ output->subregion.height < 1)
1123
+ return;
1124
+
1125
+ /* TODO Implement preserve_aspect_ratio support */
1126
+
1127
+ width = gdk_pixbuf_get_height (pixbuf);
1128
+ height = gdk_pixbuf_get_width (pixbuf);
1129
+
1130
+ if (height < 1 || width < 1)
1131
+ return;
1132
+
1133
+ zoom_x = (double) output->subregion.width / (double) width;
1134
+ zoom_y = (double) output->subregion.height / (double) height;
1135
+
1136
+ cairo = cairo_create (output->surface);
1137
+
1138
+ cairo_translate (cairo, output->subregion.x, output->subregion.y);
1139
+ cairo_scale (cairo, zoom_x, zoom_y);
1140
+ lsm_cairo_set_source_pixbuf (cairo, pixbuf, 0, 0);
1141
+ cairo_paint (cairo);
1142
+
1143
+ cairo_destroy (cairo);
1144
+ }
1145
+
1146
+ void
1147
+ lsm_svg_filter_surface_morphology (LsmSvgFilterSurface *input, LsmSvgFilterSurface *output,
1148
+ LsmSvgMorphologyOperator op, double rx, double ry)
1149
+ {
1150
+ cairo_t *cairo;
1151
+ int i, j;
1152
+ int ch, extreme;
1153
+ gint x, y, x1, x2, y1, y2;
1154
+ gint width, height;
1155
+ gint rowstride;
1156
+ guchar *in_pixels;
1157
+ guchar *output_pixels;
1158
+ gint kx, ky;
1159
+ guchar val;
1160
+
1161
+ g_return_if_fail (input != NULL);
1162
+ g_return_if_fail (output != NULL);
1163
+
1164
+ width = cairo_image_surface_get_width (input->surface);
1165
+ height = cairo_image_surface_get_height (input->surface);
1166
+
1167
+ if (width != cairo_image_surface_get_width (output->surface) ||
1168
+ height != cairo_image_surface_get_height (output->surface))
1169
+ return;
1170
+
1171
+ if (height < 1 || width < 1)
1172
+ return;
1173
+
1174
+ kx = rx;
1175
+ ky = ry;
1176
+
1177
+ if (kx < 1 && ky < 1)
1178
+ return;
1179
+
1180
+ cairo_surface_flush (input->surface);
1181
+ cairo = cairo_create (output->surface);
1182
+
1183
+ in_pixels = cairo_image_surface_get_data (input->surface);
1184
+ output_pixels = cairo_image_surface_get_data (output->surface);
1185
+ rowstride = cairo_image_surface_get_stride (input->surface);
1186
+
1187
+ x1 = CLAMP (input->subregion.x, 0, width);
1188
+ x2 = CLAMP (input->subregion.x + input->subregion.width, 0, width);
1189
+ y1 = CLAMP (input->subregion.y, 0, height);
1190
+ y2 = CLAMP (input->subregion.y + input->subregion.height, 0, height);
1191
+
1192
+ for (y = y1; y < y2; y++)
1193
+ for (x = x1; x < x2; x++)
1194
+ for (ch = 0; ch < 4; ch++) {
1195
+ if (op == LSM_SVG_MORPHOLOGY_OPERATOR_ERODE)
1196
+ extreme = 255;
1197
+ else
1198
+ extreme = 0;
1199
+ for (i = -ky; i < ky + 1; i++)
1200
+ for (j = -kx; j < kx + 1; j++) {
1201
+ if (y + i >= height || y + i < 0 || x + j >= width || x + j < 0)
1202
+ continue;
1203
+
1204
+ val = in_pixels[(y + i) * rowstride + (x + j) * 4 + ch];
1205
+
1206
+
1207
+ if (op == LSM_SVG_MORPHOLOGY_OPERATOR_ERODE) {
1208
+ if (extreme > val)
1209
+ extreme = val;
1210
+ } else {
1211
+ if (extreme < val)
1212
+ extreme = val;
1213
+ }
1214
+
1215
+ }
1216
+ output_pixels[y * rowstride + x * 4 + ch] = extreme;
1217
+ }
1218
+
1219
+ cairo_surface_mark_dirty (output->surface);
1220
+
1221
+ cairo_destroy (cairo);
1222
+ }
1223
+
1224
+ /* Produces results in the range [1, 2**31 - 2].
1225
+ Algorithm is: r = (a * r) mod m
1226
+ where a = 16807 and m = 2**31 - 1 = 2147483647
1227
+ See [Park & Miller], CACM vol. 31 no. 10 p. 1195, Oct. 1988
1228
+ To test: the algorithm should produce the result 1043618065
1229
+ as the 10,000th generated number if the original seed is 1.
1230
+ */
1231
+
1232
+ #define LSM_SVG_TURBULENCE_RAND_m 2147483647 /* 2**31 - 1 */
1233
+ #define LSM_SVG_TURBULENCE_RAND_a 16807 /* 7**5; primitive root of m */
1234
+ #define LSM_SVG_TURBULENCE_RAND_q 127773 /* m / a */
1235
+ #define LSM_SVG_TURBULENCE_RAND_r 2836 /* m % a */
1236
+ #define LSM_SVG_TURBULENCE_BSize 0x100
1237
+ #define LSM_SVG_TURBULENCE_BM 0xff
1238
+ #define LSM_SVG_TURBULENCE_PerlinN 0x1000
1239
+ #define LSM_SVG_TURBULENCE_NP 12 /* 2^PerlinN */
1240
+ #define LSM_SVG_TURBULENCE_NM 0xfff
1241
+
1242
+ typedef struct {
1243
+ double base_frequency_x;
1244
+ double base_frequency_y;
1245
+ int n_octaves;
1246
+ double seed;
1247
+ LsmSvgStitchTiles stitch_tiles;
1248
+ LsmSvgTurbulenceType type;
1249
+
1250
+ int uLatticeSelector[LSM_SVG_TURBULENCE_BSize + LSM_SVG_TURBULENCE_BSize + 2];
1251
+ double fGradient[4][LSM_SVG_TURBULENCE_BSize + LSM_SVG_TURBULENCE_BSize + 2][2];
1252
+ } LsmSvgTurbulence;
1253
+
1254
+ typedef struct {
1255
+ int nWidth; /* How much to subtract to wrap for stitching. */
1256
+ int nHeight;
1257
+ int nWrapX; /* Minimum value to wrap. */
1258
+ int nWrapY;
1259
+ } LsmSvgTurbulenceStitchInfo;
1260
+
1261
+ static long
1262
+ _turbulence_setup_seed (int lSeed)
1263
+ {
1264
+ if (lSeed <= 0)
1265
+ lSeed = -(lSeed % (LSM_SVG_TURBULENCE_RAND_m - 1)) + 1;
1266
+ if (lSeed > LSM_SVG_TURBULENCE_RAND_m - 1)
1267
+ lSeed = LSM_SVG_TURBULENCE_RAND_m - 1;
1268
+ return lSeed;
1269
+ }
1270
+
1271
+ static long
1272
+ _turbulence_random (int lSeed)
1273
+ {
1274
+ long result;
1275
+
1276
+ result =
1277
+ LSM_SVG_TURBULENCE_RAND_a * (lSeed % LSM_SVG_TURBULENCE_RAND_q) -
1278
+ LSM_SVG_TURBULENCE_RAND_r * (lSeed / LSM_SVG_TURBULENCE_RAND_q);
1279
+ if (result <= 0)
1280
+ result += LSM_SVG_TURBULENCE_RAND_m;
1281
+ return result;
1282
+ }
1283
+
1284
+ static void
1285
+ _turbulence_init (LsmSvgTurbulence *turbulence)
1286
+ {
1287
+ double s;
1288
+ int i, j, k, lSeed;
1289
+
1290
+ lSeed = _turbulence_setup_seed (turbulence->seed);
1291
+ for (k = 0; k < 4; k++) {
1292
+ for (i = 0; i < LSM_SVG_TURBULENCE_BSize; i++) {
1293
+ turbulence->uLatticeSelector[i] = i;
1294
+ for (j = 0; j < 2; j++)
1295
+ turbulence->fGradient[k][i][j] =
1296
+ (double) (((lSeed =
1297
+ _turbulence_random (lSeed)) % (LSM_SVG_TURBULENCE_BSize +
1298
+ LSM_SVG_TURBULENCE_BSize)) -
1299
+ LSM_SVG_TURBULENCE_BSize) / LSM_SVG_TURBULENCE_BSize;
1300
+ s = (double) (sqrt (turbulence->fGradient[k][i][0] * turbulence->fGradient[k][i][0] +
1301
+ turbulence->fGradient[k][i][1] * turbulence->fGradient[k][i][1]));
1302
+ turbulence->fGradient[k][i][0] /= s;
1303
+ turbulence->fGradient[k][i][1] /= s;
1304
+ }
1305
+ }
1306
+
1307
+ while (--i) {
1308
+ k = turbulence->uLatticeSelector[i];
1309
+ turbulence->uLatticeSelector[i] = turbulence->uLatticeSelector[j =
1310
+ (lSeed = _turbulence_random (lSeed)) % LSM_SVG_TURBULENCE_BSize];
1311
+ turbulence->uLatticeSelector[j] = k;
1312
+ }
1313
+
1314
+ for (i = 0; i < LSM_SVG_TURBULENCE_BSize + 2; i++) {
1315
+ turbulence->uLatticeSelector[LSM_SVG_TURBULENCE_BSize + i] = turbulence->uLatticeSelector[i];
1316
+ for (k = 0; k < 4; k++)
1317
+ for (j = 0; j < 2; j++)
1318
+ turbulence->fGradient[k][LSM_SVG_TURBULENCE_BSize + i][j] = turbulence->fGradient[k][i][j];
1319
+ }
1320
+ }
1321
+
1322
+ #define _turbulence_s_curve(t) ( t * t * (3. - 2. * t) )
1323
+ #define _turbulence_lerp(t, a, b) ( a + t * (b - a) )
1324
+
1325
+ static double
1326
+ _turbulence_noise2 (LsmSvgTurbulence * turbulence,
1327
+ int nColorChannel, double vec[2], LsmSvgTurbulenceStitchInfo *pStitchInfo)
1328
+ {
1329
+ int bx0, bx1, by0, by1, b00, b10, b01, b11;
1330
+ double rx0, rx1, ry0, ry1, *q, sx, sy, a, b, t, u, v;
1331
+ register int i, j;
1332
+
1333
+ t = vec[0] + LSM_SVG_TURBULENCE_PerlinN;
1334
+ bx0 = (int) t;
1335
+ bx1 = bx0 + 1;
1336
+ rx0 = t - (int) t;
1337
+ rx1 = rx0 - 1.0f;
1338
+ t = vec[1] + LSM_SVG_TURBULENCE_PerlinN;
1339
+ by0 = (int) t;
1340
+ by1 = by0 + 1;
1341
+ ry0 = t - (int) t;
1342
+ ry1 = ry0 - 1.0f;
1343
+
1344
+ /* If stitching, adjust lattice points accordingly. */
1345
+ if (pStitchInfo != NULL) {
1346
+ if (bx0 >= pStitchInfo->nWrapX)
1347
+ bx0 -= pStitchInfo->nWidth;
1348
+ if (bx1 >= pStitchInfo->nWrapX)
1349
+ bx1 -= pStitchInfo->nWidth;
1350
+ if (by0 >= pStitchInfo->nWrapY)
1351
+ by0 -= pStitchInfo->nHeight;
1352
+ if (by1 >= pStitchInfo->nWrapY)
1353
+ by1 -= pStitchInfo->nHeight;
1354
+ }
1355
+
1356
+ bx0 &= LSM_SVG_TURBULENCE_BM;
1357
+ bx1 &= LSM_SVG_TURBULENCE_BM;
1358
+ by0 &= LSM_SVG_TURBULENCE_BM;
1359
+ by1 &= LSM_SVG_TURBULENCE_BM;
1360
+ i = turbulence->uLatticeSelector[bx0];
1361
+ j = turbulence->uLatticeSelector[bx1];
1362
+ b00 = turbulence->uLatticeSelector[i + by0];
1363
+ b10 = turbulence->uLatticeSelector[j + by0];
1364
+ b01 = turbulence->uLatticeSelector[i + by1];
1365
+ b11 = turbulence->uLatticeSelector[j + by1];
1366
+ sx = (double) (_turbulence_s_curve (rx0));
1367
+ sy = (double) (_turbulence_s_curve (ry0));
1368
+ q = turbulence->fGradient[nColorChannel][b00];
1369
+ u = rx0 * q[0] + ry0 * q[1];
1370
+ q = turbulence->fGradient[nColorChannel][b10];
1371
+ v = rx1 * q[0] + ry0 * q[1];
1372
+ a = _turbulence_lerp (sx, u, v);
1373
+ q = turbulence->fGradient[nColorChannel][b01];
1374
+ u = rx0 * q[0] + ry1 * q[1];
1375
+ q = turbulence->fGradient[nColorChannel][b11];
1376
+ v = rx1 * q[0] + ry1 * q[1];
1377
+ b = _turbulence_lerp (sx, u, v);
1378
+
1379
+ return _turbulence_lerp (sy, a, b);
1380
+ }
1381
+
1382
+ static double
1383
+ _turbulence (LsmSvgTurbulence * turbulence,
1384
+ int nColorChannel, double *point,
1385
+ double fTileX, double fTileY, double fTileWidth, double fTileHeight)
1386
+ {
1387
+ LsmSvgTurbulenceStitchInfo stitch;
1388
+ LsmSvgTurbulenceStitchInfo *pStitchInfo = NULL; /* Not stitching when NULL. */
1389
+
1390
+ double fSum = 0.0f, vec[2], ratio = 1.;
1391
+ int nOctave;
1392
+
1393
+ /* Adjust the base frequencies if necessary for stitching. */
1394
+ if (turbulence->stitch_tiles == LSM_SVG_STITCH_TILES_STITCH) {
1395
+ /* When stitching tiled turbulence, the frequencies must be adjusted
1396
+ so that the tile borders will be continuous. */
1397
+ if (turbulence->base_frequency_x != 0.0) {
1398
+ double fLoFreq = (double) (floor (fTileWidth * turbulence->base_frequency_x)) / fTileWidth;
1399
+ double fHiFreq = (double) (ceil (fTileWidth * turbulence->base_frequency_x)) / fTileWidth;
1400
+ if (turbulence->base_frequency_x / fLoFreq < fHiFreq / turbulence->base_frequency_x)
1401
+ turbulence->base_frequency_x = fLoFreq;
1402
+ else
1403
+ turbulence->base_frequency_x = fHiFreq;
1404
+ }
1405
+
1406
+ if (turbulence->base_frequency_y != 0.0) {
1407
+ double fLoFreq = (double) (floor (fTileHeight * turbulence->base_frequency_y)) / fTileHeight;
1408
+ double fHiFreq = (double) (ceil (fTileHeight * turbulence->base_frequency_y)) / fTileHeight;
1409
+ if (turbulence->base_frequency_y / fLoFreq < fHiFreq / turbulence->base_frequency_y)
1410
+ turbulence->base_frequency_y = fLoFreq;
1411
+ else
1412
+ turbulence->base_frequency_y = fHiFreq;
1413
+ }
1414
+
1415
+ /* Set up initial stitch values. */
1416
+ pStitchInfo = &stitch;
1417
+ stitch.nWidth = (int) (fTileWidth * turbulence->base_frequency_x + 0.5f);
1418
+ stitch.nWrapX = fTileX * turbulence->base_frequency_x + LSM_SVG_TURBULENCE_PerlinN + stitch.nWidth;
1419
+ stitch.nHeight = (int) (fTileHeight * turbulence->base_frequency_y + 0.5f);
1420
+ stitch.nWrapY = fTileY * turbulence->base_frequency_y + LSM_SVG_TURBULENCE_PerlinN + stitch.nHeight;
1421
+ }
1422
+
1423
+ vec[0] = point[0] * turbulence->base_frequency_x;
1424
+ vec[1] = point[1] * turbulence->base_frequency_y;
1425
+
1426
+ for (nOctave = 0; nOctave < turbulence->n_octaves; nOctave++) {
1427
+ if (turbulence->type == LSM_SVG_TURBULENCE_TYPE_FRACTAL_NOISE)
1428
+ fSum +=
1429
+ (double) (_turbulence_noise2 (turbulence, nColorChannel, vec, pStitchInfo) / ratio);
1430
+ else
1431
+ fSum +=
1432
+ (double) (fabs (_turbulence_noise2 (turbulence, nColorChannel, vec, pStitchInfo)) /
1433
+ ratio);
1434
+
1435
+ vec[0] *= 2;
1436
+ vec[1] *= 2;
1437
+ ratio *= 2;
1438
+
1439
+ if (pStitchInfo != NULL) {
1440
+ /* Update stitch values. Subtracting PerlinN before the multiplication and
1441
+ adding it afterward simplifies to subtracting it once. */
1442
+ stitch.nWidth *= 2;
1443
+ stitch.nWrapX = 2 * stitch.nWrapX - LSM_SVG_TURBULENCE_PerlinN;
1444
+ stitch.nHeight *= 2;
1445
+ stitch.nWrapY = 2 * stitch.nWrapY - LSM_SVG_TURBULENCE_PerlinN;
1446
+ }
1447
+ }
1448
+
1449
+ return fSum;
1450
+ }
1451
+
1452
+ void
1453
+ lsm_svg_filter_surface_turbulence (LsmSvgFilterSurface *output,
1454
+ double base_frequency_x, double base_frequency_y,
1455
+ int n_octaves, double seed,
1456
+ LsmSvgStitchTiles stitch_tiles, LsmSvgTurbulenceType type,
1457
+ const cairo_matrix_t *transform)
1458
+ {
1459
+ LsmSvgTurbulence turbulence;
1460
+ cairo_t *cairo;
1461
+ gint x, y, x1, x2, y1, y2;
1462
+ gint width, height, tileWidth, tileHeight;
1463
+ gint rowstride;
1464
+ guchar *output_pixels;
1465
+ cairo_matrix_t affine;
1466
+
1467
+ g_return_if_fail (output != NULL);
1468
+ g_return_if_fail (transform != NULL);
1469
+
1470
+ affine = *transform;
1471
+ if (cairo_matrix_invert (&affine) != CAIRO_STATUS_SUCCESS)
1472
+ return;
1473
+
1474
+ width = cairo_image_surface_get_width (output->surface);
1475
+ height = cairo_image_surface_get_height (output->surface);
1476
+
1477
+ if (height < 1 || width < 1)
1478
+ return;
1479
+
1480
+ cairo = cairo_create (output->surface);
1481
+
1482
+ output_pixels = cairo_image_surface_get_data (output->surface);
1483
+ rowstride = cairo_image_surface_get_stride (output->surface);
1484
+
1485
+ x1 = CLAMP (output->subregion.x, 0, width);
1486
+ x2 = CLAMP (output->subregion.x + output->subregion.width, 0, width);
1487
+ y1 = CLAMP (output->subregion.y, 0, height);
1488
+ y2 = CLAMP (output->subregion.y + output->subregion.height, 0, height);
1489
+
1490
+ turbulence.base_frequency_x = base_frequency_x;
1491
+ turbulence.base_frequency_y = base_frequency_y;
1492
+ turbulence.n_octaves = n_octaves;
1493
+ turbulence.seed = seed;
1494
+ turbulence.stitch_tiles = stitch_tiles;
1495
+ turbulence.type = type;
1496
+
1497
+ _turbulence_init (&turbulence);
1498
+
1499
+ tileWidth = x2 - x1;
1500
+ tileHeight = y2 - y1;
1501
+
1502
+ for (y = 0; y < tileHeight; y++) {
1503
+ for (x = 0; x < tileWidth; x++) {
1504
+ gint i;
1505
+ double point[2];
1506
+ guchar *pixel;
1507
+ point[0] = affine.xx * (x + x1) + affine.xy * (y + y1) + affine.x0;
1508
+ point[1] = affine.yx * (x + x1) + affine.yy * (y + y1) + affine.y0;
1509
+
1510
+ pixel = output_pixels + 4 * (x + x1) + (y + y1) * rowstride;
1511
+
1512
+ for (i = 0; i < 4; i++) {
1513
+ double cr;
1514
+
1515
+ cr = _turbulence (&turbulence, i, point, (double) x, (double) y,
1516
+ (double) tileWidth, (double) tileHeight);
1517
+
1518
+ if (type == LSM_SVG_TURBULENCE_TYPE_FRACTAL_NOISE)
1519
+ cr = ((cr * 255.) + 255.) / 2.;
1520
+ else
1521
+ cr = (cr * 255.);
1522
+
1523
+ cr = CLAMP (cr, 0., 255.);
1524
+
1525
+ pixel[channelmap[i]] = (guchar) cr;
1526
+ }
1527
+ for (i = 0; i < 3; i++)
1528
+ pixel[channelmap[i]] =
1529
+ pixel[channelmap[i]] * pixel[channelmap[3]] / 255;
1530
+
1531
+ }
1532
+ }
1533
+
1534
+ cairo_surface_mark_dirty (output->surface);
1535
+
1536
+ cairo_destroy (cairo);
1537
+ }