diff --git a/.vscode/settings.json b/.vscode/settings.json index 88abb19..e0ac5af 100644 --- a/.vscode/settings.json +++ b/.vscode/settings.json @@ -29,6 +29,61 @@ "deque": "cpp", "__memory": "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" } } \ No newline at end of file diff --git a/bitmapx16.cpp b/bitmapx16.cpp index 202baa5..4d4396b 100644 --- a/bitmapx16.cpp +++ b/bitmapx16.cpp @@ -17,6 +17,7 @@ float BitmapX16::closeness_to_color(PaletteEntry a, PaletteEntry b) { void BitmapX16::set_bpp(uint8_t bpp) { this->bpp = bpp; quantize_colors = true; + operations_pending = true; } uint8_t BitmapX16::get_bpp() const { return bpp; @@ -27,6 +28,7 @@ void BitmapX16::set_significant(uint8_t value) { } significant_count = value; quantize_colors = true; + operations_pending = true; } uint8_t BitmapX16::get_significant() const { return significant_count; @@ -39,6 +41,7 @@ size_t BitmapX16::get_height() const { } void BitmapX16::enable_dithering(bool enabled) { dither = enabled; + operations_pending = true; } bool BitmapX16::dithering_enabled() const { 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) { tw = w; 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() { if (tw != 0 && th != 0) { @@ -70,6 +93,7 @@ void BitmapX16::apply() { } image->quantize(); generate_palette(); + operations_pending = false; } uint8_t BitmapX16::extra_to_real_palette(uint8_t idx) { return image_palette_count + idx; @@ -83,7 +107,11 @@ void BitmapX16::write_x16(const char *filename) { size_t outpixelsize; size_t pixelCount; pixels_per_byte = (8/bpp); - apply(); + if (operations_pending) { + apply(); + } else { + generate_palette(); + } w = image->columns(); h = image->rows(); 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() { palette_entries = vector(); } -void BitmapX16::generate_palette() { - size_t min; - uint16_t max; - if (!generate_palette_enabled || !write_palette) { - significant_count = write_palette ? palette_entries.size() : 0; - max = significant_count; - min = 256 - max; - 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; +void BitmapX16::prepare_palette() { + size_t max_start; + uint16_t max_colors; + if (!generate_palette_enabled) { + max_colors = palette_entries.size(); + } else { + max_colors = image->colorMapSize(); } - max = (uint16_t)image->colorMapSize(); - if (max > 256) max = 256; + max_start = 256 - max_colors; + 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 (max <= 4) { + if (max_colors <= 4) { bpp = 2; - } else if (max <= 16) { + } else if (max_colors <= 16) { bpp = 4; } else { bpp = 8; } } - min = 256 - (1 << bpp); - if (min >= 16) { - significant_start = 16; + if (generate_palette_enabled) { + if (significant_count == 0) { + significant_count = max_colors; + } } - if (significant_count == 0) { - significant_count = max; + image_palette_count = max_colors; + 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(); for (uint16_t i = 0; i < image_palette_count; i++) { ColorRGB map_color = image->colorMap(i); @@ -368,6 +395,7 @@ void BitmapX16::generate_palette() { } uint8_t BitmapX16::add_palette_entry(PaletteEntry entry) { extra_palette_entries.push_back(entry); + operations_pending = true; return (uint8_t)(extra_palette_entries.size() - 1); } 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) { 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); //printf("Closeness: %f", possibility_closeness); if (possibility_closeness < closeness) { @@ -433,19 +461,14 @@ void BitmapX16::set_palette(vector entries) { palette_entries.shrink_to_fit(); extra_palette_entries.clear(); generate_palette_enabled = false; - image->quantizeColors(entries.size()); - 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(); + operations_pending = true; } void BitmapX16::enable_palette_generation() { generate_palette_enabled = true; + operations_pending = true; } bool BitmapX16::palette_generation_enabled() const { - return generate_palette_enabled && write_palette; + return generate_palette_enabled; } void BitmapX16::read_palette(const char *filename) { size_t fsize = std::filesystem::file_size(filename); diff --git a/bitmapx16.h b/bitmapx16.h index 9f278d4..8c56d10 100644 --- a/bitmapx16.h +++ b/bitmapx16.h @@ -2,12 +2,22 @@ #include #include #include "palette.h" +#include using namespace Magick; using std::vector; -enum BitmapX16DebugFlags : int { +enum BitmapX16DebugFlags : uint16_t { DebugNone = 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 { /// \brief Bits per pixel of the image @@ -26,10 +36,12 @@ class BitmapX16 { bool quantize_colors = false; /// \brief Enables LZSA compression bool compress = false; - /// \brief False to set the used palette to 0, and palette start also to 0. - bool write_palette = true; + /// \brief Whether or not an operation is pending. + bool operations_pending = false; /// \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; + /// \brief The intended start of the palette. + uint8_t target_palette_start = 16; /// \brief Current width size_t w = 0; /// \brief Current height @@ -52,10 +64,6 @@ class BitmapX16 { uint8_t image_palette_count = 0; /// \brief Generates a palette from the current image 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 /// \param x The X 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 extra_to_real_palette(uint8_t idx); float closeness_to_color(PaletteEntry a, PaletteEntry b); + void prepare_palette(); public: vector get_palette() const; vector get_extra_entries() const; @@ -90,6 +99,11 @@ class BitmapX16 { /// \brief Sets the palette to use /// \param entries The entries to replace the existing palette void set_palette(vector 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. void enable_palette_generation(); /// \brief Checks the status of palette generation diff --git a/main.cpp b/main.cpp index 80671c5..dfdfaed 100644 --- a/main.cpp +++ b/main.cpp @@ -266,6 +266,12 @@ int main(int argc, char **argv) { } if (tbpp == 0) tbpp = 8; if (tcolorcount == 0) tcolorcount = (1 << tbpp); + if (probe_only) { + tw = 0; + th = 0; + tbpp = 0; + tcolorcount = 0; + } try { BitmapX16 bitmap; bitmap.enable_compression(compress); @@ -276,6 +282,11 @@ int main(int argc, char **argv) { } else { 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); + 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"); bitmap.load_pc(input); } @@ -292,6 +303,21 @@ int main(int argc, char **argv) { h = bitmap.get_height(); uint8_t entry_count = bitmap.get_significant(); 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 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) { error_msg_part = "write the file"; diff --git a/output.cpp b/output.cpp new file mode 100644 index 0000000..4f6332b --- /dev/null +++ b/output.cpp @@ -0,0 +1,133 @@ +#include "output.h" +#include +#include +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; +} \ No newline at end of file diff --git a/output.h b/output.h new file mode 100644 index 0000000..1c4a052 --- /dev/null +++ b/output.h @@ -0,0 +1,31 @@ +#pragma once +#include +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__) \ No newline at end of file diff --git a/test.sh b/test.sh index cde06af..24786f2 100755 --- a/test.sh +++ b/test.sh @@ -1,11 +1,21 @@ #!/bin/bash +BLACK=0 +RED=1 +GREEN=2 +YELLOW=3 +BLUE=4 +MAGENTA=5 +CYAN=6 +WHITE=7 +GRAY=8 +DEFAULT=9 bool_true() { [ "$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 $? } bool_false() { - ! bool_true + ! bool_true "$1" return $? } cmd_avail() { @@ -14,15 +24,19 @@ cmd_avail() { tests=0 failed=0 succeeded=0 +failed_ids=() color=1 tput_avail=0 if cmd_avail tput; then tput_avail=1 fi 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 color=1 + if [ $COLORS -lt 8 ]; then + GRAY=9 + fi else color=0 fi @@ -30,6 +44,7 @@ fi usage() { cat << EOF $0 usage: +-o|--output-dir -p|--use-program Uses the specified already-compiled binary rather than compiling manually -i|--input-image @@ -58,7 +73,9 @@ $0 usage: Disables color. -h|--help Shows this message. - +-O|--reverse-dir + Sets the directory for files that have been converted to PNG from BMX + No effect when reverse conversion is disabled EOF exit 1 } @@ -80,7 +97,9 @@ enable_dither=1 enable_probe=1 debug_flags="" 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 echo "Getopt error." usage @@ -88,6 +107,11 @@ fi eval set -- "$OPTIONS" while [ -n "$1" ]; do case "$1" in + -O|--reverse-dir) + reversedir="$2" + reverse_dir_set=1 + shift 2 + ;; -o|--output-dir) outdir="$2" shift 2 @@ -162,15 +186,22 @@ while [ -n "$1" ]; do ;; esac 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+="" fi -if [ $enable_defaults -ne 0 ]; then +if bool_true $enable_defaults; then images+=("TEST.png" "PACK.png" "CAT.jpg") bpps+=(1 2 4 8) - resize+=("8x8" "16x16" "32x32" "64x64" "320x240" "640x480") + resize+=("64x64" "320x240" "640x480") + palettes+=("DPAL.BIN") 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 compile -C builddir || exit $? fi @@ -201,7 +232,7 @@ setfgcolor() { if bool_true "$tput_avail"; then tput setaf "$1" else - printf "\033[0;3%sm" "$1" + printf "\033[38;5;%sm" "$1" fi } setbgcolor() { @@ -211,7 +242,7 @@ setbgcolor() { if bool_true "$tput_avail"; then tput setab "$1" else - printf "\033[0;4%sm" "$1" + printf "\033[48;5;%sm" "$1" fi } resetcolor() { @@ -224,6 +255,10 @@ resetcolor() { printf "\033[0m" fi } +extension() { + len="$(printf "%s" "$1" | sed 's/[^.]*\.[^.]*/./g' | wc -c)" + printf "%s" "$1" | cut -d. -f$(($len+1)) +} mkdir -p "$outdir" run() { converter="$1" @@ -234,41 +269,65 @@ run() { shift reverse="$1" shift + infile_for_id=$(basename $infile) + outfile_for_id=$(basename $outfile) extra_flags_run=() - if [ -n "$reverse" ]; then - extra_flags_run+=( "$reverse" ) + extra_flags_probe=() + if bool_true "$reverse"; then + extra_flags_run+=( "-reverse" ) + else + extra_flags_probe+=( "-reverse" ) fi - setfgcolor 2 + id="convert_${infile_for_id}_${outfile_for_id}" + if [ -n "$reverse" ]; then + id="${id}_reverse" + fi + setfgcolor $WHITE 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 - setfgcolor 8 + setfgcolor $GRAY tests=$(($tests+1)) "$converter" -in "$infile" -out "$outfile" "${extra_flags_run[@]}" "$@" if [ $? -ne 0 ]; then setfgcolor 1 - printf "Test failed.\n" + printf "Test $id failed.\n" resetcolor failed=$(($failed+1)) + failed_ids+=($id) else + setfgcolor $GREEN + printf "Test $id succeeded!\n" + resetcolor succeeded=$(($succeeded+1)) fi resetcolor if [ $enable_probe -ne 0 ]; then - setfgcolor 2 + id="probe_${outfile_for_id}" + if [ -z "$reverse" ]; then + id="${id}_pc" + fi + setfgcolor $BLUE bold + printf "Running test %s\n" "$id" printf "Probing %s...\n" "$outfile" resetcolor - setfgcolor 8 - "$converter" -in "$outfile" -probe "${extra_flags_run[@]}" + setfgcolor $GRAY + printf "Command: %s\n" "$converter -in $infile -probe ${extra_flags_probe[*]}" + "$converter" -in "$outfile" -probe "${extra_flags_probe[@]}" resetcolor tests=$(($tests+1)) if [ $? -ne 0 ]; then - setfgcolor 1 - printf "Test failed.\n" + setfgcolor $RED + printf "Test $id failed.\n" resetcolor failed=$(($failed+1)) + failed_ids+=($id) else + setfgcolor $GREEN + printf "Test $id succeeded!\n" + resetcolor succeeded=$(($succeeded+1)) fi fi @@ -280,11 +339,14 @@ for img in "${images[@]}"; do for palette in "${palettes[@]}"; do width="$(echo -n "$size" | cut -dx -f1)" height="$(echo -n "$size" | cut -dx -f2)" - name="$(basename "$img" | sed 's/\.png$//' | sed 's/\.jpg$//' | sed 's/\.jpeg$//')" - name="$(printf "%s.%sP.%sB" "$name" "$width" "$bpp")" + ext="$(extension "$img")" + 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=() if [ -n "$palette" ]; then extraflags+=( "-palette-file" "$palette" ) + name+=".PL-$(basename -s ".$(extension "$palette")" "$palette" | tr '[:lower:]' '[:upper]')" fi if [ -n "$compressflag" ]; then if [ $enable_compression -eq 0 ]; then @@ -293,14 +355,14 @@ for img in "${images[@]}"; do extraflags+=( "$compressflag" ) name+=".C" fi - run "$converter" "$img" "$outdir/$name.BMX" "" "${extraflags[@]}" "" -bpp "$bpp" -resize "$width" "$height" -border 15 0 15 -debug "$debug_flags" - if [ $enable_dither -ne 0 ]; 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.BMX" false "${extraflags[@]}" -bpp "$bpp" -resize "$width" "$height" -border 15 0 15 -debug "$debug_flags" + if bool_true $enable_dither; then + run "$converter" "$img" "$outdir/$name.D.BMX" false "${extraflags[@]}" -bpp "$bpp" -resize "$width" "$height" -dither -border 15 0 15 -debug "$debug_flags" fi - if [ $enable_reverse -ne 0 ]; then - run "$converter" "$outdir/$name.BMX" "$outdir/$name.PNG" -reverse "${extraflags[@]}" -resize "$width" "$height" -debug "$debug_flags" - if [ $enable_dither -ne 0 ]; then - run "$converter" "$outdir/$name.D.BMX" "$outdir/$name.D.PNG" -reverse "${extraflags[@]}" -resize "$width" "$height" -dither -debug "$debug_flags" + if bool_true $enable_reverse; then + run "$converter" "$outdir/$name.BMX" "$reversedir/$name.PNG" true "${extraflags[@]}" -resize "$width" "$height" -debug "$debug_flags" + if bool_true $enable_dither; then + run "$converter" "$outdir/$name.D.BMX" "$reversedir/$name.D.PNG" true "${extraflags[@]}" -resize "$width" "$height" -dither -debug "$debug_flags" fi fi done @@ -308,5 +370,52 @@ for img in "${images[@]}"; do 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"