ref: 969412af246eb7ca8fe1f5799281eb0df67a6102
parent: c10345f26d2aa370bc35d73ac5c81ea85beb788e
author: Rangi <35663410+Rangi42@users.noreply.github.com>
date: Sat Oct 1 08:45:00 EDT 2022
Parse HEX palettes (#1081) Addresses one item of #1065
--- a/man/rgbgfx.1
+++ b/man/rgbgfx.1
@@ -384,6 +384,10 @@
Useful to force several images to share the same palette.
.It Cm gpl
.Lk https://docs.gimp.org/2.10/en/gimp-concepts-palettes.html GIMP palette .
+.It Cm hex
+Plaintext lines of hexadecimal colors in
+.Ql rrggbb
+format.
.It Cm psp
.Lk https://www.selapa.net/swatches/colors/fileformats.php#psp_pal Paint Shop Pro palette .
.El
--- a/src/gfx/pal_spec.cpp
+++ b/src/gfx/pal_spec.cpp
@@ -55,7 +55,7 @@
template<typename Str> // Should be std::string or std::string_view
static void skipWhitespace(Str const &str, typename Str::size_type &pos) {
- pos = std::min(str.find_first_not_of(" \t", pos), str.length());
+ pos = std::min(str.find_first_not_of(" \t"sv, pos), str.length());
}
void parseInlinePalSpec(char const * const rawArg) {
@@ -233,7 +233,8 @@
std::string::size_type start = n;
uintmax_t value = 0; // Use a larger type to handle overflow more easily
- for (auto end = std::min(str.length(), str.find_first_not_of("0123456789", n)); n < end; ++n) {
+ for (auto end = std::min(str.length(), str.find_first_not_of("0123456789"sv, n)); n < end;
+ ++n) {
value = std::min(value * 10 + (str[n] - '0'), (uintmax_t)std::numeric_limits<U>::max);
}
@@ -382,6 +383,45 @@
}
}
+static void parseHEXFile(std::filebuf &file) {
+ // https://lospec.com/palette-list/tag/gbc
+
+ uint16_t nbColors = 0;
+ uint16_t maxNbColors = options.nbColorsPerPal * options.nbPalettes;
+
+ for (;;) {
+ std::string line;
+ readLine(file, line);
+ if (!line.length()) {
+ break;
+ }
+
+ if (line.length() != 6
+ || line.find_first_not_of("0123456789ABCDEFabcdef"sv) != std::string::npos) {
+ error("Failed to parse color #%" PRIu16 " (\"%s\"): invalid \"rrggbb\" line",
+ nbColors + 1, line.c_str());
+ return;
+ }
+
+ Rgba color =
+ Rgba(toHex(line[0], line[1]), toHex(line[2], line[3]), toHex(line[4], line[5]), 0xFF);
+
+ ++nbColors;
+ if (nbColors < maxNbColors) {
+ if (nbColors % options.nbColorsPerPal == 1) {
+ options.palSpec.emplace_back();
+ }
+ options.palSpec.back()[nbColors % options.nbColorsPerPal] = color;
+ }
+ }
+
+ if (nbColors > maxNbColors) {
+ warning("HEX file contains %" PRIu16 " colors, but there can only be %" PRIu16
+ "; ignoring extra",
+ nbColors, maxNbColors);
+ }
+}
+
static void parseACTFile(std::filebuf &file) {
// https://www.adobe.com/devnet-apps/photoshop/fileformatashtml/#50577411_pgfId-1070626
@@ -536,6 +576,7 @@
static std::array parsers{
std::tuple{"PSP", &parsePSPFile, std::ios::in },
std::tuple{"GPL", &parseGPLFile, std::ios::in },
+ std::tuple{"HEX", &parseHEXFile, std::ios::in },
std::tuple{"ACT", &parseACTFile, std::ios::binary},
std::tuple{"ACO", &parseACOFile, std::ios::binary},
std::tuple{"GBC", &parseGBCFile, std::ios::binary},