1 #ifndef __NR_FILTER_PIXOPS_H__
2 #define __NR_FILTER_PIXOPS_H__
4 /*
5 * Per-pixel image manipulation functions.
6 * These can be used by all filter primitives, which combine two images on
7 * per-pixel basis. These are at least feBlend, feComposite and feMerge.
8 *
9 * Authors:
10 * Niko Kiirala <niko@kiirala.com>
11 *
12 * Copyright (C) 2007 authors
13 *
14 * Released under GNU GPL, read the file 'COPYING' for more information
15 */
17 namespace NR {
19 /**
20 * Mixes the two input images using the function given as template.
21 * The result is placed in out.
22 * The mixing function should have the following type:
23 * void mix(unsigned char *result, unsigned char const *in1,
24 * unsigned char const *in2);
25 * Each of the parameters for mix-function is a pointer to four bytes of data,
26 * giving the RGBA values for that pixel. The mix function must only access
27 * the four bytes beginning at a pointer given as parameter.
28 */
29 /*
30 * The implementation is in a header file because of the template. It has to
31 * be in the same compilation unit as the code using it. Otherwise, linking
32 * the program will not succeed.
33 */
34 template <void(*blend)(unsigned char *cr, unsigned char const *ca, unsigned char const *cb)>
35 void pixops_mix(NRPixBlock &out, NRPixBlock &in1, NRPixBlock &in2) {
36 unsigned char *in1_data = NR_PIXBLOCK_PX(&in1);
37 unsigned char *in2_data = NR_PIXBLOCK_PX(&in2);
38 unsigned char *out_data = NR_PIXBLOCK_PX(&out);
39 unsigned char zero_rgba[4] = {0, 0, 0, 0};
41 if (in1.area.y0 < in2.area.y0) {
42 // in1 begins before in2 on y-axis
43 for (int y = in1.area.y0 ; y < in2.area.y0 ; y++) {
44 int out_line = (y - out.area.y0) * out.rs;
45 int in_line = (y - in1.area.y0) * in1.rs;
46 for (int x = in1.area.x0 ; x < in1.area.x1 ; x++) {
47 blend(out_data + out_line + 4 * (x - out.area.x0),
48 in1_data + in_line + 4 * (x - in1.area.x0),
49 zero_rgba);
50 }
51 }
52 } else if (in1.area.y0 > in2.area.y0) {
53 // in2 begins before in1 on y-axis
54 for (int y = in2.area.y0 ; y < in1.area.y0 ; y++) {
55 int out_line = (y - out.area.y0) * out.rs;
56 int in_line = (y - in2.area.y0) * in2.rs;
57 for (int x = in2.area.x0 ; x < in2.area.x1 ; x++) {
58 blend(out_data + out_line + 4 * (x - out.area.x0),
59 zero_rgba,
60 in2_data + in_line + 4 * (x - in2.area.x0));
61 }
62 }
63 }
65 for (int y = std::max(in1.area.y0, in2.area.y0) ;
66 y < std::min(in1.area.y1, in2.area.y1) ; ++y) {
67 int out_line = (y - out.area.y0) * out.rs;
68 int in1_line = (y - in1.area.y0) * in1.rs;
69 int in2_line = (y - in2.area.y0) * in2.rs;
71 if (in1.area.x0 < in2.area.x0) {
72 // in1 begins before in2 on x-axis
73 for (int x = in1.area.x0 ; x < in2.area.x0 ; ++x) {
74 blend(out_data + out_line + 4 * (x - out.area.x0),
75 in1_data + in1_line + 4 * (x - in1.area.x0),
76 zero_rgba);
77 }
78 } else if (in1.area.x0 > in2.area.x0) {
79 // in2 begins before in1 on x-axis
80 for (int x = in2.area.x0 ; x < in1.area.x0 ; ++x) {
81 blend(out_data + out_line + 4 * (x - out.area.x0),
82 zero_rgba,
83 in2_data + in2_line + 4 * (x - in2.area.x0));
84 }
85 }
87 for (int x = std::max(in1.area.x0, in2.area.x0) ;
88 x < std::min(in1.area.x1, in2.area.x1) ; ++x) {
89 blend(out_data + out_line + 4 * (x - out.area.x0),
90 in1_data + in1_line + 4 * (x - in1.area.x0),
91 in2_data + in2_line + 4 * (x - in2.area.x0));
92 }
94 if (in1.area.x1 > in2.area.x1) {
95 // in1 ends after in2 on x-axis
96 for (int x = in2.area.x1 ; x < in1.area.x1 ; ++x) {
97 blend(out_data + out_line + 4 * (x - out.area.x0),
98 in1_data + in1_line + 4 * (x - in1.area.x0),
99 zero_rgba);
100 }
101 } else if (in1.area.x1 < in2.area.x1) {
102 // in2 ends after in1 on x-axis
103 for (int x = in1.area.x1 ; x < in2.area.x1 ; ++x) {
104 blend(out_data + out_line + 4 * (x - out.area.x0),
105 zero_rgba,
106 in2_data + in2_line + 4 * (x - in2.area.x0));
107 }
108 }
109 }
111 if (in1.area.y1 > in2.area.y1) {
112 // in1 ends after in2 on y-axis
113 for (int y = in2.area.y1 ; y < in1.area.y1 ; y++) {
114 int out_line = (y - out.area.y0) * out.rs;
115 int in_line = (y - in1.area.y0) * in1.rs;
116 for (int x = in1.area.x0 ; x < in1.area.x1 ; x++) {
117 blend(out_data + out_line + 4 * (x - out.area.x0),
118 in1_data + in_line + 4 * (x - in1.area.x0),
119 zero_rgba);
120 }
121 }
122 } else if (in1.area.y1 < in2.area.y1) {
123 // in2 ends after in1 on y-axis
124 for (int y = in1.area.y1 ; y < in2.area.y1 ; y++) {
125 int out_line = (y - out.area.y0) * out.rs;
126 int in_line = (y - in2.area.y0) * in2.rs;
127 for (int x = in2.area.x0 ; x < in2.area.x1 ; x++) {
128 blend(out_data + out_line + 4 * (x - out.area.x0),
129 zero_rgba,
130 in2_data + in_line + 4 * (x - in2.area.x0));
131 }
132 }
133 }
134 }
136 } // namespace NR
138 #endif // __NR_FILTER_PIXOPS_H_
139 /*
140 Local Variables:
141 mode:c++
142 c-file-style:"stroustrup"
143 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
144 indent-tabs-mode:nil
145 fill-column:99
146 End:
147 */
148 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :