typo
[AROS.git] / tools / ilbmtoicon / ilbmtoicon.c
blob00e3b6100373df1f7fef4a9fb2b6dfce744243ae
1 /*
2 Copyright © 1995-2008, 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 static BOOL dualpng; /* png file contains second image */
137 static unsigned char *dualpngstart; /* address of 2nd image in filebuffer */
139 /****************************************************************************************/
141 static void freeimage(struct ILBMImage *img)
143 if (img->chunkybuffer)
145 free(img->chunkybuffer);
146 img->chunkybuffer = NULL;
149 if (img->planarbuffer)
151 free(img->planarbuffer);
152 img->planarbuffer = NULL;
155 if (filebuffer)
157 free(filebuffer);
158 filebuffer = NULL;
161 if (file)
163 fclose(file);
164 file = NULL;
167 filepos = 0;
170 /****************************************************************************************/
172 static void cleanup(char *msg, int rc)
174 if (msg) fprintf(stderr, "ilbmtoicon: %s\n", msg);
176 freeimage(&img1);
177 freeimage(&img2);
179 if (outfile) fclose(outfile);
180 if (infile) fclose(infile);
182 exit(rc);
185 /****************************************************************************************/
187 static void getarguments(int argc, char **argv)
189 WORD i;
191 if ((argc != 4) && (argc != 5))
193 fprintf(stderr, "Wrong number of arguments\n");
194 cleanup("Usage: ilbmtoicon icondescription image1 [image2] filename", 1);
197 if (argc == 4)
199 infilename = argv[1];
200 image1option = argv[2];
201 outfilename = argv[3];
203 else if (argc == 5)
205 infilename = argv[1];
206 image1option = argv[2];
207 image2option = argv[3];
208 outfilename = argv[4];
212 /****************************************************************************************/
214 static char *skipblanks(char *s)
216 while ((*s == ' ') || (*s == '\t')) s++;
218 return s;
221 /****************************************************************************************/
223 static char *skipword(char *s)
225 while((*s != ' ') &&
226 (*s != '\t') &&
227 (*s != '\0') &&
228 (*s != '\n'))
230 s++;
233 return s;
236 /****************************************************************************************/
238 static char *checkquotes(char *s)
240 char *s2;
242 if (*s != '"')
244 s2 = skipword(s);
245 *s2 = '\0';
247 return s;
250 s++;
252 s2 = s;
253 while((*s2 != '"') && (*s2 != '\0')) s2++;
254 *s2 = '\0';
256 return s;
259 /****************************************************************************************/
261 #define KEYWORD_STRING 0
262 #define KEYWORD_INTEGER 1
263 #define KEYWORD_STRINGARRAY 2
264 #define KEYWORD_CYCLE 3
266 #define MAX_ARRAY_SIZE 200
268 /****************************************************************************************/
270 struct cycle
272 char *keyword;
273 LONG value;
276 struct cycle typecycles[] =
278 {"DISK" , 1},
279 {"DRAWER" , 2},
280 {"TOOL" , 3},
281 {"PROJECT" , 4},
282 {"GARBAGE" , 5},
283 {"DEVICE" , 6},
284 {"KICK" , 7},
285 {"APPICON" , 8},
288 struct cycle showcycles[] =
290 {"DEFAULT" , 0},
291 {"ICONS" , 1},
292 {"ALL" , 2},
293 {NULL , 0}
297 struct cycle showascycles[] =
299 {"DEFAULT" , 0},
300 {"ICON" , 1},
301 {"TEXT_NAME", 2},
302 {"TEXT_DATE", 3},
303 {"TEXT_SIZE", 4},
304 {"TEXT_TYPE", 5},
305 {NULL , 0}
310 /****************************************************************************************/
312 struct keyword
314 WORD type;
315 char *keyword;
316 APTR store;
317 APTR extra;
319 keywordtable[] =
321 {KEYWORD_STRING , "DEFAULTTOOL" , &defaulttooloption , NULL },
322 {KEYWORD_STRING , "DRAWERDATA" , &drawerdataoption , NULL },
323 {KEYWORD_CYCLE , "TYPE" , &typeoption , typecycles },
324 {KEYWORD_STRINGARRAY, "TOOLTYPE" , &tooltypesoption , NULL },
325 {KEYWORD_INTEGER , "STACK" , &stackoption , NULL },
326 {KEYWORD_INTEGER , "ICONLEFTPOS" , &iconleftoption , NULL },
327 {KEYWORD_INTEGER , "ICONTOPPOS" , &icontopoption , NULL },
328 {KEYWORD_INTEGER , "DRAWERLEFTPOS" , &drawerleftoption , NULL },
329 {KEYWORD_INTEGER , "DRAWERTOPPOS" , &drawertopoption , NULL },
330 {KEYWORD_INTEGER , "DRAWERWIDTH" , &drawerwidthoption , NULL },
331 {KEYWORD_INTEGER , "DRAWERHEIGHT" , &drawerheightoption , NULL },
332 {KEYWORD_INTEGER , "DRAWERVIEWLEFT" , &drawervleftoption , NULL },
333 {KEYWORD_INTEGER , "DRAWERVIEWTOP" , &drawervtopoption , NULL },
334 {KEYWORD_CYCLE , "DRAWERSHOW" , &drawershowoption , showcycles },
335 {KEYWORD_CYCLE , "DRAWERSHOWAS" , &drawershowoption , showascycles },
336 {KEYWORD_INTEGER , "TRANSPARENT" , &transparentoption , NULL },
337 {0 , NULL , NULL }
341 /****************************************************************************************/
343 static void handleoption(char *keyword, char *keyvalue)
345 struct keyword *kw;
346 struct cycle *cy;
348 for(kw = keywordtable; kw->keyword; kw++)
350 if (strcasecmp(kw->keyword, keyword) == 0)
352 switch(kw->type)
354 case KEYWORD_STRING:
355 *(char **)kw->store = strdup(keyvalue);
356 if (!(*(char **)kw->store)) cleanup("Out of memory!", 1);
357 break;
359 case KEYWORD_INTEGER:
360 *(LONG *)kw->store = strtol(keyvalue, 0, 0);
361 break;
363 case KEYWORD_CYCLE:
364 for(cy = (struct cycle *)kw->extra; cy->keyword; cy++)
366 if (strcasecmp(keyvalue, cy->keyword) == 0)
368 *(LONG *)kw->store = cy->value;
369 break;
372 break;
374 case KEYWORD_STRINGARRAY:
375 if (!(*(char ***)kw->store))
377 *(char ***)kw->store = (char **)malloc(MAX_ARRAY_SIZE * sizeof(char *));
378 if (!(*(char ***)kw->store)) cleanup("Out of memory!", 1);
380 memset(*(char ***)kw->store, 0, MAX_ARRAY_SIZE * sizeof(char *));
384 char *dupvalue;
385 char **strarray = *(char ***)kw->store;
386 WORD i = 0;
388 dupvalue = strdup(keyvalue);
389 if (!dupvalue) cleanup("Out of memory!", 1);
391 while(*strarray)
393 strarray++;
394 i++;
397 if (i >= MAX_ARRAY_SIZE - 1) cleanup("Array overflow!", 1);
399 *strarray = dupvalue;
402 } /* switch(kw->type) */
404 break;
406 } /* if (strcasecmp(kw->keyword, keyword) == 0) */
408 } /* for(kw = keywordtable; kw->keyword; kw++) */
412 /****************************************************************************************/
414 static void parseline(char *s)
416 char *keyword;
417 char *keyvalue = NULL;
419 s = skipblanks(s);
421 if (*s == '#') return;
422 if (*s == ';') return;
424 keyword = s;
426 s = skipword(s);
427 if (*s == '\0') return;
429 *s = '\0';
430 s = skipblanks(s + 1);
432 if (*s == '=') s = skipblanks(s + 1);
433 if (*s == '\0') return;
435 keyvalue = checkquotes(s);
437 handleoption(keyword, keyvalue);
440 /****************************************************************************************/
442 static void parseiconsource(void)
444 char s[256];
446 infile = fopen(infilename, "r");
447 if (infile)
449 while(fgets(s, sizeof(s), infile))
451 parseline(s);
454 fclose(infile);
455 infile = 0;
459 /****************************************************************************************/
461 static void showoptions(void)
463 char **strarray;
465 printf("image1: %s\n", image1option ? image1option : "(NULL)");
466 printf("image2: %s\n", image2option ? image2option : "(NULL)");
467 printf("type: %ld\n", typeoption);
469 strarray = tooltypesoption;
470 if (strarray)
472 printf("tooltypes:\n");
473 while(*strarray)
475 printf(" %s\n", *strarray++);
480 /****************************************************************************************/
482 static ULONG getlong(void)
484 ULONG ret;
486 if (filepos > filesize - 4) cleanup("Tried to read over file end!", 1);
488 ret = filebuffer[filepos++] * 0x1000000;
489 ret += filebuffer[filepos++] * 0x10000;
490 ret += filebuffer[filepos++] * 0x100;
491 ret += filebuffer[filepos++];
493 return ret;
496 /****************************************************************************************/
498 static UWORD getword(void)
500 UWORD ret;
502 if (filepos > filesize - 2) cleanup("Tried to read over file end!", 1);
504 ret = filebuffer[filepos++] * 0x100;
505 ret += filebuffer[filepos++];
507 return ret;
510 /****************************************************************************************/
512 static UBYTE getbyte(void)
514 ULONG ret;
516 if (filepos > filesize - 1) cleanup("Tried to read over file end!", 1);
517 ret = filebuffer[filepos++];
519 return ret;
522 /****************************************************************************************/
524 static void skipbytes(ULONG howmany)
526 filepos += howmany;
529 /****************************************************************************************/
531 static void openimage(struct ILBMImage *img)
533 file = fopen(filename, "rb");
534 if (!file) cleanup("Can't open file!", 1);
536 fseek(file, 0, SEEK_END);
537 filesize = ftell(file);
539 if (filesize < 12) cleanup("Bad file size!", 1);
541 //fprintf(stderr, "Filesize is %d\n", filesize);
543 fseek(file, 0, SEEK_SET);
545 filebuffer = malloc(filesize + 10);
546 if (!filebuffer) cleanup("Memory allocation for file buffer failed!", 1);
548 if (fread(filebuffer, 1, filesize, file) != filesize)
549 cleanup("Error reading file!", 1);
551 fclose(file); file = NULL;
554 /****************************************************************************************/
556 static void checkimage(struct ILBMImage *img)
558 static UBYTE pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
560 ULONG id;
561 ULONG size;
563 if (memcmp(filebuffer, pngsig, 8) == 0)
565 is_png = 1;
567 /* search for second image */
570 dualpngstart = filebuffer + 8 ;
571 dualpngstart < filebuffer + filesize - 8 ;
572 dualpngstart++
575 if (memcmp(dualpngstart, pngsig, 8) == 0)
577 dualpng = 1;
578 break;
582 else if (is_png == 0)
584 id = getlong();
585 if (id != ID_FORM) cleanup("File is not an IFF file!", 1);
587 size = getlong();
588 if (size != filesize - 8) cleanup("File is IFF, but has bad size in IFF header!", 1);
590 id = getlong();
591 if (id != ID_ILBM) cleanup("File is IFF, but not of type ILBM!", 1);
593 else if (is_png == 1)
595 cleanup("Second image must be a PNG image, too!", 1);
599 /****************************************************************************************/
601 static void scanimage(struct ILBMImage *img)
603 WORD i;
605 have_bmhd = 0;
606 have_cmap = 0;
607 have_body = 0;
609 for(;;)
611 ULONG id;
612 ULONG size;
614 id = getlong();
615 size = getlong();
617 //fprintf(stderr, "Chunk: %c%c%c%c Size: %d\n", id >> 24, id >> 16, id >> 8, id, size);
619 switch(id)
621 case ID_BMHD:
622 if (size != 20) cleanup("Bad BMHD chunk size!", 1);
624 img->bmh.bmh_Width = getword();
625 img->bmh.bmh_Height = getword();
626 img->bmh.bmh_Left = (WORD)getword();
627 img->bmh.bmh_Top = (WORD)getword();
628 img->bmh.bmh_Depth = getbyte();
629 img->bmh.bmh_Masking = getbyte();
630 img->bmh.bmh_Compression = getbyte();
631 img->bmh.bmh_Pad = getbyte();
632 img->bmh.bmh_Transparent = getword();
633 img->bmh.bmh_XAspect = getbyte();
634 img->bmh.bmh_YAspect = getbyte();
635 img->bmh.bmh_PageWidth = (WORD)getword();
636 img->bmh.bmh_PageHeight = (WORD)getword();
638 if (img->bmh.bmh_Depth > 8) cleanup("ILBM file has too many colors!", 1);
639 if ((img->bmh.bmh_Compression != CMP_NONE) && (img->bmh.bmh_Compression != CMP_BYTERUN1)) cleanup("Compression method unsupported!", 1);
641 have_bmhd = 1;
643 img->totdepth = img->bmh.bmh_Depth + ((img->bmh.bmh_Masking == MSK_HASMASK) ? 1 : 0);
645 img->bpr = ((img->bmh.bmh_Width + 15) & ~15) / 8;
647 /*fprintf(stderr, "BMHD: %d x %d x %d (%d)\n", img->bmh.bmh_Width,
648 img->bmh.bmh_Height,
649 img->bmh.bmh_Depth,
650 img->totdepth);*/
651 img->planarbmh = img->bmh;
652 break;
654 case ID_CMAP:
655 if (!have_bmhd) cleanup("CMAP chunk before BMHD chunk (or no BMHD chunk at all!", 1);
657 img->cmapentries = size / 3;
658 if (size & 1) size++;
660 if ((img->cmapentries < 2) || (img->cmapentries > 256)) cleanup("CMAP chunk has bad number of entries!", 1);
662 for(i = 0; i < img->cmapentries; i++)
664 img->rgb[i][0] = getbyte();
665 img->rgb[i][1] = getbyte();
666 img->rgb[i][2] = getbyte();
667 size -= 3;
670 skipbytes(size);
672 have_cmap = 1;
674 break;
676 case ID_BODY:
677 if (!have_bmhd) cleanup("BODY chunk before BMHD chunk (or no BMHD chunk at all!", 1);
678 body = &filebuffer[filepos];
679 bodysize = size;
681 if (img->bmh.bmh_Compression == CMP_NONE)
683 LONG shouldbesize = img->totdepth * img->bpr * img->bmh.bmh_Height;
684 if (bodysize != shouldbesize) cleanup("BODY chunk size seems to be wrong!", 1);
687 have_body = 1;
688 /* Fall through */
690 default:
691 if (size & 1) size++;
692 skipbytes(size);
693 break;
696 if (filepos == filesize) break;
697 if (have_bmhd && have_body && have_cmap) break;
700 if (!have_bmhd) cleanup("BMHD chunk missing!", 1);
701 if (!have_body) cleanup("BODY chunk missing!", 1);
704 /****************************************************************************************/
706 static unsigned char *unpack_byterun1(unsigned char *source, unsigned char *dest, LONG unpackedsize)
708 unsigned char r;
709 signed char c;
711 for(;;)
713 c = (signed char)(*source++);
714 if (c >= 0)
716 while(c-- >= 0)
718 *dest++ = *source++;
719 if (--unpackedsize <= 0) return source;
722 else if (c != -128)
724 c = -c;
725 r = *source++;
727 while(c-- >= 0)
729 *dest++ = r;
730 if (--unpackedsize <= 0) return source;
737 /****************************************************************************************/
739 static BOOL norm1(LONG count, unsigned char **source_backup,
740 unsigned char **dest, LONG *checksize)
742 //if (count >= 0) fprintf(stderr, "XX: non packable %d\n",count);
744 while(count >= 0)
746 LONG step = count;
748 if (step > 127) step = 127;
750 *checksize -= step;
751 *checksize -= 2;
753 if (*checksize <= 0) return 0;
755 count -= step;
757 *(*dest)++ = step;
760 while(step-- >= 0)
762 *(*dest)++ = *(*source_backup)++;
765 count--;
769 return 1;
772 static BOOL copy1(unsigned char r, LONG count, unsigned char **dest, LONG *checksize)
774 //if (count >= 1) fprintf(stderr, "XX: repeat %02x x %d\n", r, count);
776 while(--count >= 0)
778 LONG step = count;
780 if (step > 127) step = 127;
782 count -= step;
783 step = -step;
784 *checksize -= 2;
785 if (*checksize <= 0) return 0;
787 *(*dest)++ = (unsigned char)step;
788 *(*dest)++ = r;
791 return 1;
794 static BOOL pack_byterun1(unsigned char *source, unsigned char *dest,
795 LONG size, LONG check_size, LONG *packsize)
797 unsigned char *source_backup, *dest_backup;
798 LONG samebytes_counter, samebytes, count;
799 LONG checksize = check_size;
800 unsigned char oldbyte, actbyte;
802 if (checksize < 0) checksize = 0x7FFFFFFF;
804 oldbyte = *source;
805 samebytes_counter = 0;
806 source_backup = source;
807 dest_backup = dest;
809 for(;;)
811 //fprintf(stderr, "size = %d. checksize = %d\n", size, checksize);
812 if (--size < 0) break;
813 actbyte = *source++;
814 if (actbyte == oldbyte)
816 samebytes_counter++;
817 continue;
820 oldbyte = actbyte;
822 samebytes = samebytes_counter;
823 samebytes_counter = 1;
825 if (samebytes < 3) continue;
827 count = (LONG)(source - source_backup - samebytes - 2);
828 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
830 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
832 source_backup = source - 1;
834 //fprintf(stderr, "done\n");
836 if (samebytes_counter >= 3)
838 samebytes = samebytes_counter;
839 count = (LONG)(source - source_backup - samebytes - 1);
840 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
841 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
843 else
845 count = (LONG)(source - source_backup - 1);
846 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
848 //fprintf(stderr, "realdone\n");
850 if (packsize) *packsize = (LONG)(dest - dest_backup);
852 return 1;
855 /****************************************************************************************/
857 static void p2c(unsigned char *source, unsigned char *dest, LONG width, LONG height,
858 LONG totplanes, LONG wantplanes, LONG chunkybpr)
860 LONG alignedwidth, x, y, p, bpr, bpl;
862 alignedwidth = (width + 15) & ~15;
863 bpr = alignedwidth / 8;
864 bpl = bpr * totplanes;
866 for(y = 0; y < height; y++)
868 for(x = 0; x < width; x++)
870 LONG mask = 0x80 >> (x & 7);
871 LONG offset = x / 8;
872 unsigned char chunkypix = 0;
874 for(p = 0; p < wantplanes; p++)
876 if (source[p * bpr + offset] & mask) chunkypix |= (1 << p);
878 dest[x] = chunkypix;
881 source += bpl;
882 dest += chunkybpr;
888 /****************************************************************************************/
890 static void c2p(unsigned char *source, unsigned char *dest, LONG width, LONG height, LONG planes)
892 LONG alignedwidth, x, y, p, bpr, bpl;
894 alignedwidth = (width + 15) & ~15;
895 bpr = alignedwidth / 8;
896 bpl = bpr * planes;
898 for(y = 0; y < height; y++)
900 for(x = 0; x < width; x++)
902 LONG mask = 0x80 >> (x & 7);
903 LONG offset = x / 8;
904 unsigned char chunkypix = source[x];
906 for(p = 0; p < planes; p++)
908 if (chunkypix & (1 << p))
909 dest[p * bpr + offset] |= mask;
910 else
911 dest[p * bpr + offset] &= ~mask;
915 source += width;
916 dest += bpl;
921 /****************************************************************************************/
923 static void convertbody(struct ILBMImage *img)
925 LONG unpackedsize = img->bpr * img->bmh.bmh_Height * img->totdepth;
927 img->planarbuffer = malloc(unpackedsize);
928 if (!img->planarbuffer) cleanup("Memory allocation for planar buffer failed!", 1);
930 if (img->bmh.bmh_Compression == CMP_NONE)
932 memcpy(img->planarbuffer, body, unpackedsize);
934 else
936 unpack_byterun1(body, img->planarbuffer, unpackedsize);
939 img->chunkybuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
940 if (!img->chunkybuffer) cleanup("Memory allocation for chunky buffer failed!", 1);
942 p2c(img->planarbuffer,
943 img->chunkybuffer,
944 img->bmh.bmh_Width,
945 img->bmh.bmh_Height,
946 img->totdepth,
947 img->bmh.bmh_Depth,
948 img->bmh.bmh_Width);
951 /****************************************************************************************/
953 static UBYTE findcolor(struct Palette *pal, ULONG r, ULONG g, ULONG b)
955 ULONG dist, bestdist = 0xFFFFFFFF;
956 UBYTE i, besti = 0;
958 for(i = 0; i < pal->numentries; i++)
960 LONG r1, g1, b1, r2, g2, b2, dr, dg, db;
962 r1 = (LONG)r;
963 g1 = (LONG)g;
964 b1 = (LONG)b;
966 r2 = (LONG)pal->rgb[i][0];
967 g2 = (LONG)pal->rgb[i][1];
968 b2 = (LONG)pal->rgb[i][2];
970 dr = r1 - r2;
971 dg = g1 - g2;
972 db = b1 - b2;
974 dist = (dr * dr) + (dg * dg) + (db * db);
975 if (dist < bestdist)
977 bestdist = dist;
978 besti = i;
983 return besti;
986 /****************************************************************************************/
988 static void remapplanar(struct ILBMImage *img, struct Palette *pal)
990 UBYTE *remapbuffer;
991 LONG i, x, y, highestcol = 0, newdepth = 0;
993 remapbuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
994 if (!remapbuffer) cleanup("Error allocating remap buffer!", 1);
996 for(i = 0; i < img->cmapentries; i++)
998 img->remaptable[i] = findcolor(pal, img->rgb[i][0], img->rgb[i][1], img->rgb[i][2]);
1001 for(i = 0; i < img->bmh.bmh_Width * img->bmh.bmh_Height; i++)
1003 remapbuffer[i] = img->remaptable[img->chunkybuffer[i]];
1005 if (remapbuffer[i] > highestcol)
1006 highestcol = remapbuffer[i];
1009 for(i = highestcol; i; i >>= 1) newdepth++;
1010 if (newdepth == 0) newdepth = 1;
1012 if (newdepth > img->totdepth)
1014 free(img->planarbuffer);
1016 img->planarbuffer = malloc(img->bpr * img->bmh.bmh_Height * newdepth);
1017 if (!img->planarbuffer)
1019 free(remapbuffer);
1020 cleanup("Error re-allocating planar buffer!", 1);
1024 img->planarbmh.bmh_Depth = newdepth;
1026 memset(img->planarbuffer, 0, img->bpr * img->bmh.bmh_Height * newdepth);
1028 c2p(remapbuffer, img->planarbuffer, img->bmh.bmh_Width, img->bmh.bmh_Height, newdepth);
1030 free(remapbuffer);
1033 /****************************************************************************************/
1035 static void loadimage(char *name, struct ILBMImage *img)
1037 freeimage(img);
1039 filename = name;
1041 openimage(img);
1042 checkimage(img);
1043 if (!is_png)
1045 scanimage(img);
1046 convertbody(img);
1050 /****************************************************************************************/
1052 struct diskobject
1054 UBYTE do_magic[2];
1055 UBYTE do_version[2];
1056 UBYTE do_gadget_nextgadget[4];
1057 UBYTE do_gadget_leftedge[2];
1058 UBYTE do_gadget_topedge[2];
1059 UBYTE do_gadget_width[2];
1060 UBYTE do_gadget_height[2];
1061 UBYTE do_gadget_flags[2];
1062 UBYTE do_gadget_activation[2];
1063 UBYTE do_gadget_gadgettype[2];
1064 UBYTE do_gadget_gadgetrender[4];
1065 UBYTE do_gadget_selectrender[4];
1066 UBYTE do_gadget_gadgettext[4];
1067 UBYTE do_gadget_mutualexclude[4];
1068 UBYTE do_gadget_specialinfo[4];
1069 UBYTE do_gadget_gadgetid[2];
1070 UBYTE do_gadget_userdata[4];
1071 UBYTE do_type;
1072 UBYTE do_pad;
1073 UBYTE do_defaulttool[4];
1074 UBYTE do_tooltypes[4];
1075 UBYTE do_currentx[4];
1076 UBYTE do_currenty[4];
1077 UBYTE do_drawerdata[4];
1078 UBYTE do_toolwindow[4];
1079 UBYTE do_stacksize[4];
1082 /****************************************************************************************/
1084 struct olddrawerdata
1086 UBYTE dd_newwindow_leftedge[2];
1087 UBYTE dd_newwindow_topedge[2];
1088 UBYTE dd_newwindow_width[2];
1089 UBYTE dd_newwindow_height[2];
1090 UBYTE dd_newwindow_detailpen;
1091 UBYTE dd_newwindow_blockpen;
1092 UBYTE dd_newwindow_idcmpflags[4];
1093 UBYTE dd_newwindow_flags[4];
1094 UBYTE dd_newwindow_firstgadget[4];
1095 UBYTE dd_newwindow_checkmark[4];
1096 UBYTE dd_newwindow_title[4];
1097 UBYTE dd_newwindow_screen[4];
1098 UBYTE dd_newwindow_bitmap[4];
1099 UBYTE dd_newwindow_minwidth[2];
1100 UBYTE dd_newwindow_minheight[2];
1101 UBYTE dd_newwindow_maxwidth[2];
1102 UBYTE dd_newwindow_maxheight[2];
1103 UBYTE dd_newwindow_type[2];
1104 UBYTE dd_currentx[4];
1105 UBYTE dd_currenty[4];
1108 /****************************************************************************************/
1110 struct newdrawerdata
1112 UBYTE dd_flags[4];
1113 UBYTE dd_viewmodes[2];
1116 /****************************************************************************************/
1118 struct image
1120 UBYTE leftedge[2];
1121 UBYTE topedge[2];
1122 UBYTE width[2];
1123 UBYTE height[2];
1124 UBYTE depth[2];
1125 UBYTE imagedata[4];
1126 UBYTE planepick;
1127 UBYTE planeonoff;
1128 UBYTE nextimage[4];
1131 /****************************************************************************************/
1133 #define SET_BYTE(field,value) \
1134 ACT_STRUCT.field = value
1136 #define SET_WORD(field, value) \
1137 ACT_STRUCT.field[0] = ((value) >> 8) & 0xFF; \
1138 ACT_STRUCT.field[1] = (value) & 0xFF;
1140 #define SET_LONG(field,value) \
1141 ACT_STRUCT.field[0] = ((value) >> 24) & 0xFF; \
1142 ACT_STRUCT.field[1] = ((value) >> 16) & 0xFF; \
1143 ACT_STRUCT.field[2] = ((value) >> 8) & 0xFF; \
1144 ACT_STRUCT.field[3] = (value) & 0xFF;
1146 #define BOOL_YES 0x2A2A2A2A
1147 #define BOOL_NO 0x00000000
1149 static void writediskobject(void)
1151 struct diskobject dobj;
1153 #define ACT_STRUCT dobj
1155 SET_WORD(do_magic, 0xE310);
1156 SET_WORD(do_version, 1);
1157 SET_LONG(do_gadget_nextgadget, 0);
1158 SET_WORD(do_gadget_leftedge, 0);
1159 SET_WORD(do_gadget_topedge, 0);
1160 SET_WORD(do_gadget_width, img1.bmh.bmh_Width);
1161 SET_WORD(do_gadget_height, img1.bmh.bmh_Height);
1163 if (image2option)
1165 /* GFLG_GADGHIMAGE + GFLG_GADGIMAGE */
1166 SET_WORD(do_gadget_flags, 4 + 2);
1168 else
1170 /* GFLG_GADGIMAGE */
1171 SET_WORD(do_gadget_flags, 4);
1174 SET_WORD(do_gadget_activation, 0);
1175 SET_WORD(do_gadget_gadgettype, 0);
1176 SET_LONG(do_gadget_gadgetrender, BOOL_YES);
1178 if (image2option)
1180 SET_LONG(do_gadget_selectrender, BOOL_YES);
1182 else
1184 SET_LONG(do_gadget_selectrender, BOOL_NO);
1187 SET_LONG(do_gadget_gadgettext, 0);
1188 SET_LONG(do_gadget_mutualexclude, 0);
1189 SET_LONG(do_gadget_specialinfo, 0);
1190 SET_WORD(do_gadget_gadgetid, 0);
1191 SET_LONG(do_gadget_userdata, 1); /* full drawer data */
1193 SET_BYTE(do_type, typeoption);
1194 SET_BYTE(do_pad, 0);
1196 if (defaulttooloption)
1198 SET_LONG(do_defaulttool, BOOL_YES);
1200 else
1202 SET_LONG(do_defaulttool, BOOL_NO);
1205 if (tooltypesoption)
1207 SET_LONG(do_tooltypes, BOOL_YES);
1209 else
1211 SET_LONG(do_tooltypes, BOOL_NO);
1214 SET_LONG(do_currentx, iconleftoption);
1215 SET_LONG(do_currenty, icontopoption);
1217 if (drawerdataoption)
1219 SET_LONG(do_drawerdata, BOOL_YES);
1221 else
1223 SET_LONG(do_drawerdata, BOOL_NO);
1227 SET_LONG(do_toolwindow, 0);
1228 SET_LONG(do_stacksize, stackoption);
1230 if (fwrite(&dobj, 1, sizeof(dobj), outfile) != sizeof(dobj))
1232 cleanup("Error writing diskobject structure to outfile!", 1);
1236 /****************************************************************************************/
1238 static void writeolddrawerdata(void)
1240 struct olddrawerdata dd;
1242 if (!drawerdataoption) return;
1244 #undef ACT_STRUCT
1245 #define ACT_STRUCT dd
1247 SET_WORD(dd_newwindow_leftedge, drawerleftoption);
1248 SET_WORD(dd_newwindow_topedge, drawertopoption);
1249 SET_WORD(dd_newwindow_width, drawerwidthoption);
1250 SET_WORD(dd_newwindow_height, drawerheightoption);
1251 SET_BYTE(dd_newwindow_detailpen, 0);
1252 SET_BYTE(dd_newwindow_blockpen, 0);
1253 SET_LONG(dd_newwindow_idcmpflags, 0);
1254 SET_LONG(dd_newwindow_flags, 0);
1255 SET_LONG(dd_newwindow_firstgadget, 0);
1256 SET_LONG(dd_newwindow_checkmark, 0);
1257 SET_LONG(dd_newwindow_title, 0);
1258 SET_LONG(dd_newwindow_screen, 0);
1259 SET_LONG(dd_newwindow_bitmap, 0);
1260 SET_WORD(dd_newwindow_minwidth, 0);
1261 SET_WORD(dd_newwindow_minheight, 0);
1262 SET_WORD(dd_newwindow_maxwidth, 0);
1263 SET_WORD(dd_newwindow_maxheight, 0);
1264 SET_WORD(dd_newwindow_type, 0);
1265 SET_LONG(dd_currentx, drawervleftoption);
1266 SET_LONG(dd_currenty, drawervtopoption);
1268 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1270 cleanup("Error writing olddrawerdata structure to outfile!", 1);
1276 /****************************************************************************************/
1278 static void writenewdrawerdata(void)
1280 struct newdrawerdata dd;
1282 if (!drawerdataoption) return;
1284 #undef ACT_STRUCT
1285 #define ACT_STRUCT dd
1287 SET_LONG(dd_flags, drawershowoption);
1288 SET_WORD(dd_viewmodes, drawershowasoption);
1290 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1292 cleanup("Error writing newdrawerdata structure to outfile!", 1);
1297 /****************************************************************************************/
1299 static void writelong(LONG l)
1301 UBYTE f[4];
1303 f[0] = (l >> 24) & 0xFF;
1304 f[1] = (l >> 16) & 0xFF;
1305 f[2] = (l >> 8) & 0xFF;
1306 f[3] = l & 0xFF;
1308 if (fwrite(f, 1, 4, outfile) != 4)
1310 cleanup("Error writing string long value!", 1);
1315 /****************************************************************************************/
1317 static void writenormalstring(char *s)
1319 int len = strlen(s) + 1;
1321 if (fwrite(s, 1, len, outfile) != len)
1323 cleanup("Error writing string!", 1);
1328 /****************************************************************************************/
1330 static void writestring(char *s)
1332 int len = strlen(s) + 1;
1334 writelong(len);
1336 if (fwrite(s, 1, len, outfile) != len)
1338 cleanup("Error writing string!", 1);
1343 /****************************************************************************************/
1345 static void writeimage(struct ILBMImage *img)
1347 struct image i;
1348 LONG d, y;
1350 #undef ACT_STRUCT
1351 #define ACT_STRUCT i
1353 SET_WORD(leftedge, 0);
1354 SET_WORD(topedge, 0);
1355 SET_WORD(width, img->planarbmh.bmh_Width);
1356 SET_WORD(height, img->planarbmh.bmh_Height);
1357 SET_WORD(depth, img->planarbmh.bmh_Depth);
1358 SET_LONG(imagedata, BOOL_YES);
1359 SET_BYTE(planepick, (1 << img->planarbmh.bmh_Depth) - 1);
1360 SET_BYTE(planeonoff, 0);
1361 SET_LONG(nextimage, 0);
1363 if (fwrite(&i, 1, sizeof(i), outfile) != sizeof(i))
1365 cleanup("Error writing image structure to outfile!", 1);
1368 for(d = 0; d < img->planarbmh.bmh_Depth; d++)
1370 UBYTE *dat = img->planarbuffer + img->bpr * d;
1372 for(y = 0; y < img->planarbmh.bmh_Height; y++)
1374 if(fwrite(dat, 1, img->bpr, outfile) != img->bpr)
1376 cleanup("Error writing image data to outfile!", 1);
1378 dat += (img->planarbmh.bmh_Depth * img->bpr);
1384 /****************************************************************************************/
1386 struct facechunk
1388 UBYTE fc_width;
1389 UBYTE fc_height;
1390 UBYTE fc_flags;
1391 UBYTE fc_aspect;
1392 UBYTE fc_maxpalettebytes[2];
1395 /****************************************************************************************/
1397 struct imagchunk
1399 UBYTE ic_transparentcolour;
1400 UBYTE ic_numcolours;
1401 UBYTE ic_flags;
1402 UBYTE ic_imageformat;
1403 UBYTE ic_paletteformat;
1404 UBYTE ic_depth;
1405 UBYTE ic_numimagebytes[2];
1406 UBYTE ic_numpalettebytes[2];
1409 /****************************************************************************************/
1411 static LONG writefacechunk(void)
1413 struct facechunk fc;
1414 LONG palbytes;
1416 #undef ACT_STRUCT
1417 #define ACT_STRUCT fc
1419 writelong(ID_FACE);
1420 writelong(sizeof(struct facechunk));
1422 SET_BYTE(fc_width, img1.bmh.bmh_Width - 1);
1423 SET_BYTE(fc_height, img1.bmh.bmh_Height - 1);
1424 SET_BYTE(fc_flags, 0);
1425 SET_BYTE(fc_aspect, 0); // 0x11);
1427 palbytes = (img1.cmapentries > img2.cmapentries) ? img1.cmapentries : img2.cmapentries;
1428 palbytes = palbytes * 3;
1430 SET_WORD(fc_maxpalettebytes, palbytes - 1);
1432 if (fwrite(&fc, 1, sizeof(fc), outfile) != sizeof(fc))
1434 cleanup("Error writing face chunk!", 1);
1437 return sizeof(struct facechunk) + 8;
1440 /****************************************************************************************/
1442 /* createrle() based on ModifyIcon source by Dirk Stöcker */
1444 /****************************************************************************************/
1446 static char * createrle(unsigned long depth, unsigned char *dtype, LONG *dsize, unsigned long size,
1447 unsigned char *src)
1449 int i, j, k;
1450 unsigned long bitbuf, numbits;
1451 unsigned char *buf;
1452 long ressize, numcopy, numequal;
1454 buf = malloc(size * 2);
1455 if (!buf) return NULL;
1457 numcopy = 0;
1458 numequal = 1;
1459 bitbuf = 0;
1460 numbits = 0;
1461 ressize = 0;
1462 k = 0; /* the really output pointer */
1463 for(i = 1; numequal || numcopy;)
1465 if(i < size && numequal && (src[i-1] == src[i]))
1467 ++numequal; ++i;
1469 else if(i < size && numequal*depth <= 16)
1471 numcopy += numequal; numequal = 1; ++i;
1473 else
1475 /* care for end case, where it maybe better to join the two */
1476 if(i == size && numcopy + numequal <= 128 && (numequal-1)*depth <= 8)
1478 numcopy += numequal; numequal = 0;
1480 if(numcopy)
1482 if((j = numcopy) > 128) j = 128;
1483 bitbuf = (bitbuf<<8) | (j-1);
1484 numcopy -= j;
1486 else
1488 if((j = numequal) > 128) j = 128;
1489 bitbuf = (bitbuf<<8) | (256-(j-1));
1490 numequal -= j;
1491 k += j-1;
1492 j = 1;
1494 buf[ressize++] = (bitbuf >> numbits);
1495 while(j--)
1497 numbits += depth;
1498 bitbuf = (bitbuf<<depth) | src[k++];
1499 if(numbits >= 8)
1501 numbits -= 8;
1502 buf[ressize++] = (bitbuf >> numbits);
1505 if(i < size && !numcopy && !numequal)
1507 numequal = 1; ++i;
1511 if(numbits)
1512 buf[ressize++] = bitbuf << (8-numbits);
1514 if(ressize > size) /* no RLE */
1516 ressize = size;
1517 *dtype = 0;
1518 for(i = 0; i < size; ++i)
1519 buf[i]= src[i];
1521 else
1522 *dtype = 1;
1524 *dsize = ressize;
1526 return buf;
1529 /****************************************************************************************/
1531 static LONG writeimagchunk(struct ILBMImage *img)
1533 struct imagchunk ic;
1534 LONG imagsize;
1535 UBYTE skippalette = 0;
1536 UBYTE *pal, *gfx;
1537 LONG palsize, gfxsize;
1538 UBYTE palpacked, gfxpacked;
1540 imagsize = sizeof(struct imagchunk);
1542 /* if this is second image check whether palette is identical to
1543 the one of first image */
1545 if (img == &img2)
1547 if (img1.cmapentries == img2.cmapentries)
1549 WORD i;
1551 for (i = 0; i < img1.cmapentries; i++)
1553 if (img1.rgb[i][0] != img2.rgb[i][0]) break;
1554 if (img1.rgb[i][1] != img2.rgb[i][1]) break;
1555 if (img1.rgb[i][2] != img2.rgb[i][2]) break;
1558 if (i == img1.cmapentries) skippalette = 1;
1562 if (!skippalette)
1564 pal = createrle(8,
1565 &palpacked,
1566 &palsize,
1567 img->cmapentries * 3,
1568 (unsigned char *)img->rgb);
1570 imagsize += palsize;
1573 gfx = createrle(img->bmh.bmh_Depth,
1574 &gfxpacked,
1575 &gfxsize,
1576 img->bmh.bmh_Width * img->bmh.bmh_Height,
1577 img->chunkybuffer);
1579 imagsize += gfxsize;
1581 #undef ACT_STRUCT
1582 #define ACT_STRUCT ic
1584 SET_BYTE(ic_transparentcolour, transparentoption);
1585 if (skippalette)
1587 SET_BYTE(ic_numcolours, 0);
1588 SET_BYTE(ic_flags, (transparentoption != -1) ? 1 : 0); /* 1 = HasTransparentColour */
1589 SET_BYTE(ic_paletteformat, 0);
1590 SET_WORD(ic_numpalettebytes, 0);
1592 else
1594 SET_BYTE(ic_numcolours, img->cmapentries - 1);
1595 SET_BYTE(ic_flags, (transparentoption != -1) ? 3 : 2); /* 2 = HasPalette */
1596 SET_BYTE(ic_paletteformat, palpacked);
1597 SET_WORD(ic_numpalettebytes, palsize - 1);
1600 SET_BYTE(ic_imageformat, gfxpacked);
1601 SET_BYTE(ic_depth, img->bmh.bmh_Depth);
1602 SET_WORD(ic_numimagebytes, gfxsize - 1);
1604 writelong(ID_IMAG);
1605 writelong(imagsize);
1607 if (fwrite(&ic, 1, sizeof(ic), outfile) != sizeof(ic))
1609 cleanup("Error writing imag chunk!", 1);
1612 if (fwrite(gfx, 1, gfxsize, outfile) != gfxsize)
1614 cleanup("Error write gfx data in imag chunk!", 1);
1617 if (!skippalette)
1619 if (fwrite(pal, 1, palsize, outfile) != palsize)
1621 cleanup("Error write palette data in imag chunk!", 1);
1625 if (imagsize & 1)
1627 UBYTE dummy = 0;
1629 if (fwrite(&dummy, 1, 1, outfile) != 1)
1631 cleanup("Error writing imag chunk!", 1);
1634 imagsize++;
1637 return imagsize + 8;
1640 /****************************************************************************************/
1642 static void write35data(void)
1644 LONG formsize = 4;
1645 LONG formsizeseek;
1647 writelong(ID_FORM);
1648 formsizeseek = ftell(outfile);
1649 writelong(0x12345678);
1650 writelong(ID_ICON);
1652 formsize += writefacechunk();
1653 formsize += writeimagchunk(&img1);
1654 if (image2option) formsize += writeimagchunk(&img2);
1656 fseek(outfile, formsizeseek, SEEK_SET);
1657 writelong(formsize);
1660 /****************************************************************************************/
1662 static void writeicon(void)
1664 struct diskobject dobj;
1666 outfile = fopen(outfilename, "wb");
1667 if (!outfile) cleanup("Can't open output file for writing!", 1);
1669 writediskobject();
1670 writeolddrawerdata();
1671 writeimage(&img1);
1673 if (image2option) writeimage(&img2);
1675 if (defaulttooloption) writestring(defaulttooloption);
1677 if (tooltypesoption)
1679 char **strarray;
1680 LONG numtooltypes = 0;
1682 for(strarray = tooltypesoption; *strarray; strarray++, numtooltypes++);
1684 writelong((numtooltypes + 1) * 4);
1686 for(strarray = tooltypesoption; *strarray; strarray++)
1688 writestring(*strarray);
1693 /* toolwindow would have to be saved in between here if there is any */
1695 writenewdrawerdata();
1697 write35data();
1701 /****************************************************************************************/
1703 /* Table of CRCs of all 8-bit messages. */
1704 unsigned long crc_table[256];
1706 /* Flag: has the table been computed? Initially false. */
1707 int crc_table_computed = 0;
1709 /* Make the table for a fast CRC. */
1710 void make_crc_table(void)
1712 unsigned long c;
1713 int n, k;
1715 for (n = 0; n < 256; n++)
1717 c = (unsigned long) n;
1718 for (k = 0; k < 8; k++)
1720 if (c & 1)
1721 c = 0xedb88320L ^ (c >> 1);
1722 else
1723 c = c >> 1;
1725 crc_table[n] = c;
1727 crc_table_computed = 1;
1730 /* Update a running CRC with the bytes buf[0..len-1]--the CRC
1731 should be initialized to all 1's, and the transmitted value
1732 is the 1's complement of the final running CRC (see the
1733 crc() routine below)). */
1735 unsigned long update_crc(unsigned long crc, unsigned char *buf,
1736 int len)
1738 unsigned long c = crc;
1739 int n;
1741 if (!crc_table_computed)
1742 make_crc_table();
1744 for (n = 0; n < len; n++)
1746 c = crc_table[(c ^ buf[n]) & 0xff] ^ (c >> 8);
1748 return c;
1751 /* Return the CRC of the bytes buf[0..len-1]. */
1752 unsigned long crc(unsigned char *buf, int len)
1754 return update_crc(0xffffffffL, buf, len) ^ 0xffffffffL;
1757 /****************************************************************************************/
1759 static void writepngiconattr(ULONG id, ULONG val, ULONG *chunksize, ULONG *crc)
1761 UBYTE buf[8];
1763 buf[0] = id >> 24;
1764 buf[1] = id >> 16;
1765 buf[2] = id >> 8;
1766 buf[3] = id;
1767 buf[4] = val >> 24;
1768 buf[5] = val >> 16;
1769 buf[6] = val >> 8;
1770 buf[7] = val;
1772 writelong(id);
1773 writelong(val);
1774 *chunksize += 8;
1775 *crc = update_crc(*crc, buf, 8);
1778 /****************************************************************************************/
1780 static void writepngiconstrattr(ULONG id, char *val, ULONG *chunksize, ULONG *crc)
1782 UBYTE buf[4];
1783 int len = strlen(val) + 1;
1785 buf[0] = id >> 24;
1786 buf[1] = id >> 16;
1787 buf[2] = id >> 8;
1788 buf[3] = id;
1790 writelong(id);
1791 *crc = update_crc(*crc, buf, 4);
1794 writenormalstring(val);
1795 *crc = update_crc(*crc, val, len);
1797 *chunksize += 4 + len;
1801 /****************************************************************************************/
1803 static void writepngiconchunk(void)
1805 ULONG crc = 0xffffffff;
1806 ULONG chunksize = 0;
1807 ULONG sizeseek = ftell(outfile);
1808 UBYTE iconid[] = {'i', 'c', 'O', 'n'};
1810 writelong(0x12345678);
1811 writelong(MAKE_ID('i', 'c', 'O', 'n'));
1813 crc = update_crc(crc, iconid, 4);
1815 if (iconleftoption != 0x80000000)
1817 writepngiconattr(0x80001001, iconleftoption, &chunksize, &crc);
1820 if (icontopoption != 0x80000000)
1822 writepngiconattr(0x80001002, icontopoption, &chunksize, &crc);
1825 if (drawerdataoption)
1827 ULONG flags = 0;
1829 writepngiconattr(0x80001003, drawerleftoption, &chunksize, &crc);
1830 writepngiconattr(0x80001004, drawertopoption, &chunksize, &crc);
1831 writepngiconattr(0x80001005, drawerwidthoption, &chunksize, &crc);
1832 writepngiconattr(0x80001006, drawerheightoption, &chunksize, &crc);
1834 if (drawershowoption == 2) flags |= 1;
1836 if (drawershowasoption < 2)
1838 flags |= 2;
1840 else
1842 flags |= ((drawershowasoption - 2) << 2);
1844 writepngiconattr(0x80001007, flags, &chunksize, &crc);
1847 writepngiconattr(0x80001009, stackoption, &chunksize, &crc);
1849 if (defaulttooloption)
1851 writepngiconstrattr(0x8000100a, defaulttooloption, &chunksize, &crc);
1854 if (tooltypesoption)
1856 char **tt;
1858 for(tt = tooltypesoption; *tt; tt++)
1860 writepngiconstrattr(0x8000100b, *tt, &chunksize, &crc);
1864 writelong(crc ^ 0xffffffff);
1865 fseek(outfile, sizeseek, SEEK_SET);
1866 writelong(chunksize);
1867 fseek(outfile, 0, SEEK_END);
1871 /****************************************************************************************/
1873 static void writepngicon(void)
1875 UBYTE *filepos;
1876 BOOL done = 0;
1878 outfile = fopen(outfilename, "wb");
1879 if (!outfile) cleanup("Can't open output file for writing!", 1);
1881 if (fwrite(filebuffer, 1, 8, outfile) != 8)
1883 cleanup("Error writing PNG signature!", 1);
1886 filepos = filebuffer + 8;
1888 while(!done)
1890 ULONG chunksize = (filepos[0] << 24) | (filepos[1] << 16) |
1891 (filepos[2] << 8) | filepos[3];
1892 ULONG chunktype = (filepos[4] << 24) | (filepos[5] << 16) |
1893 (filepos[6] << 8) | filepos[7];
1895 chunksize += 12;
1897 if (chunktype == MAKE_ID('I', 'E', 'N', 'D'))
1899 writepngiconchunk();
1900 done = 1;
1903 if (chunktype != MAKE_ID('i', 'c', 'O', 'n'))
1905 if (fwrite(filepos, 1, chunksize, outfile) != chunksize)
1907 cleanup("Error writing PNG icon file!", 1);
1911 filepos += chunksize;
1914 /* Create icons with two images */
1915 if (image2option && strcasecmp(image1option, image2option))
1917 /* If filenames are different, cat/attach the 2nd
1918 file onto the first one. */
1920 freeimage(&img1);
1922 loadimage(image2option, &img2);
1924 if (fwrite(filebuffer, 1, filesize, outfile) != filesize)
1926 cleanup("Error writing 2nd PNG Image!", 1);
1929 else if (dualpng)
1931 /* Handle the case where 2 PNG images are just joined together
1932 to one file. */
1933 long bytecnt = filebuffer + filesize - dualpngstart;
1934 if (fwrite(dualpngstart, 1, bytecnt, outfile) != bytecnt)
1936 cleanup("Error writing dual PNG icon file!", 1);
1941 /****************************************************************************************/
1943 static void remapicon(void)
1945 remapplanar(&img1, &std4colpal);
1946 if (image2option) remapplanar(&img2, &std4colpal);
1949 /****************************************************************************************/
1951 int main(int argc, char **argv)
1953 getarguments(argc, argv);
1954 parseiconsource();
1955 loadimage(image1option, &img1);
1956 if (!is_png)
1958 if (image2option) loadimage(image2option, &img2);
1959 remapicon();
1960 writeicon();
1962 else
1964 writepngicon();
1967 cleanup(0, 0);
1970 /****************************************************************************************/