added concrete implementations of putc(), getc(), getchar() and gets()
[tangerine.git] / tools / ilbmtoicon / ilbmtoicon.c
blob40f1b9500310b9fd6b32593f9044d2bac97c1424
1 /*
2 Copyright © 1995-2001, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Tool to convert IFF ILBM images into Amiga icon file.
7 Lang:
9 */
11 /****************************************************************************************/
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <ctype.h>
17 #include <memory.h>
19 /****************************************************************************************/
21 #define MAKE_ID(a,b,c,d) (((a)<<24) | ((b)<<16) | ((c)<<8) | ((d)))
23 #define ID_FORM MAKE_ID('F','O','R','M')
24 #define ID_ILBM MAKE_ID('I','L','B','M')
25 #define ID_CMAP MAKE_ID('C','M','A','P')
26 #define ID_BODY MAKE_ID('B','O','D','Y')
27 #define ID_BMHD MAKE_ID('B','M','H','D')
29 #define ID_ICON MAKE_ID('I','C','O','N')
30 #define ID_FACE MAKE_ID('F','A','C','E')
31 #define ID_IMAG MAKE_ID('I','M','A','G')
33 #define CMP_NONE 0
34 #define CMP_BYTERUN1 1
36 #define MSK_HASMASK 1
38 /****************************************************************************************/
40 /* For this tool it does not really matter if the following types
41 have a bigger sizeof() than on Amiga */
43 #ifndef __AROS__
44 typedef void *APTR;
45 typedef unsigned long ULONG;
46 typedef long LONG;
47 typedef unsigned short UWORD;
48 typedef short WORD;
49 typedef short BOOL;
50 typedef unsigned char UBYTE;
51 #else
52 #include <exec/types.h>
53 #endif
55 /****************************************************************************************/
57 struct BitMapHeader
59 UWORD bmh_Width;
60 UWORD bmh_Height;
61 WORD bmh_Left;
62 WORD bmh_Top;
63 UBYTE bmh_Depth;
64 UBYTE bmh_Masking;
65 UBYTE bmh_Compression;
66 UBYTE bmh_Pad;
67 UWORD bmh_Transparent;
68 UBYTE bmh_XAspect;
69 UBYTE bmh_YAspect;
70 WORD bmh_PageWidth;
71 WORD bmh_PageHeight;
74 /****************************************************************************************/
76 struct ILBMImage
78 struct BitMapHeader bmh;
79 struct BitMapHeader planarbmh;
80 unsigned char *planarbuffer, *chunkybuffer;
81 LONG cmapentries, bpr, totdepth;
82 UBYTE rgb[256][3];
83 UBYTE remaptable[256];
86 /****************************************************************************************/
88 struct Palette
90 UWORD numentries;
91 UBYTE rgb[256][3];
94 /****************************************************************************************/
96 struct Palette std4colpal =
100 {0xB3, 0xB3, 0xB3},
101 {0x00, 0x00, 0x00},
102 {0xFF, 0xFF, 0xFF},
103 {0x66, 0x88, 0xBB}
107 /****************************************************************************************/
109 static char *filename, *outfilename, *infilename;
110 static unsigned char *filebuffer, *body;
111 static FILE *file, *outfile, *infile;
112 static long filesize, bodysize, bodysize_packed;
113 static long filepos;
114 static struct ILBMImage img1, img2;
115 static BOOL have_bmhd, have_cmap, have_body, is_png;
117 static char *image1option;
118 static char *image2option;
119 static char *defaulttooloption;
120 static char *drawerdataoption;
121 static char **tooltypesoption;
122 static LONG typeoption = 3; /* WBTOOL */
123 static LONG iconleftoption = 0x80000000; /* NO_ICON_POSITION */
124 static LONG icontopoption = 0x80000000; /* NO_ICON_POSITION */
125 static LONG stackoption = 4096;
126 static LONG drawerleftoption = 0;
127 static LONG drawertopoption = 20;
128 static LONG drawerwidthoption = 300;
129 static LONG drawerheightoption = 100;
130 static LONG drawervleftoption = 0;
131 static LONG drawervtopoption = 0;
132 static LONG drawershowoption = 0;
133 static LONG drawershowasoption = 0;
134 static LONG transparentoption = 0;
136 /****************************************************************************************/
138 static void freeimage(struct ILBMImage *img)
140 if (img->chunkybuffer)
142 free(img->chunkybuffer);
143 img->chunkybuffer = NULL;
146 if (img->planarbuffer)
148 free(img->planarbuffer);
149 img->planarbuffer = NULL;
152 if (filebuffer)
154 free(filebuffer);
155 filebuffer = NULL;
158 if (file)
160 fclose(file);
161 file = NULL;
164 filepos = 0;
167 /****************************************************************************************/
169 static void cleanup(char *msg, int rc)
171 if (msg) fprintf(stderr, "ilbmtoicon: %s\n", msg);
173 freeimage(&img1);
174 freeimage(&img2);
176 if (outfile) fclose(outfile);
177 if (infile) fclose(infile);
179 exit(rc);
182 /****************************************************************************************/
184 static void getarguments(int argc, char **argv)
186 WORD i;
188 if ((argc != 4) && (argc != 5))
190 fprintf(stderr, "Wrong number of arguments\n");
191 cleanup("Usage: ilbmtoicon icondescription image1 [image2] filename", 1);
194 if (argc == 4)
196 infilename = argv[1];
197 image1option = argv[2];
198 outfilename = argv[3];
200 else if (argc == 5)
202 infilename = argv[1];
203 image1option = argv[2];
204 image2option = argv[3];
205 outfilename = argv[4];
209 /****************************************************************************************/
211 static char *skipblanks(char *s)
213 while ((*s == ' ') || (*s == '\t')) s++;
215 return s;
218 /****************************************************************************************/
220 static char *skipword(char *s)
222 while((*s != ' ') &&
223 (*s != '\t') &&
224 (*s != '\0') &&
225 (*s != '\n'))
227 s++;
230 return s;
233 /****************************************************************************************/
235 static char *checkquotes(char *s)
237 char *s2;
239 if (*s != '"')
241 s2 = skipword(s);
242 *s2 = '\0';
244 return s;
247 s++;
249 s2 = s;
250 while((*s2 != '"') && (*s2 != '\0')) s2++;
251 *s2 = '\0';
253 return s;
256 /****************************************************************************************/
258 #define KEYWORD_STRING 0
259 #define KEYWORD_INTEGER 1
260 #define KEYWORD_STRINGARRAY 2
261 #define KEYWORD_CYCLE 3
263 #define MAX_ARRAY_SIZE 200
265 /****************************************************************************************/
267 struct cycle
269 char *keyword;
270 LONG value;
273 struct cycle typecycles[] =
275 {"DISK" , 1},
276 {"DRAWER" , 2},
277 {"TOOL" , 3},
278 {"PROJECT" , 4},
279 {"GARBAGE" , 5},
280 {"DEVICE" , 6},
281 {"KICK" , 7},
282 {"APPICON" , 8},
285 struct cycle showcycles[] =
287 {"DEFAULT" , 0},
288 {"ICONS" , 1},
289 {"ALL" , 2},
290 {NULL , 0}
294 struct cycle showascycles[] =
296 {"DEFAULT" , 0},
297 {"ICON" , 1},
298 {"TEXT_NAME", 2},
299 {"TEXT_DATE", 3},
300 {"TEXT_SIZE", 4},
301 {"TEXT_TYPE", 5},
302 {NULL , 0}
307 /****************************************************************************************/
309 struct keyword
311 WORD type;
312 char *keyword;
313 APTR store;
314 APTR extra;
316 keywordtable[] =
318 {KEYWORD_STRING , "DEFAULTTOOL" , &defaulttooloption , NULL },
319 {KEYWORD_STRING , "DRAWERDATA" , &drawerdataoption , NULL },
320 {KEYWORD_CYCLE , "TYPE" , &typeoption , typecycles },
321 {KEYWORD_STRINGARRAY, "TOOLTYPE" , &tooltypesoption , NULL },
322 {KEYWORD_INTEGER , "STACK" , &stackoption , NULL },
323 {KEYWORD_INTEGER , "ICONLEFTPOS" , &iconleftoption , NULL },
324 {KEYWORD_INTEGER , "ICONTOPPOS" , &icontopoption , NULL },
325 {KEYWORD_INTEGER , "DRAWERLEFTPOS" , &drawerleftoption , NULL },
326 {KEYWORD_INTEGER , "DRAWERTOPPOS" , &drawertopoption , NULL },
327 {KEYWORD_INTEGER , "DRAWERWIDTH" , &drawerwidthoption , NULL },
328 {KEYWORD_INTEGER , "DRAWERHEIGHT" , &drawerheightoption , NULL },
329 {KEYWORD_INTEGER , "DRAWERVIEWLEFT" , &drawervleftoption , NULL },
330 {KEYWORD_INTEGER , "DRAWERVIEWTOP" , &drawervtopoption , NULL },
331 {KEYWORD_CYCLE , "DRAWERSHOW" , &drawershowoption , showcycles },
332 {KEYWORD_CYCLE , "DRAWERSHOWAS" , &drawershowoption , showascycles },
333 {KEYWORD_INTEGER , "TRANSPARENT" , &transparentoption , NULL },
334 {0 , NULL , NULL }
338 /****************************************************************************************/
340 static void handleoption(char *keyword, char *keyvalue)
342 struct keyword *kw;
343 struct cycle *cy;
345 for(kw = keywordtable; kw->keyword; kw++)
347 if (strcasecmp(kw->keyword, keyword) == 0)
349 switch(kw->type)
351 case KEYWORD_STRING:
352 *(char **)kw->store = strdup(keyvalue);
353 if (!(*(char **)kw->store)) cleanup("Out of memory!", 1);
354 break;
356 case KEYWORD_INTEGER:
357 *(LONG *)kw->store = strtol(keyvalue, 0, 0);
358 break;
360 case KEYWORD_CYCLE:
361 for(cy = (struct cycle *)kw->extra; cy->keyword; cy++)
363 if (strcasecmp(keyvalue, cy->keyword) == 0)
365 *(LONG *)kw->store = cy->value;
366 break;
369 break;
371 case KEYWORD_STRINGARRAY:
372 if (!(*(char ***)kw->store))
374 *(char ***)kw->store = (char **)malloc(MAX_ARRAY_SIZE * sizeof(char *));
375 if (!(*(char ***)kw->store)) cleanup("Out of memory!", 1);
377 memset(*(char ***)kw->store, 0, MAX_ARRAY_SIZE * sizeof(char *));
381 char *dupvalue;
382 char **strarray = *(char ***)kw->store;
383 WORD i = 0;
385 dupvalue = strdup(keyvalue);
386 if (!dupvalue) cleanup("Out of memory!", 1);
388 while(*strarray)
390 strarray++;
391 i++;
394 if (i >= MAX_ARRAY_SIZE - 1) cleanup("Array overflow!", 1);
396 *strarray = dupvalue;
399 } /* switch(kw->type) */
401 break;
403 } /* if (strcasecmp(kw->keyword, keyword) == 0) */
405 } /* for(kw = keywordtable; kw->keyword; kw++) */
409 /****************************************************************************************/
411 static void parseline(char *s)
413 char *keyword;
414 char *keyvalue = NULL;
416 s = skipblanks(s);
418 if (*s == '#') return;
419 if (*s == ';') return;
421 keyword = s;
423 s = skipword(s);
424 if (*s == '\0') return;
426 *s = '\0';
427 s = skipblanks(s + 1);
429 if (*s == '=') s = skipblanks(s + 1);
430 if (*s == '\0') return;
432 keyvalue = checkquotes(s);
434 handleoption(keyword, keyvalue);
437 /****************************************************************************************/
439 static void parseiconsource(void)
441 char s[256];
443 infile = fopen(infilename, "r");
444 if (infile)
446 while(fgets(s, sizeof(s), infile))
448 parseline(s);
451 fclose(infile);
452 infile = 0;
456 /****************************************************************************************/
458 static void showoptions(void)
460 char **strarray;
462 printf("image1: %s\n", image1option ? image1option : "(NULL)");
463 printf("image2: %s\n", image2option ? image2option : "(NULL)");
464 printf("type: %d\n", typeoption);
466 strarray = tooltypesoption;
467 if (strarray)
469 printf("tooltypes:\n");
470 while(*strarray)
472 printf(" %s\n", *strarray++);
479 /****************************************************************************************/
481 static ULONG getlong(void)
483 ULONG ret;
485 if (filepos > filesize - 4) cleanup("Tried to read over file end!", 1);
487 ret = filebuffer[filepos++] * 0x1000000;
488 ret += filebuffer[filepos++] * 0x10000;
489 ret += filebuffer[filepos++] * 0x100;
490 ret += filebuffer[filepos++];
492 return ret;
495 /****************************************************************************************/
497 static UWORD getword(void)
499 UWORD ret;
501 if (filepos > filesize - 2) cleanup("Tried to read over file end!", 1);
503 ret = filebuffer[filepos++] * 0x100;
504 ret += filebuffer[filepos++];
506 return ret;
509 /****************************************************************************************/
511 static UBYTE getbyte(void)
513 ULONG ret;
515 if (filepos > filesize - 1) cleanup("Tried to read over file end!", 1);
516 ret = filebuffer[filepos++];
518 return ret;
521 /****************************************************************************************/
523 static void skipbytes(ULONG howmany)
525 filepos += howmany;
528 /****************************************************************************************/
530 static void openimage(struct ILBMImage *img)
532 file = fopen(filename, "rb");
533 if (!file) cleanup("Can't open file!", 1);
535 fseek(file, 0, SEEK_END);
536 filesize = ftell(file);
538 if (filesize < 12) cleanup("Bad file size!", 1);
540 //fprintf(stderr, "Filesize is %d\n", filesize);
542 fseek(file, 0, SEEK_SET);
544 filebuffer = malloc(filesize + 10);
545 if (!filebuffer) cleanup("Memory allocation for file buffer failed!", 1);
547 if (fread(filebuffer, 1, filesize, file) != filesize)
548 cleanup("Error reading file!", 1);
550 fclose(file); file = NULL;
553 /****************************************************************************************/
555 static void checkimage(struct ILBMImage *img)
557 static UBYTE pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
559 ULONG id;
560 ULONG size;
562 if (memcmp(filebuffer, pngsig, 8) == 0)
564 is_png = 1;
566 else if (is_png == 0)
568 id = getlong();
569 if (id != ID_FORM) cleanup("File is not an IFF file!", 1);
571 size = getlong();
572 if (size != filesize - 8) cleanup("File is IFF, but has bad size in IFF header!", 1);
574 id = getlong();
575 if (id != ID_ILBM) cleanup("File is IFF, but not of type ILBM!", 1);
577 else if (is_png == 1)
579 cleanup("Second image must be a PNG image, too!", 1);
583 /****************************************************************************************/
585 static void scanimage(struct ILBMImage *img)
587 WORD i;
589 have_bmhd = 0;
590 have_cmap = 0;
591 have_body = 0;
593 for(;;)
595 ULONG id;
596 ULONG size;
598 id = getlong();
599 size = getlong();
601 //fprintf(stderr, "Chunk: %c%c%c%c Size: %d\n", id >> 24, id >> 16, id >> 8, id, size);
603 switch(id)
605 case ID_BMHD:
606 if (size != 20) cleanup("Bad BMHD chunk size!", 1);
608 img->bmh.bmh_Width = getword();
609 img->bmh.bmh_Height = getword();
610 img->bmh.bmh_Left = (WORD)getword();
611 img->bmh.bmh_Top = (WORD)getword();
612 img->bmh.bmh_Depth = getbyte();
613 img->bmh.bmh_Masking = getbyte();
614 img->bmh.bmh_Compression = getbyte();
615 img->bmh.bmh_Pad = getbyte();
616 img->bmh.bmh_Transparent = getword();
617 img->bmh.bmh_XAspect = getbyte();
618 img->bmh.bmh_YAspect = getbyte();
619 img->bmh.bmh_PageWidth = (WORD)getword();
620 img->bmh.bmh_PageHeight = (WORD)getword();
622 if (img->bmh.bmh_Depth > 8) cleanup("ILBM file has too many colors!", 1);
623 if ((img->bmh.bmh_Compression != CMP_NONE) && (img->bmh.bmh_Compression != CMP_BYTERUN1)) cleanup("Compression method unsupported!", 1);
625 have_bmhd = 1;
627 img->totdepth = img->bmh.bmh_Depth + ((img->bmh.bmh_Masking == MSK_HASMASK) ? 1 : 0);
629 img->bpr = ((img->bmh.bmh_Width + 15) & ~15) / 8;
631 /*fprintf(stderr, "BMHD: %d x %d x %d (%d)\n", img->bmh.bmh_Width,
632 img->bmh.bmh_Height,
633 img->bmh.bmh_Depth,
634 img->totdepth);*/
635 img->planarbmh = img->bmh;
636 break;
638 case ID_CMAP:
639 if (!have_bmhd) cleanup("CMAP chunk before BMHD chunk (or no BMHD chunk at all!", 1);
641 img->cmapentries = size / 3;
642 if (size & 1) size++;
644 if ((img->cmapentries < 2) || (img->cmapentries > 256)) cleanup("CMAP chunk has bad number of entries!", 1);
646 for(i = 0; i < img->cmapentries; i++)
648 img->rgb[i][0] = getbyte();
649 img->rgb[i][1] = getbyte();
650 img->rgb[i][2] = getbyte();
651 size -= 3;
654 skipbytes(size);
656 have_cmap = 1;
658 break;
660 case ID_BODY:
661 if (!have_bmhd) cleanup("BODY chunk before BMHD chunk (or no BMHD chunk at all!", 1);
662 body = &filebuffer[filepos];
663 bodysize = size;
665 if (img->bmh.bmh_Compression == CMP_NONE)
667 LONG shouldbesize = img->totdepth * img->bpr * img->bmh.bmh_Height;
668 if (bodysize != shouldbesize) cleanup("BODY chunk size seems to be wrong!", 1);
671 have_body = 1;
672 /* Fall through */
674 default:
675 if (size & 1) size++;
676 skipbytes(size);
677 break;
680 if (filepos == filesize) break;
681 if (have_bmhd && have_body && have_cmap) break;
684 if (!have_bmhd) cleanup("BMHD chunk missing!", 1);
685 if (!have_body) cleanup("BODY chunk missing!", 1);
688 /****************************************************************************************/
690 static unsigned char *unpack_byterun1(unsigned char *source, unsigned char *dest, LONG unpackedsize)
692 unsigned char r;
693 signed char c;
695 for(;;)
697 c = (signed char)(*source++);
698 if (c >= 0)
700 while(c-- >= 0)
702 *dest++ = *source++;
703 if (--unpackedsize <= 0) return source;
706 else if (c != -128)
708 c = -c;
709 r = *source++;
711 while(c-- >= 0)
713 *dest++ = r;
714 if (--unpackedsize <= 0) return source;
721 /****************************************************************************************/
723 static BOOL norm1(LONG count, unsigned char **source_backup,
724 unsigned char **dest, LONG *checksize)
726 //if (count >= 0) fprintf(stderr, "XX: non packable %d\n",count);
728 while(count >= 0)
730 LONG step = count;
732 if (step > 127) step = 127;
734 *checksize -= step;
735 *checksize -= 2;
737 if (*checksize <= 0) return 0;
739 count -= step;
741 *(*dest)++ = step;
744 while(step-- >= 0)
746 *(*dest)++ = *(*source_backup)++;
749 count--;
753 return 1;
756 static BOOL copy1(unsigned char r, LONG count, unsigned char **dest, LONG *checksize)
758 //if (count >= 1) fprintf(stderr, "XX: repeat %02x x %d\n", r, count);
760 while(--count >= 0)
762 LONG step = count;
764 if (step > 127) step = 127;
766 count -= step;
767 step = -step;
768 *checksize -= 2;
769 if (*checksize <= 0) return 0;
771 *(*dest)++ = (unsigned char)step;
772 *(*dest)++ = r;
775 return 1;
778 static BOOL pack_byterun1(unsigned char *source, unsigned char *dest,
779 LONG size, LONG check_size, LONG *packsize)
781 unsigned char *source_backup, *dest_backup;
782 LONG samebytes_counter, samebytes, count;
783 LONG checksize = check_size;
784 unsigned char oldbyte, actbyte;
786 if (checksize < 0) checksize = 0x7FFFFFFF;
788 oldbyte = *source;
789 samebytes_counter = 0;
790 source_backup = source;
791 dest_backup = dest;
793 for(;;)
795 //fprintf(stderr, "size = %d. checksize = %d\n", size, checksize);
796 if (--size < 0) break;
797 actbyte = *source++;
798 if (actbyte == oldbyte)
800 samebytes_counter++;
801 continue;
804 oldbyte = actbyte;
806 samebytes = samebytes_counter;
807 samebytes_counter = 1;
809 if (samebytes < 3) continue;
811 count = (LONG)(source - source_backup - samebytes - 2);
812 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
814 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
816 source_backup = source - 1;
818 //fprintf(stderr, "done\n");
820 if (samebytes_counter >= 3)
822 samebytes = samebytes_counter;
823 count = (LONG)(source - source_backup - samebytes - 1);
824 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
825 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
827 else
829 count = (LONG)(source - source_backup - 1);
830 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
832 //fprintf(stderr, "realdone\n");
834 if (packsize) *packsize = (LONG)(dest - dest_backup);
836 return 1;
839 /****************************************************************************************/
841 static void p2c(unsigned char *source, unsigned char *dest, LONG width, LONG height,
842 LONG totplanes, LONG wantplanes, LONG chunkybpr)
844 LONG alignedwidth, x, y, p, bpr, bpl;
846 alignedwidth = (width + 15) & ~15;
847 bpr = alignedwidth / 8;
848 bpl = bpr * totplanes;
850 for(y = 0; y < height; y++)
852 for(x = 0; x < width; x++)
854 LONG mask = 0x80 >> (x & 7);
855 LONG offset = x / 8;
856 unsigned char chunkypix = 0;
858 for(p = 0; p < wantplanes; p++)
860 if (source[p * bpr + offset] & mask) chunkypix |= (1 << p);
862 dest[x] = chunkypix;
865 source += bpl;
866 dest += chunkybpr;
872 /****************************************************************************************/
874 static void c2p(unsigned char *source, unsigned char *dest, LONG width, LONG height, LONG planes)
876 LONG alignedwidth, x, y, p, bpr, bpl;
878 alignedwidth = (width + 15) & ~15;
879 bpr = alignedwidth / 8;
880 bpl = bpr * planes;
882 for(y = 0; y < height; y++)
884 for(x = 0; x < width; x++)
886 LONG mask = 0x80 >> (x & 7);
887 LONG offset = x / 8;
888 unsigned char chunkypix = source[x];
890 for(p = 0; p < planes; p++)
892 if (chunkypix & (1 << p))
893 dest[p * bpr + offset] |= mask;
894 else
895 dest[p * bpr + offset] &= ~mask;
899 source += width;
900 dest += bpl;
905 /****************************************************************************************/
907 static void convertbody(struct ILBMImage *img)
909 LONG unpackedsize = img->bpr * img->bmh.bmh_Height * img->totdepth;
911 img->planarbuffer = malloc(unpackedsize);
912 if (!img->planarbuffer) cleanup("Memory allocation for planar buffer failed!", 1);
914 if (img->bmh.bmh_Compression == CMP_NONE)
916 memcpy(img->planarbuffer, body, unpackedsize);
918 else
920 unpack_byterun1(body, img->planarbuffer, unpackedsize);
923 img->chunkybuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
924 if (!img->chunkybuffer) cleanup("Memory allocation for chunky buffer failed!", 1);
926 p2c(img->planarbuffer,
927 img->chunkybuffer,
928 img->bmh.bmh_Width,
929 img->bmh.bmh_Height,
930 img->totdepth,
931 img->bmh.bmh_Depth,
932 img->bmh.bmh_Width);
935 /****************************************************************************************/
937 static UBYTE findcolor(struct Palette *pal, ULONG r, ULONG g, ULONG b)
939 ULONG dist, bestdist = 0xFFFFFFFF;
940 UBYTE i, besti = 0;
942 for(i = 0; i < pal->numentries; i++)
944 LONG r1, g1, b1, r2, g2, b2, dr, dg, db;
946 r1 = (LONG)r;
947 g1 = (LONG)g;
948 b1 = (LONG)b;
950 r2 = (LONG)pal->rgb[i][0];
951 g2 = (LONG)pal->rgb[i][1];
952 b2 = (LONG)pal->rgb[i][2];
954 dr = r1 - r2;
955 dg = g1 - g2;
956 db = b1 - b2;
958 dist = (dr * dr) + (dg * dg) + (db * db);
959 if (dist < bestdist)
961 bestdist = dist;
962 besti = i;
967 return besti;
970 /****************************************************************************************/
972 static void remapplanar(struct ILBMImage *img, struct Palette *pal)
974 UBYTE *remapbuffer;
975 LONG i, x, y, highestcol = 0, newdepth = 0;
977 remapbuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
978 if (!remapbuffer) cleanup("Error allocating remap buffer!", 1);
980 for(i = 0; i < img->cmapentries; i++)
982 img->remaptable[i] = findcolor(pal, img->rgb[i][0], img->rgb[i][1], img->rgb[i][2]);
985 for(i = 0; i < img->bmh.bmh_Width * img->bmh.bmh_Height; i++)
987 remapbuffer[i] = img->remaptable[img->chunkybuffer[i]];
989 if (remapbuffer[i] > highestcol)
990 highestcol = remapbuffer[i];
993 for(i = highestcol; i; i >>= 1) newdepth++;
994 if (newdepth == 0) newdepth = 1;
996 if (newdepth > img->totdepth)
998 free(img->planarbuffer);
1000 img->planarbuffer = malloc(img->bpr * img->bmh.bmh_Height * newdepth);
1001 if (!img->planarbuffer)
1003 free(remapbuffer);
1004 cleanup("Error re-allocating planar buffer!", 1);
1008 img->planarbmh.bmh_Depth = newdepth;
1010 memset(img->planarbuffer, 0, img->bpr * img->bmh.bmh_Height * newdepth);
1012 c2p(remapbuffer, img->planarbuffer, img->bmh.bmh_Width, img->bmh.bmh_Height, newdepth);
1014 free(remapbuffer);
1017 /****************************************************************************************/
1019 static void loadimage(char *name, struct ILBMImage *img)
1021 freeimage(img);
1023 filename = name;
1025 openimage(img);
1026 checkimage(img);
1027 if (!is_png)
1029 scanimage(img);
1030 convertbody(img);
1034 /****************************************************************************************/
1036 struct diskobject
1038 UBYTE do_magic[2];
1039 UBYTE do_version[2];
1040 UBYTE do_gadget_nextgadget[4];
1041 UBYTE do_gadget_leftedge[2];
1042 UBYTE do_gadget_topedge[2];
1043 UBYTE do_gadget_width[2];
1044 UBYTE do_gadget_height[2];
1045 UBYTE do_gadget_flags[2];
1046 UBYTE do_gadget_activation[2];
1047 UBYTE do_gadget_gadgettype[2];
1048 UBYTE do_gadget_gadgetrender[4];
1049 UBYTE do_gadget_selectrender[4];
1050 UBYTE do_gadget_gadgettext[4];
1051 UBYTE do_gadget_mutualexclude[4];
1052 UBYTE do_gadget_specialinfo[4];
1053 UBYTE do_gadget_gadgetid[2];
1054 UBYTE do_gadget_userdata[4];
1055 UBYTE do_type;
1056 UBYTE do_pad;
1057 UBYTE do_defaulttool[4];
1058 UBYTE do_tooltypes[4];
1059 UBYTE do_currentx[4];
1060 UBYTE do_currenty[4];
1061 UBYTE do_drawerdata[4];
1062 UBYTE do_toolwindow[4];
1063 UBYTE do_stacksize[4];
1066 /****************************************************************************************/
1068 struct olddrawerdata
1070 UBYTE dd_newwindow_leftedge[2];
1071 UBYTE dd_newwindow_topedge[2];
1072 UBYTE dd_newwindow_width[2];
1073 UBYTE dd_newwindow_height[2];
1074 UBYTE dd_newwindow_detailpen;
1075 UBYTE dd_newwindow_blockpen;
1076 UBYTE dd_newwindow_idcmpflags[4];
1077 UBYTE dd_newwindow_flags[4];
1078 UBYTE dd_newwindow_firstgadget[4];
1079 UBYTE dd_newwindow_checkmark[4];
1080 UBYTE dd_newwindow_title[4];
1081 UBYTE dd_newwindow_screen[4];
1082 UBYTE dd_newwindow_bitmap[4];
1083 UBYTE dd_newwindow_minwidth[2];
1084 UBYTE dd_newwindow_minheight[2];
1085 UBYTE dd_newwindow_maxwidth[2];
1086 UBYTE dd_newwindow_maxheight[2];
1087 UBYTE dd_newwindow_type[2];
1088 UBYTE dd_currentx[4];
1089 UBYTE dd_currenty[4];
1092 /****************************************************************************************/
1094 struct newdrawerdata
1096 UBYTE dd_flags[4];
1097 UBYTE dd_viewmodes[2];
1100 /****************************************************************************************/
1102 struct image
1104 UBYTE leftedge[2];
1105 UBYTE topedge[2];
1106 UBYTE width[2];
1107 UBYTE height[2];
1108 UBYTE depth[2];
1109 UBYTE imagedata[4];
1110 UBYTE planepick;
1111 UBYTE planeonoff;
1112 UBYTE nextimage[4];
1115 /****************************************************************************************/
1117 #define SET_BYTE(field,value) \
1118 ACT_STRUCT.field = value
1120 #define SET_WORD(field, value) \
1121 ACT_STRUCT.field[0] = ((value) >> 8) & 0xFF; \
1122 ACT_STRUCT.field[1] = (value) & 0xFF;
1124 #define SET_LONG(field,value) \
1125 ACT_STRUCT.field[0] = ((value) >> 24) & 0xFF; \
1126 ACT_STRUCT.field[1] = ((value) >> 16) & 0xFF; \
1127 ACT_STRUCT.field[2] = ((value) >> 8) & 0xFF; \
1128 ACT_STRUCT.field[3] = (value) & 0xFF;
1130 #define BOOL_YES 0x2A2A2A2A
1131 #define BOOL_NO 0x00000000
1133 static void writediskobject(void)
1135 struct diskobject dobj;
1137 #define ACT_STRUCT dobj
1139 SET_WORD(do_magic, 0xE310);
1140 SET_WORD(do_version, 1);
1141 SET_LONG(do_gadget_nextgadget, 0);
1142 SET_WORD(do_gadget_leftedge, 0);
1143 SET_WORD(do_gadget_topedge, 0);
1144 SET_WORD(do_gadget_width, img1.bmh.bmh_Width);
1145 SET_WORD(do_gadget_height, img1.bmh.bmh_Height);
1147 if (image2option)
1149 /* GFLG_GADGHIMAGE + GFLG_GADGIMAGE */
1150 SET_WORD(do_gadget_flags, 4 + 2);
1152 else
1154 /* GFLG_GADGIMAGE */
1155 SET_WORD(do_gadget_flags, 4);
1158 SET_WORD(do_gadget_activation, 0);
1159 SET_WORD(do_gadget_gadgettype, 0);
1160 SET_LONG(do_gadget_gadgetrender, BOOL_YES);
1162 if (image2option)
1164 SET_LONG(do_gadget_selectrender, BOOL_YES);
1166 else
1168 SET_LONG(do_gadget_selectrender, BOOL_NO);
1171 SET_LONG(do_gadget_gadgettext, 0);
1172 SET_LONG(do_gadget_mutualexclude, 0);
1173 SET_LONG(do_gadget_specialinfo, 0);
1174 SET_WORD(do_gadget_gadgetid, 0);
1175 SET_LONG(do_gadget_userdata, 1); /* full drawer data */
1177 SET_BYTE(do_type, typeoption);
1178 SET_BYTE(do_pad, 0);
1180 if (defaulttooloption)
1182 SET_LONG(do_defaulttool, BOOL_YES);
1184 else
1186 SET_LONG(do_defaulttool, BOOL_NO);
1189 if (tooltypesoption)
1191 SET_LONG(do_tooltypes, BOOL_YES);
1193 else
1195 SET_LONG(do_tooltypes, BOOL_NO);
1198 SET_LONG(do_currentx, iconleftoption);
1199 SET_LONG(do_currenty, icontopoption);
1201 if (drawerdataoption)
1203 SET_LONG(do_drawerdata, BOOL_YES);
1205 else
1207 SET_LONG(do_drawerdata, BOOL_NO);
1211 SET_LONG(do_toolwindow, 0);
1212 SET_LONG(do_stacksize, stackoption);
1214 if (fwrite(&dobj, 1, sizeof(dobj), outfile) != sizeof(dobj))
1216 cleanup("Error writing diskobject structure to outfile!", 1);
1220 /****************************************************************************************/
1222 static void writeolddrawerdata(void)
1224 struct olddrawerdata dd;
1226 if (!drawerdataoption) return;
1228 #undef ACT_STRUCT
1229 #define ACT_STRUCT dd
1231 SET_WORD(dd_newwindow_leftedge, drawerleftoption);
1232 SET_WORD(dd_newwindow_topedge, drawertopoption);
1233 SET_WORD(dd_newwindow_width, drawerwidthoption);
1234 SET_WORD(dd_newwindow_height, drawerheightoption);
1235 SET_BYTE(dd_newwindow_detailpen, 0);
1236 SET_BYTE(dd_newwindow_blockpen, 0);
1237 SET_LONG(dd_newwindow_idcmpflags, 0);
1238 SET_LONG(dd_newwindow_flags, 0);
1239 SET_LONG(dd_newwindow_firstgadget, 0);
1240 SET_LONG(dd_newwindow_checkmark, 0);
1241 SET_LONG(dd_newwindow_title, 0);
1242 SET_LONG(dd_newwindow_screen, 0);
1243 SET_LONG(dd_newwindow_bitmap, 0);
1244 SET_WORD(dd_newwindow_minwidth, 0);
1245 SET_WORD(dd_newwindow_minheight, 0);
1246 SET_WORD(dd_newwindow_maxwidth, 0);
1247 SET_WORD(dd_newwindow_maxheight, 0);
1248 SET_WORD(dd_newwindow_type, 0);
1249 SET_LONG(dd_currentx, drawervleftoption);
1250 SET_LONG(dd_currenty, drawervtopoption);
1252 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1254 cleanup("Error writing olddrawerdata structure to outfile!", 1);
1260 /****************************************************************************************/
1262 static void writenewdrawerdata(void)
1264 struct newdrawerdata dd;
1266 if (!drawerdataoption) return;
1268 #undef ACT_STRUCT
1269 #define ACT_STRUCT dd
1271 SET_LONG(dd_flags, drawershowoption);
1272 SET_WORD(dd_viewmodes, drawershowasoption);
1274 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1276 cleanup("Error writing newdrawerdata structure to outfile!", 1);
1281 /****************************************************************************************/
1283 static void writelong(LONG l)
1285 UBYTE f[4];
1287 f[0] = (l >> 24) & 0xFF;
1288 f[1] = (l >> 16) & 0xFF;
1289 f[2] = (l >> 8) & 0xFF;
1290 f[3] = l & 0xFF;
1292 if (fwrite(f, 1, 4, outfile) != 4)
1294 cleanup("Error writing string long value!", 1);
1299 /****************************************************************************************/
1301 static void writenormalstring(char *s)
1303 int len = strlen(s) + 1;
1305 if (fwrite(s, 1, len, outfile) != len)
1307 cleanup("Error writing string!", 1);
1312 /****************************************************************************************/
1314 static void writestring(char *s)
1316 int len = strlen(s) + 1;
1318 writelong(len);
1320 if (fwrite(s, 1, len, outfile) != len)
1322 cleanup("Error writing string!", 1);
1327 /****************************************************************************************/
1329 static void writeimage(struct ILBMImage *img)
1331 struct image i;
1332 LONG d, y;
1334 #undef ACT_STRUCT
1335 #define ACT_STRUCT i
1337 SET_WORD(leftedge, 0);
1338 SET_WORD(topedge, 0);
1339 SET_WORD(width, img->planarbmh.bmh_Width);
1340 SET_WORD(height, img->planarbmh.bmh_Height);
1341 SET_WORD(depth, img->planarbmh.bmh_Depth);
1342 SET_LONG(imagedata, BOOL_YES);
1343 SET_BYTE(planepick, (1 << img->planarbmh.bmh_Depth) - 1);
1344 SET_BYTE(planeonoff, 0);
1345 SET_LONG(nextimage, 0);
1347 if (fwrite(&i, 1, sizeof(i), outfile) != sizeof(i))
1349 cleanup("Error writing image structure to outfile!", 1);
1352 for(d = 0; d < img->planarbmh.bmh_Depth; d++)
1354 UBYTE *dat = img->planarbuffer + img->bpr * d;
1356 for(y = 0; y < img->planarbmh.bmh_Height; y++)
1358 if(fwrite(dat, 1, img->bpr, outfile) != img->bpr)
1360 cleanup("Error writing image data to outfile!", 1);
1362 dat += (img->planarbmh.bmh_Depth * img->bpr);
1368 /****************************************************************************************/
1370 struct facechunk
1372 UBYTE fc_width;
1373 UBYTE fc_height;
1374 UBYTE fc_flags;
1375 UBYTE fc_aspect;
1376 UBYTE fc_maxpalettebytes[2];
1379 /****************************************************************************************/
1381 struct imagchunk
1383 UBYTE ic_transparentcolour;
1384 UBYTE ic_numcolours;
1385 UBYTE ic_flags;
1386 UBYTE ic_imageformat;
1387 UBYTE ic_paletteformat;
1388 UBYTE ic_depth;
1389 UBYTE ic_numimagebytes[2];
1390 UBYTE ic_numpalettebytes[2];
1393 /****************************************************************************************/
1395 static LONG writefacechunk(void)
1397 struct facechunk fc;
1398 LONG palbytes;
1400 #undef ACT_STRUCT
1401 #define ACT_STRUCT fc
1403 writelong(ID_FACE);
1404 writelong(sizeof(struct facechunk));
1406 SET_BYTE(fc_width, img1.bmh.bmh_Width - 1);
1407 SET_BYTE(fc_height, img1.bmh.bmh_Height - 1);
1408 SET_BYTE(fc_flags, 0);
1409 SET_BYTE(fc_aspect, 0); // 0x11);
1411 palbytes = (img1.cmapentries > img2.cmapentries) ? img1.cmapentries : img2.cmapentries;
1412 palbytes = palbytes * 3;
1414 SET_WORD(fc_maxpalettebytes, palbytes - 1);
1416 if (fwrite(&fc, 1, sizeof(fc), outfile) != sizeof(fc))
1418 cleanup("Error writing face chunk!", 1);
1421 return sizeof(struct facechunk) + 8;
1424 /****************************************************************************************/
1426 /* createrle() based on ModifyIcon source by Dirk Stöcker */
1428 /****************************************************************************************/
1430 static char * createrle(unsigned long depth, unsigned char *dtype, LONG *dsize, unsigned long size,
1431 unsigned char *src)
1433 int i, j, k;
1434 unsigned long bitbuf, numbits;
1435 unsigned char *buf;
1436 long ressize, numcopy, numequal;
1438 buf = malloc(size * 2);
1439 if (!buf) return NULL;
1441 numcopy = 0;
1442 numequal = 1;
1443 bitbuf = 0;
1444 numbits = 0;
1445 ressize = 0;
1446 k = 0; /* the really output pointer */
1447 for(i = 1; numequal || numcopy;)
1449 if(i < size && numequal && (src[i-1] == src[i]))
1451 ++numequal; ++i;
1453 else if(i < size && numequal*depth <= 16)
1455 numcopy += numequal; numequal = 1; ++i;
1457 else
1459 /* care for end case, where it maybe better to join the two */
1460 if(i == size && numcopy + numequal <= 128 && (numequal-1)*depth <= 8)
1462 numcopy += numequal; numequal = 0;
1464 if(numcopy)
1466 if((j = numcopy) > 128) j = 128;
1467 bitbuf = (bitbuf<<8) | (j-1);
1468 numcopy -= j;
1470 else
1472 if((j = numequal) > 128) j = 128;
1473 bitbuf = (bitbuf<<8) | (256-(j-1));
1474 numequal -= j;
1475 k += j-1;
1476 j = 1;
1478 buf[ressize++] = (bitbuf >> numbits);
1479 while(j--)
1481 numbits += depth;
1482 bitbuf = (bitbuf<<depth) | src[k++];
1483 if(numbits >= 8)
1485 numbits -= 8;
1486 buf[ressize++] = (bitbuf >> numbits);
1489 if(i < size && !numcopy && !numequal)
1491 numequal = 1; ++i;
1495 if(numbits)
1496 buf[ressize++] = bitbuf << (8-numbits);
1498 if(ressize > size) /* no RLE */
1500 ressize = size;
1501 *dtype = 0;
1502 for(i = 0; i < size; ++i)
1503 buf[i]= src[i];
1505 else
1506 *dtype = 1;
1508 *dsize = ressize;
1510 return buf;
1513 /****************************************************************************************/
1515 static LONG writeimagchunk(struct ILBMImage *img)
1517 struct imagchunk ic;
1518 LONG imagsize;
1519 UBYTE skippalette = 0;
1520 UBYTE *pal, *gfx;
1521 LONG palsize, gfxsize;
1522 UBYTE palpacked, gfxpacked;
1524 imagsize = sizeof(struct imagchunk);
1526 /* if this is second image check whether palette is identical to
1527 the one of first image */
1529 if (img == &img2)
1531 if (img1.cmapentries == img2.cmapentries)
1533 WORD i;
1535 for (i = 0; i < img1.cmapentries; i++)
1537 if (img1.rgb[i][0] != img2.rgb[i][0]) break;
1538 if (img1.rgb[i][1] != img2.rgb[i][1]) break;
1539 if (img1.rgb[i][2] != img2.rgb[i][2]) break;
1542 if (i == img1.cmapentries) skippalette = 1;
1546 if (!skippalette)
1548 pal = createrle(8,
1549 &palpacked,
1550 &palsize,
1551 img->cmapentries * 3,
1552 (unsigned char *)img->rgb);
1554 imagsize += palsize;
1557 gfx = createrle(img->bmh.bmh_Depth,
1558 &gfxpacked,
1559 &gfxsize,
1560 img->bmh.bmh_Width * img->bmh.bmh_Height,
1561 img->chunkybuffer);
1563 imagsize += gfxsize;
1565 #undef ACT_STRUCT
1566 #define ACT_STRUCT ic
1568 SET_BYTE(ic_transparentcolour, transparentoption);
1569 if (skippalette)
1571 SET_BYTE(ic_numcolours, 0);
1572 SET_BYTE(ic_flags, (transparentoption != -1) ? 1 : 0); /* 1 = HasTransparentColour */
1573 SET_BYTE(ic_paletteformat, 0);
1574 SET_WORD(ic_numpalettebytes, 0);
1576 else
1578 SET_BYTE(ic_numcolours, img->cmapentries - 1);
1579 SET_BYTE(ic_flags, (transparentoption != -1) ? 3 : 2); /* 2 = HasPalette */
1580 SET_BYTE(ic_paletteformat, palpacked);
1581 SET_WORD(ic_numpalettebytes, palsize - 1);
1584 SET_BYTE(ic_imageformat, gfxpacked);
1585 SET_BYTE(ic_depth, img->bmh.bmh_Depth);
1586 SET_WORD(ic_numimagebytes, gfxsize - 1);
1588 writelong(ID_IMAG);
1589 writelong(imagsize);
1591 if (fwrite(&ic, 1, sizeof(ic), outfile) != sizeof(ic))
1593 cleanup("Error writing imag chunk!", 1);
1596 if (fwrite(gfx, 1, gfxsize, outfile) != gfxsize)
1598 cleanup("Error write gfx data in imag chunk!", 1);
1601 if (!skippalette)
1603 if (fwrite(pal, 1, palsize, outfile) != palsize)
1605 cleanup("Error write palette data in imag chunk!", 1);
1609 if (imagsize & 1)
1611 UBYTE dummy = 0;
1613 if (fwrite(&dummy, 1, 1, outfile) != 1)
1615 cleanup("Error writing imag chunk!", 1);
1618 imagsize++;
1621 return imagsize + 8;
1624 /****************************************************************************************/
1626 static void write35data(void)
1628 LONG formsize = 4;
1629 LONG formsizeseek;
1631 writelong(ID_FORM);
1632 formsizeseek = ftell(outfile);
1633 writelong(0x12345678);
1634 writelong(ID_ICON);
1636 formsize += writefacechunk();
1637 formsize += writeimagchunk(&img1);
1638 if (image2option) formsize += writeimagchunk(&img2);
1640 fseek(outfile, formsizeseek, SEEK_SET);
1641 writelong(formsize);
1644 /****************************************************************************************/
1646 static void writeicon(void)
1648 struct diskobject dobj;
1650 outfile = fopen(outfilename, "wb");
1651 if (!outfile) cleanup("Can't open output file for writing!", 1);
1653 writediskobject();
1654 writeolddrawerdata();
1655 writeimage(&img1);
1657 if (image2option) writeimage(&img2);
1659 if (defaulttooloption) writestring(defaulttooloption);
1661 if (tooltypesoption)
1663 char **strarray;
1664 LONG numtooltypes = 0;
1666 for(strarray = tooltypesoption; *strarray; strarray++, numtooltypes++);
1668 writelong((numtooltypes + 1) * 4);
1670 for(strarray = tooltypesoption; *strarray; strarray++)
1672 writestring(*strarray);
1677 /* toolwindow would have to be saved in between here if there is any */
1679 writenewdrawerdata();
1681 write35data();
1685 /****************************************************************************************/
1687 /* Table of CRCs of all 8-bit messages. */
1688 unsigned long crc_table[256];
1690 /* Flag: has the table been computed? Initially false. */
1691 int crc_table_computed = 0;
1693 /* Make the table for a fast CRC. */
1694 void make_crc_table(void)
1696 unsigned long c;
1697 int n, k;
1699 for (n = 0; n < 256; n++)
1701 c = (unsigned long) n;
1702 for (k = 0; k < 8; k++)
1704 if (c & 1)
1705 c = 0xedb88320L ^ (c >> 1);
1706 else
1707 c = c >> 1;
1709 crc_table[n] = c;
1711 crc_table_computed = 1;
1714 /* Update a running CRC with the bytes buf[0..len-1]--the CRC
1715 should be initialized to all 1's, and the transmitted value
1716 is the 1's complement of the final running CRC (see the
1717 crc() routine below)). */
1719 unsigned long update_crc(unsigned long crc, unsigned char *buf,
1720 int len)
1722 unsigned long c = crc;
1723 int n;
1725 if (!crc_table_computed)
1726 make_crc_table();
1728 for (n = 0; n < len; n++)
1730 c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
1732 return c;
1735 /* Return the CRC of the bytes buf[0..len-1]. */
1736 unsigned long crc(unsigned char *buf, int len)
1738 return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
1741 /****************************************************************************************/
1743 static void writepngiconattr(ULONG id, ULONG val, ULONG *chunksize, ULONG *crc)
1745 UBYTE buf[8];
1747 buf[0] = id >> 24;
1748 buf[1] = id >> 16;
1749 buf[2] = id >> 8;
1750 buf[3] = id;
1751 buf[4] = val >> 24;
1752 buf[5] = val >> 16;
1753 buf[6] = val >> 8;
1754 buf[7] = val;
1756 writelong(id);
1757 writelong(val);
1758 *chunksize += 8;
1759 *crc = update_crc(*crc, buf, 8);
1762 /****************************************************************************************/
1764 static void writepngiconstrattr(ULONG id, char *val, ULONG *chunksize, ULONG *crc)
1766 UBYTE buf[4];
1767 int len = strlen(val) + 1;
1769 buf[0] = id >> 24;
1770 buf[1] = id >> 16;
1771 buf[2] = id >> 8;
1772 buf[3] = id;
1774 writelong(id);
1775 *crc = update_crc(*crc, buf, 4);
1778 writenormalstring(val);
1779 *crc = update_crc(*crc, val, len);
1781 *chunksize += 4 + len;
1785 /****************************************************************************************/
1787 static void writepngiconchunk(void)
1789 ULONG crc = 0xffffffff;
1790 ULONG chunksize = 0;
1791 ULONG sizeseek = ftell(outfile);
1792 UBYTE iconid[] = {'i', 'c', 'O', 'n'};
1794 writelong(0x12345678);
1795 writelong(MAKE_ID('i', 'c', 'O', 'n'));
1797 crc = update_crc(crc, iconid, 4);
1799 if (iconleftoption != 0x80000000)
1801 writepngiconattr(0x80001001, iconleftoption, &chunksize, &crc);
1804 if (icontopoption != 0x80000000)
1806 writepngiconattr(0x80001002, icontopoption, &chunksize, &crc);
1809 if (drawerdataoption)
1811 ULONG flags = 0;
1813 writepngiconattr(0x80001003, drawerleftoption, &chunksize, &crc);
1814 writepngiconattr(0x80001004, drawertopoption, &chunksize, &crc);
1815 writepngiconattr(0x80001005, drawerwidthoption, &chunksize, &crc);
1816 writepngiconattr(0x80001006, drawerheightoption, &chunksize, &crc);
1818 if (drawershowoption == 2) flags |= 1;
1820 if (drawershowasoption < 2)
1822 flags |= 2;
1824 else
1826 flags |= ((drawershowasoption - 2) << 2);
1828 writepngiconattr(0x80001007, flags, &chunksize, &crc);
1831 writepngiconattr(0x80001009, stackoption, &chunksize, &crc);
1833 if (defaulttooloption)
1835 writepngiconstrattr(0x8000100a, defaulttooloption, &chunksize, &crc);
1838 if (tooltypesoption)
1840 char **tt;
1842 for(tt = tooltypesoption; *tt; tt++)
1844 writepngiconstrattr(0x8000100b, *tt, &chunksize, &crc);
1848 writelong(crc ^ 0xffffffff);
1849 fseek(outfile, sizeseek, SEEK_SET);
1850 writelong(chunksize);
1851 fseek(outfile, 0, SEEK_END);
1855 /****************************************************************************************/
1857 static void writepngicon(void)
1859 UBYTE *filepos;
1860 BOOL done = 0;
1862 outfile = fopen(outfilename, "wb");
1863 if (!outfile) cleanup("Can't open output file for writing!", 1);
1865 if (fwrite(filebuffer, 1, 8, outfile) != 8)
1867 cleanup("Error writing PNG signature!", 1);
1870 filepos = filebuffer + 8;
1872 while(!done)
1874 ULONG chunksize = (filepos[0] << 24) | (filepos[1] << 16) |
1875 (filepos[2] << 8) | filepos[3];
1876 ULONG chunktype = (filepos[4] << 24) | (filepos[5] << 16) |
1877 (filepos[6] << 8) | filepos[7];
1879 chunksize += 12;
1881 if (chunktype == MAKE_ID('I', 'E', 'N', 'D'))
1883 writepngiconchunk();
1884 done = 1;
1887 if (chunktype != MAKE_ID('i', 'c', 'O', 'n'))
1889 if (fwrite(filepos, 1, chunksize, outfile) != chunksize)
1891 cleanup("Error writing PNG icon file!", 1);
1895 filepos += chunksize;
1898 /* Two images: If filenames are different, cat/attach the 2nd
1899 file onto the first one */
1901 if (image2option && strcasecmp(image1option, image2option))
1903 freeimage(&img1);
1905 loadimage(image2option, &img2);
1907 if (fwrite(filebuffer, 1, filesize, outfile) != filesize)
1909 cleanup("Error writing 2nd PNG Image!", 1);
1915 /****************************************************************************************/
1917 static void remapicon(void)
1919 remapplanar(&img1, &std4colpal);
1920 if (image2option) remapplanar(&img2, &std4colpal);
1923 /****************************************************************************************/
1925 int main(int argc, char **argv)
1927 getarguments(argc, argv);
1928 parseiconsource();
1929 loadimage(image1option, &img1);
1930 if (!is_png)
1932 if (image2option) loadimage(image2option, &img2);
1933 remapicon();
1934 writeicon();
1936 else
1938 writepngicon();
1941 cleanup(0, 0);
1944 /****************************************************************************************/