1 // Aseprite
2 // Copyright (C) 2001-2016 David Capello
3 //
4 // This program is distributed under the terms of
5 // the End-User License Agreement for Aseprite.
6
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10
11 #include "filters/replace_color_filter.h"
12
13 #include "base/base.h"
14 #include "doc/image.h"
15 #include "doc/palette.h"
16 #include "doc/rgbmap.h"
17 #include "filters/filter_indexed_data.h"
18 #include "filters/filter_manager.h"
19
20 namespace filters {
21
22 using namespace doc;
23
ReplaceColorFilter()24 ReplaceColorFilter::ReplaceColorFilter()
25 {
26 m_from = m_to = m_tolerance = 0;
27 }
28
setFrom(int from)29 void ReplaceColorFilter::setFrom(int from)
30 {
31 m_from = from;
32 }
33
setTo(int to)34 void ReplaceColorFilter::setTo(int to)
35 {
36 m_to = to;
37 }
38
setTolerance(int tolerance)39 void ReplaceColorFilter::setTolerance(int tolerance)
40 {
41 m_tolerance = MID(0, tolerance, 255);
42 }
43
getName()44 const char* ReplaceColorFilter::getName()
45 {
46 return "Replace Color";
47 }
48
applyToRgba(FilterManager * filterMgr)49 void ReplaceColorFilter::applyToRgba(FilterManager* filterMgr)
50 {
51 const uint32_t* src_address = (uint32_t*)filterMgr->getSourceAddress();
52 uint32_t* dst_address = (uint32_t*)filterMgr->getDestinationAddress();
53 int w = filterMgr->getWidth();
54 Target target = filterMgr->getTarget();
55 int from_r, from_g, from_b, from_a;
56 int src_r, src_g, src_b, src_a;
57 int to_r, to_g, to_b, to_a;
58 int x, c;
59
60 from_r = rgba_getr(m_from);
61 from_g = rgba_getg(m_from);
62 from_b = rgba_getb(m_from);
63 from_a = rgba_geta(m_from);
64 to_r = rgba_getr(m_to);
65 to_g = rgba_getg(m_to);
66 to_b = rgba_getb(m_to);
67 to_a = rgba_geta(m_to);
68
69 for (x=0; x<w; x++) {
70 if (filterMgr->skipPixel()) {
71 ++src_address;
72 ++dst_address;
73 continue;
74 }
75
76 c = *(src_address++);
77 src_r = rgba_getr(c);
78 src_g = rgba_getg(c);
79 src_b = rgba_getb(c);
80 src_a = rgba_geta(c);
81
82 if (!(target & TARGET_RED_CHANNEL )) from_r = src_r;
83 if (!(target & TARGET_GREEN_CHANNEL)) from_g = src_g;
84 if (!(target & TARGET_BLUE_CHANNEL )) from_b = src_b;
85 if (!(target & TARGET_ALPHA_CHANNEL)) from_a = src_a;
86
87 if ((ABS(src_r-from_r) <= m_tolerance) &&
88 (ABS(src_g-from_g) <= m_tolerance) &&
89 (ABS(src_b-from_b) <= m_tolerance) &&
90 (ABS(src_a-from_a) <= m_tolerance)) {
91 *(dst_address++) = rgba(
92 (target & TARGET_RED_CHANNEL ? to_r: src_r),
93 (target & TARGET_GREEN_CHANNEL ? to_g: src_g),
94 (target & TARGET_BLUE_CHANNEL ? to_b: src_b),
95 (target & TARGET_ALPHA_CHANNEL ? to_a: src_a));
96 }
97 else
98 *(dst_address++) = c;
99 }
100 }
101
applyToGrayscale(FilterManager * filterMgr)102 void ReplaceColorFilter::applyToGrayscale(FilterManager* filterMgr)
103 {
104 const uint16_t* src_address = (uint16_t*)filterMgr->getSourceAddress();
105 uint16_t* dst_address = (uint16_t*)filterMgr->getDestinationAddress();
106 int w = filterMgr->getWidth();
107 Target target = filterMgr->getTarget();
108 int from_v, from_a;
109 int src_v, src_a;
110 int to_v, to_a;
111 int x, c;
112
113 from_v = graya_getv(m_from);
114 from_a = graya_geta(m_from);
115 to_v = graya_getv(m_to);
116 to_a = graya_geta(m_to);
117
118 for (x=0; x<w; x++) {
119 if (filterMgr->skipPixel()) {
120 ++src_address;
121 ++dst_address;
122 continue;
123 }
124
125 c = *(src_address++);
126 src_v = graya_getv(c);
127 src_a = graya_geta(c);
128
129 if (!(target & TARGET_GRAY_CHANNEL )) from_v = src_v;
130 if (!(target & TARGET_ALPHA_CHANNEL)) from_a = src_a;
131
132 if ((ABS(src_v-from_v) <= m_tolerance) &&
133 (ABS(src_a-from_a) <= m_tolerance)) {
134 *(dst_address++) = graya(
135 (target & TARGET_GRAY_CHANNEL ? to_v: src_v),
136 (target & TARGET_ALPHA_CHANNEL ? to_a: src_a));
137 }
138 else
139 *(dst_address++) = c;
140 }
141 }
142
applyToIndexed(FilterManager * filterMgr)143 void ReplaceColorFilter::applyToIndexed(FilterManager* filterMgr)
144 {
145 const uint8_t* src_address = (uint8_t*)filterMgr->getSourceAddress();
146 uint8_t* dst_address = (uint8_t*)filterMgr->getDestinationAddress();
147 int w = filterMgr->getWidth();
148 Target target = filterMgr->getTarget();
149 const Palette* pal = filterMgr->getIndexedData()->getPalette();
150 const RgbMap* rgbmap = filterMgr->getIndexedData()->getRgbMap();
151 int from_r, from_g, from_b, from_a;
152 int src_r, src_g, src_b, src_a;
153 int to_r, to_g, to_b, to_a;
154 int x, c;
155
156 c = pal->getEntry(m_from);
157 from_r = rgba_getr(c);
158 from_g = rgba_getg(c);
159 from_b = rgba_getb(c);
160 from_a = rgba_geta(c);
161
162 c = pal->getEntry(m_to);
163 to_r = rgba_getr(c);
164 to_g = rgba_getg(c);
165 to_b = rgba_getb(c);
166 to_a = rgba_geta(c);
167
168 for (x=0; x<w; x++) {
169 if (filterMgr->skipPixel()) {
170 ++src_address;
171 ++dst_address;
172 continue;
173 }
174
175 c = *(src_address++);
176
177 if (target & TARGET_INDEX_CHANNEL) {
178 if (ABS(c-m_from) <= m_tolerance)
179 *(dst_address++) = m_to;
180 else
181 *(dst_address++) = c;
182 }
183 else {
184 src_r = rgba_getr(pal->getEntry(c));
185 src_g = rgba_getg(pal->getEntry(c));
186 src_b = rgba_getb(pal->getEntry(c));
187 src_a = rgba_geta(pal->getEntry(c));
188
189 if (!(target & TARGET_RED_CHANNEL )) from_r = src_r;
190 if (!(target & TARGET_GREEN_CHANNEL)) from_g = src_g;
191 if (!(target & TARGET_BLUE_CHANNEL )) from_b = src_b;
192 if (!(target & TARGET_ALPHA_CHANNEL)) from_a = src_a;
193
194 if ((ABS(src_r-from_r) <= m_tolerance) &&
195 (ABS(src_g-from_g) <= m_tolerance) &&
196 (ABS(src_b-from_b) <= m_tolerance) &&
197 (ABS(src_a-from_a) <= m_tolerance)) {
198 *(dst_address++) = rgbmap->mapColor(
199 (target & TARGET_RED_CHANNEL ? to_r: src_r),
200 (target & TARGET_GREEN_CHANNEL ? to_g: src_g),
201 (target & TARGET_BLUE_CHANNEL ? to_b: src_b),
202 (target & TARGET_ALPHA_CHANNEL ? to_a: src_a));
203 }
204 else
205 *(dst_address++) = c;
206 }
207 }
208 }
209
210 } // namespace filters
211