delint for clang
[AROS.git] / tools / ilbmtoicon / ilbmtoicon.c
blobd8ee3645e8c4105ca8aa3fe6334de2847f3fa3da
1 /*
2 Copyright © 1995-2013, 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 #if (0)
816 img->planarbmh;
817 #endif
818 img->bpr = ((img->bmh.bmh_Width + 15) & ~15) / 8;
819 img->totdepth = 0;
821 /* Transform the RGBA data into chunky */
822 img->cmapentries = pal->numentries;
823 memcpy(img->rgb, pal->rgb, sizeof(img->rgb[0])*pal->numentries);
825 img->chunkybuffer = malloc(width * height * sizeof(UBYTE));
826 if (!img->chunkybuffer)
827 cleanup("Can't allocate the chunky buffer", 1);
829 chunkrow = img->chunkybuffer;
830 img->argb_size = width * height * sizeof(UBYTE) * 4;
831 img->argb = malloc(img->argb_size);
832 if (!img->argb)
833 cleanup("Can't allocate the ARGB buffer", 1);
835 for (y = 0; y < height; y++) {
836 png_bytep row = row_pointers[y];
837 UBYTE *ap = img->argb + (width * sizeof(UBYTE) * 4) * y;
838 for (x = 0; x < width; x++, row += 4, ap += 4, chunkrow++) {
839 UBYTE r,g,b;
841 ap[0] = row[3];
842 ap[1] = row[0];
843 ap[2] = row[1];
844 ap[3] = row[2];
846 /* Opacity of 0? Use the transparency color */
847 if (row[3] == 0) {
848 if (transparentoption < 0)
849 transparentoption = 0;
850 *chunkrow = transparentoption;
851 } else {
852 r = row[0];
853 g = row[1];
854 b = row[2];
856 *chunkrow = findcolor(pal, r, g, b, TRUE);
861 img->bmh.bmh_Transparent = transparentoption;
863 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
867 /****************************************************************************************/
869 static void scanimage(struct ILBMImage *img)
871 WORD i;
873 have_bmhd = 0;
874 have_cmap = 0;
875 have_body = 0;
877 if (img->png) {
878 /* Load the PNG, using the Scalos 16-color pallette,
879 * into the Chunky buffer.
881 loadpng(img, &scalos16colpal);
882 return;
885 for(;;)
887 ULONG id;
888 ULONG size;
890 id = getlong();
891 size = getlong();
893 //fprintf(stderr, "Chunk: %c%c%c%c Size: %d\n", id >> 24, id >> 16, id >> 8, id, size);
895 switch(id)
897 case ID_BMHD:
898 if (size != 20) cleanup("Bad BMHD chunk size!", 1);
900 img->bmh.bmh_Width = getword();
901 img->bmh.bmh_Height = getword();
902 img->bmh.bmh_Left = (WORD)getword();
903 img->bmh.bmh_Top = (WORD)getword();
904 img->bmh.bmh_Depth = getbyte();
905 img->bmh.bmh_Masking = getbyte();
906 img->bmh.bmh_Compression = getbyte();
907 img->bmh.bmh_Pad = getbyte();
908 img->bmh.bmh_Transparent = getword();
909 img->bmh.bmh_XAspect = getbyte();
910 img->bmh.bmh_YAspect = getbyte();
911 img->bmh.bmh_PageWidth = (WORD)getword();
912 img->bmh.bmh_PageHeight = (WORD)getword();
914 if (img->bmh.bmh_Depth > 8) cleanup("ILBM file has too many colors!", 1);
915 if ((img->bmh.bmh_Compression != CMP_NONE) && (img->bmh.bmh_Compression != CMP_BYTERUN1)) cleanup("Compression method unsupported!", 1);
917 have_bmhd = 1;
919 img->totdepth = img->bmh.bmh_Depth + ((img->bmh.bmh_Masking == MSK_HASMASK) ? 1 : 0);
921 img->bpr = ((img->bmh.bmh_Width + 15) & ~15) / 8;
923 /*fprintf(stderr, "BMHD: %d x %d x %d (%d)\n", img->bmh.bmh_Width,
924 img->bmh.bmh_Height,
925 img->bmh.bmh_Depth,
926 img->totdepth);*/
927 img->planarbmh = img->bmh;
928 break;
930 case ID_CMAP:
931 if (!have_bmhd) cleanup("CMAP chunk before BMHD chunk (or no BMHD chunk at all!", 1);
933 img->cmapentries = size / 3;
934 if (size & 1) size++;
936 if ((img->cmapentries < 2) || (img->cmapentries > 256)) cleanup("CMAP chunk has bad number of entries!", 1);
938 for(i = 0; i < img->cmapentries; i++)
940 img->rgb[i][0] = getbyte();
941 img->rgb[i][1] = getbyte();
942 img->rgb[i][2] = getbyte();
943 size -= 3;
946 skipbytes(size);
948 have_cmap = 1;
950 break;
952 case ID_BODY:
953 if (!have_bmhd) cleanup("BODY chunk before BMHD chunk (or no BMHD chunk at all!", 1);
954 body = &filebuffer[filepos];
955 bodysize = size;
957 if (img->bmh.bmh_Compression == CMP_NONE)
959 LONG shouldbesize = img->totdepth * img->bpr * img->bmh.bmh_Height;
960 if (bodysize != shouldbesize) cleanup("BODY chunk size seems to be wrong!", 1);
963 have_body = 1;
964 /* Fall through */
966 default:
967 if (size & 1) size++;
968 skipbytes(size);
969 break;
972 if (filepos == filesize) break;
973 if (have_bmhd && have_body && have_cmap) break;
976 if (!have_bmhd) cleanup("BMHD chunk missing!", 1);
977 if (!have_body) cleanup("BODY chunk missing!", 1);
980 /****************************************************************************************/
982 static unsigned char *unpack_byterun1(unsigned char *source, unsigned char *dest, LONG unpackedsize)
984 unsigned char r;
985 signed char c;
987 for(;;)
989 c = (signed char)(*source++);
990 if (c >= 0)
992 while(c-- >= 0)
994 *dest++ = *source++;
995 if (--unpackedsize <= 0) return source;
998 else if (c != -128)
1000 c = -c;
1001 r = *source++;
1003 while(c-- >= 0)
1005 *dest++ = r;
1006 if (--unpackedsize <= 0) return source;
1013 /****************************************************************************************/
1015 static BOOL norm1(LONG count, unsigned char **source_backup,
1016 unsigned char **dest, LONG *checksize)
1018 //if (count >= 0) fprintf(stderr, "XX: non packable %d\n",count);
1020 while(count >= 0)
1022 LONG step = count;
1024 if (step > 127) step = 127;
1026 *checksize -= step;
1027 *checksize -= 2;
1029 if (*checksize <= 0) return 0;
1031 count -= step;
1033 *(*dest)++ = step;
1036 while(step-- >= 0)
1038 *(*dest)++ = *(*source_backup)++;
1041 count--;
1045 return 1;
1048 static BOOL copy1(unsigned char r, LONG count, unsigned char **dest, LONG *checksize)
1050 //if (count >= 1) fprintf(stderr, "XX: repeat %02x x %d\n", r, count);
1052 while(--count >= 0)
1054 LONG step = count;
1056 if (step > 127) step = 127;
1058 count -= step;
1059 step = -step;
1060 *checksize -= 2;
1061 if (*checksize <= 0) return 0;
1063 *(*dest)++ = (unsigned char)step;
1064 *(*dest)++ = r;
1067 return 1;
1070 static BOOL pack_byterun1(unsigned char *source, unsigned char *dest,
1071 LONG size, LONG check_size, LONG *packsize)
1073 unsigned char *source_backup, *dest_backup;
1074 LONG samebytes_counter, samebytes, count;
1075 LONG checksize = check_size;
1076 unsigned char oldbyte, actbyte;
1078 if (checksize < 0) checksize = 0x7FFFFFFF;
1080 oldbyte = *source;
1081 samebytes_counter = 0;
1082 source_backup = source;
1083 dest_backup = dest;
1085 for(;;)
1087 //fprintf(stderr, "size = %d. checksize = %d\n", size, checksize);
1088 if (--size < 0) break;
1089 actbyte = *source++;
1090 if (actbyte == oldbyte)
1092 samebytes_counter++;
1093 continue;
1096 oldbyte = actbyte;
1098 samebytes = samebytes_counter;
1099 samebytes_counter = 1;
1101 if (samebytes < 3) continue;
1103 count = (LONG)(source - source_backup - samebytes - 2);
1104 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1106 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
1108 source_backup = source - 1;
1110 //fprintf(stderr, "done\n");
1112 if (samebytes_counter >= 3)
1114 samebytes = samebytes_counter;
1115 count = (LONG)(source - source_backup - samebytes - 1);
1116 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1117 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
1119 else
1121 count = (LONG)(source - source_backup - 1);
1122 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1124 //fprintf(stderr, "realdone\n");
1126 if (packsize) *packsize = (LONG)(dest - dest_backup);
1128 return 1;
1131 /****************************************************************************************/
1133 static void p2c(unsigned char *source, unsigned char *dest, LONG width, LONG height,
1134 LONG totplanes, LONG wantplanes, LONG chunkybpr)
1136 LONG alignedwidth, x, y, p, bpr, bpl;
1138 alignedwidth = (width + 15) & ~15;
1139 bpr = alignedwidth / 8;
1140 bpl = bpr * totplanes;
1142 for(y = 0; y < height; y++)
1144 for(x = 0; x < width; x++)
1146 LONG mask = 0x80 >> (x & 7);
1147 LONG offset = x / 8;
1148 unsigned char chunkypix = 0;
1150 for(p = 0; p < wantplanes; p++)
1152 if (source[p * bpr + offset] & mask) chunkypix |= (1 << p);
1154 dest[x] = chunkypix;
1157 source += bpl;
1158 dest += chunkybpr;
1164 /****************************************************************************************/
1166 static void c2p(unsigned char *source, unsigned char *dest, LONG width, LONG height, LONG planes)
1168 LONG alignedwidth, x, y, p, bpr, bpl;
1170 alignedwidth = (width + 15) & ~15;
1171 bpr = alignedwidth / 8;
1172 bpl = bpr * planes;
1174 for(y = 0; y < height; y++)
1176 for(x = 0; x < width; x++)
1178 LONG mask = 0x80 >> (x & 7);
1179 LONG offset = x / 8;
1180 unsigned char chunkypix = source[x];
1182 for(p = 0; p < planes; p++)
1184 if (chunkypix & (1 << p))
1185 dest[p * bpr + offset] |= mask;
1186 else
1187 dest[p * bpr + offset] &= ~mask;
1191 source += width;
1192 dest += bpl;
1197 /****************************************************************************************/
1199 static void convertbody(struct ILBMImage *img)
1201 LONG unpackedsize = img->bpr * img->bmh.bmh_Height * img->totdepth;
1203 if (is_png)
1204 return;
1206 img->planarbuffer = malloc(unpackedsize);
1207 if (!img->planarbuffer) cleanup("Memory allocation for planar buffer failed!", 1);
1209 if (img->bmh.bmh_Compression == CMP_NONE)
1211 memcpy(img->planarbuffer, body, unpackedsize);
1213 else
1215 unpack_byterun1(body, img->planarbuffer, unpackedsize);
1218 img->chunkybuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
1219 if (!img->chunkybuffer) cleanup("Memory allocation for chunky buffer failed!", 1);
1221 p2c(img->planarbuffer,
1222 img->chunkybuffer,
1223 img->bmh.bmh_Width,
1224 img->bmh.bmh_Height,
1225 img->totdepth,
1226 img->bmh.bmh_Depth,
1227 img->bmh.bmh_Width);
1230 /****************************************************************************************/
1232 static UBYTE findcolor(struct Palette *pal, ULONG r, ULONG g, ULONG b, BOOL notrans)
1234 ULONG dist, bestdist = 0xFFFFFFFF;
1235 UBYTE i, besti = 0;
1237 for(i = 0; i < pal->numentries; i++)
1239 LONG r1, g1, b1, r2, g2, b2, dr, dg, db;
1241 if (notrans && i == transparentoption)
1242 continue;
1244 r1 = (LONG)r;
1245 g1 = (LONG)g;
1246 b1 = (LONG)b;
1248 r2 = (LONG)pal->rgb[i][0];
1249 g2 = (LONG)pal->rgb[i][1];
1250 b2 = (LONG)pal->rgb[i][2];
1252 dr = r1 - r2;
1253 dg = g1 - g2;
1254 db = b1 - b2;
1256 dist = (dr * dr) + (dg * dg) + (db * db);
1257 if (dist < bestdist)
1259 bestdist = dist;
1260 besti = i;
1265 return besti;
1268 /****************************************************************************************/
1270 static void remapplanar(struct ILBMImage *img, struct Palette *pal)
1272 UBYTE *remapbuffer;
1273 LONG i, x, y, highestcol = 0, newdepth = 0;
1275 remapbuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
1276 if (!remapbuffer) cleanup("Error allocating remap buffer!", 1);
1278 for(i = 0; i < img->cmapentries; i++)
1280 img->remaptable[i] = findcolor(pal, img->rgb[i][0], img->rgb[i][1], img->rgb[i][2], FALSE);
1283 for(i = 0; i < img->bmh.bmh_Width * img->bmh.bmh_Height; i++)
1285 remapbuffer[i] = img->remaptable[img->chunkybuffer[i]];
1287 if (remapbuffer[i] > highestcol)
1288 highestcol = remapbuffer[i];
1291 for(i = highestcol; i; i >>= 1) newdepth++;
1292 if (newdepth == 0) newdepth = 1;
1294 if (newdepth > img->totdepth)
1296 if (img->planarbuffer)
1297 free(img->planarbuffer);
1299 img->planarbuffer = malloc(img->bpr * img->bmh.bmh_Height * newdepth);
1300 if (!img->planarbuffer)
1302 free(remapbuffer);
1303 cleanup("Error re-allocating planar buffer!", 1);
1307 img->planarbmh.bmh_Width = img->bmh.bmh_Width;
1308 img->planarbmh.bmh_Height= img->bmh.bmh_Height;
1309 img->planarbmh.bmh_Depth = newdepth;
1311 memset(img->planarbuffer, 0, img->bpr * img->bmh.bmh_Height * newdepth);
1313 c2p(remapbuffer, img->planarbuffer, img->bmh.bmh_Width, img->bmh.bmh_Height, newdepth);
1315 free(remapbuffer);
1318 /****************************************************************************************/
1320 static void loadimage(char *name, struct ILBMImage *img)
1322 freeimage(img);
1324 filename = name;
1326 openimage(img);
1327 checkimage(img);
1328 scanimage(img);
1329 convertbody(img);
1332 /****************************************************************************************/
1334 struct diskobject
1336 UBYTE do_magic[2];
1337 UBYTE do_version[2];
1338 UBYTE do_gadget_nextgadget[4];
1339 UBYTE do_gadget_leftedge[2];
1340 UBYTE do_gadget_topedge[2];
1341 UBYTE do_gadget_width[2];
1342 UBYTE do_gadget_height[2];
1343 UBYTE do_gadget_flags[2];
1344 UBYTE do_gadget_activation[2];
1345 UBYTE do_gadget_gadgettype[2];
1346 UBYTE do_gadget_gadgetrender[4];
1347 UBYTE do_gadget_selectrender[4];
1348 UBYTE do_gadget_gadgettext[4];
1349 UBYTE do_gadget_mutualexclude[4];
1350 UBYTE do_gadget_specialinfo[4];
1351 UBYTE do_gadget_gadgetid[2];
1352 UBYTE do_gadget_userdata[4];
1353 UBYTE do_type;
1354 UBYTE do_pad;
1355 UBYTE do_defaulttool[4];
1356 UBYTE do_tooltypes[4];
1357 UBYTE do_currentx[4];
1358 UBYTE do_currenty[4];
1359 UBYTE do_drawerdata[4];
1360 UBYTE do_toolwindow[4];
1361 UBYTE do_stacksize[4];
1364 /****************************************************************************************/
1366 struct olddrawerdata
1368 UBYTE dd_newwindow_leftedge[2];
1369 UBYTE dd_newwindow_topedge[2];
1370 UBYTE dd_newwindow_width[2];
1371 UBYTE dd_newwindow_height[2];
1372 UBYTE dd_newwindow_detailpen;
1373 UBYTE dd_newwindow_blockpen;
1374 UBYTE dd_newwindow_idcmpflags[4];
1375 UBYTE dd_newwindow_flags[4];
1376 UBYTE dd_newwindow_firstgadget[4];
1377 UBYTE dd_newwindow_checkmark[4];
1378 UBYTE dd_newwindow_title[4];
1379 UBYTE dd_newwindow_screen[4];
1380 UBYTE dd_newwindow_bitmap[4];
1381 UBYTE dd_newwindow_minwidth[2];
1382 UBYTE dd_newwindow_minheight[2];
1383 UBYTE dd_newwindow_maxwidth[2];
1384 UBYTE dd_newwindow_maxheight[2];
1385 UBYTE dd_newwindow_type[2];
1386 UBYTE dd_currentx[4];
1387 UBYTE dd_currenty[4];
1390 /****************************************************************************************/
1392 struct newdrawerdata
1394 UBYTE dd_flags[4];
1395 UBYTE dd_viewmodes[2];
1398 /****************************************************************************************/
1400 struct image
1402 UBYTE leftedge[2];
1403 UBYTE topedge[2];
1404 UBYTE width[2];
1405 UBYTE height[2];
1406 UBYTE depth[2];
1407 UBYTE imagedata[4];
1408 UBYTE planepick;
1409 UBYTE planeonoff;
1410 UBYTE nextimage[4];
1413 /****************************************************************************************/
1415 #define SET_BYTE(field,value) \
1416 ACT_STRUCT.field = value
1418 #define SET_WORD(field, value) \
1419 ACT_STRUCT.field[0] = ((value) >> 8) & 0xFF; \
1420 ACT_STRUCT.field[1] = (value) & 0xFF;
1422 #define SET_LONG(field,value) \
1423 ACT_STRUCT.field[0] = ((value) >> 24) & 0xFF; \
1424 ACT_STRUCT.field[1] = ((value) >> 16) & 0xFF; \
1425 ACT_STRUCT.field[2] = ((value) >> 8) & 0xFF; \
1426 ACT_STRUCT.field[3] = (value) & 0xFF;
1428 #define BOOL_YES 0x2A2A2A2A
1429 #define BOOL_NO 0x00000000
1431 static void writediskobject(void)
1433 struct diskobject dobj;
1435 if (typeoption == 2) /* DRAWER */
1437 drawerdataoption = "YES";
1440 #define ACT_STRUCT dobj
1442 SET_WORD(do_magic, 0xE310);
1443 SET_WORD(do_version, 1);
1444 SET_LONG(do_gadget_nextgadget, 0);
1445 SET_WORD(do_gadget_leftedge, 0);
1446 SET_WORD(do_gadget_topedge, 0);
1447 SET_WORD(do_gadget_width, img1.bmh.bmh_Width);
1448 SET_WORD(do_gadget_height, img1.bmh.bmh_Height);
1450 if (image2option)
1452 /* GFLG_GADGHIMAGE + GFLG_GADGIMAGE */
1453 SET_WORD(do_gadget_flags, 4 + 2);
1455 else
1457 /* GFLG_GADGIMAGE */
1458 SET_WORD(do_gadget_flags, 4);
1461 SET_WORD(do_gadget_activation, 1);
1462 SET_WORD(do_gadget_gadgettype, 1);
1463 SET_LONG(do_gadget_gadgetrender, BOOL_YES);
1465 if (image2option)
1467 SET_LONG(do_gadget_selectrender, BOOL_YES);
1469 else
1471 SET_LONG(do_gadget_selectrender, BOOL_NO);
1474 SET_LONG(do_gadget_gadgettext, 0);
1475 SET_LONG(do_gadget_mutualexclude, (1 << 31) | (tpdX << 8) | (tpdY << 0));
1476 SET_LONG(do_gadget_specialinfo, 0);
1477 SET_WORD(do_gadget_gadgetid, 0);
1478 SET_LONG(do_gadget_userdata, 1); /* full drawer data */
1480 SET_BYTE(do_type, typeoption);
1481 SET_BYTE(do_pad, 0);
1483 if (defaulttooloption)
1485 SET_LONG(do_defaulttool, BOOL_YES);
1487 else
1489 SET_LONG(do_defaulttool, BOOL_NO);
1492 if (tooltypesoption)
1494 SET_LONG(do_tooltypes, BOOL_YES);
1496 else
1498 SET_LONG(do_tooltypes, BOOL_NO);
1501 SET_LONG(do_currentx, iconleftoption);
1502 SET_LONG(do_currenty, icontopoption);
1504 if (drawerdataoption)
1506 SET_LONG(do_drawerdata, BOOL_YES);
1508 else
1510 SET_LONG(do_drawerdata, BOOL_NO);
1514 SET_LONG(do_toolwindow, 0);
1515 SET_LONG(do_stacksize, stackoption);
1517 if (fwrite(&dobj, 1, sizeof(dobj), outfile) != sizeof(dobj))
1519 cleanup("Error writing diskobject structure to outfile!", 1);
1523 /****************************************************************************************/
1525 static void writeolddrawerdata(void)
1527 struct olddrawerdata dd;
1529 if (!drawerdataoption) return;
1531 #undef ACT_STRUCT
1532 #define ACT_STRUCT dd
1534 SET_WORD(dd_newwindow_leftedge, drawerleftoption);
1535 SET_WORD(dd_newwindow_topedge, drawertopoption);
1536 SET_WORD(dd_newwindow_width, drawerwidthoption);
1537 SET_WORD(dd_newwindow_height, drawerheightoption);
1538 SET_BYTE(dd_newwindow_detailpen, 255);
1539 SET_BYTE(dd_newwindow_blockpen, 255);
1540 SET_LONG(dd_newwindow_idcmpflags, 0);
1541 SET_LONG(dd_newwindow_flags, 0x240027f);
1542 SET_LONG(dd_newwindow_firstgadget, 0);
1543 SET_LONG(dd_newwindow_checkmark, 0);
1544 SET_LONG(dd_newwindow_title, 0);
1545 SET_LONG(dd_newwindow_screen, 0);
1546 SET_LONG(dd_newwindow_bitmap, 0);
1547 SET_WORD(dd_newwindow_minwidth, 90);
1548 SET_WORD(dd_newwindow_minheight, 40);
1549 SET_WORD(dd_newwindow_maxwidth, 65535);
1550 SET_WORD(dd_newwindow_maxheight, 65535);
1551 SET_WORD(dd_newwindow_type, 1);
1552 SET_LONG(dd_currentx, drawervleftoption);
1553 SET_LONG(dd_currenty, drawervtopoption);
1555 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1557 cleanup("Error writing olddrawerdata structure to outfile!", 1);
1563 /****************************************************************************************/
1565 static void writenewdrawerdata(void)
1567 struct newdrawerdata dd;
1569 if (!drawerdataoption) return;
1571 #undef ACT_STRUCT
1572 #define ACT_STRUCT dd
1574 SET_LONG(dd_flags, drawershowoption);
1575 SET_WORD(dd_viewmodes, drawershowasoption);
1577 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1579 cleanup("Error writing newdrawerdata structure to outfile!", 1);
1584 /****************************************************************************************/
1586 static void writeword(WORD l)
1588 UBYTE f[2];
1590 f[0] = (l >> 8) & 0xFF;
1591 f[1] = l & 0xFF;
1593 if (fwrite(f, 1, 2, outfile) != 2)
1595 cleanup("Error writing word value!", 1);
1600 /****************************************************************************************/
1602 static void writelong(LONG l)
1604 UBYTE f[4];
1606 f[0] = (l >> 24) & 0xFF;
1607 f[1] = (l >> 16) & 0xFF;
1608 f[2] = (l >> 8) & 0xFF;
1609 f[3] = l & 0xFF;
1611 if (fwrite(f, 1, 4, outfile) != 4)
1613 cleanup("Error writing long value!", 1);
1618 /****************************************************************************************/
1620 static void writenormalstring(char *s)
1622 int len = strlen(s) + 1;
1624 if (fwrite(s, 1, len, outfile) != len)
1626 cleanup("Error writing string!", 1);
1631 /****************************************************************************************/
1633 static void writestring(char *s)
1635 int len = strlen(s) + 1;
1637 D(printf("String: \"%s\", length %d\n", s, len));
1639 writelong(len);
1641 if (fwrite(s, 1, len, outfile) != len)
1643 cleanup("Error writing string!", 1);
1648 /****************************************************************************************/
1650 static void writeimage(struct ILBMImage *img)
1652 struct image i;
1653 LONG d, y;
1655 #undef ACT_STRUCT
1656 #define ACT_STRUCT i
1658 SET_WORD(leftedge, 0);
1659 SET_WORD(topedge, 0);
1660 SET_WORD(width, img->planarbmh.bmh_Width);
1661 SET_WORD(height, img->planarbmh.bmh_Height);
1662 SET_WORD(depth, img->planarbmh.bmh_Depth);
1663 SET_LONG(imagedata, BOOL_YES);
1664 SET_BYTE(planepick, (1 << img->planarbmh.bmh_Depth) - 1);
1665 SET_BYTE(planeonoff, 0);
1666 SET_LONG(nextimage, 0);
1668 if (fwrite(&i, 1, sizeof(i), outfile) != sizeof(i))
1670 cleanup("Error writing image structure to outfile!", 1);
1673 for(d = 0; d < img->planarbmh.bmh_Depth; d++)
1675 UBYTE *dat = img->planarbuffer + img->bpr * d;
1677 for(y = 0; y < img->planarbmh.bmh_Height; y++)
1679 if(fwrite(dat, 1, img->bpr, outfile) != img->bpr)
1681 cleanup("Error writing image data to outfile!", 1);
1683 dat += (img->planarbmh.bmh_Depth * img->bpr);
1689 /****************************************************************************************/
1691 struct facechunk
1693 UBYTE fc_width;
1694 UBYTE fc_height;
1695 UBYTE fc_flags;
1696 UBYTE fc_aspect;
1697 UBYTE fc_maxpalettebytes[2];
1700 /****************************************************************************************/
1702 struct imagchunk
1704 UBYTE ic_transparentcolour;
1705 UBYTE ic_numcolours;
1706 UBYTE ic_flags;
1707 UBYTE ic_imageformat;
1708 UBYTE ic_paletteformat;
1709 UBYTE ic_depth;
1710 UBYTE ic_numimagebytes[2];
1711 UBYTE ic_numpalettebytes[2];
1714 /****************************************************************************************/
1716 static LONG writefacechunk(void)
1718 struct facechunk fc;
1719 LONG palbytes;
1721 #undef ACT_STRUCT
1722 #define ACT_STRUCT fc
1724 writelong(ID_FACE);
1725 writelong(sizeof(struct facechunk));
1727 SET_BYTE(fc_width, img1.bmh.bmh_Width - 1);
1728 SET_BYTE(fc_height, img1.bmh.bmh_Height - 1);
1729 SET_BYTE(fc_flags, 0);
1730 SET_BYTE(fc_aspect, 0); // 0x11);
1732 palbytes = (img1.cmapentries > img2.cmapentries) ? img1.cmapentries : img2.cmapentries;
1733 palbytes = palbytes * 3;
1735 SET_WORD(fc_maxpalettebytes, palbytes - 1);
1737 if (fwrite(&fc, 1, sizeof(fc), outfile) != sizeof(fc))
1739 cleanup("Error writing face chunk!", 1);
1742 return sizeof(struct facechunk) + 8;
1745 /****************************************************************************************/
1747 /* createrle() based on ModifyIcon source by Dirk Stöcker */
1749 /****************************************************************************************/
1751 static char * createrle(unsigned long depth, unsigned char *dtype, LONG *dsize, unsigned long size,
1752 unsigned char *src)
1754 int i, j, k;
1755 unsigned long bitbuf, numbits;
1756 unsigned char *buf;
1757 long ressize, numcopy, numequal;
1759 buf = malloc(size * 2);
1760 if (!buf) return NULL;
1762 numcopy = 0;
1763 numequal = 1;
1764 bitbuf = 0;
1765 numbits = 0;
1766 ressize = 0;
1767 k = 0; /* the really output pointer */
1768 for(i = 1; numequal || numcopy;)
1770 if(i < size && numequal && (src[i-1] == src[i]))
1772 ++numequal; ++i;
1774 else if(i < size && numequal*depth <= 16)
1776 numcopy += numequal; numequal = 1; ++i;
1778 else
1780 /* care for end case, where it maybe better to join the two */
1781 if(i == size && numcopy + numequal <= 128 && (numequal-1)*depth <= 8)
1783 numcopy += numequal; numequal = 0;
1785 if(numcopy)
1787 if((j = numcopy) > 128) j = 128;
1788 bitbuf = (bitbuf<<8) | (j-1);
1789 numcopy -= j;
1791 else
1793 if((j = numequal) > 128) j = 128;
1794 bitbuf = (bitbuf<<8) | (256-(j-1));
1795 numequal -= j;
1796 k += j-1;
1797 j = 1;
1799 buf[ressize++] = (bitbuf >> numbits);
1800 while(j--)
1802 numbits += depth;
1803 bitbuf = (bitbuf<<depth) | src[k++];
1804 if(numbits >= 8)
1806 numbits -= 8;
1807 buf[ressize++] = (bitbuf >> numbits);
1810 if(i < size && !numcopy && !numequal)
1812 numequal = 1; ++i;
1816 if(numbits)
1817 buf[ressize++] = bitbuf << (8-numbits);
1819 if(ressize > size) /* no RLE */
1821 ressize = size;
1822 *dtype = 0;
1823 for(i = 0; i < size; ++i)
1824 buf[i]= src[i];
1826 else
1827 *dtype = 1;
1829 *dsize = ressize;
1831 return buf;
1834 /****************************************************************************************/
1836 static LONG writeimagchunk(struct ILBMImage *img)
1838 struct imagchunk ic;
1839 LONG imagsize;
1840 UBYTE skippalette = 0;
1841 UBYTE *pal, *gfx;
1842 LONG palsize, gfxsize;
1843 UBYTE palpacked, gfxpacked;
1845 imagsize = sizeof(struct imagchunk);
1847 /* if this is second image check whether palette is identical to
1848 the one of first image */
1850 if (img == &img2)
1852 if (img1.cmapentries == img2.cmapentries)
1854 WORD i;
1856 for (i = 0; i < img1.cmapentries; i++)
1858 if (img1.rgb[i][0] != img2.rgb[i][0]) break;
1859 if (img1.rgb[i][1] != img2.rgb[i][1]) break;
1860 if (img1.rgb[i][2] != img2.rgb[i][2]) break;
1863 if (i == img1.cmapentries) skippalette = 1;
1867 if (!skippalette)
1869 pal = createrle(8,
1870 &palpacked,
1871 &palsize,
1872 img->cmapentries * 3,
1873 (unsigned char *)img->rgb);
1875 imagsize += palsize;
1878 gfx = createrle(img->bmh.bmh_Depth,
1879 &gfxpacked,
1880 &gfxsize,
1881 img->bmh.bmh_Width * img->bmh.bmh_Height,
1882 img->chunkybuffer);
1884 imagsize += gfxsize;
1886 #undef ACT_STRUCT
1887 #define ACT_STRUCT ic
1889 SET_BYTE(ic_transparentcolour, transparentoption);
1890 if (skippalette)
1892 SET_BYTE(ic_numcolours, 0);
1893 SET_BYTE(ic_flags, (transparentoption != -1) ? 1 : 0); /* 1 = HasTransparentColour */
1894 SET_BYTE(ic_paletteformat, 0);
1895 SET_WORD(ic_numpalettebytes, 0);
1897 else
1899 SET_BYTE(ic_numcolours, img->cmapentries - 1);
1900 SET_BYTE(ic_flags, (transparentoption != -1) ? 3 : 2); /* 2 = HasPalette */
1901 SET_BYTE(ic_paletteformat, palpacked);
1902 SET_WORD(ic_numpalettebytes, palsize - 1);
1905 SET_BYTE(ic_imageformat, gfxpacked);
1906 SET_BYTE(ic_depth, img->bmh.bmh_Depth);
1907 SET_WORD(ic_numimagebytes, gfxsize - 1);
1909 writelong(ID_IMAG);
1910 writelong(imagsize);
1912 if (fwrite(&ic, 1, sizeof(ic), outfile) != sizeof(ic))
1914 cleanup("Error writing imag chunk!", 1);
1917 if (fwrite(gfx, 1, gfxsize, outfile) != gfxsize)
1919 cleanup("Error write gfx data in imag chunk!", 1);
1922 if (!skippalette)
1924 if (fwrite(pal, 1, palsize, outfile) != palsize)
1926 cleanup("Error write palette data in imag chunk!", 1);
1930 if (imagsize & 1)
1932 UBYTE dummy = 0;
1934 if (fwrite(&dummy, 1, 1, outfile) != 1)
1936 cleanup("Error writing imag chunk!", 1);
1939 imagsize++;
1942 return imagsize + 8;
1945 /****************************************************************************************/
1946 static LONG writeargb(APTR argb, ULONG argb_size)
1948 LONG formsize = 10;
1949 struct ARGB35_Header {
1950 ULONG ztype; /* Always 1 */
1951 ULONG zsize; /* Compressed size, or -1 */
1952 UWORD resv; /* Always 0 */
1953 } ahdr;
1954 Bytef *zdest;
1955 uLongf zsize, size;
1956 int err;
1958 zsize = size = argb_size;
1960 zdest = malloc(zsize);
1961 if (!zdest)
1962 return 0;
1964 err = compress(zdest, &zsize, argb, size);
1965 if (err != Z_OK) {
1966 free(zdest);
1967 return 0;
1970 D(printf("ARGB: Compressed %d => %d\n", size, zsize));
1972 writelong(ID_ARGB);
1973 formsize = 10 + zsize;
1974 writelong(formsize);
1975 writelong(1);
1976 writelong(zsize);
1977 writeword(0);
1978 fwrite(zdest, 1, zsize, outfile);
1979 if (zsize & 1) {
1980 char c = 0;
1981 fwrite(&c, 1, 1, outfile);
1984 free(zdest);
1986 if (formsize & 1)
1987 formsize++;
1988 return 8 + formsize;
1991 /****************************************************************************************/
1993 static void write35data(void)
1995 LONG formsize = 4;
1996 LONG formsizeseek;
1998 if (nosaveIFF)
1999 return;
2001 writelong(ID_FORM);
2002 formsizeseek = ftell(outfile);
2003 writelong(0x12345678);
2004 writelong(ID_ICON);
2006 formsize += writefacechunk();
2007 formsize += writeimagchunk(&img1);
2008 if (image2option) formsize += writeimagchunk(&img2);
2010 if (!nosaveARGB && img1.argb) {
2011 formsize += writeargb(img1.argb, img1.argb_size);
2014 if (!nosaveARGB && img2.argb) {
2015 formsize += writeargb(img2.argb, img2.argb_size);
2018 if (!nosavePNG && img1.png) {
2019 writelong(ID_PNG);
2020 writelong(img1.png_size);
2021 fwrite(img1.png, 1, img1.png_size, outfile);
2022 if (img1.png_size & 1) {
2023 char c = 0;
2024 fwrite(&c, 1, 1, outfile);
2025 img1.png_size++;
2027 formsize += 8 + img1.png_size;
2030 if (!nosavePNG && img2.png) {
2031 writelong(ID_PNG);
2032 writelong(img2.png_size);
2033 fwrite(img2.png, 1, img2.png_size, outfile);
2034 if (img2.png_size & 1) {
2035 char c = 0;
2036 fwrite(&c, 1, 1, outfile);
2037 img2.png_size++;
2039 formsize += 8 + img2.png_size;
2042 fseek(outfile, formsizeseek, SEEK_SET);
2043 writelong(formsize);
2046 /****************************************************************************************/
2048 static void writeicon(void)
2050 struct diskobject dobj;
2052 D(printf("Writing %s\n", outfilename));
2053 outfile = fopen(outfilename, "wb");
2054 if (!outfile) cleanup("Can't open output file for writing!", 1);
2056 writediskobject();
2057 writeolddrawerdata();
2058 writeimage(&img1);
2060 if (image2option) writeimage(&img2);
2062 if (defaulttooloption) writestring(defaulttooloption);
2064 if (tooltypesoption)
2066 char **strarray;
2067 LONG numtooltypes = 0;
2069 for(strarray = tooltypesoption; *strarray; strarray++, numtooltypes++);
2071 writelong((numtooltypes + 1) * 4);
2073 for(strarray = tooltypesoption; *strarray; strarray++)
2075 writestring(*strarray);
2080 /* toolwindow would have to be saved in between here if there is any */
2082 writenewdrawerdata();
2084 write35data();
2088 /****************************************************************************************/
2090 static void remapicon(void)
2092 remapplanar(&img1, &std4colpal);
2093 if (image2option) remapplanar(&img2, &std4colpal);
2096 /****************************************************************************************/
2098 int main(int argc, char **argv)
2100 getarguments(argc, argv);
2101 parseiconsource();
2102 loadimage(image1option, &img1);
2103 if (image2option) {
2104 loadimage(image2option, &img2);
2105 if ((img2.bmh.bmh_Width && img2.bmh.bmh_Width != img1.bmh.bmh_Width) ||
2106 (img2.bmh.bmh_Height && img2.bmh.bmh_Height != img1.bmh.bmh_Height)) {
2107 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);
2111 remapicon();
2112 writeicon();
2114 cleanup(0, 0);
2117 /****************************************************************************************/