1 // Aseprite
2 // Copyright (C) 2001-2018  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 "app/modules/palettes.h"
12 
13 #include "app/app.h"
14 #include "app/extensions.h"
15 #include "app/file/palette_file.h"
16 #include "app/resource_finder.h"
17 #include "base/fs.h"
18 #include "doc/image.h"
19 #include "doc/palette.h"
20 #include "doc/sprite.h"
21 
22 #include <cstring>
23 
24 namespace app {
25 
26 // The default color palette.
27 static Palette* ase_default_palette = NULL;
28 
29 // Palette in current sprite frame.
30 static Palette* ase_current_palette = NULL;
31 
init_module_palette()32 int init_module_palette()
33 {
34   ase_default_palette = new Palette(frame_t(0), 256);
35   ase_current_palette = new Palette(frame_t(0), 256);
36   return 0;
37 }
38 
exit_module_palette()39 void exit_module_palette()
40 {
41   delete ase_default_palette;
42   delete ase_current_palette;
43 }
44 
load_default_palette()45 void load_default_palette()
46 {
47   base::UniquePtr<Palette> pal;
48   std::string defaultPalName = get_preset_palette_filename(
49     get_default_palette_preset_name(), ".ase");
50 
51   // If there is no palette in command line, we use the default one.
52   std::string palFile = defaultPalName;
53   if (base::is_file(palFile)) {
54     pal.reset(load_palette(palFile.c_str()));
55   }
56   else {
57     // Migrate old default.gpl to default.ase format
58     palFile = get_preset_palette_filename(
59       get_default_palette_preset_name(), ".gpl");
60 
61     if (base::is_file(palFile)) {
62       pal.reset(load_palette(palFile.c_str()));
63 
64       // Remove duplicate black entries at the end (as old palettes
65       // contains 256 colors)
66       if (pal && pal->size() == 256) {
67         doc::color_t black = rgba(0, 0, 0, 255);
68 
69         // Get the last non-black entry
70         int i = 0;
71         for (i=pal->size()-1; i>0; --i) {
72           if (pal->getEntry(i) != black)
73             break;
74         }
75 
76         if (i < pal->size()-1) {
77           // Check if there is a black entry in the first entries.
78           bool hasBlack = false;
79           for (int j=0; j<i; ++j) {
80             if (pal->getEntry(j) == black) {
81               hasBlack = true;
82               break;
83             }
84           }
85           if (!hasBlack)
86             ++i;                // Leave one black entry
87 
88           // Resize the palette
89           if (i < pal->size()-1)
90             pal->resize(i+1);
91         }
92       }
93 
94       // We could remove the old .gpl file (palFile), but as the
95       // user could be using multiple versions of Aseprite, it's a
96       // good idea to keep both formats (.gpl for Aseprite <=
97       // v1.1-beta5, and .ase for future versions).
98     }
99     // If the default palette file doesn't exist, we copy db32.gpl
100     // as the default one (default.ase).
101     else {
102       std::string path = App::instance()->extensions().palettePath("DB32");
103       if (path.empty())
104         path = App::instance()->extensions().palettePath("VGA 13h");
105       if (!path.empty())
106         pal.reset(load_palette(path.c_str()));
107     }
108 
109     // Save default.ase file
110     if (pal) {
111       palFile = defaultPalName;
112       save_palette(palFile.c_str(), pal.get(), 0);
113     }
114   }
115 
116   if (pal)
117     set_default_palette(pal.get());
118 
119   set_current_palette(nullptr, true);
120 }
121 
get_current_palette()122 Palette* get_current_palette()
123 {
124   return ase_current_palette;
125 }
126 
get_default_palette()127 Palette* get_default_palette()
128 {
129   return ase_default_palette;
130 }
131 
set_default_palette(const Palette * palette)132 void set_default_palette(const Palette* palette)
133 {
134   palette->copyColorsTo(ase_default_palette);
135 }
136 
137 // Changes the current system palette and triggers the
138 // App::PaletteChange signal.
139 //
140 // If "_palette" is nullptr the default palette is set.
set_current_palette(const Palette * _palette,bool forced)141 bool set_current_palette(const Palette *_palette, bool forced)
142 {
143   const Palette* palette = (_palette ? _palette: ase_default_palette);
144   bool ret = false;
145 
146   // Have changes
147   if (forced ||
148       palette->countDiff(ase_current_palette, NULL, NULL) > 0) {
149     // Copy current palette
150     palette->copyColorsTo(ase_current_palette);
151 
152     // Call slots in signals
153     App::instance()->PaletteChange();
154 
155     ret = true;
156   }
157 
158   return ret;
159 }
160 
get_preset_palette_filename(const std::string & preset,const std::string & dot_extension)161 std::string get_preset_palette_filename(const std::string& preset,
162                                         const std::string& dot_extension)
163 {
164   ResourceFinder rf;
165   rf.includeUserDir(base::join_path("palettes", ".").c_str());
166   std::string palettesDir = rf.getFirstOrCreateDefault();
167 
168   if (!base::is_directory(palettesDir))
169     base::make_directory(palettesDir);
170 
171   return base::join_path(palettesDir, preset + dot_extension);
172 }
173 
get_default_palette_preset_name()174 std::string get_default_palette_preset_name()
175 {
176   return "default";
177 }
178 
179 } // namespace app
180