Prefer significant_start = 16, improve test, add debug option
This commit is contained in:
parent
57f2d5d96b
commit
6ff4f78680
8 changed files with 191 additions and 63 deletions
9
.vscode/settings.json
vendored
9
.vscode/settings.json
vendored
|
@ -5,6 +5,13 @@
|
||||||
"cstdint": "cpp",
|
"cstdint": "cpp",
|
||||||
"iosfwd": "cpp",
|
"iosfwd": "cpp",
|
||||||
"*.ipp": "cpp",
|
"*.ipp": "cpp",
|
||||||
"ios": "cpp"
|
"ios": "cpp",
|
||||||
|
"chrono": "cpp",
|
||||||
|
"random": "cpp",
|
||||||
|
"limits": "cpp",
|
||||||
|
"semaphore": "cpp",
|
||||||
|
"valarray": "cpp",
|
||||||
|
"ratio": "cpp",
|
||||||
|
"algorithm": "cpp"
|
||||||
}
|
}
|
||||||
}
|
}
|
106
bitmapx16.cpp
106
bitmapx16.cpp
|
@ -1,10 +1,12 @@
|
||||||
#include "bitmapx16.h"
|
#include "bitmapx16.h"
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
#include <fstream>
|
#include <fstream>
|
||||||
|
#include <filesystem>
|
||||||
#include <exception>
|
#include <exception>
|
||||||
|
using namespace std::filesystem;
|
||||||
#define X16_IMG_START (512+32)
|
#define X16_IMG_START (512+32)
|
||||||
BitmapX16DebugFlags BitmapX16::debug = DebugNone;
|
BitmapX16DebugFlags BitmapX16::debug = DebugNone;
|
||||||
float closeness_to_color(PaletteEntry a, PaletteEntry b) {
|
float BitmapX16::closeness_to_color(PaletteEntry a, PaletteEntry b) {
|
||||||
float closeness = ((float)((((float)a.r - (float)b.r) * (1 << 4)) + (((float)a.g - (float)b.g) * (1 << 8)) + ((float)a.b - (float)b.b)));
|
float closeness = ((float)((((float)a.r - (float)b.r) * (1 << 4)) + (((float)a.g - (float)b.g) * (1 << 8)) + ((float)a.b - (float)b.b)));
|
||||||
if (closeness < 0.0f) {
|
if (closeness < 0.0f) {
|
||||||
closeness = -closeness;
|
closeness = -closeness;
|
||||||
|
@ -18,7 +20,7 @@ void BitmapX16::set_bpp(uint8_t bpp) {
|
||||||
set_significant((1 << bpp) - 1);
|
set_significant((1 << bpp) - 1);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t BitmapX16::get_bpp() {
|
uint8_t BitmapX16::get_bpp() const {
|
||||||
return bpp;
|
return bpp;
|
||||||
}
|
}
|
||||||
void BitmapX16::set_significant(uint8_t value) {
|
void BitmapX16::set_significant(uint8_t value) {
|
||||||
|
@ -28,19 +30,19 @@ void BitmapX16::set_significant(uint8_t value) {
|
||||||
significant_count = value;
|
significant_count = value;
|
||||||
quantize_colors = true;
|
quantize_colors = true;
|
||||||
}
|
}
|
||||||
uint8_t BitmapX16::get_significant() {
|
uint8_t BitmapX16::get_significant() const {
|
||||||
return significant_count;
|
return significant_count;
|
||||||
}
|
}
|
||||||
size_t BitmapX16::get_width() {
|
size_t BitmapX16::get_width() const {
|
||||||
return w;
|
return w;
|
||||||
}
|
}
|
||||||
size_t BitmapX16::get_height() {
|
size_t BitmapX16::get_height() const {
|
||||||
return h;
|
return h;
|
||||||
}
|
}
|
||||||
void BitmapX16::enable_dithering(bool enabled) {
|
void BitmapX16::enable_dithering(bool enabled) {
|
||||||
dither = enabled;
|
dither = enabled;
|
||||||
}
|
}
|
||||||
bool BitmapX16::dithering_enabled() {
|
bool BitmapX16::dithering_enabled() const {
|
||||||
return dither;
|
return dither;
|
||||||
}
|
}
|
||||||
void BitmapX16::resize(size_t w, size_t h) {
|
void BitmapX16::resize(size_t w, size_t h) {
|
||||||
|
@ -58,22 +60,18 @@ void BitmapX16::apply() {
|
||||||
th = 0;
|
th = 0;
|
||||||
}
|
}
|
||||||
if (bpp == 0) {
|
if (bpp == 0) {
|
||||||
bpp = 8;
|
set_bpp(8);
|
||||||
quantize_colors = true;
|
|
||||||
}
|
}
|
||||||
if (significant_count == 0) {
|
if (significant_count == 0 || significant_count >= (1 << bpp)) {
|
||||||
significant_count = (1 << bpp) - 1;
|
set_significant((1 << bpp) - 1);
|
||||||
quantize_colors = true;
|
|
||||||
}
|
}
|
||||||
if (quantize_colors) {
|
image->quantizeColors(significant_count);
|
||||||
image->quantizeColors(significant_count);
|
image->quantizeDither(dither);
|
||||||
image->quantizeDither(dither);
|
if (dither) {
|
||||||
if (dither) {
|
image->quantizeDitherMethod(Magick::FloydSteinbergDitherMethod);
|
||||||
image->quantizeDitherMethod(Magick::FloydSteinbergDitherMethod);
|
|
||||||
}
|
|
||||||
image->quantize();
|
|
||||||
generate_palette();
|
|
||||||
}
|
}
|
||||||
|
image->quantize();
|
||||||
|
generate_palette();
|
||||||
}
|
}
|
||||||
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;
|
||||||
|
@ -157,7 +155,15 @@ void BitmapX16::load_x16(const char *filename) {
|
||||||
vector<uint8_t> pixels;
|
vector<uint8_t> pixels;
|
||||||
bufsize = 3;
|
bufsize = 3;
|
||||||
buf.resize(bufsize);
|
buf.resize(bufsize);
|
||||||
|
if (!exists(filename)) {
|
||||||
|
printf("File not found!\n");
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
std::ifstream infile(filename, std::ifstream::binary);
|
std::ifstream infile(filename, std::ifstream::binary);
|
||||||
|
if (infile.bad()) {
|
||||||
|
printf("Failed to open file!\n");
|
||||||
|
throw std::exception();
|
||||||
|
}
|
||||||
infile.read((char*)buf.data() + bufpos, bufsize - bufpos);
|
infile.read((char*)buf.data() + bufpos, bufsize - bufpos);
|
||||||
bufpos += bufsize - bufpos;
|
bufpos += bufsize - bufpos;
|
||||||
uint8_t magic[3] = {0x42, 0x4D, 0x58};
|
uint8_t magic[3] = {0x42, 0x4D, 0x58};
|
||||||
|
@ -176,7 +182,7 @@ void BitmapX16::load_x16(const char *filename) {
|
||||||
throw std::exception();
|
throw std::exception();
|
||||||
}
|
}
|
||||||
bpp = buf[4];
|
bpp = buf[4];
|
||||||
uint8_t vera_color_depth = buf[5]; // Ignore for now.
|
/*uint8_t vera_color_depth = buf[5];*/ // Ignore for now.
|
||||||
pixels_per_byte = (8 / bpp);
|
pixels_per_byte = (8 / bpp);
|
||||||
w = buf[6] | (buf[7] << 8);
|
w = buf[6] | (buf[7] << 8);
|
||||||
h = buf[8] | (buf[9] << 8);
|
h = buf[8] | (buf[9] << 8);
|
||||||
|
@ -192,7 +198,7 @@ void BitmapX16::load_x16(const char *filename) {
|
||||||
bufpos += bufsize - bufpos;
|
bufpos += bufsize - bufpos;
|
||||||
|
|
||||||
for (size_t i = 0; i < 256; i++) {
|
for (size_t i = 0; i < 256; i++) {
|
||||||
palette[i] = PaletteEntry(buf.data() + (32+(i*2)));
|
palette[(uint8_t)(i-significant_start)] = PaletteEntry(buf.data() + (32+(i*2)));
|
||||||
}
|
}
|
||||||
// Border is always an extra palette entry.
|
// Border is always an extra palette entry.
|
||||||
extra_palette_entries.push_back(palette[border]);
|
extra_palette_entries.push_back(palette[border]);
|
||||||
|
@ -232,6 +238,13 @@ void BitmapX16::write_pc(const char *filename) {
|
||||||
}
|
}
|
||||||
image->write(filename);
|
image->write(filename);
|
||||||
}
|
}
|
||||||
|
PaletteEntry BitmapX16::get_palette_entry(uint8_t idx, bool extra) const {
|
||||||
|
if (extra) {
|
||||||
|
return extra_palette_entries.at(idx);
|
||||||
|
} else {
|
||||||
|
return palette[idx];
|
||||||
|
}
|
||||||
|
}
|
||||||
void BitmapX16::load_pc(const char *filename) {
|
void BitmapX16::load_pc(const char *filename) {
|
||||||
image = new Image(filename);
|
image = new Image(filename);
|
||||||
w = image->columns();
|
w = image->columns();
|
||||||
|
@ -265,7 +278,6 @@ BitmapX16::BitmapX16() {
|
||||||
}
|
}
|
||||||
void BitmapX16::generate_palette() {
|
void BitmapX16::generate_palette() {
|
||||||
uint16_t max = (uint16_t)image->colorMapSize();
|
uint16_t max = (uint16_t)image->colorMapSize();
|
||||||
uint8_t color[3];
|
|
||||||
if (max > 256) max = 256;
|
if (max > 256) max = 256;
|
||||||
if (bpp == 0) {
|
if (bpp == 0) {
|
||||||
if (max <= 4) {
|
if (max <= 4) {
|
||||||
|
@ -276,25 +288,36 @@ void BitmapX16::generate_palette() {
|
||||||
bpp = 8;
|
bpp = 8;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
size_t min = 256 - (1 << bpp);
|
||||||
|
if (min >= 16) {
|
||||||
|
significant_start = 16;
|
||||||
|
}
|
||||||
if (significant_count == 0) {
|
if (significant_count == 0) {
|
||||||
significant_count = max;
|
significant_count = max;
|
||||||
}
|
}
|
||||||
bitmask = (1 << bpp) - 1;
|
bitmask = (1 << bpp) - 1;
|
||||||
for (uint16_t i = 0; i < max; i++) {
|
for (uint16_t i = 0; i < significant_start; i++) {
|
||||||
ColorRGB map_color = image->colorMap(i);
|
palette[i] = PaletteEntry();
|
||||||
|
}
|
||||||
|
for (uint16_t i = significant_start; i < max+significant_start; i++) {
|
||||||
|
ColorRGB map_color = image->colorMap(i-significant_start);
|
||||||
palette[i] = PaletteEntry(map_color);
|
palette[i] = PaletteEntry(map_color);
|
||||||
}
|
}
|
||||||
image_palette_count = max;
|
image_palette_count = max;
|
||||||
for (uint16_t i = max; i < 256; i++) {
|
for (uint16_t i = max+significant_start; i < 256; i++) {
|
||||||
if ((uint16_t)extra_palette_entries.size() > i - max) {
|
if ((uint16_t)extra_palette_entries.size() > i - (max+significant_start)) {
|
||||||
palette[i] = extra_palette_entries[i - max];
|
palette[i] = extra_palette_entries[i - (max+significant_start)];
|
||||||
} else {
|
} else {
|
||||||
palette[i] = PaletteEntry();
|
palette[i] = PaletteEntry();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return;
|
if (debug & DebugShowPalette) {
|
||||||
for (uint16_t i = 0; i < max; i++) {
|
for (size_t i = 0; i < 256; i++) {
|
||||||
printf("pallete[%u] = #%02x%02x%02x\n", i, palette[i].r, palette[i].g, palette[i].b);
|
uint8_t significant_end = significant_start+significant_count;
|
||||||
|
bool significant = i >= significant_start && i < significant_end;
|
||||||
|
bool extra = i >= significant_end && i < significant_end+extra_palette_entries.size();
|
||||||
|
printf("palette[%02x] = %s %s\n", (uint16_t)i, palette[i].to_string().c_str(), significant ? "(Significant)" : extra ? "(Extra)" : "");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t BitmapX16::add_palette_entry(PaletteEntry entry) {
|
uint8_t BitmapX16::add_palette_entry(PaletteEntry entry) {
|
||||||
|
@ -305,7 +328,10 @@ uint8_t BitmapX16::color_to_palette_entry(const ColorRGB &rgb) {
|
||||||
PaletteEntry color(rgb);
|
PaletteEntry color(rgb);
|
||||||
float closeness = 100000.0f;
|
float closeness = 100000.0f;
|
||||||
uint8_t output;
|
uint8_t output;
|
||||||
for (size_t i = 0; i < significant_count; i++) {
|
if (debug & DebugShowCloseness) {
|
||||||
|
printf("Closest color for %s: ", color.to_string().c_str());
|
||||||
|
}
|
||||||
|
for (size_t i = significant_start; i < significant_count+significant_start; i++) {
|
||||||
float possibility_closeness = closeness_to_color(palette[i], color);
|
float possibility_closeness = closeness_to_color(palette[i], color);
|
||||||
//printf("Closeness: %f", possibility_closeness);
|
//printf("Closeness: %f", possibility_closeness);
|
||||||
if (possibility_closeness < closeness) {
|
if (possibility_closeness < closeness) {
|
||||||
|
@ -313,16 +339,32 @@ uint8_t BitmapX16::color_to_palette_entry(const ColorRGB &rgb) {
|
||||||
closeness = possibility_closeness;
|
closeness = possibility_closeness;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
if (debug & DebugShowCloseness) {
|
||||||
|
PaletteEntry output_entry = palette[output];
|
||||||
|
printf("%s\n", output_entry.to_string().c_str());
|
||||||
|
}
|
||||||
//PaletteEntry entry = palette[output];
|
//PaletteEntry entry = palette[output];
|
||||||
//printf("Color: #%0x%0x%0x -> Palette entry#%0x%0x%0x, closeness: %f\n", color.r, color.g, color.b , entry.r, entry.g, entry.b, closeness);
|
//printf("Color: #%0x%0x%0x -> Palette entry#%0x%0x%0x, closeness: %f\n", color.r, color.g, color.b , entry.r, entry.g, entry.b, closeness);
|
||||||
return output;
|
return output;
|
||||||
}
|
}
|
||||||
|
void BitmapX16::set_debug_flag(BitmapX16DebugFlags flag, bool enabled) {
|
||||||
|
int value = (int)debug;
|
||||||
|
if (enabled) {
|
||||||
|
value |= (int)flag;
|
||||||
|
} else {
|
||||||
|
value &= ~(int)flag;
|
||||||
|
}
|
||||||
|
debug = (BitmapX16DebugFlags)value;
|
||||||
|
}
|
||||||
BitmapX16::~BitmapX16() {
|
BitmapX16::~BitmapX16() {
|
||||||
if (image != nullptr) {
|
if (image != nullptr) {
|
||||||
delete image;
|
delete image;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
uint8_t BitmapX16::get_border_color() {
|
uint8_t BitmapX16::get_significant_start() const {
|
||||||
|
return significant_start;
|
||||||
|
}
|
||||||
|
uint8_t BitmapX16::get_border_color() const {
|
||||||
return border;
|
return border;
|
||||||
}
|
}
|
||||||
void BitmapX16::set_border_color(uint8_t idx) {
|
void BitmapX16::set_border_color(uint8_t idx) {
|
||||||
|
|
26
bitmapx16.h
26
bitmapx16.h
|
@ -4,9 +4,10 @@
|
||||||
#include "palette.h"
|
#include "palette.h"
|
||||||
using namespace Magick;
|
using namespace Magick;
|
||||||
using std::vector;
|
using std::vector;
|
||||||
enum BitmapX16DebugFlags {
|
enum BitmapX16DebugFlags : int {
|
||||||
DebugNone = 0,
|
DebugNone = 0,
|
||||||
DebugShowPalette = (1 << 0),
|
DebugShowPalette = (1 << 0),
|
||||||
|
DebugShowCloseness = (1 << 1)
|
||||||
};
|
};
|
||||||
class BitmapX16 {
|
class BitmapX16 {
|
||||||
/// \brief Bits per pixel of the image
|
/// \brief Bits per pixel of the image
|
||||||
|
@ -75,45 +76,54 @@ class BitmapX16 {
|
||||||
/// \returns The palette entry index
|
/// \returns The palette entry index
|
||||||
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);
|
||||||
public:
|
public:
|
||||||
/// \brief Sets the border color extra palette entry.
|
/// \brief Sets the border color extra palette entry.
|
||||||
/// \param idx The index of the palette entry, must be an index into the extra palette entry list.
|
/// \param idx The index of the palette entry, must be an index into the extra palette entry list.
|
||||||
void set_border_color(uint8_t idx);
|
void set_border_color(uint8_t idx);
|
||||||
/// \brief Gets the current extra palette entry of the border color
|
/// \brief Gets the current extra palette entry of the border color
|
||||||
/// \returns The border color palette entry from the extra palette entry list
|
/// \returns The border color palette entry from the extra palette entry list
|
||||||
uint8_t get_border_color();
|
uint8_t get_border_color() const;
|
||||||
/// \brief Adds an entry to the list of extra palette entries. Not guaranteed to continue existing after a new palette entry has been added.
|
/// \brief Adds an entry to the list of extra palette entries. Not guaranteed to continue existing after a new palette entry has been added.
|
||||||
/// \param entry The new entry to add
|
/// \param entry The new entry to add
|
||||||
/// \returns The palette index within the extra palette entries of the new entry
|
/// \returns The palette index within the extra palette entries of the new entry
|
||||||
uint8_t add_palette_entry(PaletteEntry entry);
|
uint8_t add_palette_entry(PaletteEntry entry);
|
||||||
|
/// \brief Obtains a palette entry within the image
|
||||||
|
/// \param id The index of the palette entry
|
||||||
|
/// \param extra Set to true for an extra palette entry, false for a normal palette entry.
|
||||||
|
/// \returns The palette entry requested.
|
||||||
|
PaletteEntry get_palette_entry(uint8_t id, bool extra) const;
|
||||||
/// \brief Sets the bits per pixel of the image
|
/// \brief Sets the bits per pixel of the image
|
||||||
/// \param bpp The bits per pixel of the image, one of 1, 2, 4, or 8
|
/// \param bpp The bits per pixel of the image, one of 1, 2, 4, or 8
|
||||||
void set_bpp(uint8_t bpp);
|
void set_bpp(uint8_t bpp);
|
||||||
/// \brief Returns the bits per pixel of the image
|
/// \brief Returns the bits per pixel of the image
|
||||||
/// \returns The bits per pixel of the image, one of 1, 2, 4, or 8
|
/// \returns The bits per pixel of the image, one of 1, 2, 4, or 8
|
||||||
uint8_t get_bpp();
|
uint8_t get_bpp() const;
|
||||||
/// \brief Sets the maximum amount of colors to be used.
|
/// \brief Sets the maximum amount of colors to be used.
|
||||||
/// \param value The maximum amount of colors to use.
|
/// \param value The maximum amount of colors to use.
|
||||||
void set_significant(uint8_t value);
|
void set_significant(uint8_t value);
|
||||||
/// \brief Returns the maximum amount of colors to be used
|
/// \brief Returns the maximum amount of colors to be used
|
||||||
/// \returns The maximum amount of colors once written
|
/// \returns The maximum amount of colors once written
|
||||||
uint8_t get_significant();
|
uint8_t get_significant() const;
|
||||||
|
/// \brief Gets the beginning index of the significant palette entries.
|
||||||
|
/// \returns The start index of significant palette entries.
|
||||||
|
uint8_t get_significant_start() const;
|
||||||
/// \brief Queues a resize operation. Call BitmapX16::apply() to apply
|
/// \brief Queues a resize operation. Call BitmapX16::apply() to apply
|
||||||
/// \param w The width to resize to
|
/// \param w The width to resize to
|
||||||
/// \param h The height to resize to
|
/// \param h The height to resize to
|
||||||
void queue_resize(size_t w, size_t h);
|
void queue_resize(size_t w, size_t h);
|
||||||
/// \brief Gets the width of the image
|
/// \brief Gets the width of the image
|
||||||
/// \returns The width of the image
|
/// \returns The width of the image
|
||||||
size_t get_width();
|
size_t get_width() const;
|
||||||
/// \brief Gets the height of the image
|
/// \brief Gets the height of the image
|
||||||
/// \returns The height of the image
|
/// \returns The height of the image
|
||||||
size_t get_height();
|
size_t get_height() const;
|
||||||
/// \brief Enables or disables dithering
|
/// \brief Enables or disables dithering
|
||||||
/// \param enabled Pass true to enable, false to disable
|
/// \param enabled Pass true to enable, false to disable
|
||||||
void enable_dithering(bool enabled);
|
void enable_dithering(bool enabled);
|
||||||
/// \brief Returns the status of the dithering flag
|
/// \brief Returns the status of the dithering flag
|
||||||
/// \returns The value of the dithering flag
|
/// \returns The value of the dithering flag
|
||||||
bool dithering_enabled();
|
bool dithering_enabled() const;
|
||||||
/// \brief Applies queued operations to the internal representation of the image
|
/// \brief Applies queued operations to the internal representation of the image
|
||||||
void apply();
|
void apply();
|
||||||
/// \brief Applies queued operations and writes the image to a PC-compatible file
|
/// \brief Applies queued operations and writes the image to a PC-compatible file
|
||||||
|
@ -128,7 +138,7 @@ class BitmapX16 {
|
||||||
/// \brief Loads a Commander X16-compatible image file
|
/// \brief Loads a Commander X16-compatible image file
|
||||||
/// \param filename The path to the file to load
|
/// \param filename The path to the file to load
|
||||||
void load_x16(const char *filename);
|
void load_x16(const char *filename);
|
||||||
|
static void set_debug_flag(BitmapX16DebugFlags flag, bool enabled = true);
|
||||||
/// \brief The debug flags to use.
|
/// \brief The debug flags to use.
|
||||||
static BitmapX16DebugFlags debug;
|
static BitmapX16DebugFlags debug;
|
||||||
/// \brief Constructs an unloaded X16-compatible bitmap image. Call load_pc or load_x16 before using any other functions.
|
/// \brief Constructs an unloaded X16-compatible bitmap image. Call load_pc or load_x16 before using any other functions.
|
||||||
|
|
56
main.cpp
56
main.cpp
|
@ -31,6 +31,10 @@ void usage() {
|
||||||
printf("\tIf possible, adds a border color with the specified RGB values which are in the range of 0-15.\n");
|
printf("\tIf possible, adds a border color with the specified RGB values which are in the range of 0-15.\n");
|
||||||
printf("-reverse\n");
|
printf("-reverse\n");
|
||||||
printf("\tConverts to PC formats. Incompatible with -dither, -type, and -significant - they will be ignored.\n");
|
printf("\tConverts to PC formats. Incompatible with -dither, -type, and -significant - they will be ignored.\n");
|
||||||
|
printf("-debug <flags>\n");
|
||||||
|
printf("\tEnables debugging flags. May contain any number of single-letter debugging flags.\n");
|
||||||
|
printf("\tFlags: p = show palette entry, c = show palette closeness lookups\n");
|
||||||
|
printf("\tUse an ! before a flag to disable it.\n");
|
||||||
printf("-help\n");
|
printf("-help\n");
|
||||||
printf("\tDisplays this help message.\n");
|
printf("\tDisplays this help message.\n");
|
||||||
exit(1);
|
exit(1);
|
||||||
|
@ -40,6 +44,7 @@ int main(int argc, char **argv) {
|
||||||
size_t tw = 0, th = 0; // Target width & height;
|
size_t tw = 0, th = 0; // Target width & height;
|
||||||
uint8_t tbpp = 0;
|
uint8_t tbpp = 0;
|
||||||
uint16_t tcolorcount = 0;
|
uint16_t tcolorcount = 0;
|
||||||
|
const char *error_msg_part = "load the image";
|
||||||
bool dither = false;
|
bool dither = false;
|
||||||
bool reverse = false;
|
bool reverse = false;
|
||||||
uint8_t br, bg, bb;
|
uint8_t br, bg, bb;
|
||||||
|
@ -177,6 +182,35 @@ int main(int argc, char **argv) {
|
||||||
argv++;
|
argv++;
|
||||||
} else if (!strcmp(argv[0], "-help")) {
|
} else if (!strcmp(argv[0], "-help")) {
|
||||||
usage();
|
usage();
|
||||||
|
} else if (!strcmp(argv[0], "-debug")) {
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
|
if (!argc || argv[0][0] == '-') {
|
||||||
|
usage();
|
||||||
|
}
|
||||||
|
bool flag_enable = true;
|
||||||
|
for (size_t i = 0; i < strlen(argv[0]); i++) {
|
||||||
|
switch (argv[0][i]) {
|
||||||
|
case '!': {
|
||||||
|
flag_enable = false;
|
||||||
|
} break;
|
||||||
|
case 'p': {
|
||||||
|
BitmapX16::set_debug_flag(DebugShowPalette, flag_enable);
|
||||||
|
} break;
|
||||||
|
case 'c': {
|
||||||
|
BitmapX16::set_debug_flag(DebugShowCloseness, flag_enable);
|
||||||
|
} break;
|
||||||
|
default: {
|
||||||
|
printf("Error: Invalid debugging flag.\n");
|
||||||
|
usage();
|
||||||
|
} break;
|
||||||
|
}
|
||||||
|
if (argv[0][i] != '!') {
|
||||||
|
flag_enable = true;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
argc--;
|
||||||
|
argv++;
|
||||||
} else {
|
} else {
|
||||||
printf("Error: Invalid command line argument.\n");
|
printf("Error: Invalid command line argument.\n");
|
||||||
usage();
|
usage();
|
||||||
|
@ -191,19 +225,27 @@ int main(int argc, char **argv) {
|
||||||
try {
|
try {
|
||||||
BitmapX16 bitmap;
|
BitmapX16 bitmap;
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
printf("Converting %s to a PC format...\n", input);
|
printf("Loading X16 bitmap file '%s' to be convertedto a PC format...\n", input);
|
||||||
bitmap.load_x16(input);
|
bitmap.load_x16(input);
|
||||||
|
printf("Image has %u significant colors starting at %u and is %u bpp\n", bitmap.get_significant(), bitmap.get_significant_start(), bitmap.get_bpp());
|
||||||
|
PaletteEntry border = bitmap.get_palette_entry(bitmap.get_border_color(), true);
|
||||||
|
printf("Border color: %s\n", border.to_string().c_str());
|
||||||
} else {
|
} else {
|
||||||
printf("Using at most %u colors at %u bpp\n", tcolorcount, tbpp);
|
printf("Loading PC image file '%s' to be converted to the X16 bitmap format...\n", input);
|
||||||
printf("Converting %s to BMX16...\n", input);
|
printf("Using at most %u colors (excluding border color) at %u bpp\n", tcolorcount, tbpp);
|
||||||
bitmap.load_pc(input);
|
bitmap.load_pc(input);
|
||||||
}
|
}
|
||||||
if (tw != 0 && th != 0) {
|
if (tw != 0 && th != 0) {
|
||||||
|
error_msg_part = "resize the image";
|
||||||
bitmap.queue_resize(tw, th);
|
bitmap.queue_resize(tw, th);
|
||||||
}
|
}
|
||||||
if (reverse) {
|
if (reverse) {
|
||||||
|
error_msg_part = "write the file";
|
||||||
|
printf("Writing PC image file...\n");
|
||||||
bitmap.write_pc(output);
|
bitmap.write_pc(output);
|
||||||
} else {
|
} else {
|
||||||
|
error_msg_part = "apply the settings";
|
||||||
|
printf("Applying settings...\n");
|
||||||
bitmap.enable_dithering(dither);
|
bitmap.enable_dithering(dither);
|
||||||
bitmap.set_bpp(tbpp);
|
bitmap.set_bpp(tbpp);
|
||||||
bitmap.set_significant(tcolorcount);
|
bitmap.set_significant(tcolorcount);
|
||||||
|
@ -212,10 +254,16 @@ int main(int argc, char **argv) {
|
||||||
bitmap.set_border_color(bitmap.add_palette_entry(entry));
|
bitmap.set_border_color(bitmap.add_palette_entry(entry));
|
||||||
}
|
}
|
||||||
bitmap.apply();
|
bitmap.apply();
|
||||||
|
uint8_t significant_start = bitmap.get_significant_start();
|
||||||
|
uint8_t significant_count = bitmap.get_significant();
|
||||||
|
uint8_t significant_end = significant_start + significant_count;
|
||||||
|
printf("Significant colors start at %u and end at %u (%u entries)\n", significant_start, significant_end, significant_count);
|
||||||
|
printf("Writing X16 bitmap file...\n");
|
||||||
|
error_msg_part = "write the file";
|
||||||
bitmap.write_x16(output);
|
bitmap.write_x16(output);
|
||||||
}
|
}
|
||||||
} catch (std::exception &e) {
|
} catch (std::exception &e) {
|
||||||
printf("Failed to convert image '%s'!\n", input);
|
printf("Failed to %s!\n", error_msg_part);
|
||||||
}
|
}
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
|
@ -1,7 +1,7 @@
|
||||||
project('graphicsconverter', 'cpp',
|
project('graphicsconverter', 'cpp',
|
||||||
version : '0.1',
|
version : '0.1',
|
||||||
default_options : ['warning_level=3',
|
default_options : ['warning_level=3',
|
||||||
'cpp_std=c++14',
|
'cpp_std=c++17',
|
||||||
'default_library=static'])
|
'default_library=static'])
|
||||||
|
|
||||||
deps = [
|
deps = [
|
||||||
|
|
12
palette.cpp
12
palette.cpp
|
@ -1,15 +1,21 @@
|
||||||
#include "palette.h"
|
#include "palette.h"
|
||||||
ColorRGB PaletteEntry::toColor() {
|
ColorRGB PaletteEntry::toColor() const {
|
||||||
ColorRGB color;
|
ColorRGB color;
|
||||||
color.red(((double)r) / 15.0);
|
color.red(((double)r) / 15.0);
|
||||||
color.green(((double)g) / 15.0);
|
color.green(((double)g) / 15.0);
|
||||||
color.blue(((double)b) / 15.0);
|
color.blue(((double)b) / 15.0);
|
||||||
return color;
|
return color;
|
||||||
}
|
}
|
||||||
void PaletteEntry::write(uint8_t *ptr) {
|
void PaletteEntry::write(uint8_t *ptr) const {
|
||||||
ptr[0] = ((g & 0b1111) << 4) | (b & 0b1111);
|
ptr[0] = ((g & 0b1111) << 4) | (b & 0b1111);
|
||||||
ptr[1] = r;
|
ptr[1] = r;
|
||||||
}
|
}
|
||||||
|
std::string PaletteEntry::to_string() const {
|
||||||
|
char buf[65];
|
||||||
|
snprintf(buf, 64, "#%0x%0x%0x", r, g, b);
|
||||||
|
std::string output(buf);
|
||||||
|
return output;
|
||||||
|
}
|
||||||
PaletteEntry::PaletteEntry(uint8_t *ptr) {
|
PaletteEntry::PaletteEntry(uint8_t *ptr) {
|
||||||
b = (ptr[0] & 0b1111);
|
b = (ptr[0] & 0b1111);
|
||||||
g = ((ptr[0] >> 4) & 0b1111);
|
g = ((ptr[0] >> 4) & 0b1111);
|
||||||
|
@ -25,7 +31,7 @@ PaletteEntry::PaletteEntry(const ColorRGB &rgb) {
|
||||||
g = (uint8_t)((rgb.green()) * 15);
|
g = (uint8_t)((rgb.green()) * 15);
|
||||||
b = (uint8_t)((rgb.blue()) * 15);
|
b = (uint8_t)((rgb.blue()) * 15);
|
||||||
}
|
}
|
||||||
uint16_t PaletteEntry::hash() {
|
uint16_t PaletteEntry::hash() const {
|
||||||
return ((r & 0b1111) << 8) | ((g & 0b1111) << 4) | (b & 0b1111);
|
return ((r & 0b1111) << 8) | ((g & 0b1111) << 4) | (b & 0b1111);
|
||||||
}
|
}
|
||||||
PaletteEntry::PaletteEntry() {
|
PaletteEntry::PaletteEntry() {
|
||||||
|
|
|
@ -1,15 +1,17 @@
|
||||||
#pragma once
|
#pragma once
|
||||||
#include <stdint.h>
|
#include <stdint.h>
|
||||||
#include <Magick++.h>
|
#include <Magick++.h>
|
||||||
|
#include <string>
|
||||||
using namespace Magick;
|
using namespace Magick;
|
||||||
class PaletteEntry {
|
class PaletteEntry {
|
||||||
public:
|
public:
|
||||||
uint8_t r;
|
uint8_t r;
|
||||||
uint8_t g;
|
uint8_t g;
|
||||||
uint8_t b;
|
uint8_t b;
|
||||||
uint16_t hash();
|
uint16_t hash() const;
|
||||||
void write(uint8_t *ptr);
|
void write(uint8_t *ptr) const;
|
||||||
ColorRGB toColor();
|
ColorRGB toColor() const;
|
||||||
|
std::string to_string() const;
|
||||||
PaletteEntry();
|
PaletteEntry();
|
||||||
PaletteEntry(uint8_t *ptr);
|
PaletteEntry(uint8_t *ptr);
|
||||||
PaletteEntry(uint8_t r, uint8_t g, uint8_t b);
|
PaletteEntry(uint8_t r, uint8_t g, uint8_t b);
|
||||||
|
|
33
test.sh
33
test.sh
|
@ -8,12 +8,14 @@ $0 usage:
|
||||||
Adds an image input at the specified path to the image list.
|
Adds an image input at the specified path to the image list.
|
||||||
-b|--output-bpp <bpp>
|
-b|--output-bpp <bpp>
|
||||||
Adds a bitdepth to the list to test with
|
Adds a bitdepth to the list to test with
|
||||||
-r|--resize <width> <height>
|
-r|--resize <width>x<height>
|
||||||
Adds a resize to the list to test with
|
Adds a resize to the list to test with
|
||||||
--no-reverse
|
--no-reverse
|
||||||
Disables reverse operation testing
|
Disables reverse operation testing
|
||||||
--no-dither
|
--no-dither
|
||||||
Disables dithering testing
|
Disables dithering testing
|
||||||
|
-d|--debug
|
||||||
|
Use debug flags with the converter program.
|
||||||
-n|--no-defaults
|
-n|--no-defaults
|
||||||
Disables default settings
|
Disables default settings
|
||||||
EOF
|
EOF
|
||||||
|
@ -24,16 +26,18 @@ cd "$(dirname "$0")"
|
||||||
converter="./builddir/b16converter"
|
converter="./builddir/b16converter"
|
||||||
prebuilt=0
|
prebuilt=0
|
||||||
images=()
|
images=()
|
||||||
bpp=()
|
bpps=()
|
||||||
resize=()
|
resize=()
|
||||||
enable_defaults=1
|
enable_defaults=1
|
||||||
dither=1
|
dither=1
|
||||||
reverse=1
|
reverse=1
|
||||||
enable_reverse=1
|
enable_reverse=1
|
||||||
enable_dither=1
|
enable_dither=1
|
||||||
|
debug_flags=""
|
||||||
outdir="testout"
|
outdir="testout"
|
||||||
OPTIONS=$(getopt -o "hp:i:r::no:" --long "help,use-program:,input-image:,output-bpp:,resize::,no-defaults,output-dir:,no-reverse,no-dither" -- "$@")
|
OPTIONS=$(getopt -o "b:hp:i:r:no:d:" --long "help,use-program:,input-image:,output-bpp:,resize:,no-defaults,output-dir:,debug:,no-reverse,no-dither" -- "$@")
|
||||||
if [ $? != 0 ]; then
|
if [ $? != 0 ]; then
|
||||||
|
echo "Getopt error."
|
||||||
usage
|
usage
|
||||||
fi
|
fi
|
||||||
eval set -- "$OPTIONS"
|
eval set -- "$OPTIONS"
|
||||||
|
@ -60,7 +64,7 @@ while [ -n "$1" ]; do
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
-r|--resize)
|
-r|--resize)
|
||||||
resize+="$2x$3"
|
resize+="$2"
|
||||||
shift 2
|
shift 2
|
||||||
;;
|
;;
|
||||||
-n|--no-defaults)
|
-n|--no-defaults)
|
||||||
|
@ -75,18 +79,23 @@ while [ -n "$1" ]; do
|
||||||
enable_dither=0
|
enable_dither=0
|
||||||
shift
|
shift
|
||||||
;;
|
;;
|
||||||
|
-d|--debug)
|
||||||
|
debug_flags="${debug_flags}$2"
|
||||||
|
shift 2
|
||||||
|
;;
|
||||||
--)
|
--)
|
||||||
shift
|
shift
|
||||||
break
|
break
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
|
echo "Invalid option: $0"
|
||||||
usage
|
usage
|
||||||
;;
|
;;
|
||||||
esac
|
esac
|
||||||
done
|
done
|
||||||
if [ $enable_defaults -ne 0 ]; then
|
if [ $enable_defaults -ne 0 ]; then
|
||||||
images+=("TEST.png" "PACK.png")
|
images+=("TEST.png" "PACK.png")
|
||||||
bpp+=(1 2 4 8)
|
bpps+=(1 2 4 8)
|
||||||
resize+=("8x8" "16x16" "32x32" "64x64" "320x240" "640x480")
|
resize+=("8x8" "16x16" "32x32" "64x64" "320x240" "640x480")
|
||||||
fi
|
fi
|
||||||
if [ $prebuilt -eq 0 ]; then
|
if [ $prebuilt -eq 0 ]; then
|
||||||
|
@ -94,21 +103,25 @@ if [ $prebuilt -eq 0 ]; then
|
||||||
meson compile -C builddir || exit $?
|
meson compile -C builddir || exit $?
|
||||||
fi
|
fi
|
||||||
mkdir -p "$outdir"
|
mkdir -p "$outdir"
|
||||||
|
run() {
|
||||||
|
printf "Running: %s\n" "$*"
|
||||||
|
"$@"
|
||||||
|
}
|
||||||
for img in "${images[@]}"; do
|
for img in "${images[@]}"; do
|
||||||
for bpp in "${bpp[@]}"; do
|
for bpp in "${bpps[@]}"; do
|
||||||
for size in "${resize[@]}"; do
|
for size in "${resize[@]}"; 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$//')"
|
name="$(basename "$img" | sed 's/\.png$//')"
|
||||||
name="$(printf "%s.%sP.%sB" "$name" "$width" "$bpp")"
|
name="$(printf "%s.%sP.%sB" "$name" "$width" "$bpp")"
|
||||||
./builddir/b16converter -in "$img" -out "$outdir/$name.B16" -bpp "$bpp" -resize "$width" "$height" -border 15 0 15
|
run "$converter" -in "$img" -out "$outdir/$name.B16" -bpp "$bpp" -resize "$width" "$height" -border 15 0 15 -debug "$debug_flags"
|
||||||
if [ $enable_dither -ne 0 ]; then
|
if [ $enable_dither -ne 0 ]; then
|
||||||
./builddir/b16converter -in "$img" -out "$outdir/$name.D.B16" -bpp "$bpp" -resize "$width" "$height" -dither -border 15 0 15
|
run "$converter" -in "$img" -out "$outdir/$name.D.B16" -bpp "$bpp" -resize "$width" "$height" -dither -border 15 0 15 -debug "$debug_flags"
|
||||||
fi
|
fi
|
||||||
if [ $enable_reverse -ne 0 ]; then
|
if [ $enable_reverse -ne 0 ]; then
|
||||||
./builddir/b16converter -reverse -in "$outdir/$name.B16" -out "$outdir/$name.PNG" -resize "$width" "$height"
|
run "$converter" -reverse -in "$outdir/$name.B16" -out "$outdir/$name.PNG" -resize "$width" "$height" -debug "$debug_flags"
|
||||||
if [ $enable_dither -ne 0 ]; then
|
if [ $enable_dither -ne 0 ]; then
|
||||||
./builddir/b16converter -reverse -in "$outdir/$name.D.B16" -out "$outdir/$name.D.PNG" -resize "$width" "$height" -dither
|
run "$converter" -reverse -in "$outdir/$name.D.B16" -out "$outdir/$name.D.PNG" -resize "$width" "$height" -dither -debug "$debug_flags"
|
||||||
fi
|
fi
|
||||||
fi
|
fi
|
||||||
done
|
done
|
||||||
|
|
Loading…
Reference in a new issue