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