1e95d7cf120a5cb4e9b86ea5773928ee5980217c
1 /*
2 * feMerge filter effect renderer
3 *
4 * Authors:
5 * Niko Kiirala <niko@kiirala.com>
6 *
7 * Copyright (C) 2007 authors
8 *
9 * Released under GNU GPL, read the file 'COPYING' for more information
10 */
12 #include <cmath>
13 #include <vector>
15 #include "isnan.h"
16 #include "sp-femerge.h"
17 #include "display/nr-filter-merge.h"
18 #include "display/nr-filter-pixops.h"
19 #include "display/nr-filter-slot.h"
20 #include "display/nr-filter-units.h"
21 #include "display/nr-filter-utils.h"
22 #include "libnr/nr-blit.h"
23 #include "libnr/nr-pixblock.h"
24 #include "libnr/nr-pixops.h"
25 #include "libnr/nr-matrix.h"
27 inline void
28 composite_over(unsigned char *r, unsigned char const *a, unsigned char const *b)
29 {
30 r[0] = a[0] + NR_NORMALIZE_21(b[0] * (255 - a[3]));
31 r[1] = a[1] + NR_NORMALIZE_21(b[1] * (255 - a[3]));
32 r[2] = a[2] + NR_NORMALIZE_21(b[2] * (255 - a[3]));
33 r[3] = a[3] + NR_NORMALIZE_21(b[3] * (255 - a[3]));
34 }
36 namespace NR {
38 FilterMerge::FilterMerge() :
39 _input_image(1, NR_FILTER_SLOT_NOT_SET)
40 {}
42 FilterPrimitive * FilterMerge::create() {
43 return new FilterMerge();
44 }
46 FilterMerge::~FilterMerge()
47 {}
49 int FilterMerge::render(FilterSlot &slot, FilterUnits const &units) {
50 NRPixBlock *in[_input_image.size()];
51 NRPixBlock *original_in[_input_image.size()];
53 for (unsigned int i = 0 ; i < _input_image.size() ; i++) {
54 in[i] = slot.get(_input_image[i]);
55 original_in[i] = in[i];
56 }
58 NRPixBlock *out;
60 // Bail out if either one of source images is missing
61 for (unsigned int i = 0 ; i < _input_image.size() ; i++) {
62 if (!in[i]) {
63 g_warning("Missing source image for feMerge (number=%d slot=%d)", i, _input_image[i]);
64 return 1;
65 }
66 }
68 out = new NRPixBlock;
69 NRRectL out_area = in[0]->area;
70 for (unsigned int i = 1 ; i < _input_image.size() ; i++) {
71 nr_rect_l_union(&out_area, &out_area, &in[i]->area);
72 }
73 nr_pixblock_setup_fast(out, NR_PIXBLOCK_MODE_R8G8B8A8P,
74 out_area.x0, out_area.y0, out_area.x1, out_area.y1,
75 true);
77 // Merge is defined for premultiplied RGBA values, thus convert them to
78 // that format before blending
79 for (unsigned int i = 0 ; i < _input_image.size() ; i++) {
80 if (in[i]->mode != NR_PIXBLOCK_MODE_R8G8B8A8P) {
81 in[i] = new NRPixBlock;
82 nr_pixblock_setup_fast(in[i], NR_PIXBLOCK_MODE_R8G8B8A8P,
83 original_in[i]->area.x0,
84 original_in[i]->area.y0,
85 original_in[i]->area.x1,
86 original_in[i]->area.y1,
87 false);
88 nr_blit_pixblock_pixblock(in[i], original_in[i]);
89 }
90 }
92 /* pixops_mix is defined in display/nr-filter-pixops.h
93 * It mixes the two input images with the function given as template
94 * and places the result in output image.
95 */
96 for (unsigned int i = 0 ; i < _input_image.size() ; i++) {
97 pixops_mix<composite_over>(*out, *in[i], *out);
98 }
100 for (unsigned int i = 0 ; i < _input_image.size() ; i++) {
101 if (in[i] != original_in[i]) {
102 nr_pixblock_release(in[i]);
103 delete in[i];
104 }
105 }
107 out->empty = FALSE;
108 slot.set(_output, out);
110 return 0;
111 }
113 void FilterMerge::set_input(int slot) {
114 _input_image[0] = slot;
115 }
117 void FilterMerge::set_input(int input, int slot) {
118 if (input < 0) return;
120 if (_input_image.size() > input) {
121 _input_image[input] = slot;
122 } else {
123 for (unsigned int i = _input_image.size() ; i < input ; i++) {
124 _input_image.push_back(NR_FILTER_SLOT_NOT_SET);
125 }
126 _input_image.push_back(slot);
127 }
128 }
130 } /* namespace NR */
132 /*
133 Local Variables:
134 mode:c++
135 c-file-style:"stroustrup"
136 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
137 indent-tabs-mode:nil
138 fill-column:99
139 End:
140 */
141 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :