Add rgbgfx -r 0 to infer a width (#1437)

This commit is contained in:
Sylvie
2024-08-04 14:31:05 -04:00
committed by GitHub
parent 98bca79df4
commit 8af9e9d465
4 changed files with 27 additions and 17 deletions

View File

@@ -13,9 +13,6 @@
#include "gfx/rgba.hpp" #include "gfx/rgba.hpp"
struct Options { struct Options {
uint16_t reversedWidth = 0; // -r, in tiles
bool reverse() const { return reversedWidth != 0; }
bool useColorCurve = false; // -C bool useColorCurve = false; // -C
bool allowMirroring = false; // -m bool allowMirroring = false; // -m
bool allowDedup = false; // -u bool allowDedup = false; // -u
@@ -42,6 +39,7 @@ struct Options {
std::string output{}; // -o std::string output{}; // -o
std::string palettes{}; // -p, -P std::string palettes{}; // -p, -P
std::string palmap{}; // -q, -Q std::string palmap{}; // -q, -Q
uint16_t reversedWidth = 0; // -r, in tiles
uint8_t nbColorsPerPal = 0; // -s; 0 means "auto" = 1 << bitDepth; uint8_t nbColorsPerPal = 0; // -s; 0 means "auto" = 1 << bitDepth;
std::string tilemap{}; // -t, -T std::string tilemap{}; // -t, -T
uint64_t trim = 0; // -x uint64_t trim = 0; // -x

View File

@@ -22,7 +22,7 @@
.Op Fl o Ar out_file .Op Fl o Ar out_file
.Op Fl p Ar pal_file | Fl P .Op Fl p Ar pal_file | Fl P
.Op Fl q Ar pal_map | Fl Q .Op Fl q Ar pal_map | Fl Q
.Op Fl r Ar stride .Op Fl r Ar width
.Op Fl s Ar nb_colors .Op Fl s Ar nb_colors
.Op Fl t Ar tilemap | Fl T .Op Fl t Ar tilemap | Fl T
.Op Fl x Ar quantity .Op Fl x Ar quantity
@@ -246,6 +246,9 @@ below for details.
.Pp .Pp
.Ar width .Ar width
is the width of the image to generate, in tiles. is the width of the image to generate, in tiles.
.Fl r 0
chooses a width to make the image as square as possible.
This is useful if you do not know the original width.
.It Fl s Ar nb_colors , Fl \-palette-size Ar nb_colors .It Fl s Ar nb_colors , Fl \-palette-size Ar nb_colors
Specify how many colors each palette contains, including the transparent one if any. Specify how many colors each palette contains, including the transparent one if any.
.Ar nb_colors .Ar nb_colors

View File

@@ -36,6 +36,7 @@ static struct LocalOptions {
bool autoPalettes; bool autoPalettes;
bool autoPalmap; bool autoPalmap;
bool groupOutputs; bool groupOutputs;
bool reverse;
} localOptions; } localOptions;
static uintmax_t nbErrors; static uintmax_t nbErrors;
@@ -535,13 +536,11 @@ static char *parseArgv(int argc, char *argv[]) {
options.palmap = musl_optarg; options.palmap = musl_optarg;
break; break;
case 'r': case 'r':
localOptions.reverse = true;
options.reversedWidth = parseNumber(arg, "Reversed image stride"); options.reversedWidth = parseNumber(arg, "Reversed image stride");
if (*arg != '\0') { if (*arg != '\0') {
error("Reversed image stride (-r) must be a valid number, not \"%s\"", musl_optarg); error("Reversed image stride (-r) must be a valid number, not \"%s\"", musl_optarg);
} }
if (options.reversedWidth == 0) {
error("Reversed image stride (-r) may not be 0!");
}
break; break;
case 's': case 's':
options.nbColorsPerPal = parseNumber(arg, "Number of colors per palette", 4); options.nbColorsPerPal = parseNumber(arg, "Number of colors per palette", 4);
@@ -830,13 +829,13 @@ int main(int argc, char *argv[]) {
} }
if (!options.input.empty()) { if (!options.input.empty()) {
if (options.reverse()) { if (localOptions.reverse) {
reverse(); reverse();
} else { } else {
process(); process();
} }
} else if (!options.palettes.empty() && options.palSpecType == Options::EXPLICIT } else if (!options.palettes.empty() && options.palSpecType == Options::EXPLICIT
&& !options.reverse()) { && !localOptions.reverse) {
processPalettes(); processPalettes();
} else { } else {
fputs("FATAL: No input image specified\n", stderr); fputs("FATAL: No input image specified\n", stderr);

View File

@@ -6,6 +6,7 @@
#include <array> #include <array>
#include <errno.h> #include <errno.h>
#include <inttypes.h> #include <inttypes.h>
#include <math.h>
#include <optional> #include <optional>
#include <png.h> #include <png.h>
#include <string.h> #include <string.h>
@@ -159,6 +160,17 @@ void reverse() {
} }
size_t width = options.reversedWidth, height; // In tiles size_t width = options.reversedWidth, height; // In tiles
if (width == 0) {
// Pick the smallest width that will result in a landscape-aspect rectangular image.
// Thus a prime number of tiles will result in a horizontal row.
// This avoids redundancy with `-r 1` which results in a vertical column.
width = (size_t)ceil(sqrt(nbTileInstances));
for (; width < nbTileInstances; ++width) {
if (nbTileInstances % width == 0)
break;
}
options.verbosePrint(Options::VERB_INTERM, "Picked reversing width of %zu tiles\n", width);
}
if (nbTileInstances % width != 0) { if (nbTileInstances % width != 0) {
fatal( fatal(
"Total number of tiles read (%zu) cannot be divided by image width (%zu tiles)", "Total number of tiles read (%zu) cannot be divided by image width (%zu tiles)",
@@ -219,11 +231,9 @@ void reverse() {
if (options.palSpecType == Options::EXPLICIT && palettes != options.palSpec) { if (options.palSpecType == Options::EXPLICIT && palettes != options.palSpec) {
warning("Colors in the palette file do not match those specified with `-c`!"); warning("Colors in the palette file do not match those specified with `-c`!");
// [#111111ff, #222222ff, #333333ff, #444444ff] [#111111ff, #222222ff, #333333ff, #444444ff] // This spacing aligns "...versus with `-c`" above the column of `-c` palettes
fputs("Colors specified in the palette file: ...versus with `-c`:\n", stderr); fputs("Colors specified in the palette file: ...versus with `-c`:\n", stderr);
for (size_t i = 0; for (size_t i = 0; i < palettes.size() && i < options.palSpec.size(); ++i) {
i < palettes.size() && i < options.palSpec.size();
++i) {
if (i < palettes.size()) { if (i < palettes.size()) {
printPalette(palettes[i]); printPalette(palettes[i]);
} else { } else {
@@ -336,7 +346,7 @@ void reverse() {
png_set_IHDR( png_set_IHDR(
png, png,
pngInfo, pngInfo,
options.reversedWidth * 8, width * 8,
height * 8, height * 8,
8, 8,
PNG_COLOR_TYPE_RGB_ALPHA, PNG_COLOR_TYPE_RGB_ALPHA,
@@ -353,8 +363,8 @@ void reverse() {
sbitChunk.alpha = 1; sbitChunk.alpha = 1;
png_set_sBIT(png, pngInfo, &sbitChunk); png_set_sBIT(png, pngInfo, &sbitChunk);
constexpr uint8_t SIZEOF_PIXEL = 4; // Each pixel is 4 bytes (RGBA @ 8 bits/component) constexpr uint8_t SIZEOF_TILE = 4 * 8; // 4 bytes/pixel (RGBA @ 8 bits/channel) * 8 pixels/tile
size_t const SIZEOF_ROW = options.reversedWidth * 8 * SIZEOF_PIXEL; size_t const SIZEOF_ROW = width * SIZEOF_TILE;
std::vector<uint8_t> tileRow(8 * SIZEOF_ROW, 0xFF); // Data for 8 rows of pixels std::vector<uint8_t> tileRow(8 * SIZEOF_ROW, 0xFF); // Data for 8 rows of pixels
uint8_t * const rowPtrs[8] = { uint8_t * const rowPtrs[8] = {
&tileRow.data()[0 * SIZEOF_ROW], &tileRow.data()[0 * SIZEOF_ROW],
@@ -415,7 +425,7 @@ void reverse() {
bitplane0 = flipTable[bitplane0]; bitplane0 = flipTable[bitplane0];
bitplane1 = flipTable[bitplane1]; bitplane1 = flipTable[bitplane1];
} }
uint8_t *ptr = &rowPtrs[y][tx * 8 * SIZEOF_PIXEL]; uint8_t *ptr = &rowPtrs[y][tx * SIZEOF_TILE];
for (uint8_t x = 0; x < 8; ++x) { for (uint8_t x = 0; x < 8; ++x) {
uint8_t bit0 = bitplane0 & 0x80, bit1 = bitplane1 & 0x80; uint8_t bit0 = bitplane0 & 0x80, bit1 = bitplane1 & 0x80;
Rgba const &pixel = *palette[bit0 >> 7 | bit1 >> 6]; Rgba const &pixel = *palette[bit0 >> 7 | bit1 >> 6];