Various improvements

This commit is contained in:
Zachary Hall 2023-12-07 13:04:14 -08:00
parent 1b93f5d09d
commit 37b80d3624
7 changed files with 474 additions and 83 deletions

57
.vscode/settings.json vendored
View file

@ -29,6 +29,61 @@
"deque": "cpp", "deque": "cpp",
"__memory": "cpp", "__memory": "cpp",
"locale": "cpp", "locale": "cpp",
"vector": "cpp" "vector": "cpp",
"cctype": "cpp",
"clocale": "cpp",
"cmath": "cpp",
"cstdarg": "cpp",
"cstddef": "cpp",
"cstdio": "cpp",
"cstdlib": "cpp",
"cstring": "cpp",
"ctime": "cpp",
"cwchar": "cpp",
"cwctype": "cpp",
"hash_map": "cpp",
"bit": "cpp",
"*.tcc": "cpp",
"codecvt": "cpp",
"compare": "cpp",
"complex": "cpp",
"concepts": "cpp",
"condition_variable": "cpp",
"list": "cpp",
"map": "cpp",
"set": "cpp",
"string": "cpp",
"unordered_map": "cpp",
"exception": "cpp",
"iterator": "cpp",
"memory": "cpp",
"memory_resource": "cpp",
"string_view": "cpp",
"fstream": "cpp",
"initializer_list": "cpp",
"iomanip": "cpp",
"iostream": "cpp",
"istream": "cpp",
"mutex": "cpp",
"new": "cpp",
"ostream": "cpp",
"sstream": "cpp",
"stdexcept": "cpp",
"stop_token": "cpp",
"streambuf": "cpp",
"thread": "cpp",
"cinttypes": "cpp",
"typeinfo": "cpp",
"variant": "cpp",
"__config": "cpp",
"__debug": "cpp",
"__errc": "cpp",
"__hash_table": "cpp",
"__locale": "cpp",
"__mutex_base": "cpp",
"__split_buffer": "cpp",
"__threading_support": "cpp",
"__tree": "cpp",
"__verbose_abort": "cpp"
} }
} }

View file

@ -17,6 +17,7 @@ float BitmapX16::closeness_to_color(PaletteEntry a, PaletteEntry b) {
void BitmapX16::set_bpp(uint8_t bpp) { void BitmapX16::set_bpp(uint8_t bpp) {
this->bpp = bpp; this->bpp = bpp;
quantize_colors = true; quantize_colors = true;
operations_pending = true;
} }
uint8_t BitmapX16::get_bpp() const { uint8_t BitmapX16::get_bpp() const {
return bpp; return bpp;
@ -27,6 +28,7 @@ void BitmapX16::set_significant(uint8_t value) {
} }
significant_count = value; significant_count = value;
quantize_colors = true; quantize_colors = true;
operations_pending = true;
} }
uint8_t BitmapX16::get_significant() const { uint8_t BitmapX16::get_significant() const {
return significant_count; return significant_count;
@ -39,6 +41,7 @@ size_t BitmapX16::get_height() const {
} }
void BitmapX16::enable_dithering(bool enabled) { void BitmapX16::enable_dithering(bool enabled) {
dither = enabled; dither = enabled;
operations_pending = true;
} }
bool BitmapX16::dithering_enabled() const { bool BitmapX16::dithering_enabled() const {
return dither; return dither;
@ -50,6 +53,26 @@ void BitmapX16::resize(size_t w, size_t h) {
void BitmapX16::queue_resize(size_t w, size_t h) { void BitmapX16::queue_resize(size_t w, size_t h) {
tw = w; tw = w;
th = h; th = h;
operations_pending = true;
}
void BitmapX16::apply_operations(BitmapX16Operation operations) {
if (operations & BitmapX16Operation::Resize) {
if (tw != 0 && th != 0) {
resize(tw, th);
tw = 0;
th = 0;
}
}
if (operations & BitmapX16Operation::Quantize) {
if (significant_count != 0) {
image->quantizeColors(significant_count);
image->quantizeDither(dither);
image->quantize();
}
}
if (operations & BitmapX16Operation::PreparePalette) {
}
} }
void BitmapX16::apply() { void BitmapX16::apply() {
if (tw != 0 && th != 0) { if (tw != 0 && th != 0) {
@ -70,6 +93,7 @@ void BitmapX16::apply() {
} }
image->quantize(); image->quantize();
generate_palette(); generate_palette();
operations_pending = false;
} }
uint8_t BitmapX16::extra_to_real_palette(uint8_t idx) { uint8_t BitmapX16::extra_to_real_palette(uint8_t idx) {
return image_palette_count + idx; return image_palette_count + idx;
@ -83,7 +107,11 @@ void BitmapX16::write_x16(const char *filename) {
size_t outpixelsize; size_t outpixelsize;
size_t pixelCount; size_t pixelCount;
pixels_per_byte = (8/bpp); pixels_per_byte = (8/bpp);
apply(); if (operations_pending) {
apply();
} else {
generate_palette();
}
w = image->columns(); w = image->columns();
h = image->rows(); h = image->rows();
printf("Image size: (%lu, %lu)\n", w, h); printf("Image size: (%lu, %lu)\n", w, h);
@ -306,48 +334,47 @@ uint8_t BitmapX16::get_orable_pixel(uint8_t pixelinbyte, uint8_t color) {
BitmapX16::BitmapX16() { BitmapX16::BitmapX16() {
palette_entries = vector<PaletteEntry>(); palette_entries = vector<PaletteEntry>();
} }
void BitmapX16::generate_palette() { void BitmapX16::prepare_palette() {
size_t min; size_t max_start;
uint16_t max; uint16_t max_colors;
if (!generate_palette_enabled || !write_palette) { if (!generate_palette_enabled) {
significant_count = write_palette ? palette_entries.size() : 0; max_colors = palette_entries.size();
max = significant_count; } else {
min = 256 - max; max_colors = image->colorMapSize();
if (min >= 16 && write_palette) {
significant_start = 16;
}
if (max > 256) max = 256;
if (bpp == 0) {
if (max <= 4) {
bpp = 2;
} else if (max <= 16) {
bpp = 4;
} else {
bpp = 8;
}
}
return;
} }
max = (uint16_t)image->colorMapSize(); max_start = 256 - max_colors;
if (max > 256) max = 256; if (max_start >= target_palette_start) {
significant_start = target_palette_start;
} else {
significant_start = max_start;
}
if (max_colors > 256) max_colors = 256;
if (bpp == 0) { if (bpp == 0) {
if (max <= 4) { if (max_colors <= 4) {
bpp = 2; bpp = 2;
} else if (max <= 16) { } else if (max_colors <= 16) {
bpp = 4; bpp = 4;
} else { } else {
bpp = 8; bpp = 8;
} }
} }
min = 256 - (1 << bpp); if (generate_palette_enabled) {
if (min >= 16) { if (significant_count == 0) {
significant_start = 16; significant_count = max_colors;
}
} }
if (significant_count == 0) { image_palette_count = max_colors;
significant_count = max; if (debug & DebugShowSignificant) {
uint16_t significant_end = significant_start + significant_count;
uint16_t image_end = significant_start + image_palette_count;
printf("Significant: %u-%u, %u entries\n", significant_start, significant_end, significant_count);
printf("Image: %u-%u, %u entries\n", significant_start, image_end, image_palette_count);
} }
bitmask = (1 << bpp) - 1; }
image_palette_count = max; void BitmapX16::generate_palette() {
uint16_t max_colors;
prepare_palette();
max_colors = image_palette_count;
palette_entries.clear(); palette_entries.clear();
for (uint16_t i = 0; i < image_palette_count; i++) { for (uint16_t i = 0; i < image_palette_count; i++) {
ColorRGB map_color = image->colorMap(i); ColorRGB map_color = image->colorMap(i);
@ -368,6 +395,7 @@ void BitmapX16::generate_palette() {
} }
uint8_t BitmapX16::add_palette_entry(PaletteEntry entry) { uint8_t BitmapX16::add_palette_entry(PaletteEntry entry) {
extra_palette_entries.push_back(entry); extra_palette_entries.push_back(entry);
operations_pending = true;
return (uint8_t)(extra_palette_entries.size() - 1); return (uint8_t)(extra_palette_entries.size() - 1);
} }
uint8_t BitmapX16::color_to_palette_entry(const ColorRGB &rgb) { uint8_t BitmapX16::color_to_palette_entry(const ColorRGB &rgb) {
@ -377,7 +405,7 @@ uint8_t BitmapX16::color_to_palette_entry(const ColorRGB &rgb) {
if (debug & DebugShowCloseness) { if (debug & DebugShowCloseness) {
printf("Closest color for %s: ", color.to_string().c_str()); printf("Closest color for %s: ", color.to_string().c_str());
} }
for (size_t i = 0; i < image_palette_count; i++) { for (size_t i = 0; i < image_palette_count && i < (1 << bpp); i++) {
float possibility_closeness = closeness_to_color(palette_entries[i], color); float possibility_closeness = closeness_to_color(palette_entries[i], color);
//printf("Closeness: %f", possibility_closeness); //printf("Closeness: %f", possibility_closeness);
if (possibility_closeness < closeness) { if (possibility_closeness < closeness) {
@ -433,19 +461,14 @@ void BitmapX16::set_palette(vector<PaletteEntry> entries) {
palette_entries.shrink_to_fit(); palette_entries.shrink_to_fit();
extra_palette_entries.clear(); extra_palette_entries.clear();
generate_palette_enabled = false; generate_palette_enabled = false;
image->quantizeColors(entries.size()); operations_pending = true;
image->quantizeColorSpace(MagickCore::RGBColorspace);
image->colorMapSize(entries.size());
for (uint16_t i = 0; i < entries.size(); i++) {
image->colorMap(i, entries[i].toColor());
}
image->quantize();
} }
void BitmapX16::enable_palette_generation() { void BitmapX16::enable_palette_generation() {
generate_palette_enabled = true; generate_palette_enabled = true;
operations_pending = true;
} }
bool BitmapX16::palette_generation_enabled() const { bool BitmapX16::palette_generation_enabled() const {
return generate_palette_enabled && write_palette; return generate_palette_enabled;
} }
void BitmapX16::read_palette(const char *filename) { void BitmapX16::read_palette(const char *filename) {
size_t fsize = std::filesystem::file_size(filename); size_t fsize = std::filesystem::file_size(filename);

View file

@ -2,12 +2,22 @@
#include <vector> #include <vector>
#include <Magick++.h> #include <Magick++.h>
#include "palette.h" #include "palette.h"
#include <stdint.h>
using namespace Magick; using namespace Magick;
using std::vector; using std::vector;
enum BitmapX16DebugFlags : int { enum BitmapX16DebugFlags : uint16_t {
DebugNone = 0, DebugNone = 0,
DebugShowPalette = (1 << 0), DebugShowPalette = (1 << 0),
DebugShowCloseness = (1 << 1) DebugShowCloseness = (1 << 1),
DebugShowSignificant = (1 << 2),
};
enum BitmapX16Operation : uint16_t {
None = 0,
Resize = (1 << 0),
Quantize = (1 << 1),
PreparePalette = (1 << 2),
GeneratePalette = (1 << 15),
}; };
class BitmapX16 { class BitmapX16 {
/// \brief Bits per pixel of the image /// \brief Bits per pixel of the image
@ -26,10 +36,12 @@ class BitmapX16 {
bool quantize_colors = false; bool quantize_colors = false;
/// \brief Enables LZSA compression /// \brief Enables LZSA compression
bool compress = false; bool compress = false;
/// \brief False to set the used palette to 0, and palette start also to 0. /// \brief Whether or not an operation is pending.
bool write_palette = true; bool operations_pending = false;
/// \brief True if the palette should be generated, false if it has been set manually and shouldn't be regenerated. /// \brief True if the palette should be generated, false if it has been set manually and shouldn't be regenerated.
bool generate_palette_enabled = true; bool generate_palette_enabled = true;
/// \brief The intended start of the palette.
uint8_t target_palette_start = 16;
/// \brief Current width /// \brief Current width
size_t w = 0; size_t w = 0;
/// \brief Current height /// \brief Current height
@ -52,10 +64,6 @@ class BitmapX16 {
uint8_t image_palette_count = 0; uint8_t image_palette_count = 0;
/// \brief Generates a palette from the current image /// \brief Generates a palette from the current image
void generate_palette(); void generate_palette();
/// \brief Actually resizes the image. User code should call queue_resize then apply
/// \param w The width to resize to
/// \param h The height to resize to
void resize(size_t w, size_t h);
/// \brief Gets the pixel index within this image based on X and Y values, as well as the width of the image /// \brief Gets the pixel index within this image based on X and Y values, as well as the width of the image
/// \param x The X value of the pixel /// \param x The X value of the pixel
/// \param y The Y value of the pixel /// \param y The Y value of the pixel
@ -83,6 +91,7 @@ class BitmapX16 {
uint8_t color_to_palette_entry(const ColorRGB &rgb); uint8_t color_to_palette_entry(const ColorRGB &rgb);
uint8_t extra_to_real_palette(uint8_t idx); uint8_t extra_to_real_palette(uint8_t idx);
float closeness_to_color(PaletteEntry a, PaletteEntry b); float closeness_to_color(PaletteEntry a, PaletteEntry b);
void prepare_palette();
public: public:
vector<PaletteEntry> get_palette() const; vector<PaletteEntry> get_palette() const;
vector<PaletteEntry> get_extra_entries() const; vector<PaletteEntry> get_extra_entries() const;
@ -90,6 +99,11 @@ class BitmapX16 {
/// \brief Sets the palette to use /// \brief Sets the palette to use
/// \param entries The entries to replace the existing palette /// \param entries The entries to replace the existing palette
void set_palette(vector<PaletteEntry> entries); void set_palette(vector<PaletteEntry> entries);
/// \brief Actually resizes the image. User code should call queue_resize then apply
/// \param w The width to resize to
/// \param h The height to resize to
void resize(size_t w, size_t h);
void apply_operations(BitmapX16Operation operations);
/// \brief Enables palette generation after disabling it with set_palette. /// \brief Enables palette generation after disabling it with set_palette.
void enable_palette_generation(); void enable_palette_generation();
/// \brief Checks the status of palette generation /// \brief Checks the status of palette generation

View file

@ -266,6 +266,12 @@ int main(int argc, char **argv) {
} }
if (tbpp == 0) tbpp = 8; if (tbpp == 0) tbpp = 8;
if (tcolorcount == 0) tcolorcount = (1 << tbpp); if (tcolorcount == 0) tcolorcount = (1 << tbpp);
if (probe_only) {
tw = 0;
th = 0;
tbpp = 0;
tcolorcount = 0;
}
try { try {
BitmapX16 bitmap; BitmapX16 bitmap;
bitmap.enable_compression(compress); bitmap.enable_compression(compress);
@ -276,6 +282,11 @@ int main(int argc, char **argv) {
} else { } else {
printf("Loading PC image file '%s' to be converted to the X16 bitmap format...\n", input); printf("Loading PC image file '%s' to be converted to the X16 bitmap format...\n", input);
printf("Using at most %u colors (excluding border color) at %u bpp\n", tcolorcount, tbpp); printf("Using at most %u colors (excluding border color) at %u bpp\n", tcolorcount, tbpp);
if (palette_file != NULL) {
printf("Using palette file '%s'\n", palette_file);
} else {
printf("Using generated palette.\n");
}
if (bitmap.compression_enabled()) printf("Compression enabled\n"); if (bitmap.compression_enabled()) printf("Compression enabled\n");
bitmap.load_pc(input); bitmap.load_pc(input);
} }
@ -292,6 +303,21 @@ int main(int argc, char **argv) {
h = bitmap.get_height(); h = bitmap.get_height();
uint8_t entry_count = bitmap.get_significant(); uint8_t entry_count = bitmap.get_significant();
uint8_t entry_start = bitmap.get_significant_start(); uint8_t entry_start = bitmap.get_significant_start();
printf("Image BPP: %u\n", tbpp);
printf("Image size: (%u, %u)\n", w, h);
printf("Palette starts at %u, has %u entries, and ends at %u\n", entry_start, entry_count == 0 ? 256 : entry_count, entry_start + entry_count);
printf("Palette:\n");
vector<PaletteEntry> entries = bitmap.get_palette();
for (size_t i = 0; i < entries.size(); i+=8) {
for (size_t j = 0; j < 8; j++) {
if (i + j > entries.size()) {
break;
}
printf("[%u] = %s, ", i + j, entries[i + j].to_string().c_str());
}
printf("\n");
}
return 0;
} }
if (reverse) { if (reverse) {
error_msg_part = "write the file"; error_msg_part = "write the file";

133
output.cpp Normal file
View file

@ -0,0 +1,133 @@
#include "output.h"
#include <stdarg.h>
#include <stdio.h>
ConsoleOutput::FormatType ConsoleOutput::format_type = ConsoleOutput::Text;
std::string ConsoleOutput::CategoryPrefix(Category category) {
if (format_type == Text) {
switch (category) {
case Debug:
return "Debug: ";
case Warning:
return "WARNING: ";
case Error:
return "ERROR: ";
case Info:
case None:
default:
return "";
}
} else {
std::string output;
switch (category) {
case Debug:
output = "DEBUG";
break;
case Info:
output = "INFO";
break;
case Warning:
output = "WARNING";
break;
case Error:
output = "ERROR";
break;
default:
if (format_type == Json) {
output = "NONE";
} else {
output = "";
}
}
if (format_type == LogStyle) {
output = "[" + output + "] ";
}
return output;
}
}
std::string ConsoleOutput::InsertCategoryPrefix(Category category, std::string input) {
std::string output = "";
std::string categoryPrefix = CategoryPrefix(category);
if (format_type == Json) {
output = "{\"category\": \"";
output += categoryPrefix;
output += "\", \"text\": \"";
for (size_t i = 0; i < input.length(); i++) {
char inChar = input[i];
switch (inChar) {
case '\"':
output += "\\\"";
break;
case '\n':
output += "\\n";
break;
case '\r':
output += "\\r";
break;
case '\\':
output += '\\\\';
break;
case '/':
output += "\\/";
break;
case '\b':
output += "\\b";
break;
case '\t':
output += '\\t';
break;
default:
output += inChar;
}
}
output += "\"}";
} else {
for (size_t i = 0; i < input.length(); i++) {
char inChar = input[i];
if (inChar == '\n' || (inChar == '\r' && (i + 1 < input.length() && input[i] != '\n'))) {
output += "\n";
output += categoryPrefix;
} else {
output += inChar;
}
}
}
return output;
}
void ConsoleOutput::Write(Category category, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
std::string output = VFormat(fmt, args);
va_end(args);
output = InsertCategoryPrefix(category, output);
printf("%s", output.c_str());
}
void ConsoleOutput::WriteLn(Category category, const char *fmt, ...) {
va_list args;
va_start(args, fmt);
std::string output = VFormat(fmt, args);
va_end(args);
output = InsertCategoryPrefix(category, output);
printf("%s", output.c_str());
}
std::string ConsoleOutput::Format(const char *fmt, ...) {
va_list args;
va_start(args, fmt);
std::string output = VFormat(fmt, args);
va_end(args);
return output;
}
std::string ConsoleOutput::VFormat(const char *fmt, va_list args) {
size_t len = 0;
char *buf = NULL;
va_list args_copy;
va_copy(args_copy, args);
len = vsnprintf(NULL, 0, fmt, args_copy);
va_end(args_copy);
buf = (char*)malloc(len);
va_copy(args_copy, args);
len = vsnprintf(buf, len, fmt, args_copy);
va_end(args_copy);
std::string output(buf);
free(buf);
return output;
}

31
output.h Normal file
View file

@ -0,0 +1,31 @@
#pragma once
#include <string>
class ConsoleOutput;
class ConsoleOutput {
public:
enum FormatType {
Text,
LogStyle,
Json
}
enum Category {
None,
Debug,
Info,
Warning,
Error,
};
static FormatType format_type;
static std::string CategoryPrefix(Category category);
static std::string InsertCategoryPrefix(Category category, std::string input);
static void Write(Category category, const char *fmt, ...);
static void WriteLn(Category category, const char *fmt, ...);
static std::string Format(const char *fmt, ...);
static std::string VFormat(const char *fmt, va_list args);
};
#define Debug(...) ConsoleOutput::WriteLn(ConsoleOutput::Debug, __VA_ARGS__)
#define Info(...) ConsoleOutput::WriteLn(ConsoleOutput::Info, __VA_ARGS__)
#define Warning(...) ConsoleOutput::WriteLn(ConsoleOutput::Warning, __VA_ARGS__)
#define Error(...) ConsoleOutput::WriteLn(ConsoleOutput::Error, __VA_ARGS__)
#define Print(...) ConsoleOutput::Write(ConsoleOutput::None, __VA_ARGS__)
#define PrintLn(...) ConsoleOutput::WriteLn(ConsoleOutput::None, __VA_ARGS__)

173
test.sh
View file

@ -1,11 +1,21 @@
#!/bin/bash #!/bin/bash
BLACK=0
RED=1
GREEN=2
YELLOW=3
BLUE=4
MAGENTA=5
CYAN=6
WHITE=7
GRAY=8
DEFAULT=9
bool_true() { bool_true() {
[ "$1" = "true" ] 2>/dev/null || [ "$1" -ne 0 ] 2>/dev/null [ "$1" = "true" ] 2>/dev/null || [ "$1" -ne 0 ] 2>/dev/null
[ $? -ne 0 ] # Convert $? to 1 or 0 value [ $? -eq 0 ] # Convert $? to 1 or 0 value
return $? return $?
} }
bool_false() { bool_false() {
! bool_true ! bool_true "$1"
return $? return $?
} }
cmd_avail() { cmd_avail() {
@ -14,15 +24,19 @@ cmd_avail() {
tests=0 tests=0
failed=0 failed=0
succeeded=0 succeeded=0
failed_ids=()
color=1 color=1
tput_avail=0 tput_avail=0
if cmd_avail tput; then if cmd_avail tput; then
tput_avail=1 tput_avail=1
fi fi
if bool_true $tput_avail; then if bool_true $tput_avail; then
COLORS=$(tput color 2>/dev/null) COLORS=$(tput colors 2>/dev/null)
if [ $? -eq 0 ] && [ $COLORS -gt 2 ]; then if [ $? -eq 0 ] && [ $COLORS -gt 2 ]; then
color=1 color=1
if [ $COLORS -lt 8 ]; then
GRAY=9
fi
else else
color=0 color=0
fi fi
@ -30,6 +44,7 @@ fi
usage() { usage() {
cat << EOF cat << EOF
$0 usage: $0 usage:
-o|--output-dir <output directory>
-p|--use-program <program path> -p|--use-program <program path>
Uses the specified already-compiled binary rather than compiling manually Uses the specified already-compiled binary rather than compiling manually
-i|--input-image <image path> -i|--input-image <image path>
@ -58,7 +73,9 @@ $0 usage:
Disables color. Disables color.
-h|--help -h|--help
Shows this message. Shows this message.
-O|--reverse-dir <directory for reverse conversion files>
Sets the directory for files that have been converted to PNG from BMX
No effect when reverse conversion is disabled
EOF EOF
exit 1 exit 1
} }
@ -80,7 +97,9 @@ enable_dither=1
enable_probe=1 enable_probe=1
debug_flags="" debug_flags=""
outdir="testout" outdir="testout"
OPTIONS=$(getopt -o "b:hp:i:r:no:d:p:cCDRS" --long "help,use-program:,input-image:,output-bpp:,resize:,no-defaults,output-dir:,debug:,no-reverse,no-dither,no-compress,palette-file,no-generate-palette,no-probe,color,no-color" -- "$@") reverse_dir_set=0
reversedir=""
OPTIONS=$(getopt -o "b:hp:i:r:no:d:p:cCDRSO" --long "help,use-program:,input-image:,output-bpp:,resize:,no-defaults,output-dir:,debug:,no-reverse,no-dither,no-compress,palette-file,no-generate-palette,no-probe,color,no-color,reverse-dir" -- "$@")
if [ $? != 0 ]; then if [ $? != 0 ]; then
echo "Getopt error." echo "Getopt error."
usage usage
@ -88,6 +107,11 @@ fi
eval set -- "$OPTIONS" eval set -- "$OPTIONS"
while [ -n "$1" ]; do while [ -n "$1" ]; do
case "$1" in case "$1" in
-O|--reverse-dir)
reversedir="$2"
reverse_dir_set=1
shift 2
;;
-o|--output-dir) -o|--output-dir)
outdir="$2" outdir="$2"
shift 2 shift 2
@ -162,15 +186,22 @@ while [ -n "$1" ]; do
;; ;;
esac esac
done done
if [ $generate_palette -ne 0 ]; then if bool_false $reverse_dir_set; then
reversedir="$outdir/reverse"
fi
if bool_true $generate_palette; then
palettes+="" palettes+=""
fi fi
if [ $enable_defaults -ne 0 ]; then if bool_true $enable_defaults; then
images+=("TEST.png" "PACK.png" "CAT.jpg") images+=("TEST.png" "PACK.png" "CAT.jpg")
bpps+=(1 2 4 8) bpps+=(1 2 4 8)
resize+=("8x8" "16x16" "32x32" "64x64" "320x240" "640x480") resize+=("64x64" "320x240" "640x480")
palettes+=("DPAL.BIN")
fi fi
if [ $prebuilt -eq 0 ]; then if bool_true $enable_reverse; then
mkdir -p $reversedir
fi
if bool_false $prebuilt; then
meson setup builddir meson setup builddir
meson compile -C builddir || exit $? meson compile -C builddir || exit $?
fi fi
@ -201,7 +232,7 @@ setfgcolor() {
if bool_true "$tput_avail"; then if bool_true "$tput_avail"; then
tput setaf "$1" tput setaf "$1"
else else
printf "\033[0;3%sm" "$1" printf "\033[38;5;%sm" "$1"
fi fi
} }
setbgcolor() { setbgcolor() {
@ -211,7 +242,7 @@ setbgcolor() {
if bool_true "$tput_avail"; then if bool_true "$tput_avail"; then
tput setab "$1" tput setab "$1"
else else
printf "\033[0;4%sm" "$1" printf "\033[48;5;%sm" "$1"
fi fi
} }
resetcolor() { resetcolor() {
@ -224,6 +255,10 @@ resetcolor() {
printf "\033[0m" printf "\033[0m"
fi fi
} }
extension() {
len="$(printf "%s" "$1" | sed 's/[^.]*\.[^.]*/./g' | wc -c)"
printf "%s" "$1" | cut -d. -f$(($len+1))
}
mkdir -p "$outdir" mkdir -p "$outdir"
run() { run() {
converter="$1" converter="$1"
@ -234,41 +269,65 @@ run() {
shift shift
reverse="$1" reverse="$1"
shift shift
infile_for_id=$(basename $infile)
outfile_for_id=$(basename $outfile)
extra_flags_run=() extra_flags_run=()
if [ -n "$reverse" ]; then extra_flags_probe=()
extra_flags_run+=( "$reverse" ) if bool_true "$reverse"; then
extra_flags_run+=( "-reverse" )
else
extra_flags_probe+=( "-reverse" )
fi fi
setfgcolor 2 id="convert_${infile_for_id}_${outfile_for_id}"
if [ -n "$reverse" ]; then
id="${id}_reverse"
fi
setfgcolor $WHITE
bold bold
printf "Running: %s\n" "$converter $* -in $infile -out $outfile" printf "Running test %s\n" "$id"
printf "Command: %s\n" "$converter -in $infile -out $outfile ${extra_flags_run[*]} $*"
resetcolor resetcolor
setfgcolor 8 setfgcolor $GRAY
tests=$(($tests+1)) tests=$(($tests+1))
"$converter" -in "$infile" -out "$outfile" "${extra_flags_run[@]}" "$@" "$converter" -in "$infile" -out "$outfile" "${extra_flags_run[@]}" "$@"
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
setfgcolor 1 setfgcolor 1
printf "Test failed.\n" printf "Test $id failed.\n"
resetcolor resetcolor
failed=$(($failed+1)) failed=$(($failed+1))
failed_ids+=($id)
else else
setfgcolor $GREEN
printf "Test $id succeeded!\n"
resetcolor
succeeded=$(($succeeded+1)) succeeded=$(($succeeded+1))
fi fi
resetcolor resetcolor
if [ $enable_probe -ne 0 ]; then if [ $enable_probe -ne 0 ]; then
setfgcolor 2 id="probe_${outfile_for_id}"
if [ -z "$reverse" ]; then
id="${id}_pc"
fi
setfgcolor $BLUE
bold bold
printf "Running test %s\n" "$id"
printf "Probing %s...\n" "$outfile" printf "Probing %s...\n" "$outfile"
resetcolor resetcolor
setfgcolor 8 setfgcolor $GRAY
"$converter" -in "$outfile" -probe "${extra_flags_run[@]}" printf "Command: %s\n" "$converter -in $infile -probe ${extra_flags_probe[*]}"
"$converter" -in "$outfile" -probe "${extra_flags_probe[@]}"
resetcolor resetcolor
tests=$(($tests+1)) tests=$(($tests+1))
if [ $? -ne 0 ]; then if [ $? -ne 0 ]; then
setfgcolor 1 setfgcolor $RED
printf "Test failed.\n" printf "Test $id failed.\n"
resetcolor resetcolor
failed=$(($failed+1)) failed=$(($failed+1))
failed_ids+=($id)
else else
setfgcolor $GREEN
printf "Test $id succeeded!\n"
resetcolor
succeeded=$(($succeeded+1)) succeeded=$(($succeeded+1))
fi fi
fi fi
@ -280,11 +339,14 @@ for img in "${images[@]}"; do
for palette in "${palettes[@]}"; do for palette in "${palettes[@]}"; do
width="$(echo -n "$size" | cut -dx -f1)" width="$(echo -n "$size" | cut -dx -f1)"
height="$(echo -n "$size" | cut -dx -f2)" height="$(echo -n "$size" | cut -dx -f2)"
name="$(basename "$img" | sed 's/\.png$//' | sed 's/\.jpg$//' | sed 's/\.jpeg$//')" ext="$(extension "$img")"
name="$(printf "%s.%sP.%sB" "$name" "$width" "$bpp")" ext_upper="$(printf "%s" "$ext" | tr '[:lower:]' '[:upper:]')"
name="$(basename -s ".$ext" "$img")"
name="$(printf "%s.%s.%sPX.%sB" "$name" "$ext_upper" "$width" "$bpp")"
extraflags=() extraflags=()
if [ -n "$palette" ]; then if [ -n "$palette" ]; then
extraflags+=( "-palette-file" "$palette" ) extraflags+=( "-palette-file" "$palette" )
name+=".PL-$(basename -s ".$(extension "$palette")" "$palette" | tr '[:lower:]' '[:upper]')"
fi fi
if [ -n "$compressflag" ]; then if [ -n "$compressflag" ]; then
if [ $enable_compression -eq 0 ]; then if [ $enable_compression -eq 0 ]; then
@ -293,14 +355,14 @@ for img in "${images[@]}"; do
extraflags+=( "$compressflag" ) extraflags+=( "$compressflag" )
name+=".C" name+=".C"
fi fi
run "$converter" "$img" "$outdir/$name.BMX" "" "${extraflags[@]}" "" -bpp "$bpp" -resize "$width" "$height" -border 15 0 15 -debug "$debug_flags" run "$converter" "$img" "$outdir/$name.BMX" false "${extraflags[@]}" -bpp "$bpp" -resize "$width" "$height" -border 15 0 15 -debug "$debug_flags"
if [ $enable_dither -ne 0 ]; then if bool_true $enable_dither; then
run "$converter" "$img" "$outdir/$name.D.BMX" "" "${extraflags[@]}" "" -bpp "$bpp" -resize "$width" "$height" -dither -border 15 0 15 -debug "$debug_flags" run "$converter" "$img" "$outdir/$name.D.BMX" false "${extraflags[@]}" -bpp "$bpp" -resize "$width" "$height" -dither -border 15 0 15 -debug "$debug_flags"
fi fi
if [ $enable_reverse -ne 0 ]; then if bool_true $enable_reverse; then
run "$converter" "$outdir/$name.BMX" "$outdir/$name.PNG" -reverse "${extraflags[@]}" -resize "$width" "$height" -debug "$debug_flags" run "$converter" "$outdir/$name.BMX" "$reversedir/$name.PNG" true "${extraflags[@]}" -resize "$width" "$height" -debug "$debug_flags"
if [ $enable_dither -ne 0 ]; then if bool_true $enable_dither; then
run "$converter" "$outdir/$name.D.BMX" "$outdir/$name.D.PNG" -reverse "${extraflags[@]}" -resize "$width" "$height" -dither -debug "$debug_flags" run "$converter" "$outdir/$name.D.BMX" "$reversedir/$name.D.PNG" true "${extraflags[@]}" -resize "$width" "$height" -dither -debug "$debug_flags"
fi fi
fi fi
done done
@ -308,5 +370,52 @@ for img in "${images[@]}"; do
done done
done done
done done
printf "%s total test cases, %s failed, %s succeeded, %s%% succeeded and %s%% failed.\n" "$tests" "$failed" "$succeeded" "$((($succeeded*100)/$tests))" "$((($failed*100)/$tests))" badcolor=$RED
goodcolor=$GREEN
okcolor=$YELLOW
success_good=90
success_ok=50
percent_out_of_tests() {
if [ "$tests" -eq 0 ]; then
printf "100"
else
printf "%s" "$((($1*100)/$tests))"
fi
}
invert_percent() {
printf "%s" "$((100-$1))"
}
success_percent="$(percent_out_of_tests $succeeded)"
failed_percent="$(percent_out_of_tests $failed)"
set_color_by_good_percentage() {
if [ "$1" -ge $success_good ]; then
setfgcolor "$goodcolor"
elif [ "$1" -ge $success_ok ]; then
setfgcolor "$okcolor"
else
setfgcolor "$badcolor"
fi
}
set_color_by_bad_percentage() {
set_color_by_good_percentage "$(invert_percent $1)"
}
bold
setfgcolor $WHITE
printf "%s total test cases, " "$tests"
set_color_by_bad_percentage "$failed_percent"
printf "%s failed (%s%%) " "$failed" "$failed_percent"
setfgcolor $WHITE
printf "and "
set_color_by_good_percentage "$success_percent"
printf "%s succeeded (%s%%)." "$succeeded" "$success_percent"
resetcolor
printf "\n"
if [ "$failed" -gt 0 ]; then
setfgcolor $RED
printf "Failing tests:\n"
for test in "${failed_ids[@]}"; do
printf "Test '%s'\n"
done
resetcolor
fi
cd "$oldpwd" cd "$oldpwd"