summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rwxr-xr-xdoc/README.txt51
-rwxr-xr-xpng8.c275
-rwxr-xr-xtest/1.pngbin0 -> 196 bytes
-rwxr-xr-xtest/4.pngbin0 -> 196 bytes
4 files changed, 323 insertions, 3 deletions
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 <options> <file> -- 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 <text> - Use <text> in place of 'byte' for output.
+-s - For monochrome data, produce pre-shifted values.
+-w <width> - Set the sprite width to <width>. 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 <text> - Use <text> 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 <width> - Set the sprite width to <width>. 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
--- /dev/null
+++ b/test/1.png
Binary files differ
diff --git a/test/4.png b/test/4.png
new file mode 100755
index 0000000..2ccad08
--- /dev/null
+++ b/test/4.png
Binary files differ