1// Aseprite Document Library
2// Copyright (c) 2020 Igara Studio S.A.
3// Copyright (c) 2001-2018 David Capello
4//
5// This file is released under the terms of the MIT license.
6// Read LICENSE.txt for more information.
7
8#ifdef HAVE_CONFIG_H
9#include "config.h"
10#endif
11
12#include "base/fstream_path.h"
13#include "base/log.h"
14#include "base/split_string.h"
15#include "base/trim_string.h"
16#include "doc/image.h"
17#include "doc/palette.h"
18
19#include <cctype>
20#include <fstream>
21#include <iomanip>
22#include <memory>
23#include <sstream>
24#include <string>
25
26namespace doc {
27namespace file {
28
29std::unique_ptr<Palette> load_gpl_file(const char* filename)
30{
31 std::ifstream f(FSTREAM_PATH(filename));
32 if (f.bad()) return NULL;
33
34 // Read first line, it must be "GIMP Palette"
35 std::string line;
36 if (!std::getline(f, line)) return NULL;
37 base::trim_string(line, line);
38 if (line != "GIMP Palette") return NULL;
39
40 std::unique_ptr<Palette> pal(new Palette(frame_t(0), 0));
41 std::string comment;
42 bool hasAlpha = false;
43
44 while (std::getline(f, line)) {
45 // Trim line.
46 base::trim_string(line, line);
47
48 // Remove empty lines
49 if (line.empty())
50 continue;
51
52 // Concatenate comments
53 if (line[0] == '#') {
54 line = line.substr(1);
55 base::trim_string(line, line);
56 comment += line;
57 comment.push_back('\n');
58 continue;
59 }
60
61 // Remove properties (TODO add these properties in the palette)
62 if (!std::isdigit(line[0])) {
63 std::vector<std::string> parts;
64 base::split_string(line, parts, ":");
65 // Aseprite extension for palettes with alpha channel.
66 if (parts.size() == 2 &&
67 parts[0] == "Channels") {
68 base::trim_string(parts[1], parts[1]);
69 if (parts[1] == "RGBA")
70 hasAlpha = true;
71 }
72 continue;
73 }
74
75 int r, g, b, a = 255;
76 std::string entryName;
77 std::istringstream lineIn(line);
78 lineIn >> r >> g >> b;
79 if (hasAlpha) {
80 lineIn >> a;
81 }
82 lineIn >> entryName;
83
84 if (lineIn.fail())
85 continue;
86
87 pal->addEntry(rgba(r, g, b, a));
88 if (!entryName.empty()) {
89 base::trim_string(entryName, entryName);
90 if (!entryName.empty())
91 pal->setEntryName(pal->size()-1, entryName);
92 }
93 }
94
95 base::trim_string(comment, comment);
96 if (!comment.empty()) {
97 LOG(VERBOSE, "PAL: %s comment: %s\n", filename, comment.c_str());
98 pal->setComment(comment);
99 }
100
101 return pal;
102}
103
104bool save_gpl_file(const Palette* pal, const char* filename)
105{
106 std::ofstream f(FSTREAM_PATH(filename));
107 if (f.bad()) return false;
108
109 const bool hasAlpha = pal->hasAlpha();
110
111 f << "GIMP Palette\n";
112 if (hasAlpha)
113 f << "Channels: RGBA\n";
114 f << "#\n";
115
116 for (int i=0; i<pal->size(); ++i) {
117 uint32_t col = pal->getEntry(i);
118 f << std::setfill(' ') << std::setw(3) << ((int)rgba_getr(col)) << " "
119 << std::setfill(' ') << std::setw(3) << ((int)rgba_getg(col)) << " "
120 << std::setfill(' ') << std::setw(3) << ((int)rgba_getb(col));
121 if (hasAlpha)
122 f << " " << std::setfill(' ') << std::setw(3) << ((int)rgba_geta(col));
123 f << "\tUntitled\n"; // TODO add support for color name entries
124 }
125
126 return true;
127}
128
129} // namespace file
130} // namespace doc
131