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