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