19 std::vector<std::string> color_components =
split(std::string{line},
" ");
21 if (color_components.size() != 3) {
22 return std::unexpected{fmt::format(
"invalid JASC color format, expected line in format 'R G B'")};
25 auto red_result = parse_int<int>(color_components[0]);
26 auto green_result = parse_int<int>(color_components[1]);
27 auto blue_result = parse_int<int>(color_components[2]);
29 if (!red_result.has_value()) {
30 return std::unexpected{fmt::format(
"invalid rgb red component: {}", red_result.error())};
32 if (!green_result.has_value()) {
33 return std::unexpected{fmt::format(
"invalid rgb green component: {}", green_result.error())};
35 if (!blue_result.has_value()) {
36 return std::unexpected{fmt::format(
"invalid rgb blue component: {}", blue_result.error())};
39 const auto red = red_result.value();
40 const auto green = green_result.value();
41 const auto blue = blue_result.value();
43 if (red < 0 || red > 255) {
44 return std::unexpected{fmt::format(
"invalid rgb red component '{}': range must be 0 <= red <= 255",
red)};
47 if (green < 0 || green > 255) {
48 return std::unexpected{fmt::format(
"invalid rgb green component '{}': range must be 0 <= green <= 255",
green)};
51 if (blue < 0 || blue > 255) {
52 return std::unexpected{fmt::format(
"invalid rgb blue component '{}': range must be 0 <= blue <= 255",
blue)};
56 static_cast<std::uint8_t
>(
red),
57 static_cast<std::uint8_t
>(
green),
58 static_cast<std::uint8_t
>(
blue),
69 return std::unexpected{fmt::format(
"does not exist: {}", path.string())};
73 std::string line_buf{};
74 std::ifstream stream{path};
77 std::getline(stream, line_buf);
79 if (line_buf !=
"JASC-PAL") {
80 return std::unexpected{fmt::format(
"{}: expected 'JASC-PAL' on line 1, saw '{}'", path.c_str(), line_buf)};
84 std::getline(stream, line_buf);
86 if (line_buf !=
"0100") {
87 return std::unexpected{fmt::format(
"{}: expected '0100' on line 2, saw '{}'", path.c_str(), line_buf)};
91 std::getline(stream, line_buf);
93 const auto declared_size_result = parse_int<unsigned int>(line_buf);
94 if (!declared_size_result.has_value()) {
95 return std::unexpected{fmt::format(
96 "{}: expected integral value on line 3: {}", path.c_str(), line_buf, declared_size_result.error())};
98 const auto declared_size = declared_size_result.value();
99 if (declared_size < 1) {
100 return std::unexpected{fmt::format(
"{}: expected declared size >= 1, saw '{}'", path.c_str(), declared_size)};
104 unsigned int color_index = 0;
105 while (std::getline(stream, line_buf)) {
107 if (!color_result.has_value()) {
108 return std::unexpected{fmt::format(
109 "{}: error parsing color on line {}: {}", path.c_str(), color_index + 4, color_result.error())};
111 pal.add(color_result.value());
115 if (color_index != declared_size) {
116 return std::unexpected{fmt::format(
117 "{}: declared size was '{}' but only saw {} defined colors", path.c_str(), declared_size, color_index)};
Result< Palette< Rgba32 > > load(const std::filesystem::path &path) const override
A palette container for colors that support transparency checking.
Represents a 32-bit RGBA color.
static constexpr std::uint8_t alpha_opaque
std::expected< T, E > Result
A result with some type T on success, otherwise an error of type E.
std::vector< std::string > split(std::string input, const std::string &delimiter)
Splits a string into tokens based on a delimiter.
std::string & trim_line_ending(std::string &line)
Removes line ending characters from a string in-place.