Code

Super duper mega (fun!) commit: replaced encoding=utf-8 with fileencoding=utf-8 in...
[inkscape.git] / src / display / nr-filter-pixops.h
1 #ifndef __NR_FILTER_PIXOPS_H__
2 #define __NR_FILTER_PIXOPS_H__
4 #include "libnr/nr-pixblock.h"
5 #include <algorithm>
7 /*
8  * Per-pixel image manipulation functions.
9  * These can be used by all filter primitives, which combine two images on
10  * per-pixel basis. These are at least feBlend, feComposite and feMerge.
11  *
12  * Authors:
13  *   Niko Kiirala <niko@kiirala.com>
14  *
15  * Copyright (C) 2007 authors
16  *
17  * Released under GNU GPL, read the file 'COPYING' for more information
18  */
20 namespace Inkscape {
21 namespace Filters {
23 /**
24  * Mixes the two input images using the function given as template.
25  * The result is placed in out.
26  * The mixing function should have the following type:
27  * void mix(unsigned char *result, unsigned char const *in1,
28  *          unsigned char const *in2);
29  * Each of the parameters for mix-function is a pointer to four bytes of data,
30  * giving the RGBA values for that pixel. The mix function must only access
31  * the four bytes beginning at a pointer given as parameter.
32  */
33 /*
34  * The implementation is in a header file because of the template. It has to
35  * be in the same compilation unit as the code using it. Otherwise, linking
36  * the program will not succeed.
37  */
38 template <void(*blend)(unsigned char *cr, unsigned char const *ca, unsigned char const *cb)>
39 void pixops_mix(NRPixBlock &out, NRPixBlock &in1, NRPixBlock &in2) {
40     unsigned char *in1_data = NR_PIXBLOCK_PX(&in1);
41     unsigned char *in2_data = NR_PIXBLOCK_PX(&in2);
42     unsigned char *out_data = NR_PIXBLOCK_PX(&out);
43     unsigned char zero_rgba[4] = {0, 0, 0, 0};
45     // Possible scenarios (omitting cases where an interval is empty and those which are the same by interchanging 1 and 2):
46     // 01020, 01320, 01310 (no overlap, partial overlap, full overlap)
47     int out_y0 = out.area.y0;
48     int out_y1 = std::max(out.area.y1,out_y0); // Enforce sanity
49     int in1_y0 = std::min(std::max(in1.area.y0,out_y0),out_y1);
50     int in2_y0 = std::min(std::max(in2.area.y0,out_y0),out_y1);
51     int in1_y1 = std::min(std::max(in1.area.y1,in1_y0),out_y1);
52     int in2_y1 = std::min(std::max(in2.area.y1,in2_y0),out_y1);
53     int min_in_y0 = std::min(in1_y0,in2_y0);
54     int max_in_y0 = std::max(in1_y0,in2_y0);
55     int min_in_y1 = std::min(in1_y1,in2_y1);
56     int max_in_y1 = std::max(in1_y1,in2_y1);
57     int const yBound[6] = {out_y0, min_in_y0, std::min(max_in_y0,min_in_y1), std::max(max_in_y0,min_in_y1), max_in_y1, out_y1};
58     bool const in1_zero_y[5] = {true, in1_y0>yBound[1], in1_y0>yBound[2] || in1_y1<=yBound[2], in1_y1<=yBound[3], true};
59     bool const in2_zero_y[5] = {true, in2_y0>yBound[1], in2_y0>yBound[2] || in2_y1<=yBound[2], in2_y1<=yBound[3], true};
61     int out_x0 = out.area.x0;
62     int out_x1 = std::max(out.area.x1,out_x0);
63     int in1_x0 = std::min(std::max(in1.area.x0,out_x0),out_x1);
64     int in2_x0 = std::min(std::max(in2.area.x0,out_x0),out_x1);
65     int in1_x1 = std::min(std::max(in1.area.x1,in1_x0),out_x1);
66     int in2_x1 = std::min(std::max(in2.area.x1,in2_x0),out_x1);
67     int min_in_x0 = std::min(in1_x0,in2_x0);
68     int max_in_x0 = std::max(in1_x0,in2_x0);
69     int min_in_x1 = std::min(in1_x1,in2_x1);
70     int max_in_x1 = std::max(in1_x1,in2_x1);
71     int const xBound[6] = {out_x0, min_in_x0, std::min(max_in_x0,min_in_x1), std::max(max_in_x0,min_in_x1), max_in_x1, out_x1};
72     bool const in1_zero_x[5] = {true, in1_x0>xBound[1], in1_x0>xBound[2] || in1_x1<=xBound[2], in1_x1<=xBound[3], true};
73     bool const in2_zero_x[5] = {true, in2_x0>xBound[1], in2_x0>xBound[2] || in2_x1<=xBound[2], in2_x1<=xBound[3], true};
75     for (int yr = 0 ; yr < 5 ; yr++) {
76         for(int y = yBound[yr] ; y < yBound[yr+1] ; y++) {
77             int out_line = (y - out.area.y0) * out.rs;
78             int in1_line = (y - in1.area.y0) * in1.rs;
79             int in2_line = (y - in2.area.y0) * in2.rs;
80             for (int xr = 0 ; xr < 5 ; xr++) {
81                 for(int x = xBound[xr] ; x < xBound[xr+1] ; x++) {
82                     blend(out_data + out_line + 4 * (x - out.area.x0),
83                         (in1_zero_x[xr]||in1_zero_y[yr]) ? zero_rgba : (in1_data + in1_line + 4 * (x - in1.area.x0)),
84                         (in2_zero_x[xr]||in2_zero_y[yr]) ? zero_rgba : (in2_data + in2_line + 4 * (x - in2.area.x0)));
85                 }
86             }
87         }
88     }
89 }
91 } /* namespace Filters */
92 } /* namespace Inkscape */
94 #endif // __NR_FILTER_PIXOPS_H_
95 /*
96   Local Variables:
97   mode:c++
98   c-file-style:"stroustrup"
99   c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
100   indent-tabs-mode:nil
101   fill-column:99
102   End:
103 */
104 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :