1 #include <stdio.h>
2 #include <stdlib.h>
3 #include <string.h>
4 #ifdef HAVE_UNISTD_H
5 #include <unistd.h>
6 #endif
7 #ifdef HAVE_SYS_TIME_H
8 #include <sys/time.h>
9 #endif
10 
11 #define WB_DISKMAGIC	0xe310
12 #define WB_DISKVERSION	1
13 #define WB_DISKREVISION	1
14 #define WB_DISKREVISIONMASK	255
15 
16 #define NO_ICON_POSITION	(0x80000000)
17 
18 #define	WBDISK		1
19 #define	WBDRAWER	2
20 #define	WBTOOL		3
21 #define	WBPROJECT	4
22 #define	WBGARBAGE	5
23 #define	WBDEVICE	6
24 #define	WBKICK		7
25 #define WBAPPICON	8
26 
27 #define NONNULL 0x123456
28 
29 
30 struct { char *name; int minl, code; } icontype[] = {
31   { "appicon", 1, WBAPPICON },
32   { "device", 2, WBDEVICE },
33   { "disk", 2, WBDISK },
34   { "drawer", 2, WBDRAWER },
35   { "garbage", 1, WBGARBAGE },
36   { "kick", 1, WBKICK },
37   { "project", 1, WBPROJECT },
38   { "tool", 1, WBTOOL },
39 };
40 #define NUM_ICONTYPES (sizeof(icontype)/sizeof(icontype[0]))
41 
42 typedef unsigned short pixval;
43 typedef struct {
44   pixval r, g, b;
45 } pixel;
46 
usage()47 void usage()
48 {
49   fprintf(stderr, "usage:  ppmtoinfo [-type icontype][-floyd|-fs] [-map mapfile] [ppmfile] [ppmfile]\n");
50   exit(1);
51 }
52 
w16(FILE * file,int v)53 void w16(FILE *file, int v)
54 {
55   putc((v>>8)&0xff, file);
56   putc(v&0xff, file);
57 }
58 
w32(FILE * file,int v)59 void w32(FILE *file, int v)
60 {
61   w16(file, v>>16);
62   w16(file, v);
63 }
64 
myalloc(int size)65 char *myalloc(int size)
66 {
67   char *p=malloc(size);
68   if(!p) {
69     fprintf(stderr, "out of memory!\n");
70     exit(1);
71   }
72   return p;
73 }
74 
readppm(FILE * file,int * colsP,int * rowsP,pixval * maxvalP)75 pixel **readppm(FILE *file, int *colsP, int *rowsP, pixval *maxvalP)
76 {
77   pixel** pixels;
78   int row, col;
79   int format, mv;
80 
81   if(4!=fscanf(file, "P%d %d %d %d", &format, colsP, rowsP, &mv) ||
82      (format!=3 && format!=6)) {
83     fprintf(stderr, "bad magic number - not a ppm file\n");
84     exit(1);
85   }
86   if(format==6)
87     getc(file);
88   *maxvalP=mv;
89   pixels = (pixel **)myalloc(*rowsP * sizeof(pixel*));
90   pixels[0] = (pixel *)myalloc(*rowsP * *colsP * sizeof(pixel));
91   for(row=1; row<*rowsP; row++)
92     pixels[row] = &(pixels[0][row * *colsP]);
93   for ( row = 0; row < *rowsP; ++row )
94     if(format==3)
95       for( col = 0; col < *colsP; ++col) {
96 	int r, g, b;
97 	fscanf(file, "%d %d %d", &r, &g, &b);
98 	pixels[row][col].r=r;
99 	pixels[row][col].g=g;
100 	pixels[row][col].b=b;
101       }
102     else
103       for( col = 0; col < *colsP; ++col) {
104 	pixels[row][col].r=getc(file);
105 	pixels[row][col].g=getc(file);
106 	pixels[row][col].b=getc(file);
107       }
108   return pixels;
109 }
110 
makelibfilename(char * oldname)111 char *makelibfilename(char *oldname)
112 {
113   char *newname;
114   if(*oldname=='/') return oldname;
115   newname=myalloc(strlen(oldname)+strlen(AMIWM_HOME)+2);
116   sprintf(newname, AMIWM_HOME"/%s", oldname);
117   return newname;
118 }
119 
120 #define HSTYLE_COMPL    0
121 #define HSTYLE_BACKFILL 1
122 #define HSTYLE_IMAGE    2
123 
writeiconheader(FILE * file,int type,int hstyle,int cols,int rows,char * deftool,char ** tooltypes,char * toolwin,int stksize)124 void writeiconheader(FILE *file, int type, int hstyle, int cols, int rows,
125 		     char *deftool, char **tooltypes, char *toolwin,
126 		     int stksize)
127 {
128   int drw=0;
129 
130   if(type==1 || type==2 || type==5 || type==6)
131     drw=1;
132   w16(file, WB_DISKMAGIC); w16(file, WB_DISKVERSION);
133   w32(file, 0);
134   w16(file, 0); w16(file, 0); w16(file, cols); w16(file, rows);
135   w16(file, 4|hstyle); w16(file, 3); w16(file, 1);
136   w32(file, NONNULL); w32(file, (hstyle==HSTYLE_IMAGE? NONNULL:0));
137   w32(file, 0); w32(file, 0); w32(file, 0);
138   w16(file, 0); w32(file, WB_DISKREVISION);
139   putc(type, file); putc(0, file);
140   w32(file, (deftool!=NULL? NONNULL:0));
141   w32(file, (tooltypes!=NULL? NONNULL:0));
142   w32(file, NO_ICON_POSITION); w32(file, NO_ICON_POSITION);
143   w32(file, (drw? NONNULL:0)); w32(file, (toolwin? NONNULL:0));
144   w32(file, stksize);
145   if(drw) {
146     w16(file, 50); w16(file, 50); w16(file, 400); w16(file, 100);
147     w16(file, ~0); w32(file, 0); w32(file, 0x0240027f);
148     w32(file, 0); w32(file, 0); w32(file, NONNULL);
149     w32(file, 0); w32(file, 0);
150     w16(file, 90); w16(file, 40); w16(file, ~0); w16(file, ~0);
151     w16(file, 1);
152     w32(file, 0); w32(file, 0);
153   }
154 }
155 
writeiconinit(FILE * file,int cols,int rows,int planes)156 void writeiconinit(FILE *file, int cols, int rows, int planes)
157 {
158   w16(file, 0); w16(file, 0);
159   w16(file, cols); w16(file, rows); w16(file, planes);
160   w32(file, NONNULL);
161   putc((1<<planes)-1, file); putc(0, file);
162   w32(file, 0);
163 }
164 
writeiconimage(FILE * file,unsigned char * pixels,int cols,int rows,int planes)165 void writeiconimage(FILE *file, unsigned char *pixels,
166 		    int cols, int rows, int planes)
167 {
168   register int i, j, k, l;
169   register unsigned char pat;
170   for(i=0; i<planes; i++)
171     for(j=0; j<rows; j++)
172       for(k=0; k<cols; k+=8) {
173 	pat=0;
174 	for(l=0; l<8; l++)
175 	  if(pixels[j*cols+k+l]&(1<<i))
176 	    pat|=0x80>>l;
177 	putc(pat, file);
178       }
179 }
180 
writeiconstr(FILE * file,char * str)181 void writeiconstr(FILE *file, char *str)
182 {
183   int l=strlen(str)+1;
184   w32(file, l);
185   fwrite(str, 1, l, file);
186 }
187 
writeiconend(FILE * file,int type,char * deftool,char ** tooltypes,char * toolwin)188 void writeiconend(FILE *file, int type,
189 		  char *deftool, char **tooltypes, char *toolwin)
190 {
191   if(deftool) writeiconstr(file, deftool);
192   if(tooltypes) {
193     int n;
194     for(n=0; tooltypes[n]!=NULL; n++);
195     w32(file, 4*(n+1));
196     for(n=0; tooltypes[n]!=NULL; n++)
197       writeiconstr(file, tooltypes[n]);
198   }
199   if(toolwin) writeiconstr(file, toolwin);
200   if(type==1 || type==2 || type==5 || type==6) {
201     w32(file, 0); w16(file, 0);
202   }
203 }
204 
205 #define mx(a,b) ((a)>(b)?(a):(b))
206 
processicon(FILE * ifp,int floyd,pixel ** mappixels,int maprows,int mapcols,pixval * mapmaxval,int * rowsP,int * colsP,int * planesP)207 unsigned char *processicon(FILE *ifp, int floyd, pixel **mappixels,
208 			   int maprows, int mapcols, pixval *mapmaxval,
209 			   int *rowsP, int *colsP, int *planesP)
210 {
211   int rows, cols, planes, bpr, imgsz;
212   pixval maxval;
213   pixel **pixels, *colormap;
214   unsigned char *outimg, *oip;
215   register int row, col, limitcol;
216   register pixel *pP;
217   int newcolors;
218   register int ind;
219   long* thisrerr;
220   long* nextrerr;
221   long* thisgerr;
222   long* nextgerr;
223   long* thisberr;
224   long* nextberr;
225   long* temperr;
226   register long sr, sg, sb, err;
227   int fs_direction, dscale;
228 
229   pixels = readppm( ifp, &cols, &rows, &maxval );
230   if(ifp != stdin)
231     fclose( ifp );
232 
233   if ( *mapmaxval != maxval ) {
234     if ( *mapmaxval > maxval )
235       fprintf(stderr, "rescaling colormap colors\n");
236     for ( row = 0; row < maprows; ++row )
237       for ( col = 0, pP = mappixels[row]; col < mapcols; ++col, ++pP ) {
238 	pP->r=((int)pP->r*maxval+*mapmaxval/2)/ *mapmaxval;
239         pP->g=((int)pP->g*maxval+*mapmaxval/2)/ *mapmaxval;
240 	pP->b=((int)pP->b*maxval+*mapmaxval/2)/ *mapmaxval;
241       }
242     *mapmaxval = maxval;
243   }
244 
245   newcolors=mapcols*maprows;
246   colormap=mappixels[0];
247   if(newcolors>256) newcolors=256;
248   for(planes=1; (1<<planes)<newcolors; planes++);
249 
250   bpr=2*((cols+15)>>4);
251   imgsz=rows*bpr*8*sizeof(unsigned char);
252   outimg = (unsigned char *)myalloc(imgsz);
253   memset(outimg, 0, imgsz);
254   oip = outimg;
255 
256   dscale = 0;
257   if(maxval>=16384)
258     while(maxval>=(16384<<dscale))
259       dscale++;
260 
261   if ( floyd ) {
262     /* Initialize Floyd-Steinberg error vectors. */
263     thisrerr = (long*) myalloc( (cols + 2) * sizeof(long) );
264     nextrerr = (long*) myalloc( (cols + 2) * sizeof(long) );
265     thisgerr = (long*) myalloc( (cols + 2) * sizeof(long) );
266     nextgerr = (long*) myalloc( (cols + 2) * sizeof(long) );
267     thisberr = (long*) myalloc( (cols + 2) * sizeof(long) );
268     nextberr = (long*) myalloc( (cols + 2) * sizeof(long) );
269     srand( (int) ( time( 0 ) ^ getpid( ) ) );
270     for ( col = 0; col < cols + 2; ++col ) {
271       thisrerr[col] = rand( ) % ( 1024 * 2 ) - 1024;
272       thisgerr[col] = rand( ) % ( 1024 * 2 ) - 1024;
273       thisberr[col] = rand( ) % ( 1024 * 2 ) - 1024;
274       /* (random errors in [-1 .. 1]) */
275     }
276     fs_direction = 1;
277   }
278   for ( row = 0; row < rows; ++row ) {
279     if ( floyd )
280       for ( col = 0; col < cols + 2; ++col )
281 	nextrerr[col] = nextgerr[col] = nextberr[col] = 0;
282     if ( ( ! floyd ) || fs_direction ) {
283       col = 0;
284       limitcol = cols;
285       pP = pixels[row];
286     } else {
287       col = cols - 1;
288       limitcol = -1;
289       pP = &(pixels[row][col]);
290     }
291     do {
292       register int i, r2, g2, b2;
293       register long dist, newdist;
294 
295       if ( floyd ) {
296 	/* Use Floyd-Steinberg errors to adjust actual color. */
297 	sr = pP->r + thisrerr[col + 1] / 1024;
298 	sg = pP->g + thisgerr[col + 1] / 1024;
299 	sb = pP->b + thisberr[col + 1] / 1024;
300 	if ( sr < 0 ) sr = 0;
301 	else if ( sr > maxval ) sr = maxval;
302 	if ( sg < 0 ) sg = 0;
303 	else if ( sg > maxval ) sg = maxval;
304 	if ( sb < 0 ) sb = 0;
305 	else if ( sb > maxval ) sb = maxval;
306       } else {
307 	sr = pP->r;
308 	sg = pP->g;
309 	sb = pP->b;
310       }
311 
312       for ( i = 0; i < newcolors; ++i ) {
313 	r2 = sr - colormap[i].r;
314 	g2 = sg - colormap[i].g;
315 	b2 = sb - colormap[i].b;
316 	if (dscale) {
317 	  r2 >>= dscale;
318 	  g2 >>= dscale;
319 	  b2 >>= dscale;
320 	}
321 
322 	newdist = r2 * r2 + g2 * g2 + b2 * b2;
323 	if ( i==0 || newdist < dist ) {
324 	  ind = i;
325 	  dist = newdist;
326 	}
327       }
328 
329       if ( floyd ) {
330 	/* Propagate Floyd-Steinberg error terms. */
331 	if ( fs_direction ) {
332 	  err = ( sr - (long) colormap[ind].r ) * 1024;
333 	  thisrerr[col + 2] += ( err * 7 ) / 16;
334 	  nextrerr[col    ] += ( err * 3 ) / 16;
335 	  nextrerr[col + 1] += ( err * 5 ) / 16;
336 	  nextrerr[col + 2] += ( err     ) / 16;
337 	  err = ( sg - (long) colormap[ind].g ) * 1024;
338 	  thisgerr[col + 2] += ( err * 7 ) / 16;
339 	  nextgerr[col    ] += ( err * 3 ) / 16;
340 	  nextgerr[col + 1] += ( err * 5 ) / 16;
341 	  nextgerr[col + 2] += ( err     ) / 16;
342 	  err = ( sb - (long) colormap[ind].b ) * 1024;
343 	  thisberr[col + 2] += ( err * 7 ) / 16;
344 	  nextberr[col    ] += ( err * 3 ) / 16;
345 	  nextberr[col + 1] += ( err * 5 ) / 16;
346 	  nextberr[col + 2] += ( err     ) / 16;
347 	} else {
348 	  err = ( sr - (long) colormap[ind].r ) * 1024;
349 	  thisrerr[col    ] += ( err * 7 ) / 16;
350 	  nextrerr[col + 2] += ( err * 3 ) / 16;
351 	  nextrerr[col + 1] += ( err * 5 ) / 16;
352 	  nextrerr[col    ] += ( err     ) / 16;
353 	  err = ( sg - (long) colormap[ind].g ) * 1024;
354 	  thisgerr[col    ] += ( err * 7 ) / 16;
355 	  nextgerr[col + 2] += ( err * 3 ) / 16;
356 	  nextgerr[col + 1] += ( err * 5 ) / 16;
357 	  nextgerr[col    ] += ( err     ) / 16;
358 	  err = ( sb - (long) colormap[ind].b ) * 1024;
359 	  thisberr[col    ] += ( err * 7 ) / 16;
360 	  nextberr[col + 2] += ( err * 3 ) / 16;
361 	  nextberr[col + 1] += ( err * 5 ) / 16;
362 	  nextberr[col    ] += ( err     ) / 16;
363 	}
364       }
365 
366       oip[col] = ind;
367 
368       if ( ( ! floyd ) || fs_direction ) {
369 	++col;
370 	++pP;
371       } else {
372 	--col;
373 	--pP;
374       }
375     }
376     while ( col != limitcol );
377 
378     oip += bpr*8;
379 
380     if ( floyd ) {
381       temperr = thisrerr;
382       thisrerr = nextrerr;
383       nextrerr = temperr;
384       temperr = thisgerr;
385       thisgerr = nextgerr;
386       nextgerr = temperr;
387       temperr = thisberr;
388       thisberr = nextberr;
389       nextberr = temperr;
390       fs_direction = ! fs_direction;
391     }
392 
393   }
394 
395   if(floyd) {
396     free(thisrerr); free(nextrerr);
397     free(thisgerr); free(nextgerr);
398     free(thisberr); free(nextberr);
399   }
400   free(pixels[0]); free(pixels);
401   *rowsP=rows; *colsP=cols; *planesP=planes;
402   return outimg;
403 }
404 
405 
main(int argc,char * argv[])406 int main(int argc, char *argv[])
407 {
408   char *mapname = "system.map";
409   int argn, maprows, mapcols;
410   int floyd;
411   pixel **mappixels;
412   pixval mapmaxval;
413   FILE* ifp;
414   FILE *ifp2=NULL;
415   unsigned char *outimg;
416   int planes, rows, cols;
417   char *deftool=NULL, **tooltypes=NULL, *toolwin=NULL;
418   int stksize=0;
419   int type=WBPROJECT;
420 
421   argn = 1;
422   floyd = 0;
423 
424   while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' ) {
425     int l=strlen(argv[argn]);
426     if ( !strncmp( argv[argn], "-fs", mx(l, 2) ) ||
427 	 !strncmp( argv[argn], "-floyd", mx(l, 2) ) )
428       floyd = 1;
429     else if ( !strncmp( argv[argn], "-nofs", mx(l, 2) ) ||
430 	      !strncmp( argv[argn], "-nofloyd", mx(l, 2) ) )
431       floyd = 0;
432     else if ( !strncmp( argv[argn], "-map", mx(l, 2) ) ) {
433       ++argn;
434       if ( argn == argc )
435 	usage();
436       mapname = argv[argn];
437     }
438     else if ( !strncmp( argv[argn], "-type", mx(l, 2) ) ) {
439       int i;
440       ++argn;
441       if ( argn == argc )
442 	usage();
443       l=strlen(argv[argn]);
444       for(i=0; i<NUM_ICONTYPES; i++)
445 	if( !strncmp( argv[argn], icontype[i].name, mx(l, icontype[i].minl))) {
446 	  type = icontype[i].code;
447 	  break;
448 	}
449       if(i>=NUM_ICONTYPES) {
450 	fprintf(stderr, "Unknown icon type.  Supported types:\n");
451 	for(i=0; i<NUM_ICONTYPES; i++)
452 	  fprintf(stderr, "  %s\n", icontype[i].name);
453 	exit(1);
454       }
455     } else
456       usage();
457     ++argn;
458   }
459 
460   if(!strcmp(mapname, "-"))
461     ifp = stdin;
462   else
463     if((ifp = fopen(mapname, "r"))==NULL)
464       ifp = fopen(makelibfilename(mapname), "r");
465   if(!ifp) {
466     perror(mapname);
467     exit(1);
468   }
469   mappixels = readppm( ifp, &mapcols, &maprows, &mapmaxval );
470   if(ifp != stdin)
471     fclose( ifp );
472   if ( mapcols == 0 || maprows == 0 ) {
473     fprintf(stderr, "null colormap??\n");
474     exit(1);
475   }
476 
477   if ( argn != argc ) {
478     if(!strcmp(argv[argn], "-"))
479       ifp = stdin;
480     else
481       ifp = fopen(argv[argn], "r");
482     if(!ifp) {
483       perror(argv[argn]);
484       exit(1);
485     }
486     ++argn;
487   }
488   else
489     ifp = stdin;
490 
491   if ( argn != argc ) {
492     if(!strcmp(argv[argn], "-"))
493       ifp2 = stdin;
494     else
495       ifp2 = fopen(argv[argn], "r");
496     if(!ifp) {
497       perror(argv[argn]);
498       exit(1);
499     }
500     ++argn;
501   }
502 
503   if ( argn != argc )
504     usage();
505 
506   outimg = processicon(ifp, floyd, mappixels, maprows, mapcols, &mapmaxval,
507 		       &rows, &cols, &planes);
508   writeiconheader(stdout, type,
509 		  (ifp2==NULL? HSTYLE_BACKFILL:HSTYLE_IMAGE),
510 		  cols, rows, deftool, tooltypes, toolwin, stksize);
511   writeiconinit(stdout, cols, rows, planes);
512   writeiconimage(stdout, outimg, 16*((cols+15)>>4), rows, planes);
513   free(outimg);
514 
515   if(ifp2) {
516     outimg = processicon(ifp2, floyd, mappixels, maprows, mapcols, &mapmaxval,
517 			 &rows, &cols, &planes);
518     writeiconinit(stdout, cols, rows, planes);
519     writeiconimage(stdout, outimg, 16*((cols+15)>>4), rows, planes);
520     free(outimg);
521   }
522 
523   writeiconend(stdout, type, deftool, tooltypes, toolwin);
524 
525   return 0;
526 }
527