1 // Aseprite Document Library
2 // Copyright (c) 2001-2016 David Capello
3 //
4 // This file is released under the terms of the MIT license.
5 // Read LICENSE.txt for more information.
6 
7 #ifdef HAVE_CONFIG_H
8 #include "config.h"
9 #endif
10 
11 #include "doc/remap.h"
12 
13 #include "base/base.h"
14 #include "doc/palette.h"
15 #include "doc/palette_picks.h"
16 #include "doc/rgbmap.h"
17 
18 namespace doc {
19 
create_remap_to_move_picks(const PalettePicks & picks,int beforeIndex)20 Remap create_remap_to_move_picks(const PalettePicks& picks, int beforeIndex)
21 {
22   Remap map(picks.size());
23 
24   int selectedTotal = 0;
25   int selectedBeforeIndex = 0;
26 
27   for (int i=0; i<map.size(); ++i) {
28     if (picks[i]) {
29       ++selectedTotal;
30       if (i < beforeIndex)
31         ++selectedBeforeIndex;
32     }
33   }
34 
35   for (int i=0, j=0, k=0; i<map.size(); ++i) {
36     if (k == beforeIndex - selectedBeforeIndex)
37       k += selectedTotal;
38 
39     if (picks[i]) {
40       map.map(i, beforeIndex - selectedBeforeIndex + j);
41       ++j;
42     }
43     else {
44       map.map(i, k++);
45     }
46   }
47 
48   return map;
49 }
50 
create_remap_to_expand_palette(int size,int count,int beforeIndex)51 Remap create_remap_to_expand_palette(int size, int count, int beforeIndex)
52 {
53   Remap map(size);
54 
55   int j, k = 0;
56   for (int i=0; i<size; ++i) {
57     if (i < beforeIndex)
58       j = i;
59     else if (i + count < size)
60       j = i + count;
61     else
62       j = beforeIndex + (k++);
63 
64     map.map(i, j);
65   }
66   return map;
67 }
68 
create_remap_to_change_palette(const Palette * oldPalette,const Palette * newPalette,const int oldMaskIndex,const bool remapMaskIndex)69 Remap create_remap_to_change_palette(
70   const Palette* oldPalette, const Palette* newPalette,
71   const int oldMaskIndex,
72   const bool remapMaskIndex)
73 {
74   Remap remap(MAX(oldPalette->size(), newPalette->size()));
75   int maskIndex = oldMaskIndex;
76 
77   if (maskIndex >= 0) {
78     if (remapMaskIndex &&
79         oldPalette->getEntry(maskIndex) !=
80         newPalette->getEntry(maskIndex)) {
81       color_t maskColor = oldPalette->getEntry(maskIndex);
82       int r = rgba_getr(maskColor);
83       int g = rgba_getg(maskColor);
84       int b = rgba_getb(maskColor);
85       int a = rgba_geta(maskColor);
86 
87       // Find the new mask color
88       maskIndex = newPalette->findExactMatch(r, g, b, a, -1);
89       if (maskIndex >= 0)
90         remap.map(oldMaskIndex, maskIndex);
91     }
92     else {
93       remap.map(maskIndex, maskIndex);
94     }
95   }
96 
97   RgbMap rgbmap;
98   rgbmap.regenerate(newPalette, maskIndex);
99 
100   for (int i=0; i<oldPalette->size(); ++i) {
101     if (i == oldMaskIndex)
102       continue;
103 
104     const color_t color = oldPalette->getEntry(i);
105 
106     // If in both palettes, it's the same color, we don't need to
107     // remap this entry.
108     if (color == newPalette->getEntry(i)) {
109       remap.map(i, i);
110       continue;
111     }
112 
113     int j = newPalette->findExactMatch(
114       rgba_getr(color),
115       rgba_getg(color),
116       rgba_getb(color),
117       rgba_geta(color), maskIndex);
118 
119     if (j < 0)
120       j = newPalette->findBestfit(
121         rgba_getr(color),
122         rgba_getg(color),
123         rgba_getb(color),
124         rgba_geta(color), maskIndex);
125 
126     remap.map(i, j);
127   }
128   return remap;
129 }
130 
merge(const Remap & other)131 void Remap::merge(const Remap& other)
132 {
133   for (int i=0; i<size(); ++i) {
134     m_map[i] = other[m_map[i]];
135   }
136 }
137 
invert() const138 Remap Remap::invert() const
139 {
140   Remap inv(size());
141   for (int i=0; i<size(); ++i)
142     inv.map(operator[](i), i);
143   return inv;
144 }
145 
isFor8bit() const146 bool Remap::isFor8bit() const
147 {
148   for (int i=0; i<size(); ++i) {
149     // Moving entries between [0,255] range to or from [256,+inf)
150     // range are invalid for 8-bit images.
151     if ((i <  256 && m_map[i] >= 256) ||
152         (i >= 256 && m_map[i] <  256))
153       return false;
154   }
155   return true;
156 }
157 
isInvertible(const PalettePicks & usedEntries) const158 bool Remap::isInvertible(const PalettePicks& usedEntries) const
159 {
160   PalettePicks picks(size());
161   for (int i=0; i<size(); ++i) {
162     if (!usedEntries[i])
163       continue;
164 
165     int j = m_map[i];
166     if (picks[j])
167       return false;
168 
169     picks[j] = true;
170   }
171   return true;
172 }
173 
174 } // namespace doc
175