second: work on automatic conversion

This commit is contained in:
Vince Weaver 2023-09-30 00:50:37 -04:00
parent d4951f41eb
commit cfe857dff1
5 changed files with 759 additions and 0 deletions

View File

@ -0,0 +1,24 @@
CC = gcc
CFLAGS = -g -Wall -O2
all: box_convert
###
loadpng.o: loadpng.c loadpng.h
$(CC) $(CFLAGS) -c loadpng.c
###
box_convert: box_convert.o loadpng.o
$(CC) $(LFLAGS) -o box_convert box_convert.o loadpng.o -lpng
box_convert.o: box_convert.c loadpng.h
$(CC) $(CFLAGS) -c box_convert.c
###
clean:
rm -f *~ *.o box_convert

View File

@ -0,0 +1,18 @@
frame50 as benchmark:
+ raw binary is 1024 bytes (2048 pixels)
hand-crafted:
+ 25e0 - 24d8 = 264 bytes
todo, compressed:
+ ???
try1: all plots, even zeros
+ 2c2 - 20c2 = 7680 bytes (4 bytes each pixel)
try2: all plots, don't write black pixels
+ 2c2 - 147b = 4537 bytes
try3: only do color if it changes
+ 2c2 - 1137 = 3701 bytes

View File

@ -0,0 +1,179 @@
/* box_convert */
/* Try to automate the loser conversion process */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include "loadpng.h"
int main(int argc, char **argv) {
int row=0;
int col=0;
int pixel;
int i;
unsigned char *image;
int xsize,ysize;
if (argc<1) {
fprintf(stderr,"Usage:\t%s INFILE\n",argv[0]);
exit(-1);
}
if (loadpng(argv[1],&image,&xsize,&ysize,PNG_WHOLETHING)<0) {
fprintf(stderr,"Error loading png!\n");
exit(-1);
}
fprintf(stderr,"Loaded image %d by %d\n",xsize,ysize);
if (ysize!=48) {
fprintf(stderr,"Error! Ysize must be 48!\n");
exit(1);
}
if (xsize==40) {
}
else if (xsize==80) {
}
else {
fprintf(stderr,"Error! Improper xsize %d!\n",xsize);
exit(1);
}
char color_names[16][16]={
"BLACK", /* $00 */
"RED", /* $01 */
"DARK_BLUE", /* $02 */
"MAGENTA", /* $03 */
"GREEN", /* $04 */
"GREY1", /* $05 */
"MEDIUM_BLUE", /* $06 */
"LIGHT_BLUE", /* $07 */
"BROWN", /* $08 */
"ORANGE", /* $09 */
"GREY2", /* $0A */
"PINK", /* $0B */
"LIGHT_GREEN", /* $0C */
"YELLOW", /* $0D */
"AQUA", /* $0E */
"WHITE", /* $0F */
};
/* SET_COLOR = $C0 */
#define ACTION_END 0x0
#define ACTION_CLEAR 0x1
#define ACTION_BOX 0x2
#define ACTION_HLIN 0x3
#define ACTION_VLIN 0x4
#define ACTION_PLOT 0x5
#define ACTION_HLIN_ADD 0x6
#define ACTION_HLIN_ADD_LSAME 0x7
#define ACTION_HLIN_ADD_RSAME 0x8
char action_names[9][16]={
"END","CLEAR","BOX","HLIN","VLIN","PLOT",
"HLIN_ADD","HLIN_ADD_LSAME","HLIN_ADD_RSAME"
};
int color_count[16];
int framebuffer[40][48];
int current_color=0;
struct {
int type;
int color;
int x1,y1,x2,y2;
} primitive_list[4096];
int current_primitive=0;
memset(color_count,0,16*sizeof(int));
for(row=0;row<24;row++) {
for(col=0;col<40;col++) {
pixel=(image[row*40+col]);
color_count[pixel&0xf]++;
color_count[(pixel>>4)&0xf]++;
framebuffer[col][row*2]=pixel&0xf;
framebuffer[col][(row*2)+1]=(pixel>>4)&0xf;
}
}
/* TODO: sort */
printf("; Histogram\n");
for(i=0;i<16;i++) {
printf("; $%02X %s: %d\n",i,color_names[i],color_count[i]);
}
/* Initial Implementation, All Plots */
current_primitive=0;
for(row=0;row<48;row++) {
for(col=0;col<40;col++) {
primitive_list[current_primitive].color=framebuffer[col][row];
primitive_list[current_primitive].x1=col;
primitive_list[current_primitive].y1=row;
primitive_list[current_primitive].type=ACTION_PLOT;
current_primitive++;
}
}
/* Dump results */
for(i=0;i<current_primitive;i++) {
if (primitive_list[i].color==0) continue;
if (current_color!=primitive_list[i].color) {
printf("\t.byte SET_COLOR | %s\n",
color_names[primitive_list[i].color]);
current_color=primitive_list[i].color;
}
switch(primitive_list[i].type) {
case ACTION_END:
break;
case ACTION_CLEAR:
break;
case ACTION_BOX:
break;
case ACTION_HLIN:
break;
case ACTION_VLIN:
break;
case ACTION_PLOT:
printf("\t.byte PLOT,%d,%d\n",
primitive_list[i].x1,
primitive_list[i].y1);
break;
case ACTION_HLIN_ADD:
break;
case ACTION_HLIN_ADD_LSAME:
break;
case ACTION_HLIN_ADD_RSAME:
break;
default:
fprintf(stderr,"Error unknown type!\n");
exit(1);
break;
}
}
printf("\t.byte END\n");
return 0;
}

View File

@ -0,0 +1,527 @@
/* Loads a 80x48 (or 40x48) PNG image into a 40x48 Apple II layout */
/* Also supports 280x192 */
/* It's not interleaved like an actual Apple II */
/* But the top/bottom are pre-packed into a naive 40x24 array */
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <stdarg.h>
#include <png.h>
#include "loadpng.h"
static int convert_color(int color, char *filename) {
int c=0;
switch(color) {
case 0x000000: c=0; break; /* black */
case 0xe31e60: c=1; break; /* magenta */
case 0x604ebd: c=2; break; /* dark blue */
case 0xff44fd: c=3; break; /* purple */
case 0x00a360: c=4; break; /* dark green */
case 0x9c9c9c: c=5; break; /* grey 1 */
case 0x14cffd: c=6; break; /* medium blue */
case 0xd0c3ff: c=7; break; /* light blue */
case 0x607203: c=8; break; /* brown */
case 0xff6a3c: c=9; break; /* orange */
case 0x9d9d9d: c=10; break; /* grey 2 */
case 0xffa0d0: c=11; break; /* pink */
case 0x14f53c: c=12; break; /* bright green */
case 0xd0dd8d: c=13; break; /* yellow */
case 0x72ffd0: c=14; break; /* aqua */
case 0xffffff: c=15; break; /* white */
default:
fprintf(stderr,"Unknown color %x, file %s\n",
color,filename);
exit(-1);
break;
}
return c;
}
/* expects a PNG where the xsize is either 40 or 80 or 280 */
/* if it is 80, it skips every other */
/* if 280, it skips every 7 */
/* why do that? when editing an image the aspect ratio looks better if */
/* it is an 80 wide picture */
/* xsize, ysize is the size of the result, not size of */
/* the input image */
int loadpng(char *filename, unsigned char **image_ptr, int *xsize, int *ysize,
int png_type) {
int x,y,ystart,yadd,xadd;
int color;
FILE *infile;
int debug=0;
unsigned char *image,*out_ptr;
int width, height;
int a2_color;
png_byte bit_depth;
png_structp png_ptr;
png_infop info_ptr;
png_bytep *row_pointers;
png_byte color_type;
unsigned char header[8];
/* open file and test for it being a png */
infile = fopen(filename, "rb");
if (infile==NULL) {
fprintf(stderr,"Error! Could not open %s\n",filename);
return -1;
}
/* Check the header */
fread(header, 1, 8, infile);
if (png_sig_cmp(header, 0, 8)) {
fprintf(stderr,"Error! %s is not a PNG file\n",filename);
return -1;
}
/* initialize stuff */
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
fprintf(stderr,"Error create_read_struct\n");
exit(-1);
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
fprintf(stderr,"Error png_create_info_struct\n");
exit(-1);
}
png_init_io(png_ptr, infile);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
width = png_get_image_width(png_ptr, info_ptr);
height = png_get_image_height(png_ptr, info_ptr);
/* get the xadd */
if (width==40) {
*xsize=40;
xadd=1;
yadd=1;
}
else if (width==80) {
if (png_type==PNG_NO_ADJUST) {
*xsize=80;
xadd=1;
}
else {
*xsize=40;
xadd=2;
}
yadd=1;
}
else if (width==280) {
*xsize=40;
xadd=7;
yadd=4; /* FIXME: check we are 192 in ysize */
}
else if (width==16) {
*xsize=16;
xadd=1;
yadd=1;
}
else {
fprintf(stderr,"Unsupported width %d\n",width);
return -1;
}
if ((png_type==PNG_WHOLETHING) || (png_type==PNG_NO_ADJUST)) {
*ysize=height;
ystart=0;
yadd*=2;
}
else if (png_type==PNG_ODDLINES) {
*ysize=height/2;
ystart=1;
yadd*=4;
}
else if (png_type==PNG_EVENLINES) {
*ysize=height/2;
ystart=0;
yadd*=4;
}
else if (png_type==PNG_RAW) {
/* FIXME, not working */
*ysize=height;
ystart=0;
yadd=1;
}
else {
fprintf(stderr,"Unknown PNG type\n");
return -1;
}
color_type = png_get_color_type(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
if (debug) {
printf("PNG: width=%d height=%d depth=%d\n",width,height,bit_depth);
if (color_type==PNG_COLOR_TYPE_RGB) printf("Type RGB\n");
else if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) printf("Type RGBA\n");
else if (color_type==PNG_COLOR_TYPE_PALETTE) printf("Type palette\n");
printf("Generating output size %d x %d\n",*xsize,*ysize);
}
// number_of_passes = png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr);
row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
for (y=0; y<height; y++) {
/* FIXME: do we ever free these? */
row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
}
png_read_image(png_ptr, row_pointers);
fclose(infile);
/* FIXME: this should be 40x24 max??? */
image=calloc(width*height,sizeof(unsigned char));
if (image==NULL) {
fprintf(stderr,"Memory error!\n");
return -1;
}
out_ptr=image;
if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) {
for(y=ystart;y<height;y+=yadd) {
for(x=0;x<width;x+=xadd) {
/* top color */
color= (row_pointers[y][x*xadd*4]<<16)+
(row_pointers[y][x*xadd*4+1]<<8)+
(row_pointers[y][x*xadd*4+2]);
if (debug) {
printf("%x ",color);
}
a2_color=convert_color(color,filename);
/* bottom color */
color= (row_pointers[y+1][x*xadd*4]<<16)+
(row_pointers[y+1][x*xadd*4+1]<<8)+
(row_pointers[y+1][x*xadd*4+2]);
if (debug) {
printf("%x ",color);
}
a2_color|=(convert_color(color,filename)<<4);
*out_ptr=a2_color;
out_ptr++;
}
if (debug) printf("\n");
}
}
else if (color_type==PNG_COLOR_TYPE_PALETTE) {
for(y=ystart;y<height;y+=yadd) {
for(x=0;x<width;x+=xadd) {
if (bit_depth==8) {
/* top color */
a2_color=row_pointers[y][x];
/* bottom color */
color=row_pointers[y+(yadd/2)][x];
a2_color|=(color<<4);
if (debug) {
printf("%x ",a2_color);
}
*out_ptr=a2_color;
out_ptr++;
}
else if (bit_depth==4) {
/* top color */
a2_color=row_pointers[y][x/2];
if (x%2==0) {
a2_color=(a2_color>>4);
}
a2_color&=0xf;
/* bottom color */
color=row_pointers[y+(yadd/2)][x/2];
if (x%2==0) {
color=(color>>4);
}
color&=0xf;
a2_color|=(color<<4);
if (debug) {
printf("%x ",a2_color);
}
*out_ptr=a2_color;
out_ptr++;
}
}
if (debug) printf("\n");
}
}
else {
printf("Unknown color type\n");
}
/* Stripe test image */
// for(x=0;x<40;x++) for(y=0;y<40;y++) image[(y*width)+x]=y%16;
/*
Addr Row /80 %40
$400 0 0 0 0
$428 28 16 0
$450 50 32 0
$480 80 2 1
$4A8 a8 18 1
$4D0 d0 34 1
$500 100 3 2
0,0 0,1 0,2....0,39 16,0 16,1 ....16,39 32,0..32,39, X X X X X X X X
*/
*image_ptr=image;
return 0;
}
/* for 80 column mode or double-lores */
int loadpng80(char *filename, unsigned char **image_ptr, int *xsize, int *ysize,
int png_type) {
int x,y,ystart,yadd,xadd;
int color;
FILE *infile;
int debug=0;
unsigned char *image,*out_ptr;
int width, height;
int a2_color;
png_byte bit_depth;
png_structp png_ptr;
png_infop info_ptr;
png_bytep *row_pointers;
png_byte color_type;
unsigned char header[8];
/* open file and test for it being a png */
infile = fopen(filename, "rb");
if (infile==NULL) {
fprintf(stderr,"Error! Could not open %s\n",filename);
return -1;
}
/* Check the header */
fread(header, 1, 8, infile);
if (png_sig_cmp(header, 0, 8)) {
fprintf(stderr,"Error! %s is not a PNG file\n",filename);
return -1;
}
/* initialize stuff */
png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING, NULL, NULL, NULL);
if (!png_ptr) {
fprintf(stderr,"Error create_read_struct\n");
exit(-1);
}
info_ptr = png_create_info_struct(png_ptr);
if (!info_ptr) {
fprintf(stderr,"Error png_create_info_struct\n");
exit(-1);
}
png_init_io(png_ptr, infile);
png_set_sig_bytes(png_ptr, 8);
png_read_info(png_ptr, info_ptr);
width = png_get_image_width(png_ptr, info_ptr);
height = png_get_image_height(png_ptr, info_ptr);
if (width==80) {
*xsize=80;
xadd=1;
}
else {
fprintf(stderr,"Unsupported width %d\n",width);
return -1;
}
if (png_type==PNG_WHOLETHING) {
*ysize=height;
ystart=0;
yadd=2;
}
else if (png_type==PNG_ODDLINES) {
*ysize=height/2;
ystart=1;
yadd=4;
}
else if (png_type==PNG_EVENLINES) {
*ysize=height/2;
ystart=0;
yadd=4;
}
else {
fprintf(stderr,"Unknown PNG type\n");
return -1;
}
color_type = png_get_color_type(png_ptr, info_ptr);
bit_depth = png_get_bit_depth(png_ptr, info_ptr);
if (debug) {
printf("PNG: width=%d height=%d depth=%d\n",width,height,bit_depth);
if (color_type==PNG_COLOR_TYPE_RGB) printf("Type RGB\n");
else if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) printf("Type RGBA\n");
else if (color_type==PNG_COLOR_TYPE_PALETTE) printf("Type palette\n");
printf("Generating output size %d x %d\n",*xsize,*ysize);
}
// number_of_passes = png_set_interlace_handling(png_ptr);
png_read_update_info(png_ptr, info_ptr);
row_pointers = (png_bytep*) malloc(sizeof(png_bytep) * height);
for (y=0; y<height; y++) {
/* FIXME: do we ever free these? */
row_pointers[y] = (png_byte*) malloc(png_get_rowbytes(png_ptr,info_ptr));
}
png_read_image(png_ptr, row_pointers);
fclose(infile);
/* FIXME: this should be 40x24 max??? */
image=calloc(width*height,sizeof(unsigned char));
if (image==NULL) {
fprintf(stderr,"Memory error!\n");
return -1;
}
out_ptr=image;
if (color_type==PNG_COLOR_TYPE_RGB_ALPHA) {
for(y=ystart;y<height;y+=yadd) {
for(x=0;x<width;x+=xadd) {
/* top color */
color= (row_pointers[y][x*xadd*4]<<16)+
(row_pointers[y][x*xadd*4+1]<<8)+
(row_pointers[y][x*xadd*4+2]);
if (debug) {
printf("%x ",color);
}
a2_color=convert_color(color,filename);
/* bottom color */
color= (row_pointers[y+1][x*xadd*4]<<16)+
(row_pointers[y+1][x*xadd*4+1]<<8)+
(row_pointers[y+1][x*xadd*4+2]);
if (debug) {
printf("%x ",color);
}
a2_color|=(convert_color(color,filename)<<4);
*out_ptr=a2_color;
out_ptr++;
}
if (debug) printf("\n");
}
}
else if (color_type==PNG_COLOR_TYPE_PALETTE) {
for(y=ystart;y<height;y+=yadd) {
for(x=0;x<width;x+=xadd) {
if (bit_depth==8) {
/* top color */
a2_color=row_pointers[y][x];
/* bottom color */
color=row_pointers[y+(yadd/2)][x];
a2_color|=(color<<4);
if (debug) {
printf("%x ",a2_color);
}
*out_ptr=a2_color;
out_ptr++;
}
else if (bit_depth==4) {
/* top color */
a2_color=row_pointers[y][x/2];
if (x%2==0) {
a2_color=(a2_color>>4);
}
a2_color&=0xf;
/* bottom color */
color=row_pointers[y+(yadd/2)][x/2];
if (x%2==0) {
color=(color>>4);
}
color&=0xf;
a2_color|=(color<<4);
if (debug) {
printf("%x ",a2_color);
}
*out_ptr=a2_color;
out_ptr++;
}
}
if (debug) printf("\n");
}
}
else {
printf("Unknown color type\n");
}
/* Stripe test image */
// for(x=0;x<40;x++) for(y=0;y<40;y++) image[(y*width)+x]=y%16;
/*
Addr Row /80 %40
$400 0 0 0 0
$428 28 16 0
$450 50 32 0
$480 80 2 1
$4A8 a8 18 1
$4D0 d0 34 1
$500 100 3 2
0,0 0,1 0,2....0,39 16,0 16,1 ....16,39 32,0..32,39, X X X X X X X X
*/
*image_ptr=image;
return 0;
}

View File

@ -0,0 +1,11 @@
#define PNG_WHOLETHING 0
#define PNG_ODDLINES 1
#define PNG_EVENLINES 2
#define PNG_RAW 3
#define PNG_NO_ADJUST 4
int loadpng(char *filename, unsigned char **image_ptr, int *xsize, int *ysize,
int png_type);
int loadpng80(char *filename, unsigned char **image_ptr, int *xsize, int *ysize,
int png_type);