1 #define __NR_COMPOSE_TRANSFORM_C__
3 /*
4 * Pixel buffer rendering library
5 *
6 * Authors:
7 * Lauris Kaplinski <lauris@kaplinski.com>
8 *
9 * This code is in public domain
10 */
12 #ifdef HAVE_CONFIG_H
13 # include "config.h"
14 #endif
16 #include "nr-pixops.h"
17 #include "nr-matrix.h"
19 /*#ifdef WITH_MMX
20 #ifdef __cplusplus
21 extern "C" {
22 #endif // __cplusplus
23 / * fixme: * /
24 / *int nr_have_mmx (void);
25 #define NR_PIXOPS_MMX (1 && nr_have_mmx ())
26 #ifdef __cplusplus
27 }
28 #endif //__cplusplus
29 #endif
30 */
32 /* fixme: Implement missing (Lauris) */
33 /* fixme: PREMUL colors before calculating average (Lauris) */
35 /* Fixed point precision */
36 #define FBITS 12
37 #define FBITS_HP 18 // In some places we need a higher precision
39 void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
40 const unsigned char *spx, int sw, int sh, int srs,
41 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
42 void nr_R8G8B8A8_N_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
43 const unsigned char *spx, int sw, int sh, int srs,
44 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
45 void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
46 const unsigned char *spx, int sw, int sh, int srs,
47 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
48 void nr_R8G8B8A8_P_EMPTY_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
49 const unsigned char *spx, int sw, int sh, int srs,
50 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
52 void
53 nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
54 const unsigned char *spx, int sw, int sh, int srs,
55 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd)
56 {
57 int xsize, ysize, size, dbits;
58 long FFs_x_x, FFs_x_y, FFs_y_x, FFs_y_y, FFs__x, FFs__y;
59 long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S;
60 /* Subpixel positions */
61 int FF_sx_S[256];
62 int FF_sy_S[256];
63 unsigned char *d0;
64 int FFsx0, FFsy0;
65 int x, y;
67 if (alpha == 0) return;
68 if (alpha>255) {
69 g_warning("In transform PPN alpha=%u>255",alpha);
70 }
72 // The color component is stored temporarily with a range of [0,255^3], so more supersampling and we get an overflow (fortunately Inkscape's preferences also doesn't allow a higher setting)
73 if (xd+yd>8) {
74 xd = 4;
75 yd = 4;
76 }
78 xsize = (1 << xd);
79 ysize = (1 << yd);
80 size = xsize * ysize;
81 dbits = xd + yd;
82 unsigned int rounding_fix = size/2;
84 /* Set up fixed point matrix */
85 FFs_x_x = (long) floor(d2s[0] * (1 << FBITS) + 0.5);
86 FFs_x_y = (long) floor(d2s[1] * (1 << FBITS) + 0.5);
87 FFs_y_x = (long) floor(d2s[2] * (1 << FBITS) + 0.5);
88 FFs_y_y = (long) floor(d2s[3] * (1 << FBITS) + 0.5);
89 FFs__x = (long) floor(d2s[4] * (1 << FBITS) + 0.5);
90 FFs__y = (long) floor(d2s[5] * (1 << FBITS) + 0.5);
92 FFs_x_x_S = FFs_x_x >> xd;
93 FFs_x_y_S = FFs_x_y >> xd;
94 FFs_y_x_S = FFs_y_x >> yd;
95 FFs_y_y_S = FFs_y_y >> yd;
97 /* Set up subpixel matrix */
98 /* fixme: We can calculate that in floating point (Lauris) */
99 for (y = 0; y < ysize; y++) {
100 for (x = 0; x < xsize; x++) {
101 FF_sx_S[y * xsize + x] = FFs_x_x_S * x + FFs_y_x_S * y;
102 FF_sy_S[y * xsize + x] = FFs_x_y_S * x + FFs_y_y_S * y;
103 }
104 }
106 d0 = px;
107 FFsx0 = FFs__x;
108 FFsy0 = FFs__y;
110 for (y = 0; y < h; y++) {
111 unsigned char *d;
112 long FFsx, FFsy;
113 d = d0;
114 FFsx = FFsx0;
115 FFsy = FFsy0;
116 for (x = 0; x < w; x++) {
117 unsigned int r, g, b, a;
118 long sx, sy;
119 int i;
120 r = g = b = a = 0;
121 for (i = 0; i < size; i++) {
122 sx = (FFsx + FF_sx_S[i]) >> FBITS;
123 if ((sx >= 0) && (sx < sw)) {
124 sy = (FFsy + FF_sy_S[i]) >> FBITS;
125 if ((sy >= 0) && (sy < sh)) {
126 const unsigned char *s;
127 s = spx + sy * srs + sx * 4;
128 r += NR_PREMUL_112 (s[0], s[3]); // s in [0,255]
129 g += NR_PREMUL_112 (s[1], s[3]);
130 b += NR_PREMUL_112 (s[2], s[3]);
131 a += s[3];
132 // a=sum(s3)
133 // r,g,b in [0,sum(s3)*255]
134 }
135 }
136 }
137 a = (a*alpha + rounding_fix) >> dbits;
138 // a=sum(s3)*alpha/size=avg(s3)*alpha
139 // Compare to nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P
140 if (a != 0) {
141 r = (r*alpha + rounding_fix) >> dbits;
142 g = (g*alpha + rounding_fix) >> dbits;
143 b = (b*alpha + rounding_fix) >> dbits;
144 // r,g,b in [0,avg(s3)*alpha*255]=[0,a*255]
145 if (a == 255*255) {
146 /* Full coverage, demul src */
147 d[0] = NR_NORMALIZE_31(r);
148 d[1] = NR_NORMALIZE_31(g);
149 d[2] = NR_NORMALIZE_31(b);
150 d[3] = NR_NORMALIZE_21(a);
151 } else if (d[3] == 0) {
152 /* Only foreground, demul src */
153 d[0] = NR_DEMUL_321(r,a);
154 d[1] = NR_DEMUL_321(g,a);
155 d[2] = NR_DEMUL_321(b,a);
156 d[3] = NR_NORMALIZE_21(a);
157 } else {
158 unsigned int ca;
159 /* Full composition */
160 ca = NR_COMPOSEA_213(a, d[3]);
161 d[0] = NR_COMPOSEPNN_321131 (r, a, d[0], d[3], ca);
162 d[1] = NR_COMPOSEPNN_321131 (g, a, d[1], d[3], ca);
163 d[2] = NR_COMPOSEPNN_321131 (b, a, d[2], d[3], ca);
164 d[3] = NR_NORMALIZE_31(ca);
165 }
166 }
167 /* Advance pointers */
168 FFsx += FFs_x_x;
169 FFsy += FFs_x_y;
170 d += 4;
171 }
172 FFsx0 += FFs_y_x;
173 FFsy0 += FFs_y_y;
174 d0 += rs;
175 }
176 }
178 void nr_R8G8B8A8_N_R8G8B8A8_N_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
179 const unsigned char *spx, int sw, int sh, int srs,
180 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);
182 static void
183 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (unsigned char *px, int w, int h, int rs,
184 const unsigned char *spx, int sw, int sh, int srs,
185 const long long *FFd2s, unsigned int alpha)
186 {
187 unsigned char *d0;
188 long long FFsx0, FFsy0;
189 int x, y;
191 d0 = px;
192 FFsx0 = FFd2s[4];
193 FFsy0 = FFd2s[5];
195 for (y = 0; y < h; y++) {
196 unsigned char *d;
197 long long FFsx, FFsy;
198 d = d0;
199 FFsx = FFsx0;
200 FFsy = FFsy0;
201 for (x = 0; x < w; x++) {
202 long sx, sy;
203 sx = long(FFsx >> FBITS_HP);
204 if ((sx >= 0) && (sx < sw)) {
205 sy = long(FFsy >> FBITS_HP);
206 if ((sy >= 0) && (sy < sh)) {
207 const unsigned char *s;
208 unsigned int a;
209 s = spx + sy * srs + sx * 4;
210 a = NR_PREMUL_112 (s[3], alpha);
211 if (a != 0) {
212 if ((a == 255*255) || (d[3] == 0)) {
213 /* Transparent BG, premul src */
214 d[0] = NR_PREMUL_121 (s[0], a);
215 d[1] = NR_PREMUL_121 (s[1], a);
216 d[2] = NR_PREMUL_121 (s[2], a);
217 d[3] = NR_NORMALIZE_21(a);
218 } else {
219 d[0] = NR_COMPOSENPP_1211 (s[0], a, d[0]);
220 d[1] = NR_COMPOSENPP_1211 (s[1], a, d[1]);
221 d[2] = NR_COMPOSENPP_1211 (s[2], a, d[2]);
222 d[3] = NR_COMPOSEA_211(a, d[3]);
223 }
224 }
225 }
226 }
227 /* Advance pointers */
228 FFsx += FFd2s[0];
229 FFsy += FFd2s[1];
230 d += 4;
231 }
232 FFsx0 += FFd2s[2];
233 FFsy0 += FFd2s[3];
234 d0 += rs;
235 }
236 }
238 static void
239 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (unsigned char *px, int w, int h, int rs,
240 const unsigned char *spx, int sw, int sh, int srs,
241 const long long *FFd2s, const long *FF_S, unsigned int alpha, int dbits)
242 {
243 int size;
244 unsigned char *d0;
245 long long FFsx0, FFsy0;
246 int x, y;
248 size = (1 << dbits);
249 unsigned int rounding_fix = size/2;
251 d0 = px;
252 FFsx0 = FFd2s[4];
253 FFsy0 = FFd2s[5];
255 for (y = 0; y < h; y++) {
256 unsigned char *d;
257 long long FFsx, FFsy;
258 d = d0;
259 FFsx = FFsx0;
260 FFsy = FFsy0;
261 for (x = 0; x < w; x++) {
262 unsigned int r, g, b, a;
263 int i;
264 r = g = b = a = 0;
265 for (i = 0; i < size; i++) {
266 long sx, sy;
267 sx = (long (FFsx >> (FBITS_HP - FBITS)) + FF_S[2 * i]) >> FBITS;
268 if ((sx >= 0) && (sx < sw)) {
269 sy = (long (FFsy >> (FBITS_HP - FBITS)) + FF_S[2 * i + 1]) >> FBITS;
270 if ((sy >= 0) && (sy < sh)) {
271 const unsigned char *s;
272 s = spx + sy * srs + sx * 4;
273 r += NR_PREMUL_112(s[0], s[3]);
274 g += NR_PREMUL_112(s[1], s[3]);
275 b += NR_PREMUL_112(s[2], s[3]);
276 a += s[3];
277 }
278 }
279 }
280 a = (a*alpha + rounding_fix) >> dbits;
281 if (a != 0) {
282 r = (r*alpha + rounding_fix) >> dbits;
283 g = (g*alpha + rounding_fix) >> dbits;
284 b = (b*alpha + rounding_fix) >> dbits;
285 if ((a == 255*255) || (d[3] == 0)) {
286 /* Transparent BG, premul src */
287 d[0] = NR_NORMALIZE_31(r);
288 d[1] = NR_NORMALIZE_31(g);
289 d[2] = NR_NORMALIZE_31(b);
290 d[3] = NR_NORMALIZE_21(a);
291 } else {
292 d[0] = NR_COMPOSEPPP_3211 (r, a, d[0]);
293 d[1] = NR_COMPOSEPPP_3211 (g, a, d[1]);
294 d[2] = NR_COMPOSEPPP_3211 (b, a, d[2]);
295 d[3] = NR_COMPOSEA_211(a, d[3]);
296 }
297 }
298 /* Advance pointers */
299 FFsx += FFd2s[0];
300 FFsy += FFd2s[1];
301 d += 4;
302 }
303 FFsx0 += FFd2s[2];
304 FFsy0 += FFd2s[3];
305 d0 += rs;
306 }
307 }
309 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM (unsigned char *px, int w, int h, int rs,
310 const unsigned char *spx, int sw, int sh, int srs,
311 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd)
312 {
313 int dbits;
314 long FFd2s[6];
315 long long FFd2s_HP[6]; // with higher precision
316 int i;
318 if (alpha == 0) return;
319 if (alpha>255) {
320 g_warning("In transform PPN alpha=%u>255",alpha);
321 }
323 // The color component is stored temporarily with a range of [0,255^3], so more supersampling and we get an overflow (fortunately Inkscape's preferences also doesn't allow a higher setting)
324 if (xd+yd>8) {
325 xd = 4;
326 yd = 4;
327 }
329 dbits = xd + yd;
331 for (i = 0; i < 6; i++) {
332 FFd2s[i] = (long) floor(d2s[i] * (1 << FBITS) + 0.5);
333 FFd2s_HP[i] = (long long) floor(d2s[i] * (1 << FBITS_HP) + 0.5);;
334 }
336 if (dbits == 0) {
337 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_0 (px, w, h, rs, spx, sw, sh, srs, FFd2s_HP, alpha);
338 } else {
339 int xsize, ysize;
340 long FFs_x_x_S, FFs_x_y_S, FFs_y_x_S, FFs_y_y_S;
341 long FF_S[2 * 256];
342 int x, y;
344 xsize = (1 << xd);
345 ysize = (1 << yd);
347 FFs_x_x_S = FFd2s[0] >> xd;
348 FFs_x_y_S = FFd2s[1] >> xd;
349 FFs_y_x_S = FFd2s[2] >> yd;
350 FFs_y_y_S = FFd2s[3] >> yd;
352 /* Set up subpixel matrix */
353 /* fixme: We can calculate that in floating point (Lauris) */
354 for (y = 0; y < ysize; y++) {
355 for (x = 0; x < xsize; x++) {
356 FF_S[2 * (y * xsize + x)] = FFs_x_x_S * x + FFs_y_x_S * y;
357 FF_S[2 * (y * xsize + x) + 1] = FFs_x_y_S * x + FFs_y_y_S * y;
358 }
359 }
361 nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_N_TRANSFORM_n (px, w, h, rs, spx, sw, sh, srs, FFd2s_HP, FF_S, alpha, dbits);
362 }
363 }
365 void nr_R8G8B8A8_P_R8G8B8A8_P_R8G8B8A8_P_TRANSFORM (unsigned char *px, int w, int h, int rs,
366 const unsigned char *spx, int sw, int sh, int srs,
367 const NR::Matrix &d2s, unsigned int alpha, int xd, int yd);