Files
amiwm-neo/ppmtoinfo.c
James Le Cuirot d91710ba03 Fix all implicit declarations
AC_HEADER_TIME is only needed if you need to include time.h and
sys/time.h at the same time.

The truth is this codebase is an unholy mess but at least this fixes
the warnings.
2023-10-07 23:02:51 +01:00

525 lines
13 KiB
C

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#ifdef HAVE_UNISTD_H
#include <unistd.h>
#endif
#define WB_DISKMAGIC 0xe310
#define WB_DISKVERSION 1
#define WB_DISKREVISION 1
#define WB_DISKREVISIONMASK 255
#define NO_ICON_POSITION (0x80000000)
#define WBDISK 1
#define WBDRAWER 2
#define WBTOOL 3
#define WBPROJECT 4
#define WBGARBAGE 5
#define WBDEVICE 6
#define WBKICK 7
#define WBAPPICON 8
#define NONNULL 0x123456
struct { char *name; int minl, code; } icontype[] = {
{ "appicon", 1, WBAPPICON },
{ "device", 2, WBDEVICE },
{ "disk", 2, WBDISK },
{ "drawer", 2, WBDRAWER },
{ "garbage", 1, WBGARBAGE },
{ "kick", 1, WBKICK },
{ "project", 1, WBPROJECT },
{ "tool", 1, WBTOOL },
};
#define NUM_ICONTYPES (sizeof(icontype)/sizeof(icontype[0]))
typedef unsigned short pixval;
typedef struct {
pixval r, g, b;
} pixel;
void usage()
{
fprintf(stderr, "usage: ppmtoinfo [-type icontype][-floyd|-fs] [-map mapfile] [ppmfile] [ppmfile]\n");
exit(1);
}
void w16(FILE *file, int v)
{
putc((v>>8)&0xff, file);
putc(v&0xff, file);
}
void w32(FILE *file, int v)
{
w16(file, v>>16);
w16(file, v);
}
char *myalloc(int size)
{
char *p=malloc(size);
if(!p) {
fprintf(stderr, "out of memory!\n");
exit(1);
}
return p;
}
pixel **readppm(FILE *file, int *colsP, int *rowsP, pixval *maxvalP)
{
pixel** pixels;
int row, col;
int format, mv;
if(4!=fscanf(file, "P%d %d %d %d", &format, colsP, rowsP, &mv) ||
(format!=3 && format!=6)) {
fprintf(stderr, "bad magic number - not a ppm file\n");
exit(1);
}
if(format==6)
getc(file);
*maxvalP=mv;
pixels = (pixel **)myalloc(*rowsP * sizeof(pixel*));
pixels[0] = (pixel *)myalloc(*rowsP * *colsP * sizeof(pixel));
for(row=1; row<*rowsP; row++)
pixels[row] = &(pixels[0][row * *colsP]);
for ( row = 0; row < *rowsP; ++row )
if(format==3)
for( col = 0; col < *colsP; ++col) {
int r, g, b;
fscanf(file, "%d %d %d", &r, &g, &b);
pixels[row][col].r=r;
pixels[row][col].g=g;
pixels[row][col].b=b;
}
else
for( col = 0; col < *colsP; ++col) {
pixels[row][col].r=getc(file);
pixels[row][col].g=getc(file);
pixels[row][col].b=getc(file);
}
return pixels;
}
char *makelibfilename(char *oldname)
{
char *newname;
if(*oldname=='/') return oldname;
newname=myalloc(strlen(oldname)+strlen(AMIWM_HOME)+2);
sprintf(newname, AMIWM_HOME"/%s", oldname);
return newname;
}
#define HSTYLE_COMPL 0
#define HSTYLE_BACKFILL 1
#define HSTYLE_IMAGE 2
void writeiconheader(FILE *file, int type, int hstyle, int cols, int rows,
char *deftool, char **tooltypes, char *toolwin,
int stksize)
{
int drw=0;
if(type==1 || type==2 || type==5 || type==6)
drw=1;
w16(file, WB_DISKMAGIC); w16(file, WB_DISKVERSION);
w32(file, 0);
w16(file, 0); w16(file, 0); w16(file, cols); w16(file, rows);
w16(file, 4|hstyle); w16(file, 3); w16(file, 1);
w32(file, NONNULL); w32(file, (hstyle==HSTYLE_IMAGE? NONNULL:0));
w32(file, 0); w32(file, 0); w32(file, 0);
w16(file, 0); w32(file, WB_DISKREVISION);
putc(type, file); putc(0, file);
w32(file, (deftool!=NULL? NONNULL:0));
w32(file, (tooltypes!=NULL? NONNULL:0));
w32(file, NO_ICON_POSITION); w32(file, NO_ICON_POSITION);
w32(file, (drw? NONNULL:0)); w32(file, (toolwin? NONNULL:0));
w32(file, stksize);
if(drw) {
w16(file, 50); w16(file, 50); w16(file, 400); w16(file, 100);
w16(file, ~0); w32(file, 0); w32(file, 0x0240027f);
w32(file, 0); w32(file, 0); w32(file, NONNULL);
w32(file, 0); w32(file, 0);
w16(file, 90); w16(file, 40); w16(file, ~0); w16(file, ~0);
w16(file, 1);
w32(file, 0); w32(file, 0);
}
}
void writeiconinit(FILE *file, int cols, int rows, int planes)
{
w16(file, 0); w16(file, 0);
w16(file, cols); w16(file, rows); w16(file, planes);
w32(file, NONNULL);
putc((1<<planes)-1, file); putc(0, file);
w32(file, 0);
}
void writeiconimage(FILE *file, unsigned char *pixels,
int cols, int rows, int planes)
{
register int i, j, k, l;
register unsigned char pat;
for(i=0; i<planes; i++)
for(j=0; j<rows; j++)
for(k=0; k<cols; k+=8) {
pat=0;
for(l=0; l<8; l++)
if(pixels[j*cols+k+l]&(1<<i))
pat|=0x80>>l;
putc(pat, file);
}
}
void writeiconstr(FILE *file, char *str)
{
int l=strlen(str)+1;
w32(file, l);
fwrite(str, 1, l, file);
}
void writeiconend(FILE *file, int type,
char *deftool, char **tooltypes, char *toolwin)
{
if(deftool) writeiconstr(file, deftool);
if(tooltypes) {
int n;
for(n=0; tooltypes[n]!=NULL; n++);
w32(file, 4*(n+1));
for(n=0; tooltypes[n]!=NULL; n++)
writeiconstr(file, tooltypes[n]);
}
if(toolwin) writeiconstr(file, toolwin);
if(type==1 || type==2 || type==5 || type==6) {
w32(file, 0); w16(file, 0);
}
}
#define mx(a,b) ((a)>(b)?(a):(b))
unsigned char *processicon(FILE *ifp, int floyd, pixel **mappixels,
int maprows, int mapcols, pixval *mapmaxval,
int *rowsP, int *colsP, int *planesP)
{
int rows, cols, planes, bpr, imgsz;
pixval maxval;
pixel **pixels, *colormap;
unsigned char *outimg, *oip;
register int row, col, limitcol;
register pixel *pP;
int newcolors;
register int ind;
long* thisrerr;
long* nextrerr;
long* thisgerr;
long* nextgerr;
long* thisberr;
long* nextberr;
long* temperr;
register long sr, sg, sb, err;
int fs_direction, dscale;
pixels = readppm( ifp, &cols, &rows, &maxval );
if(ifp != stdin)
fclose( ifp );
if ( *mapmaxval != maxval ) {
if ( *mapmaxval > maxval )
fprintf(stderr, "rescaling colormap colors\n");
for ( row = 0; row < maprows; ++row )
for ( col = 0, pP = mappixels[row]; col < mapcols; ++col, ++pP ) {
pP->r=((int)pP->r*maxval+*mapmaxval/2)/ *mapmaxval;
pP->g=((int)pP->g*maxval+*mapmaxval/2)/ *mapmaxval;
pP->b=((int)pP->b*maxval+*mapmaxval/2)/ *mapmaxval;
}
*mapmaxval = maxval;
}
newcolors=mapcols*maprows;
colormap=mappixels[0];
if(newcolors>256) newcolors=256;
for(planes=1; (1<<planes)<newcolors; planes++);
bpr=2*((cols+15)>>4);
imgsz=rows*bpr*8*sizeof(unsigned char);
outimg = (unsigned char *)myalloc(imgsz);
memset(outimg, 0, imgsz);
oip = outimg;
dscale = 0;
if(maxval>=16384)
while(maxval>=(16384<<dscale))
dscale++;
if ( floyd ) {
/* Initialize Floyd-Steinberg error vectors. */
thisrerr = (long*) myalloc( (cols + 2) * sizeof(long) );
nextrerr = (long*) myalloc( (cols + 2) * sizeof(long) );
thisgerr = (long*) myalloc( (cols + 2) * sizeof(long) );
nextgerr = (long*) myalloc( (cols + 2) * sizeof(long) );
thisberr = (long*) myalloc( (cols + 2) * sizeof(long) );
nextberr = (long*) myalloc( (cols + 2) * sizeof(long) );
srand( (int) ( time( 0 ) ^ getpid( ) ) );
for ( col = 0; col < cols + 2; ++col ) {
thisrerr[col] = rand( ) % ( 1024 * 2 ) - 1024;
thisgerr[col] = rand( ) % ( 1024 * 2 ) - 1024;
thisberr[col] = rand( ) % ( 1024 * 2 ) - 1024;
/* (random errors in [-1 .. 1]) */
}
fs_direction = 1;
}
for ( row = 0; row < rows; ++row ) {
if ( floyd )
for ( col = 0; col < cols + 2; ++col )
nextrerr[col] = nextgerr[col] = nextberr[col] = 0;
if ( ( ! floyd ) || fs_direction ) {
col = 0;
limitcol = cols;
pP = pixels[row];
} else {
col = cols - 1;
limitcol = -1;
pP = &(pixels[row][col]);
}
do {
register int i, r2, g2, b2;
register long dist, newdist;
if ( floyd ) {
/* Use Floyd-Steinberg errors to adjust actual color. */
sr = pP->r + thisrerr[col + 1] / 1024;
sg = pP->g + thisgerr[col + 1] / 1024;
sb = pP->b + thisberr[col + 1] / 1024;
if ( sr < 0 ) sr = 0;
else if ( sr > maxval ) sr = maxval;
if ( sg < 0 ) sg = 0;
else if ( sg > maxval ) sg = maxval;
if ( sb < 0 ) sb = 0;
else if ( sb > maxval ) sb = maxval;
} else {
sr = pP->r;
sg = pP->g;
sb = pP->b;
}
for ( i = 0; i < newcolors; ++i ) {
r2 = sr - colormap[i].r;
g2 = sg - colormap[i].g;
b2 = sb - colormap[i].b;
if (dscale) {
r2 >>= dscale;
g2 >>= dscale;
b2 >>= dscale;
}
newdist = r2 * r2 + g2 * g2 + b2 * b2;
if ( i==0 || newdist < dist ) {
ind = i;
dist = newdist;
}
}
if ( floyd ) {
/* Propagate Floyd-Steinberg error terms. */
if ( fs_direction ) {
err = ( sr - (long) colormap[ind].r ) * 1024;
thisrerr[col + 2] += ( err * 7 ) / 16;
nextrerr[col ] += ( err * 3 ) / 16;
nextrerr[col + 1] += ( err * 5 ) / 16;
nextrerr[col + 2] += ( err ) / 16;
err = ( sg - (long) colormap[ind].g ) * 1024;
thisgerr[col + 2] += ( err * 7 ) / 16;
nextgerr[col ] += ( err * 3 ) / 16;
nextgerr[col + 1] += ( err * 5 ) / 16;
nextgerr[col + 2] += ( err ) / 16;
err = ( sb - (long) colormap[ind].b ) * 1024;
thisberr[col + 2] += ( err * 7 ) / 16;
nextberr[col ] += ( err * 3 ) / 16;
nextberr[col + 1] += ( err * 5 ) / 16;
nextberr[col + 2] += ( err ) / 16;
} else {
err = ( sr - (long) colormap[ind].r ) * 1024;
thisrerr[col ] += ( err * 7 ) / 16;
nextrerr[col + 2] += ( err * 3 ) / 16;
nextrerr[col + 1] += ( err * 5 ) / 16;
nextrerr[col ] += ( err ) / 16;
err = ( sg - (long) colormap[ind].g ) * 1024;
thisgerr[col ] += ( err * 7 ) / 16;
nextgerr[col + 2] += ( err * 3 ) / 16;
nextgerr[col + 1] += ( err * 5 ) / 16;
nextgerr[col ] += ( err ) / 16;
err = ( sb - (long) colormap[ind].b ) * 1024;
thisberr[col ] += ( err * 7 ) / 16;
nextberr[col + 2] += ( err * 3 ) / 16;
nextberr[col + 1] += ( err * 5 ) / 16;
nextberr[col ] += ( err ) / 16;
}
}
oip[col] = ind;
if ( ( ! floyd ) || fs_direction ) {
++col;
++pP;
} else {
--col;
--pP;
}
}
while ( col != limitcol );
oip += bpr*8;
if ( floyd ) {
temperr = thisrerr;
thisrerr = nextrerr;
nextrerr = temperr;
temperr = thisgerr;
thisgerr = nextgerr;
nextgerr = temperr;
temperr = thisberr;
thisberr = nextberr;
nextberr = temperr;
fs_direction = ! fs_direction;
}
}
if(floyd) {
free(thisrerr); free(nextrerr);
free(thisgerr); free(nextgerr);
free(thisberr); free(nextberr);
}
free(pixels[0]); free(pixels);
*rowsP=rows; *colsP=cols; *planesP=planes;
return outimg;
}
int main(int argc, char *argv[])
{
char *mapname = "system.map";
int argn, maprows, mapcols;
int floyd;
pixel **mappixels;
pixval mapmaxval;
FILE* ifp;
FILE *ifp2=NULL;
unsigned char *outimg;
int planes, rows, cols;
char *deftool=NULL, **tooltypes=NULL, *toolwin=NULL;
int stksize=0;
int type=WBPROJECT;
argn = 1;
floyd = 0;
while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
int l=strlen(argv[argn]);
if ( !strncmp( argv[argn], "-fs", mx(l, 2) ) ||
!strncmp( argv[argn], "-floyd", mx(l, 2) ) )
floyd = 1;
else if ( !strncmp( argv[argn], "-nofs", mx(l, 2) ) ||
!strncmp( argv[argn], "-nofloyd", mx(l, 2) ) )
floyd = 0;
else if ( !strncmp( argv[argn], "-map", mx(l, 2) ) ) {
++argn;
if ( argn == argc )
usage();
mapname = argv[argn];
}
else if ( !strncmp( argv[argn], "-type", mx(l, 2) ) ) {
int i;
++argn;
if ( argn == argc )
usage();
l=strlen(argv[argn]);
for(i=0; i<NUM_ICONTYPES; i++)
if( !strncmp( argv[argn], icontype[i].name, mx(l, icontype[i].minl))) {
type = icontype[i].code;
break;
}
if(i>=NUM_ICONTYPES) {
fprintf(stderr, "Unknown icon type. Supported types:\n");
for(i=0; i<NUM_ICONTYPES; i++)
fprintf(stderr, " %s\n", icontype[i].name);
exit(1);
}
} else
usage();
++argn;
}
if(!strcmp(mapname, "-"))
ifp = stdin;
else
if((ifp = fopen(mapname, "r"))==NULL)
ifp = fopen(makelibfilename(mapname), "r");
if(!ifp) {
perror(mapname);
exit(1);
}
mappixels = readppm( ifp, &mapcols, &maprows, &mapmaxval );
if(ifp != stdin)
fclose( ifp );
if ( mapcols == 0 || maprows == 0 ) {
fprintf(stderr, "null colormap??\n");
exit(1);
}
if ( argn != argc ) {
if(!strcmp(argv[argn], "-"))
ifp = stdin;
else
ifp = fopen(argv[argn], "r");
if(!ifp) {
perror(argv[argn]);
exit(1);
}
++argn;
}
else
ifp = stdin;
if ( argn != argc ) {
if(!strcmp(argv[argn], "-"))
ifp2 = stdin;
else
ifp2 = fopen(argv[argn], "r");
if(!ifp) {
perror(argv[argn]);
exit(1);
}
++argn;
}
if ( argn != argc )
usage();
outimg = processicon(ifp, floyd, mappixels, maprows, mapcols, &mapmaxval,
&rows, &cols, &planes);
writeiconheader(stdout, type,
(ifp2==NULL? HSTYLE_BACKFILL:HSTYLE_IMAGE),
cols, rows, deftool, tooltypes, toolwin, stksize);
writeiconinit(stdout, cols, rows, planes);
writeiconimage(stdout, outimg, 16*((cols+15)>>4), rows, planes);
free(outimg);
if(ifp2) {
outimg = processicon(ifp2, floyd, mappixels, maprows, mapcols, &mapmaxval,
&rows, &cols, &planes);
writeiconinit(stdout, cols, rows, planes);
writeiconimage(stdout, outimg, 16*((cols+15)>>4), rows, planes);
free(outimg);
}
writeiconend(stdout, type, deftool, tooltypes, toolwin);
return 0;
}