ilbmtoicon: Refuse to generate icons with differently sized select and normal images
[AROS.git] / tools / ilbmtoicon / ilbmtoicon.c
blob9feaf23b616088313f493aa369465e8d688dadce
1 /*
2 Copyright © 1995-2012, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Tool to convert IFF ILBM images into Amiga icon file.
7 Lang: English
9 */
11 #define D(x)
13 /****************************************************************************************/
15 #include <stdio.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <ctype.h>
20 #include <png.h>
21 #include <zlib.h>
23 /****************************************************************************************/
25 #define TRUE ~0
26 #define FALSE 0
28 #define MAKE_ID(a,b,c,d) (((a)<<24) | ((b)<<16) | ((c)<<8) | ((d)))
30 #define ID_FORM MAKE_ID('F','O','R','M')
31 #define ID_ILBM MAKE_ID('I','L','B','M')
32 #define ID_CMAP MAKE_ID('C','M','A','P')
33 #define ID_BODY MAKE_ID('B','O','D','Y')
34 #define ID_BMHD MAKE_ID('B','M','H','D')
36 #define ID_ICON MAKE_ID('I','C','O','N')
37 #define ID_FACE MAKE_ID('F','A','C','E')
38 #define ID_IMAG MAKE_ID('I','M','A','G')
39 #define ID_PNG MAKE_ID('p','n','g',' ')
40 #define ID_ARGB MAKE_ID('A','R','G','B')
42 #define CMP_NONE 0
43 #define CMP_BYTERUN1 1
45 #define MSK_HASMASK 1
46 #define MSK_HASTRANS 2
48 /****************************************************************************************/
50 /* For this tool it does not really matter if the following types
51 have a bigger sizeof() than on Amiga */
53 #ifndef __AROS__
54 typedef void *APTR;
55 typedef unsigned long ULONG;
56 typedef long LONG;
57 typedef unsigned short UWORD;
58 typedef short WORD;
59 typedef short BOOL;
60 typedef unsigned char UBYTE;
61 #else
62 #include <exec/types.h>
63 #endif
65 /****************************************************************************************/
67 struct BitMapHeader
69 UWORD bmh_Width;
70 UWORD bmh_Height;
71 WORD bmh_Left;
72 WORD bmh_Top;
73 UBYTE bmh_Depth;
74 UBYTE bmh_Masking;
75 UBYTE bmh_Compression;
76 UBYTE bmh_Pad;
77 UWORD bmh_Transparent;
78 UBYTE bmh_XAspect;
79 UBYTE bmh_YAspect;
80 WORD bmh_PageWidth;
81 WORD bmh_PageHeight;
84 /****************************************************************************************/
86 struct ILBMImage
88 struct BitMapHeader bmh;
89 struct BitMapHeader planarbmh;
90 unsigned char *planarbuffer, *chunkybuffer;
91 LONG cmapentries, bpr, totdepth;
92 UBYTE rgb[256][3];
93 UBYTE remaptable[256];
94 APTR png;
95 ULONG png_size;
96 APTR argb;
97 ULONG argb_size;
100 /****************************************************************************************/
102 struct Palette
104 UWORD numentries;
105 UBYTE rgb[][3];
108 /****************************************************************************************/
110 struct Palette std4colpal =
114 {0x95, 0x95, 0x95}, /* Gray (and transparent!) */
115 {0x00, 0x00, 0x00}, /* Black */
116 {0xFF, 0xFF, 0xFF}, /* White */
117 {0x3b, 0x67, 0xa2} /* Blue */
121 /****************************************************************************************/
123 struct Palette magicwb8colpal =
127 {0x95, 0x95, 0x95}, /* Gray (and transparent!) */
128 {0x00, 0x00, 0x00}, /* Black */
129 {0xFF, 0xFF, 0xFF}, /* White */
130 {0x3b, 0x67, 0xa2}, /* Blue */
131 {0x7b, 0x7b, 0x7b}, /* Dk. Gray */
132 {0xaf, 0xaf, 0xaf}, /* Lt. Gray */
133 {0xaa, 0x90, 0x7c}, /* Brown */
134 {0xff, 0xa9, 0x97} /* Pink */
138 /****************************************************************************************/
140 struct Palette scalos16colpal =
144 { 0x9c, 0x9c, 0x9c }, /* 0 - Gray */
145 { 0x00, 0x00, 0x00 }, /* 1 - Black */
146 { 0xFF, 0xFF, 0xFF }, /* 2 - White */
147 { 0x3a, 0x3a, 0xd7 }, /* 3 - Blue */
148 { 0x75, 0x75, 0x75 }, /* 4 - Med. Gray */
149 { 0xc4, 0xc4, 0xc4 }, /* 5 - Lt. Gray */
150 { 0xd7, 0xb0, 0x75 }, /* 6 - Peach */
151 { 0xeb, 0x62, 0x9c }, /* 7 - Pink */
152 { 0x13, 0x75, 0x27 }, /* 8 - Dk. Green */
153 { 0x75, 0x3a, 0x00 }, /* 9 - Brown */
154 { 0xff, 0xd7, 0x13 }, /* 10 - Yellow */
155 { 0x3a, 0x3a, 0x3a }, /* 11 - Dk. Gray */
156 { 0xc4, 0x13, 0x27 }, /* 12 - Red */
157 { 0x27, 0xb0, 0x3a }, /* 13 - Lt. Green */
158 { 0x3a, 0x75, 0xff }, /* 14 - Lt. Blue */
159 { 0xd7, 0x75, 0x27 }, /* 15 - Orange */
163 /* Convert from DPI to Amiga 'ticks' resolution */
164 #define TPD_X(x) ((11*1280*100/104/(x)+5)/10)
165 #define TPD_Y(y) ((11*1024*100/78/(y)+5)/10)
167 /****************************************************************************************/
169 static char *filename, *outfilename, *infilename;
170 static unsigned char *filebuffer, *body;
171 static FILE *file, *outfile, *infile;
172 static long filesize, bodysize, bodysize_packed;
173 static long filepos;
174 static struct ILBMImage img1, img2;
175 static BOOL have_bmhd, have_cmap, have_body, is_png;
177 /* 'ticks' per dot, corresponding to ~72dpi */
178 static ULONG tpdX = TPD_X(72), tpdY = TPD_Y(72);
179 static char *image1option;
180 static char *image2option;
181 static char *defaulttooloption;
182 static char *drawerdataoption;
183 static char **tooltypesoption;
184 static LONG typeoption = 3; /* WBTOOL */
185 static LONG iconleftoption = 0x80000000; /* NO_ICON_POSITION */
186 static LONG icontopoption = 0x80000000; /* NO_ICON_POSITION */
187 static LONG stackoption = 4096;
188 static LONG drawerleftoption = 50;
189 static LONG drawertopoption = 50;
190 static LONG drawerwidthoption = 400;
191 static LONG drawerheightoption = 100;
192 static LONG drawervleftoption = 0;
193 static LONG drawervtopoption = 0;
194 static LONG drawershowoption = 0;
195 static LONG drawershowasoption = 0;
196 static LONG transparentoption = -1;
198 static BOOL dualpng; /* png file contains second image */
199 static unsigned char *dualpngstart; /* address of 2nd image in filebuffer */
200 static BOOL nosavePNG; /* Don't save the original PNG data */
201 static BOOL nosaveARGB; /* Don't ARGB data */
202 static BOOL nosaveIFF; /* Don't save any IFF data */
204 /****************************************************************************************/
206 static void freeimage(struct ILBMImage *img)
208 if (img->chunkybuffer)
210 free(img->chunkybuffer);
211 img->chunkybuffer = NULL;
214 if (img->planarbuffer)
216 free(img->planarbuffer);
217 img->planarbuffer = NULL;
220 if (img->argb)
222 free(img->argb);
223 img->argb = NULL;
226 if (filebuffer)
228 free(filebuffer);
229 filebuffer = NULL;
232 if (file)
234 fclose(file);
235 file = NULL;
238 filepos = 0;
241 /****************************************************************************************/
243 static void cleanup(char *msg, int rc)
245 if (msg) fprintf(stderr, "ilbmtoicon: %s\n", msg);
247 freeimage(&img1);
248 freeimage(&img2);
250 if (outfile) fclose(outfile);
251 if (infile) fclose(infile);
253 exit(rc);
256 /****************************************************************************************/
258 static void getarguments(int argc, char **argv)
260 WORD i;
262 nosavePNG = 1;
264 for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
265 if (strcmp(argv[1],"--png") == 0) {
266 nosavePNG = 0;
267 continue;
269 if (strcmp(argv[1],"--no-iff") == 0) {
270 nosaveIFF = 1;
271 continue;
273 if (strcmp(argv[1],"--no-argb") == 0) {
274 nosaveIFF = 1;
275 continue;
277 if (strcmp(argv[1],"--dpi") == 0) {
278 char *cp;
279 long dpiX, dpiY;
280 argc--;
281 argv++;
282 dpiX = strtol(argv[1], &cp, 0);
283 if (*cp == ':') {
284 cp++;
285 dpiY = strtol(cp, NULL, 0);
286 } else {
287 dpiY = dpiX;
289 tpdX = TPD_X(dpiX);
290 tpdY = TPD_Y(dpiY);
291 continue;
296 if ((argc != 4) && (argc != 5))
298 fprintf(stderr, "Wrong number of arguments\n");
299 cleanup("Usage: ilbmtoicon [--png] [--no-argb] [--no-iff] icondescription image1 [image2] filename", 1);
302 if (argc == 4)
304 infilename = argv[1];
305 image1option = argv[2];
306 outfilename = argv[3];
308 else if (argc == 5)
310 infilename = argv[1];
311 image1option = argv[2];
312 image2option = argv[3];
313 outfilename = argv[4];
317 /****************************************************************************************/
319 static char *skipblanks(char *s)
321 while ((*s == ' ') || (*s == '\t')) s++;
323 return s;
326 /****************************************************************************************/
328 static char *skipword(char *s)
330 while((*s != ' ') &&
331 (*s != '\t') &&
332 (*s != '\0') &&
333 (*s != '\n'))
335 s++;
338 return s;
341 /****************************************************************************************/
343 static char *checkquotes(char *s)
345 char *s2;
346 static char s3[256];
347 BOOL escaped = 0;
348 int i = 0;
350 if (*s != '"')
352 s2 = skipword(s);
353 *s2 = '\0';
355 return s;
358 s++;
361 while ((i < 256) && (s3[i] = *s))
363 if (!escaped)
365 if (*s == '\\')
367 escaped = !escaped;
368 i--;
370 else if (*s == '"')
371 break;
373 else
374 escaped = !escaped;
375 i++;
376 s++;
378 s3[i] = '\0';
379 s = s3;
381 return s;
384 /****************************************************************************************/
386 #define KEYWORD_STRING 0
387 #define KEYWORD_INTEGER 1
388 #define KEYWORD_STRINGARRAY 2
389 #define KEYWORD_CYCLE 3
391 #define MAX_ARRAY_SIZE 200
393 /****************************************************************************************/
395 struct cycle
397 char *keyword;
398 LONG value;
401 struct cycle typecycles[] =
403 {"DISK" , 1},
404 {"DRAWER" , 2},
405 {"TOOL" , 3},
406 {"PROJECT" , 4},
407 {"GARBAGE" , 5},
408 {"DEVICE" , 6},
409 {"KICK" , 7},
410 {"APPICON" , 8},
413 struct cycle showcycles[] =
415 {"DEFAULT" , 0},
416 {"ICONS" , 1},
417 {"ALL" , 2},
418 {NULL , 0}
422 struct cycle showascycles[] =
424 {"DEFAULT" , 0},
425 {"ICON" , 1},
426 {"TEXT_NAME", 2},
427 {"TEXT_DATE", 3},
428 {"TEXT_SIZE", 4},
429 {"TEXT_TYPE", 5},
430 {NULL , 0}
435 /****************************************************************************************/
437 struct keyword
439 WORD type;
440 char *keyword;
441 APTR store;
442 APTR extra;
444 keywordtable[] =
446 {KEYWORD_STRING , "DEFAULTTOOL" , &defaulttooloption , NULL },
447 {KEYWORD_STRING , "DRAWERDATA" , &drawerdataoption , NULL },
448 {KEYWORD_CYCLE , "TYPE" , &typeoption , typecycles },
449 {KEYWORD_STRINGARRAY, "TOOLTYPE" , &tooltypesoption , NULL },
450 {KEYWORD_INTEGER , "STACK" , &stackoption , NULL },
451 {KEYWORD_INTEGER , "ICONLEFTPOS" , &iconleftoption , NULL },
452 {KEYWORD_INTEGER , "ICONTOPPOS" , &icontopoption , NULL },
453 {KEYWORD_INTEGER , "DRAWERLEFTPOS" , &drawerleftoption , NULL },
454 {KEYWORD_INTEGER , "DRAWERTOPPOS" , &drawertopoption , NULL },
455 {KEYWORD_INTEGER , "DRAWERWIDTH" , &drawerwidthoption , NULL },
456 {KEYWORD_INTEGER , "DRAWERHEIGHT" , &drawerheightoption , NULL },
457 {KEYWORD_INTEGER , "DRAWERVIEWLEFT" , &drawervleftoption , NULL },
458 {KEYWORD_INTEGER , "DRAWERVIEWTOP" , &drawervtopoption , NULL },
459 {KEYWORD_CYCLE , "DRAWERSHOW" , &drawershowoption , showcycles },
460 {KEYWORD_CYCLE , "DRAWERSHOWAS" , &drawershowoption , showascycles },
461 {KEYWORD_INTEGER , "TRANSPARENT" , &transparentoption , NULL },
462 {0 , NULL , NULL }
466 /****************************************************************************************/
468 static void handleoption(char *keyword, char *keyvalue)
470 struct keyword *kw;
471 struct cycle *cy;
473 D(printf("Keyword %s, value %s\n", keyword, keyvalue));
475 for(kw = keywordtable; kw->keyword; kw++)
477 if (strcasecmp(kw->keyword, keyword) == 0)
479 switch(kw->type)
481 case KEYWORD_STRING:
482 *(char **)kw->store = strdup(keyvalue);
483 if (!(*(char **)kw->store)) cleanup("Out of memory!", 1);
484 break;
486 case KEYWORD_INTEGER:
487 *(LONG *)kw->store = strtol(keyvalue, 0, 0);
488 break;
490 case KEYWORD_CYCLE:
491 for(cy = (struct cycle *)kw->extra; cy->keyword; cy++)
493 if (strcasecmp(keyvalue, cy->keyword) == 0)
495 *(LONG *)kw->store = cy->value;
496 break;
499 break;
501 case KEYWORD_STRINGARRAY:
502 if (!(*(char ***)kw->store))
504 *(char ***)kw->store = (char **)malloc(MAX_ARRAY_SIZE * sizeof(char *));
505 if (!(*(char ***)kw->store)) cleanup("Out of memory!", 1);
507 memset(*(char ***)kw->store, 0, MAX_ARRAY_SIZE * sizeof(char *));
511 char *dupvalue;
512 char **strarray = *(char ***)kw->store;
513 WORD i = 0;
515 dupvalue = strdup(keyvalue);
516 if (!dupvalue) cleanup("Out of memory!", 1);
518 while(*strarray)
520 strarray++;
521 i++;
524 if (i >= MAX_ARRAY_SIZE - 1) cleanup("Array overflow!", 1);
526 *strarray = dupvalue;
529 } /* switch(kw->type) */
531 break;
533 } /* if (strcasecmp(kw->keyword, keyword) == 0) */
535 } /* for(kw = keywordtable; kw->keyword; kw++) */
539 /****************************************************************************************/
541 static void parseline(char *s)
543 char *keyword;
544 char *keyvalue = NULL;
546 s = skipblanks(s);
548 if (*s == '#') return;
549 if (*s == ';') return;
551 keyword = s;
553 s = skipword(s);
554 if (*s == '\0') return;
556 *s = '\0';
557 s = skipblanks(s + 1);
559 if (*s == '=') s = skipblanks(s + 1);
560 if (*s == '\0') return;
562 keyvalue = checkquotes(s);
564 handleoption(keyword, keyvalue);
567 /****************************************************************************************/
569 static void parseiconsource(void)
571 char s[256];
573 infile = fopen(infilename, "r");
574 if (infile)
576 while(fgets(s, sizeof(s), infile))
578 D(printf("Read line: %s\n", s));
579 parseline(s);
582 fclose(infile);
583 infile = 0;
587 /****************************************************************************************/
589 static void showoptions(void)
591 char **strarray;
593 printf("image1: %s\n", image1option ? image1option : "(NULL)");
594 printf("image2: %s\n", image2option ? image2option : "(NULL)");
595 printf("type: %ld\n", typeoption);
597 strarray = tooltypesoption;
598 if (strarray)
600 printf("tooltypes:\n");
601 while(*strarray)
603 printf(" %s\n", *strarray++);
608 /****************************************************************************************/
610 static ULONG getlong(void)
612 ULONG ret;
614 if (filepos > filesize - 4) cleanup("Tried to read over file end!", 1);
616 ret = filebuffer[filepos++] * 0x1000000;
617 ret += filebuffer[filepos++] * 0x10000;
618 ret += filebuffer[filepos++] * 0x100;
619 ret += filebuffer[filepos++];
621 return ret;
624 /****************************************************************************************/
626 static UWORD getword(void)
628 UWORD ret;
630 if (filepos > filesize - 2) cleanup("Tried to read over file end!", 1);
632 ret = filebuffer[filepos++] * 0x100;
633 ret += filebuffer[filepos++];
635 return ret;
638 /****************************************************************************************/
640 static UBYTE getbyte(void)
642 ULONG ret;
644 if (filepos > filesize - 1) cleanup("Tried to read over file end!", 1);
645 ret = filebuffer[filepos++];
647 return ret;
650 /****************************************************************************************/
652 static void skipbytes(ULONG howmany)
654 filepos += howmany;
657 /****************************************************************************************/
659 static void openimage(struct ILBMImage *img)
661 file = fopen(filename, "rb");
662 if (!file) cleanup("Can't open file!", 1);
664 fseek(file, 0, SEEK_END);
665 filesize = ftell(file);
667 if (filesize < 12) cleanup("Bad file size!", 1);
669 //fprintf(stderr, "Filesize is %d\n", filesize);
671 fseek(file, 0, SEEK_SET);
673 filebuffer = malloc(filesize + 10);
674 if (!filebuffer) cleanup("Memory allocation for file buffer failed!", 1);
676 if (fread(filebuffer, 1, filesize, file) != filesize)
677 cleanup("Error reading file!", 1);
679 fclose(file); file = NULL;
682 /****************************************************************************************/
684 static void checkimage(struct ILBMImage *img)
686 static UBYTE pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
688 ULONG id;
689 ULONG size;
691 if (dualpng) {
692 img->png = dualpngstart;
693 img->png_size = filesize - (dualpngstart - filebuffer);
694 return;
697 if (memcmp(filebuffer, pngsig, 8) == 0)
699 is_png = 1;
700 img->png = filebuffer;
702 /* search for second image */
705 dualpngstart = filebuffer + 8 ;
706 dualpngstart < filebuffer + filesize - 8 ;
707 dualpngstart++
710 if (memcmp(dualpngstart, pngsig, 8) == 0)
712 dualpng = 1;
713 break;
716 if (dualpng)
717 img->png_size = dualpngstart - filebuffer;
718 else
719 img->png_size = filesize;
721 else if (is_png == 0)
723 id = getlong();
724 if (id != ID_FORM) cleanup("File is not an IFF file!", 1);
726 size = getlong();
727 if (size != filesize - 8) cleanup("File is IFF, but has bad size in IFF header!", 1);
729 id = getlong();
730 if (id != ID_ILBM) cleanup("File is IFF, but not of type ILBM!", 1);
732 else if (is_png == 1)
734 cleanup("Second image must be a PNG image, too!", 1);
739 /****************************************************************************************/
741 static void my_read_fn(png_structp png_ptr, png_bytep data, png_size_t length)
743 png_bytep *pdata = png_get_io_ptr(png_ptr);
745 if (*pdata-filebuffer >= filesize)
746 png_error(png_ptr, "Read past end of file");
748 memcpy(data, *pdata, length);
749 *pdata += length;
752 static UBYTE findcolor(struct Palette *pal, ULONG r, ULONG g, ULONG b, BOOL notrans);
754 static void loadpng(struct ILBMImage *img, struct Palette *pal)
756 png_structp png_ptr;
757 png_infop info_ptr, end_info;
758 png_bytep fpos, *row_pointers;
759 UBYTE *chunkrow;
760 UWORD width, height;
761 int x, y;
763 if (png_sig_cmp(img->png, 0, img->png_size) != 0)
764 cleanup("I thought it was a PNG, but I was wrong.", 1);
766 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
767 0, /* error ptr */
770 if (!png_ptr)
771 cleanup("png_create_read_struct() failed", 1);
773 info_ptr = png_create_info_struct(png_ptr);
774 if (!info_ptr) {
775 png_destroy_read_struct(&png_ptr, NULL, NULL);
776 cleanup("png_create_info_struct() failed", 1);
779 end_info = png_create_info_struct(png_ptr);
780 if (!end_info) {
781 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
782 cleanup("png_create_info_struct() failed", 1);
785 fpos = img->png;
786 png_set_read_fn(png_ptr, &fpos, my_read_fn);
788 if (setjmp(png_jmpbuf(png_ptr))) {
789 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
790 cleanup("png read failed", 1);
793 /* Read the PNG as RGBA */
794 png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
795 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16, NULL);
797 row_pointers = png_get_rows(png_ptr, info_ptr);
799 width = png_get_image_width(png_ptr, info_ptr);
800 height = png_get_image_height(png_ptr, info_ptr);
802 img->bmh.bmh_Width = width;
803 img->bmh.bmh_Height = height;
804 img->bmh.bmh_Left = 0;
805 img->bmh.bmh_Top = 0;
806 img->bmh.bmh_Depth = 8;
807 img->bmh.bmh_Masking = MSK_HASTRANS;
808 img->bmh.bmh_Compression = CMP_NONE;
809 img->bmh.bmh_Pad = 0;
810 img->bmh.bmh_XAspect = 1;
811 img->bmh.bmh_YAspect = 1;
812 img->bmh.bmh_PageWidth = 320;
813 img->bmh.bmh_PageHeight = 200;
815 img->planarbmh;
816 img->bpr = ((img->bmh.bmh_Width + 15) & ~15) / 8;
817 img->totdepth = 0;
819 /* Transform the RGBA data into chunky */
820 img->cmapentries = pal->numentries;
821 memcpy(img->rgb, pal->rgb, sizeof(img->rgb[0])*pal->numentries);
823 img->chunkybuffer = malloc(width * height * sizeof(UBYTE));
824 if (!img->chunkybuffer)
825 cleanup("Can't allocate the chunky buffer", 1);
827 chunkrow = img->chunkybuffer;
828 img->argb_size = width * height * sizeof(UBYTE) * 4;
829 img->argb = malloc(img->argb_size);
830 if (!img->argb)
831 cleanup("Can't allocate the ARGB buffer", 1);
833 for (y = 0; y < height; y++) {
834 png_bytep row = row_pointers[y];
835 UBYTE *ap = img->argb + (width * sizeof(UBYTE) * 4) * y;
836 for (x = 0; x < width; x++, row += 4, ap += 4, chunkrow++) {
837 UBYTE r,g,b;
839 ap[0] = row[3];
840 ap[1] = row[0];
841 ap[2] = row[1];
842 ap[3] = row[2];
844 /* Opacity of 0? Use the transparency color */
845 if (row[3] == 0) {
846 if (transparentoption < 0)
847 transparentoption = 0;
848 *chunkrow = transparentoption;
849 } else {
850 r = row[0];
851 g = row[1];
852 b = row[2];
854 *chunkrow = findcolor(pal, r, g, b, TRUE);
859 img->bmh.bmh_Transparent = transparentoption;
861 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
865 /****************************************************************************************/
867 static void scanimage(struct ILBMImage *img)
869 WORD i;
871 have_bmhd = 0;
872 have_cmap = 0;
873 have_body = 0;
875 if (img->png) {
876 /* Load the PNG, using the Scalos 16-color pallette,
877 * into the Chunky buffer.
879 loadpng(img, &scalos16colpal);
880 return;
883 for(;;)
885 ULONG id;
886 ULONG size;
888 id = getlong();
889 size = getlong();
891 //fprintf(stderr, "Chunk: %c%c%c%c Size: %d\n", id >> 24, id >> 16, id >> 8, id, size);
893 switch(id)
895 case ID_BMHD:
896 if (size != 20) cleanup("Bad BMHD chunk size!", 1);
898 img->bmh.bmh_Width = getword();
899 img->bmh.bmh_Height = getword();
900 img->bmh.bmh_Left = (WORD)getword();
901 img->bmh.bmh_Top = (WORD)getword();
902 img->bmh.bmh_Depth = getbyte();
903 img->bmh.bmh_Masking = getbyte();
904 img->bmh.bmh_Compression = getbyte();
905 img->bmh.bmh_Pad = getbyte();
906 img->bmh.bmh_Transparent = getword();
907 img->bmh.bmh_XAspect = getbyte();
908 img->bmh.bmh_YAspect = getbyte();
909 img->bmh.bmh_PageWidth = (WORD)getword();
910 img->bmh.bmh_PageHeight = (WORD)getword();
912 if (img->bmh.bmh_Depth > 8) cleanup("ILBM file has too many colors!", 1);
913 if ((img->bmh.bmh_Compression != CMP_NONE) && (img->bmh.bmh_Compression != CMP_BYTERUN1)) cleanup("Compression method unsupported!", 1);
915 have_bmhd = 1;
917 img->totdepth = img->bmh.bmh_Depth + ((img->bmh.bmh_Masking == MSK_HASMASK) ? 1 : 0);
919 img->bpr = ((img->bmh.bmh_Width + 15) & ~15) / 8;
921 /*fprintf(stderr, "BMHD: %d x %d x %d (%d)\n", img->bmh.bmh_Width,
922 img->bmh.bmh_Height,
923 img->bmh.bmh_Depth,
924 img->totdepth);*/
925 img->planarbmh = img->bmh;
926 break;
928 case ID_CMAP:
929 if (!have_bmhd) cleanup("CMAP chunk before BMHD chunk (or no BMHD chunk at all!", 1);
931 img->cmapentries = size / 3;
932 if (size & 1) size++;
934 if ((img->cmapentries < 2) || (img->cmapentries > 256)) cleanup("CMAP chunk has bad number of entries!", 1);
936 for(i = 0; i < img->cmapentries; i++)
938 img->rgb[i][0] = getbyte();
939 img->rgb[i][1] = getbyte();
940 img->rgb[i][2] = getbyte();
941 size -= 3;
944 skipbytes(size);
946 have_cmap = 1;
948 break;
950 case ID_BODY:
951 if (!have_bmhd) cleanup("BODY chunk before BMHD chunk (or no BMHD chunk at all!", 1);
952 body = &filebuffer[filepos];
953 bodysize = size;
955 if (img->bmh.bmh_Compression == CMP_NONE)
957 LONG shouldbesize = img->totdepth * img->bpr * img->bmh.bmh_Height;
958 if (bodysize != shouldbesize) cleanup("BODY chunk size seems to be wrong!", 1);
961 have_body = 1;
962 /* Fall through */
964 default:
965 if (size & 1) size++;
966 skipbytes(size);
967 break;
970 if (filepos == filesize) break;
971 if (have_bmhd && have_body && have_cmap) break;
974 if (!have_bmhd) cleanup("BMHD chunk missing!", 1);
975 if (!have_body) cleanup("BODY chunk missing!", 1);
978 /****************************************************************************************/
980 static unsigned char *unpack_byterun1(unsigned char *source, unsigned char *dest, LONG unpackedsize)
982 unsigned char r;
983 signed char c;
985 for(;;)
987 c = (signed char)(*source++);
988 if (c >= 0)
990 while(c-- >= 0)
992 *dest++ = *source++;
993 if (--unpackedsize <= 0) return source;
996 else if (c != -128)
998 c = -c;
999 r = *source++;
1001 while(c-- >= 0)
1003 *dest++ = r;
1004 if (--unpackedsize <= 0) return source;
1011 /****************************************************************************************/
1013 static BOOL norm1(LONG count, unsigned char **source_backup,
1014 unsigned char **dest, LONG *checksize)
1016 //if (count >= 0) fprintf(stderr, "XX: non packable %d\n",count);
1018 while(count >= 0)
1020 LONG step = count;
1022 if (step > 127) step = 127;
1024 *checksize -= step;
1025 *checksize -= 2;
1027 if (*checksize <= 0) return 0;
1029 count -= step;
1031 *(*dest)++ = step;
1034 while(step-- >= 0)
1036 *(*dest)++ = *(*source_backup)++;
1039 count--;
1043 return 1;
1046 static BOOL copy1(unsigned char r, LONG count, unsigned char **dest, LONG *checksize)
1048 //if (count >= 1) fprintf(stderr, "XX: repeat %02x x %d\n", r, count);
1050 while(--count >= 0)
1052 LONG step = count;
1054 if (step > 127) step = 127;
1056 count -= step;
1057 step = -step;
1058 *checksize -= 2;
1059 if (*checksize <= 0) return 0;
1061 *(*dest)++ = (unsigned char)step;
1062 *(*dest)++ = r;
1065 return 1;
1068 static BOOL pack_byterun1(unsigned char *source, unsigned char *dest,
1069 LONG size, LONG check_size, LONG *packsize)
1071 unsigned char *source_backup, *dest_backup;
1072 LONG samebytes_counter, samebytes, count;
1073 LONG checksize = check_size;
1074 unsigned char oldbyte, actbyte;
1076 if (checksize < 0) checksize = 0x7FFFFFFF;
1078 oldbyte = *source;
1079 samebytes_counter = 0;
1080 source_backup = source;
1081 dest_backup = dest;
1083 for(;;)
1085 //fprintf(stderr, "size = %d. checksize = %d\n", size, checksize);
1086 if (--size < 0) break;
1087 actbyte = *source++;
1088 if (actbyte == oldbyte)
1090 samebytes_counter++;
1091 continue;
1094 oldbyte = actbyte;
1096 samebytes = samebytes_counter;
1097 samebytes_counter = 1;
1099 if (samebytes < 3) continue;
1101 count = (LONG)(source - source_backup - samebytes - 2);
1102 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1104 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
1106 source_backup = source - 1;
1108 //fprintf(stderr, "done\n");
1110 if (samebytes_counter >= 3)
1112 samebytes = samebytes_counter;
1113 count = (LONG)(source - source_backup - samebytes - 1);
1114 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1115 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
1117 else
1119 count = (LONG)(source - source_backup - 1);
1120 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1122 //fprintf(stderr, "realdone\n");
1124 if (packsize) *packsize = (LONG)(dest - dest_backup);
1126 return 1;
1129 /****************************************************************************************/
1131 static void p2c(unsigned char *source, unsigned char *dest, LONG width, LONG height,
1132 LONG totplanes, LONG wantplanes, LONG chunkybpr)
1134 LONG alignedwidth, x, y, p, bpr, bpl;
1136 alignedwidth = (width + 15) & ~15;
1137 bpr = alignedwidth / 8;
1138 bpl = bpr * totplanes;
1140 for(y = 0; y < height; y++)
1142 for(x = 0; x < width; x++)
1144 LONG mask = 0x80 >> (x & 7);
1145 LONG offset = x / 8;
1146 unsigned char chunkypix = 0;
1148 for(p = 0; p < wantplanes; p++)
1150 if (source[p * bpr + offset] & mask) chunkypix |= (1 << p);
1152 dest[x] = chunkypix;
1155 source += bpl;
1156 dest += chunkybpr;
1162 /****************************************************************************************/
1164 static void c2p(unsigned char *source, unsigned char *dest, LONG width, LONG height, LONG planes)
1166 LONG alignedwidth, x, y, p, bpr, bpl;
1168 alignedwidth = (width + 15) & ~15;
1169 bpr = alignedwidth / 8;
1170 bpl = bpr * planes;
1172 for(y = 0; y < height; y++)
1174 for(x = 0; x < width; x++)
1176 LONG mask = 0x80 >> (x & 7);
1177 LONG offset = x / 8;
1178 unsigned char chunkypix = source[x];
1180 for(p = 0; p < planes; p++)
1182 if (chunkypix & (1 << p))
1183 dest[p * bpr + offset] |= mask;
1184 else
1185 dest[p * bpr + offset] &= ~mask;
1189 source += width;
1190 dest += bpl;
1195 /****************************************************************************************/
1197 static void convertbody(struct ILBMImage *img)
1199 LONG unpackedsize = img->bpr * img->bmh.bmh_Height * img->totdepth;
1201 if (is_png)
1202 return;
1204 img->planarbuffer = malloc(unpackedsize);
1205 if (!img->planarbuffer) cleanup("Memory allocation for planar buffer failed!", 1);
1207 if (img->bmh.bmh_Compression == CMP_NONE)
1209 memcpy(img->planarbuffer, body, unpackedsize);
1211 else
1213 unpack_byterun1(body, img->planarbuffer, unpackedsize);
1216 img->chunkybuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
1217 if (!img->chunkybuffer) cleanup("Memory allocation for chunky buffer failed!", 1);
1219 p2c(img->planarbuffer,
1220 img->chunkybuffer,
1221 img->bmh.bmh_Width,
1222 img->bmh.bmh_Height,
1223 img->totdepth,
1224 img->bmh.bmh_Depth,
1225 img->bmh.bmh_Width);
1228 /****************************************************************************************/
1230 static UBYTE findcolor(struct Palette *pal, ULONG r, ULONG g, ULONG b, BOOL notrans)
1232 ULONG dist, bestdist = 0xFFFFFFFF;
1233 UBYTE i, besti = 0;
1235 for(i = 0; i < pal->numentries; i++)
1237 LONG r1, g1, b1, r2, g2, b2, dr, dg, db;
1239 if (notrans && i == transparentoption)
1240 continue;
1242 r1 = (LONG)r;
1243 g1 = (LONG)g;
1244 b1 = (LONG)b;
1246 r2 = (LONG)pal->rgb[i][0];
1247 g2 = (LONG)pal->rgb[i][1];
1248 b2 = (LONG)pal->rgb[i][2];
1250 dr = r1 - r2;
1251 dg = g1 - g2;
1252 db = b1 - b2;
1254 dist = (dr * dr) + (dg * dg) + (db * db);
1255 if (dist < bestdist)
1257 bestdist = dist;
1258 besti = i;
1263 return besti;
1266 /****************************************************************************************/
1268 static void remapplanar(struct ILBMImage *img, struct Palette *pal)
1270 UBYTE *remapbuffer;
1271 LONG i, x, y, highestcol = 0, newdepth = 0;
1273 remapbuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
1274 if (!remapbuffer) cleanup("Error allocating remap buffer!", 1);
1276 for(i = 0; i < img->cmapentries; i++)
1278 img->remaptable[i] = findcolor(pal, img->rgb[i][0], img->rgb[i][1], img->rgb[i][2], FALSE);
1281 for(i = 0; i < img->bmh.bmh_Width * img->bmh.bmh_Height; i++)
1283 remapbuffer[i] = img->remaptable[img->chunkybuffer[i]];
1285 if (remapbuffer[i] > highestcol)
1286 highestcol = remapbuffer[i];
1289 for(i = highestcol; i; i >>= 1) newdepth++;
1290 if (newdepth == 0) newdepth = 1;
1292 if (newdepth > img->totdepth)
1294 if (img->planarbuffer)
1295 free(img->planarbuffer);
1297 img->planarbuffer = malloc(img->bpr * img->bmh.bmh_Height * newdepth);
1298 if (!img->planarbuffer)
1300 free(remapbuffer);
1301 cleanup("Error re-allocating planar buffer!", 1);
1305 img->planarbmh.bmh_Width = img->bmh.bmh_Width;
1306 img->planarbmh.bmh_Height= img->bmh.bmh_Height;
1307 img->planarbmh.bmh_Depth = newdepth;
1309 memset(img->planarbuffer, 0, img->bpr * img->bmh.bmh_Height * newdepth);
1311 c2p(remapbuffer, img->planarbuffer, img->bmh.bmh_Width, img->bmh.bmh_Height, newdepth);
1313 free(remapbuffer);
1316 /****************************************************************************************/
1318 static void loadimage(char *name, struct ILBMImage *img)
1320 freeimage(img);
1322 filename = name;
1324 openimage(img);
1325 checkimage(img);
1326 scanimage(img);
1327 convertbody(img);
1330 /****************************************************************************************/
1332 struct diskobject
1334 UBYTE do_magic[2];
1335 UBYTE do_version[2];
1336 UBYTE do_gadget_nextgadget[4];
1337 UBYTE do_gadget_leftedge[2];
1338 UBYTE do_gadget_topedge[2];
1339 UBYTE do_gadget_width[2];
1340 UBYTE do_gadget_height[2];
1341 UBYTE do_gadget_flags[2];
1342 UBYTE do_gadget_activation[2];
1343 UBYTE do_gadget_gadgettype[2];
1344 UBYTE do_gadget_gadgetrender[4];
1345 UBYTE do_gadget_selectrender[4];
1346 UBYTE do_gadget_gadgettext[4];
1347 UBYTE do_gadget_mutualexclude[4];
1348 UBYTE do_gadget_specialinfo[4];
1349 UBYTE do_gadget_gadgetid[2];
1350 UBYTE do_gadget_userdata[4];
1351 UBYTE do_type;
1352 UBYTE do_pad;
1353 UBYTE do_defaulttool[4];
1354 UBYTE do_tooltypes[4];
1355 UBYTE do_currentx[4];
1356 UBYTE do_currenty[4];
1357 UBYTE do_drawerdata[4];
1358 UBYTE do_toolwindow[4];
1359 UBYTE do_stacksize[4];
1362 /****************************************************************************************/
1364 struct olddrawerdata
1366 UBYTE dd_newwindow_leftedge[2];
1367 UBYTE dd_newwindow_topedge[2];
1368 UBYTE dd_newwindow_width[2];
1369 UBYTE dd_newwindow_height[2];
1370 UBYTE dd_newwindow_detailpen;
1371 UBYTE dd_newwindow_blockpen;
1372 UBYTE dd_newwindow_idcmpflags[4];
1373 UBYTE dd_newwindow_flags[4];
1374 UBYTE dd_newwindow_firstgadget[4];
1375 UBYTE dd_newwindow_checkmark[4];
1376 UBYTE dd_newwindow_title[4];
1377 UBYTE dd_newwindow_screen[4];
1378 UBYTE dd_newwindow_bitmap[4];
1379 UBYTE dd_newwindow_minwidth[2];
1380 UBYTE dd_newwindow_minheight[2];
1381 UBYTE dd_newwindow_maxwidth[2];
1382 UBYTE dd_newwindow_maxheight[2];
1383 UBYTE dd_newwindow_type[2];
1384 UBYTE dd_currentx[4];
1385 UBYTE dd_currenty[4];
1388 /****************************************************************************************/
1390 struct newdrawerdata
1392 UBYTE dd_flags[4];
1393 UBYTE dd_viewmodes[2];
1396 /****************************************************************************************/
1398 struct image
1400 UBYTE leftedge[2];
1401 UBYTE topedge[2];
1402 UBYTE width[2];
1403 UBYTE height[2];
1404 UBYTE depth[2];
1405 UBYTE imagedata[4];
1406 UBYTE planepick;
1407 UBYTE planeonoff;
1408 UBYTE nextimage[4];
1411 /****************************************************************************************/
1413 #define SET_BYTE(field,value) \
1414 ACT_STRUCT.field = value
1416 #define SET_WORD(field, value) \
1417 ACT_STRUCT.field[0] = ((value) >> 8) & 0xFF; \
1418 ACT_STRUCT.field[1] = (value) & 0xFF;
1420 #define SET_LONG(field,value) \
1421 ACT_STRUCT.field[0] = ((value) >> 24) & 0xFF; \
1422 ACT_STRUCT.field[1] = ((value) >> 16) & 0xFF; \
1423 ACT_STRUCT.field[2] = ((value) >> 8) & 0xFF; \
1424 ACT_STRUCT.field[3] = (value) & 0xFF;
1426 #define BOOL_YES 0x2A2A2A2A
1427 #define BOOL_NO 0x00000000
1429 static void writediskobject(void)
1431 struct diskobject dobj;
1433 if (typeoption == 2) /* DRAWER */
1435 drawerdataoption = "YES";
1438 #define ACT_STRUCT dobj
1440 SET_WORD(do_magic, 0xE310);
1441 SET_WORD(do_version, 1);
1442 SET_LONG(do_gadget_nextgadget, 0);
1443 SET_WORD(do_gadget_leftedge, 0);
1444 SET_WORD(do_gadget_topedge, 0);
1445 SET_WORD(do_gadget_width, img1.bmh.bmh_Width);
1446 SET_WORD(do_gadget_height, img1.bmh.bmh_Height);
1448 if (image2option)
1450 /* GFLG_GADGHIMAGE + GFLG_GADGIMAGE */
1451 SET_WORD(do_gadget_flags, 4 + 2);
1453 else
1455 /* GFLG_GADGIMAGE */
1456 SET_WORD(do_gadget_flags, 4);
1459 SET_WORD(do_gadget_activation, 1);
1460 SET_WORD(do_gadget_gadgettype, 1);
1461 SET_LONG(do_gadget_gadgetrender, BOOL_YES);
1463 if (image2option)
1465 SET_LONG(do_gadget_selectrender, BOOL_YES);
1467 else
1469 SET_LONG(do_gadget_selectrender, BOOL_NO);
1472 SET_LONG(do_gadget_gadgettext, 0);
1473 SET_LONG(do_gadget_mutualexclude, (1 << 31) | (tpdX << 8) | (tpdY << 0));
1474 SET_LONG(do_gadget_specialinfo, 0);
1475 SET_WORD(do_gadget_gadgetid, 0);
1476 SET_LONG(do_gadget_userdata, 1); /* full drawer data */
1478 SET_BYTE(do_type, typeoption);
1479 SET_BYTE(do_pad, 0);
1481 if (defaulttooloption)
1483 SET_LONG(do_defaulttool, BOOL_YES);
1485 else
1487 SET_LONG(do_defaulttool, BOOL_NO);
1490 if (tooltypesoption)
1492 SET_LONG(do_tooltypes, BOOL_YES);
1494 else
1496 SET_LONG(do_tooltypes, BOOL_NO);
1499 SET_LONG(do_currentx, iconleftoption);
1500 SET_LONG(do_currenty, icontopoption);
1502 if (drawerdataoption)
1504 SET_LONG(do_drawerdata, BOOL_YES);
1506 else
1508 SET_LONG(do_drawerdata, BOOL_NO);
1512 SET_LONG(do_toolwindow, 0);
1513 SET_LONG(do_stacksize, stackoption);
1515 if (fwrite(&dobj, 1, sizeof(dobj), outfile) != sizeof(dobj))
1517 cleanup("Error writing diskobject structure to outfile!", 1);
1521 /****************************************************************************************/
1523 static void writeolddrawerdata(void)
1525 struct olddrawerdata dd;
1527 if (!drawerdataoption) return;
1529 #undef ACT_STRUCT
1530 #define ACT_STRUCT dd
1532 SET_WORD(dd_newwindow_leftedge, drawerleftoption);
1533 SET_WORD(dd_newwindow_topedge, drawertopoption);
1534 SET_WORD(dd_newwindow_width, drawerwidthoption);
1535 SET_WORD(dd_newwindow_height, drawerheightoption);
1536 SET_BYTE(dd_newwindow_detailpen, 255);
1537 SET_BYTE(dd_newwindow_blockpen, 255);
1538 SET_LONG(dd_newwindow_idcmpflags, 0);
1539 SET_LONG(dd_newwindow_flags, 0x240027f);
1540 SET_LONG(dd_newwindow_firstgadget, 0);
1541 SET_LONG(dd_newwindow_checkmark, 0);
1542 SET_LONG(dd_newwindow_title, 0);
1543 SET_LONG(dd_newwindow_screen, 0);
1544 SET_LONG(dd_newwindow_bitmap, 0);
1545 SET_WORD(dd_newwindow_minwidth, 90);
1546 SET_WORD(dd_newwindow_minheight, 40);
1547 SET_WORD(dd_newwindow_maxwidth, 65535);
1548 SET_WORD(dd_newwindow_maxheight, 65535);
1549 SET_WORD(dd_newwindow_type, 1);
1550 SET_LONG(dd_currentx, drawervleftoption);
1551 SET_LONG(dd_currenty, drawervtopoption);
1553 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1555 cleanup("Error writing olddrawerdata structure to outfile!", 1);
1561 /****************************************************************************************/
1563 static void writenewdrawerdata(void)
1565 struct newdrawerdata dd;
1567 if (!drawerdataoption) return;
1569 #undef ACT_STRUCT
1570 #define ACT_STRUCT dd
1572 SET_LONG(dd_flags, drawershowoption);
1573 SET_WORD(dd_viewmodes, drawershowasoption);
1575 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1577 cleanup("Error writing newdrawerdata structure to outfile!", 1);
1582 /****************************************************************************************/
1584 static void writeword(WORD l)
1586 UBYTE f[2];
1588 f[1] = (l >> 8) & 0xFF;
1589 f[2] = l & 0xFF;
1591 if (fwrite(f, 1, 2, outfile) != 2)
1593 cleanup("Error writing word value!", 1);
1598 /****************************************************************************************/
1600 static void writelong(LONG l)
1602 UBYTE f[4];
1604 f[0] = (l >> 24) & 0xFF;
1605 f[1] = (l >> 16) & 0xFF;
1606 f[2] = (l >> 8) & 0xFF;
1607 f[3] = l & 0xFF;
1609 if (fwrite(f, 1, 4, outfile) != 4)
1611 cleanup("Error writing long value!", 1);
1616 /****************************************************************************************/
1618 static void writenormalstring(char *s)
1620 int len = strlen(s) + 1;
1622 if (fwrite(s, 1, len, outfile) != len)
1624 cleanup("Error writing string!", 1);
1629 /****************************************************************************************/
1631 static void writestring(char *s)
1633 int len = strlen(s) + 1;
1635 D(printf("String: \"%s\", length %d\n", s, len));
1637 writelong(len);
1639 if (fwrite(s, 1, len, outfile) != len)
1641 cleanup("Error writing string!", 1);
1646 /****************************************************************************************/
1648 static void writeimage(struct ILBMImage *img)
1650 struct image i;
1651 LONG d, y;
1653 #undef ACT_STRUCT
1654 #define ACT_STRUCT i
1656 SET_WORD(leftedge, 0);
1657 SET_WORD(topedge, 0);
1658 SET_WORD(width, img->planarbmh.bmh_Width);
1659 SET_WORD(height, img->planarbmh.bmh_Height);
1660 SET_WORD(depth, img->planarbmh.bmh_Depth);
1661 SET_LONG(imagedata, BOOL_YES);
1662 SET_BYTE(planepick, (1 << img->planarbmh.bmh_Depth) - 1);
1663 SET_BYTE(planeonoff, 0);
1664 SET_LONG(nextimage, 0);
1666 if (fwrite(&i, 1, sizeof(i), outfile) != sizeof(i))
1668 cleanup("Error writing image structure to outfile!", 1);
1671 for(d = 0; d < img->planarbmh.bmh_Depth; d++)
1673 UBYTE *dat = img->planarbuffer + img->bpr * d;
1675 for(y = 0; y < img->planarbmh.bmh_Height; y++)
1677 if(fwrite(dat, 1, img->bpr, outfile) != img->bpr)
1679 cleanup("Error writing image data to outfile!", 1);
1681 dat += (img->planarbmh.bmh_Depth * img->bpr);
1687 /****************************************************************************************/
1689 struct facechunk
1691 UBYTE fc_width;
1692 UBYTE fc_height;
1693 UBYTE fc_flags;
1694 UBYTE fc_aspect;
1695 UBYTE fc_maxpalettebytes[2];
1698 /****************************************************************************************/
1700 struct imagchunk
1702 UBYTE ic_transparentcolour;
1703 UBYTE ic_numcolours;
1704 UBYTE ic_flags;
1705 UBYTE ic_imageformat;
1706 UBYTE ic_paletteformat;
1707 UBYTE ic_depth;
1708 UBYTE ic_numimagebytes[2];
1709 UBYTE ic_numpalettebytes[2];
1712 /****************************************************************************************/
1714 static LONG writefacechunk(void)
1716 struct facechunk fc;
1717 LONG palbytes;
1719 #undef ACT_STRUCT
1720 #define ACT_STRUCT fc
1722 writelong(ID_FACE);
1723 writelong(sizeof(struct facechunk));
1725 SET_BYTE(fc_width, img1.bmh.bmh_Width - 1);
1726 SET_BYTE(fc_height, img1.bmh.bmh_Height - 1);
1727 SET_BYTE(fc_flags, 0);
1728 SET_BYTE(fc_aspect, 0); // 0x11);
1730 palbytes = (img1.cmapentries > img2.cmapentries) ? img1.cmapentries : img2.cmapentries;
1731 palbytes = palbytes * 3;
1733 SET_WORD(fc_maxpalettebytes, palbytes - 1);
1735 if (fwrite(&fc, 1, sizeof(fc), outfile) != sizeof(fc))
1737 cleanup("Error writing face chunk!", 1);
1740 return sizeof(struct facechunk) + 8;
1743 /****************************************************************************************/
1745 /* createrle() based on ModifyIcon source by Dirk Stöcker */
1747 /****************************************************************************************/
1749 static char * createrle(unsigned long depth, unsigned char *dtype, LONG *dsize, unsigned long size,
1750 unsigned char *src)
1752 int i, j, k;
1753 unsigned long bitbuf, numbits;
1754 unsigned char *buf;
1755 long ressize, numcopy, numequal;
1757 buf = malloc(size * 2);
1758 if (!buf) return NULL;
1760 numcopy = 0;
1761 numequal = 1;
1762 bitbuf = 0;
1763 numbits = 0;
1764 ressize = 0;
1765 k = 0; /* the really output pointer */
1766 for(i = 1; numequal || numcopy;)
1768 if(i < size && numequal && (src[i-1] == src[i]))
1770 ++numequal; ++i;
1772 else if(i < size && numequal*depth <= 16)
1774 numcopy += numequal; numequal = 1; ++i;
1776 else
1778 /* care for end case, where it maybe better to join the two */
1779 if(i == size && numcopy + numequal <= 128 && (numequal-1)*depth <= 8)
1781 numcopy += numequal; numequal = 0;
1783 if(numcopy)
1785 if((j = numcopy) > 128) j = 128;
1786 bitbuf = (bitbuf<<8) | (j-1);
1787 numcopy -= j;
1789 else
1791 if((j = numequal) > 128) j = 128;
1792 bitbuf = (bitbuf<<8) | (256-(j-1));
1793 numequal -= j;
1794 k += j-1;
1795 j = 1;
1797 buf[ressize++] = (bitbuf >> numbits);
1798 while(j--)
1800 numbits += depth;
1801 bitbuf = (bitbuf<<depth) | src[k++];
1802 if(numbits >= 8)
1804 numbits -= 8;
1805 buf[ressize++] = (bitbuf >> numbits);
1808 if(i < size && !numcopy && !numequal)
1810 numequal = 1; ++i;
1814 if(numbits)
1815 buf[ressize++] = bitbuf << (8-numbits);
1817 if(ressize > size) /* no RLE */
1819 ressize = size;
1820 *dtype = 0;
1821 for(i = 0; i < size; ++i)
1822 buf[i]= src[i];
1824 else
1825 *dtype = 1;
1827 *dsize = ressize;
1829 return buf;
1832 /****************************************************************************************/
1834 static LONG writeimagchunk(struct ILBMImage *img)
1836 struct imagchunk ic;
1837 LONG imagsize;
1838 UBYTE skippalette = 0;
1839 UBYTE *pal, *gfx;
1840 LONG palsize, gfxsize;
1841 UBYTE palpacked, gfxpacked;
1843 imagsize = sizeof(struct imagchunk);
1845 /* if this is second image check whether palette is identical to
1846 the one of first image */
1848 if (img == &img2)
1850 if (img1.cmapentries == img2.cmapentries)
1852 WORD i;
1854 for (i = 0; i < img1.cmapentries; i++)
1856 if (img1.rgb[i][0] != img2.rgb[i][0]) break;
1857 if (img1.rgb[i][1] != img2.rgb[i][1]) break;
1858 if (img1.rgb[i][2] != img2.rgb[i][2]) break;
1861 if (i == img1.cmapentries) skippalette = 1;
1865 if (!skippalette)
1867 pal = createrle(8,
1868 &palpacked,
1869 &palsize,
1870 img->cmapentries * 3,
1871 (unsigned char *)img->rgb);
1873 imagsize += palsize;
1876 gfx = createrle(img->bmh.bmh_Depth,
1877 &gfxpacked,
1878 &gfxsize,
1879 img->bmh.bmh_Width * img->bmh.bmh_Height,
1880 img->chunkybuffer);
1882 imagsize += gfxsize;
1884 #undef ACT_STRUCT
1885 #define ACT_STRUCT ic
1887 SET_BYTE(ic_transparentcolour, transparentoption);
1888 if (skippalette)
1890 SET_BYTE(ic_numcolours, 0);
1891 SET_BYTE(ic_flags, (transparentoption != -1) ? 1 : 0); /* 1 = HasTransparentColour */
1892 SET_BYTE(ic_paletteformat, 0);
1893 SET_WORD(ic_numpalettebytes, 0);
1895 else
1897 SET_BYTE(ic_numcolours, img->cmapentries - 1);
1898 SET_BYTE(ic_flags, (transparentoption != -1) ? 3 : 2); /* 2 = HasPalette */
1899 SET_BYTE(ic_paletteformat, palpacked);
1900 SET_WORD(ic_numpalettebytes, palsize - 1);
1903 SET_BYTE(ic_imageformat, gfxpacked);
1904 SET_BYTE(ic_depth, img->bmh.bmh_Depth);
1905 SET_WORD(ic_numimagebytes, gfxsize - 1);
1907 writelong(ID_IMAG);
1908 writelong(imagsize);
1910 if (fwrite(&ic, 1, sizeof(ic), outfile) != sizeof(ic))
1912 cleanup("Error writing imag chunk!", 1);
1915 if (fwrite(gfx, 1, gfxsize, outfile) != gfxsize)
1917 cleanup("Error write gfx data in imag chunk!", 1);
1920 if (!skippalette)
1922 if (fwrite(pal, 1, palsize, outfile) != palsize)
1924 cleanup("Error write palette data in imag chunk!", 1);
1928 if (imagsize & 1)
1930 UBYTE dummy = 0;
1932 if (fwrite(&dummy, 1, 1, outfile) != 1)
1934 cleanup("Error writing imag chunk!", 1);
1937 imagsize++;
1940 return imagsize + 8;
1943 /****************************************************************************************/
1944 static LONG writeargb(APTR argb, ULONG argb_size)
1946 LONG formsize = 10;
1947 struct ARGB35_Header {
1948 ULONG ztype; /* Always 1 */
1949 ULONG zsize; /* Compressed size, or -1 */
1950 UWORD resv; /* Always 0 */
1951 } ahdr;
1952 Bytef *zdest;
1953 uLongf zsize, size;
1954 int err;
1956 zsize = size = argb_size;
1958 zdest = malloc(zsize);
1959 if (!zdest)
1960 return 0;
1962 err = compress(zdest, &zsize, argb, size);
1963 if (err != Z_OK) {
1964 free(zdest);
1965 return 0;
1968 writelong(ID_ARGB);
1969 formsize = 10 + zsize;
1970 writelong(formsize);
1971 writelong(1);
1972 writelong(zsize);
1973 writeword(0);
1974 fwrite(zdest, 1, zsize, outfile);
1975 if (zsize & 1) {
1976 char c = 0;
1977 fwrite(&c, 1, 1, outfile);
1980 free(zdest);
1982 if (formsize & 1)
1983 formsize++;
1984 return 8 + formsize;
1987 /****************************************************************************************/
1989 static void write35data(void)
1991 LONG formsize = 4;
1992 LONG formsizeseek;
1994 if (nosaveIFF)
1995 return;
1997 writelong(ID_FORM);
1998 formsizeseek = ftell(outfile);
1999 writelong(0x12345678);
2000 writelong(ID_ICON);
2002 formsize += writefacechunk();
2003 formsize += writeimagchunk(&img1);
2004 if (image2option) formsize += writeimagchunk(&img2);
2006 if (!nosaveARGB && img1.argb) {
2007 formsize += writeargb(img1.argb, img1.argb_size);
2010 if (!nosaveARGB && img2.argb) {
2011 formsize += writeargb(img2.argb, img2.argb_size);
2014 if (!nosavePNG && img1.png) {
2015 writelong(ID_PNG);
2016 writelong(img1.png_size);
2017 fwrite(img1.png, 1, img1.png_size, outfile);
2018 if (img1.png_size & 1) {
2019 char c = 0;
2020 fwrite(&c, 1, 1, outfile);
2021 img1.png_size++;
2023 formsize += 8 + img1.png_size;
2026 if (!nosavePNG && img2.png) {
2027 writelong(ID_PNG);
2028 writelong(img2.png_size);
2029 fwrite(img2.png, 1, img2.png_size, outfile);
2030 if (img2.png_size & 1) {
2031 char c = 0;
2032 fwrite(&c, 1, 1, outfile);
2033 img2.png_size++;
2035 formsize += 8 + img2.png_size;
2038 fseek(outfile, formsizeseek, SEEK_SET);
2039 writelong(formsize);
2042 /****************************************************************************************/
2044 static void writeicon(void)
2046 struct diskobject dobj;
2048 outfile = fopen(outfilename, "wb");
2049 if (!outfile) cleanup("Can't open output file for writing!", 1);
2051 writediskobject();
2052 writeolddrawerdata();
2053 writeimage(&img1);
2055 if (image2option) writeimage(&img2);
2057 if (defaulttooloption) writestring(defaulttooloption);
2059 if (tooltypesoption)
2061 char **strarray;
2062 LONG numtooltypes = 0;
2064 for(strarray = tooltypesoption; *strarray; strarray++, numtooltypes++);
2066 writelong((numtooltypes + 1) * 4);
2068 for(strarray = tooltypesoption; *strarray; strarray++)
2070 writestring(*strarray);
2075 /* toolwindow would have to be saved in between here if there is any */
2077 writenewdrawerdata();
2079 write35data();
2083 /****************************************************************************************/
2085 static void remapicon(void)
2087 remapplanar(&img1, &std4colpal);
2088 if (image2option) remapplanar(&img2, &std4colpal);
2091 /****************************************************************************************/
2093 int main(int argc, char **argv)
2095 getarguments(argc, argv);
2096 parseiconsource();
2097 loadimage(image1option, &img1);
2098 if (image2option) {
2099 loadimage(image2option, &img2);
2100 if ((img2.bmh.bmh_Width && img2.bmh.bmh_Width != img1.bmh.bmh_Width) ||
2101 (img2.bmh.bmh_Height && img2.bmh.bmh_Height != img1.bmh.bmh_Height)) {
2102 fprintf(stderr, "%s: Image %s (%dx%d) is not the same size as Image %s (%dx%d)\n", argv[0], image1option, img1.bmh.bmh_Width, img1.bmh.bmh_Height, image2option, img2.bmh.bmh_Width, img2.bmh.bmh_Height);
2106 remapicon();
2107 writeicon();
2109 cleanup(0, 0);
2112 /****************************************************************************************/