From 112ae49145da644f0e6a682d5e45be23cfd3d44b Mon Sep 17 00:00:00 2001 From: Ian C Date: Mon, 28 Nov 2016 16:00:48 +0000 Subject: Initial seemingly working version. --- doc/README.txt | 51 +++++++++++ png8.c | 275 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++- test/1.png | Bin 0 -> 196 bytes test/4.png | Bin 0 -> 196 bytes 4 files changed, 323 insertions(+), 3 deletions(-) create mode 100755 doc/README.txt create mode 100755 test/1.png create mode 100755 test/4.png diff --git a/doc/README.txt b/doc/README.txt new file mode 100755 index 0000000..0de321f --- /dev/null +++ b/doc/README.txt @@ -0,0 +1,51 @@ + PNG8 + ==== + +This program is distributed in the hope that it will be useful, +but WITHOUT ANY WARRANTY; without even the implied warranty of +MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +GNU General Public License (Version 3) for more details. + +Usage: +------ + +png8 -- convert a file + + +Options +------- + +General switches: +-h - Help text. + +One of these switches must be provided: +-1 - Produce a monochrome sprite data set (e.g. Spectrum). +-4 - Produce a 4-colour sprite data set (e.g. Commodore 64). + +Optional switches: +-b - Don't treat black the same as a transparent pixel. +-p - Use in place of 'byte' for output. +-s - For monochrome data, produce pre-shifted values. +-w - Set the sprite width to . This must be a multiple of 8. +-d - Don't use double-width pixels in 4 colour mode. +-c0 - Set colour 0 to RGB value RRGGBB, expressed as a hex number. +-c1 - Set colour 1 to RGB value RRGGBB, expressed as a hex number. +-c2 - Set colour 2 to RGB value RRGGBB, expressed as a hex number. +-c3 - Set colour 3 to RGB value RRGGBB, expressed as a hex number. + +Instructions +------------ + +PNG8 processes a sprite image strip and produces output that should be +compatible with most 8-bit assemblers. + +For monochrome images it produces 1-bit per pixel output, where any pixel that +is transparent or black (by default; this can be disabled with the -b switch) +is treated as a clear bit in the generated output. Other pixels are treated as +a set bit. + +For 4-colour images it generates bit patterns "00" for colour 0 (default black), +"01" for colour 1 (default red), "10" for colour 2 (default green) and "11" for +colour 3 (default blue). + +The colours used can be controlled by the switches -c0 to -c3. diff --git a/png8.c b/png8.c index 6022562..6db1769 100755 --- a/png8.c +++ b/png8.c @@ -41,7 +41,8 @@ #define FALSE (0) #endif -#define IS_BLACK(ul) (((ul) && 0x00FFFFFFul) == 0) +#define COLOUR(ul) ((ul) & 0x00FFFFFFul) +#define IS_BLACK(ul) (COLOUR(ul) == 0) #define IS_TRANS(ul) (((ul) && 0xFF000000ul) == 0) @@ -92,9 +93,15 @@ static void Help(void) "-1 - Produce a monochrome sprite data set (e.g. Spectrum).\n" "-4 - Produce a 4-colour sprite data set (e.g. Commodore 64).\n" "\nOptional switches:\n" -"-s - Treat black the same as a transparent pixel.\n" +"-b - Don't treat black the same as a transparent pixel.\n" "-p - Use in place of 'byte' for output.\n" -"-i - For monochrome data, produce pre-shifted values.\n" +"-s - For monochrome data, produce pre-shifted values.\n" +"-w - Set the sprite width to . This must be a multiple of 8.\n" +"-d - Don't use double-width pixels in 4 colour mode.\n" +"-c0 - Set colour 0 to RGB value RRGGBB, expressed as a hex number.\n" +"-c1 - Set colour 1 to RGB value RRGGBB, expressed as a hex number.\n" +"-c2 - Set colour 2 to RGB value RRGGBB, expressed as a hex number.\n" +"-c3 - Set colour 3 to RGB value RRGGBB, expressed as a hex number.\n" ""; fprintf(stderr,"%s\n", help); @@ -116,6 +123,18 @@ static void Exit(const char *fmt, ...) } +static void Warning(const char *fmt, ...) +{ + va_list va; + + fprintf(stderr, "WARNING: "); + + va_start(va, fmt); + vfprintf(stderr, fmt, va); + va_end(va); +} + + static void *Malloc(size_t size) { void *p = malloc(size); @@ -138,6 +157,84 @@ static ulong RGBA(png_byte r, png_byte g, png_byte b, png_byte a) } +static void PrintSpriteData(const char *opcode, + ulong sprite_data[], + int max, + int pre_shift) +{ + int f; + + printf("\t%s ", opcode); + + for(f = 0; f < max; f++) + { + if (f) + { + printf(","); + } + + printf("%lu", sprite_data[f]); + } + + if (pre_shift) + { + printf(",0"); + } + + printf("\n"); +} + + +static void PrintSpriteDataShifted(const char *opcode, + ulong sprite_data[], + int max) +{ + int s; + int f; + ulong data[8][5] = {0}; + + for(s = 1; s < 8; s++) + { + for(f = 0; f <= max; f++) + { + if (f == max) + { + data[s][f] = (sprite_data[f-1] << (8 - s)) & 0xff; + } + else if (f) + { + data[s][f] = + ((sprite_data[f] >> s) | (sprite_data[f-1] << (8 - s))) + & 0xff; + } + else + { + data[s][f] = sprite_data[f] >> s; + } + } + } + + max++; + + for(s = 1; s < 8; s++) + { + printf("\t%s ", opcode); + + for(f = 0; f < max; f++) + { + if (f) + { + printf(","); + } + + printf("%lu", data[s][f]); + } + + printf("\n"); + } +} + + /* ---------------------------------------- MAIN */ int main(int argc, char *argv[]) @@ -151,6 +248,11 @@ int main(int argc, char *argv[]) const char *opcode = "byte"; output_type_t output = OUTPUT_Undefined; int pre_shift = FALSE; + int use_black = TRUE; + int sprite_width = 8; + int pix_per_byte = 8; + int step = 1; + ulong col[4] = {0, 0xff0000ul, 0x00ff00ul, 0x0000fful}; int f; FILE *fp; char header[8]; @@ -171,6 +273,74 @@ int main(int argc, char *argv[]) case '4': output = OUTPUT_4Col; + sprite_width = 24; + step = 2; + pix_per_byte = 4; + pre_shift = FALSE; + break; + + case 'b': + use_black = FALSE; + break; + + case 's': + if (output != OUTPUT_4Col) + { + pre_shift = TRUE; + } + break; + + case 'd': + step = 1; + break; + + case 'c': + { + int c = argv[f][2] - '0'; + + if (argv[++f] && c >= 0 && c <= 3) + { + col[c] = strtoul(argv[f], NULL, 16); + } + else + { + Usage(); + } + + break; + } + + case 'p': + if (argv[++f]) + { + opcode = argv[f]; + } + else + { + Usage(); + } + break; + + case 'w': + if (argv[++f]) + { + sprite_width = atoi(argv[f]); + + if (sprite_width % 8) + { + Exit("Sprite width must be a multiple of 8.\n"); + } + + if (sprite_width < 8 || sprite_width > 32) + { + Exit("Sprite width mustn't be greater than " + "32 or less than 8.\n"); + } + } + else + { + Usage(); + } break; default: @@ -224,6 +394,22 @@ int main(int argc, char *argv[]) colour_depth = png_get_bit_depth(png, png_info); num_passes = png_set_interlace_handling(png); + if (width < sprite_width * step) + { + Exit("Width %d less than sprite width %d\n", width, + sprite_width * step); + } + + if (width % (sprite_width * step)) + { + Warning("Width not a multiple of %d.\n", sprite_width * step); + } + + if (sprite_width > 16 && output == OUTPUT_4Col) + { + Exit("Width must be 16 or less in 4-colour mode.\n"); + } + if (colour_type != PNG_COLOR_TYPE_RGBA) { Exit("PNG must be an RGB image with an alpha channel.\n"); @@ -247,6 +433,89 @@ int main(int argc, char *argv[]) fclose(fp); + for(f = 0; f < width/(sprite_width*step); f++) + { + int x,y; + int bx; + + printf("sprite_%d:\n", f); + + bx = sprite_width * step * f * 4; + + for(y = 0; y < height; y++) + { + ulong sprite_data[4] = {0}; + int i = 0; + + for(x = 0; x < sprite_width; x++) + { + ulong pcol = RGBA(data[y][bx + x * 4 * step + 0], + data[y][bx + x * 4 * step + 1], + data[y][bx + x * 4 * step + 2], + data[y][bx + x * 4 * step + 3]); + + if ((x) && (x % pix_per_byte) == 0) + { + i++; + } + + switch(output) + { + case OUTPUT_Mono: + if (IS_TRANS(pcol) || (use_black && IS_BLACK(pcol))) + { + sprite_data[i] <<= 1ul; + sprite_data[i] |= 0; + } + else + { + sprite_data[i] <<= 1ul; + sprite_data[i] |= 1; + } + break; + + case OUTPUT_4Col: + if (COLOUR(pcol) == col[1]) + { + sprite_data[i] <<= 2ul; + sprite_data[i] |= 0x01; + } + else if (COLOUR(pcol) == col[2]) + { + sprite_data[i] <<= 2ul; + sprite_data[i] |= 0x02; + } + else if (COLOUR(pcol) == col[3]) + { + sprite_data[i] <<= 2ul; + sprite_data[i] |= 0x03; + } + else + { + sprite_data[i] <<= 2ul; + sprite_data[i] |= 0; + } + break; + + default: + break; + } + } + + if ((x) && (x % pix_per_byte) == 0) + { + i++; + } + + PrintSpriteData(opcode, sprite_data, i, pre_shift); + + if (pre_shift) + { + PrintSpriteDataShifted(opcode, sprite_data, i); + } + } + } + for(f = 0; f < height; f++) { free(data[f]); diff --git a/test/1.png b/test/1.png new file mode 100755 index 0000000..ea1dcb3 Binary files /dev/null and b/test/1.png differ diff --git a/test/4.png b/test/4.png new file mode 100755 index 0000000..2ccad08 Binary files /dev/null and b/test/4.png differ -- cgit v1.2.3