ppp.device: Remove stale header
[AROS.git] / tools / ilbmtoicon / ilbmtoicon.c
blobd2a9d7a26cf54c64ee73bc39a7b6b01348536ae7
1 /*
2 Copyright © 1995-2011, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Tool to convert IFF ILBM images into Amiga icon file.
7 Lang:
9 */
11 #define D(x)
13 /****************************************************************************************/
15 #include <stdio.h>
16 #include <string.h>
17 #include <stdlib.h>
18 #include <ctype.h>
20 #include <png.h>
22 /****************************************************************************************/
24 #define TRUE ~0
25 #define FALSE 0
27 #define MAKE_ID(a,b,c,d) (((a)<<24) | ((b)<<16) | ((c)<<8) | ((d)))
29 #define ID_FORM MAKE_ID('F','O','R','M')
30 #define ID_ILBM MAKE_ID('I','L','B','M')
31 #define ID_CMAP MAKE_ID('C','M','A','P')
32 #define ID_BODY MAKE_ID('B','O','D','Y')
33 #define ID_BMHD MAKE_ID('B','M','H','D')
35 #define ID_ICON MAKE_ID('I','C','O','N')
36 #define ID_FACE MAKE_ID('F','A','C','E')
37 #define ID_IMAG MAKE_ID('I','M','A','G')
38 #define ID_PNG MAKE_ID('p','n','g',' ')
39 #define ID_ARGB MAKE_ID('A','R','G','B')
41 #define CMP_NONE 0
42 #define CMP_BYTERUN1 1
44 #define MSK_HASMASK 1
45 #define MSK_HASTRANS 2
47 /****************************************************************************************/
49 /* For this tool it does not really matter if the following types
50 have a bigger sizeof() than on Amiga */
52 #ifndef __AROS__
53 typedef void *APTR;
54 typedef unsigned long ULONG;
55 typedef long LONG;
56 typedef unsigned short UWORD;
57 typedef short WORD;
58 typedef short BOOL;
59 typedef unsigned char UBYTE;
60 #else
61 #include <exec/types.h>
62 #endif
64 /****************************************************************************************/
66 struct BitMapHeader
68 UWORD bmh_Width;
69 UWORD bmh_Height;
70 WORD bmh_Left;
71 WORD bmh_Top;
72 UBYTE bmh_Depth;
73 UBYTE bmh_Masking;
74 UBYTE bmh_Compression;
75 UBYTE bmh_Pad;
76 UWORD bmh_Transparent;
77 UBYTE bmh_XAspect;
78 UBYTE bmh_YAspect;
79 WORD bmh_PageWidth;
80 WORD bmh_PageHeight;
83 /****************************************************************************************/
85 struct ILBMImage
87 struct BitMapHeader bmh;
88 struct BitMapHeader planarbmh;
89 unsigned char *planarbuffer, *chunkybuffer;
90 LONG cmapentries, bpr, totdepth;
91 UBYTE rgb[256][3];
92 UBYTE remaptable[256];
93 APTR png;
94 ULONG png_size;
95 APTR argb;
96 ULONG argb_size;
99 /****************************************************************************************/
101 struct Palette
103 UWORD numentries;
104 UBYTE rgb[][3];
107 /****************************************************************************************/
109 struct Palette std4colpal =
113 {0x95, 0x95, 0x95}, /* Gray (and transparent!) */
114 {0x00, 0x00, 0x00}, /* Black */
115 {0xFF, 0xFF, 0xFF}, /* White */
116 {0x3b, 0x67, 0xa2} /* Blue */
120 /****************************************************************************************/
122 struct Palette magicwb8colpal =
126 {0x95, 0x95, 0x95}, /* Gray (and transparent!) */
127 {0x00, 0x00, 0x00}, /* Black */
128 {0xFF, 0xFF, 0xFF}, /* White */
129 {0x3b, 0x67, 0xa2}, /* Blue */
130 {0x7b, 0x7b, 0x7b}, /* Dk. Gray */
131 {0xaf, 0xaf, 0xaf}, /* Lt. Gray */
132 {0xaa, 0x90, 0x7c}, /* Brown */
133 {0xff, 0xa9, 0x97} /* Pink */
137 /****************************************************************************************/
139 struct Palette scalos16colpal =
143 { 0x9c, 0x9c, 0x9c }, /* 0 - Gray */
144 { 0x00, 0x00, 0x00 }, /* 1 - Black */
145 { 0xFF, 0xFF, 0xFF }, /* 2 - White */
146 { 0x3a, 0x3a, 0xd7 }, /* 3 - Blue */
147 { 0x75, 0x75, 0x75 }, /* 4 - Med. Gray */
148 { 0xc4, 0xc4, 0xc4 }, /* 5 - Lt. Gray */
149 { 0xd7, 0xb0, 0x75 }, /* 6 - Peach */
150 { 0xeb, 0x62, 0x9c }, /* 7 - Pink */
151 { 0x13, 0x75, 0x27 }, /* 8 - Dk. Green */
152 { 0x75, 0x3a, 0x00 }, /* 9 - Brown */
153 { 0xff, 0xd7, 0x13 }, /* 10 - Yellow */
154 { 0x3a, 0x3a, 0x3a }, /* 11 - Dk. Gray */
155 { 0xc4, 0x13, 0x27 }, /* 12 - Red */
156 { 0x27, 0xb0, 0x3a }, /* 13 - Lt. Green */
157 { 0x3a, 0x75, 0xff }, /* 14 - Lt. Blue */
158 { 0xd7, 0x75, 0x27 }, /* 15 - Orange */
162 /* Convert from DPI to Amiga 'ticks' resolution */
163 #define TPD_X(x) ((11*1280*100/104/(x)+5)/10)
164 #define TPD_Y(y) ((11*1024*100/78/(y)+5)/10)
166 /****************************************************************************************/
168 static char *filename, *outfilename, *infilename;
169 static unsigned char *filebuffer, *body;
170 static FILE *file, *outfile, *infile;
171 static long filesize, bodysize, bodysize_packed;
172 static long filepos;
173 static struct ILBMImage img1, img2;
174 static BOOL have_bmhd, have_cmap, have_body, is_png;
176 /* 'ticks' per dot, corresponding to ~72dpi */
177 static ULONG tpdX = TPD_X(72), tpdY = TPD_Y(72);
178 static char *image1option;
179 static char *image2option;
180 static char *defaulttooloption;
181 static char *drawerdataoption;
182 static char **tooltypesoption;
183 static LONG typeoption = 3; /* WBTOOL */
184 static LONG iconleftoption = 0x80000000; /* NO_ICON_POSITION */
185 static LONG icontopoption = 0x80000000; /* NO_ICON_POSITION */
186 static LONG stackoption = 4096;
187 static LONG drawerleftoption = 50;
188 static LONG drawertopoption = 50;
189 static LONG drawerwidthoption = 400;
190 static LONG drawerheightoption = 100;
191 static LONG drawervleftoption = 0;
192 static LONG drawervtopoption = 0;
193 static LONG drawershowoption = 0;
194 static LONG drawershowasoption = 0;
195 static LONG transparentoption = -1;
197 static BOOL dualpng; /* png file contains second image */
198 static unsigned char *dualpngstart; /* address of 2nd image in filebuffer */
199 static BOOL nosavePNG; /* Don't save the original PNG data */
200 static BOOL nosaveARGB; /* Don't ARGB data */
201 static BOOL nosaveIFF; /* Don't save any IFF data */
203 /****************************************************************************************/
205 static void freeimage(struct ILBMImage *img)
207 if (img->chunkybuffer)
209 free(img->chunkybuffer);
210 img->chunkybuffer = NULL;
213 if (img->planarbuffer)
215 free(img->planarbuffer);
216 img->planarbuffer = NULL;
219 if (img->argb)
221 free(img->argb);
222 img->argb = NULL;
225 if (filebuffer)
227 free(filebuffer);
228 filebuffer = NULL;
231 if (file)
233 fclose(file);
234 file = NULL;
237 filepos = 0;
240 /****************************************************************************************/
242 static void cleanup(char *msg, int rc)
244 if (msg) fprintf(stderr, "ilbmtoicon: %s\n", msg);
246 freeimage(&img1);
247 freeimage(&img2);
249 if (outfile) fclose(outfile);
250 if (infile) fclose(infile);
252 exit(rc);
255 /****************************************************************************************/
257 static void getarguments(int argc, char **argv)
259 WORD i;
261 nosavePNG = 1;
263 for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
264 if (strcmp(argv[1],"--png") == 0) {
265 nosavePNG = 0;
266 continue;
268 if (strcmp(argv[1],"--no-iff") == 0) {
269 nosaveIFF = 1;
270 continue;
272 if (strcmp(argv[1],"--no-argb") == 0) {
273 nosaveIFF = 1;
274 continue;
276 if (strcmp(argv[1],"--dpi") == 0) {
277 char *cp;
278 long dpiX, dpiY;
279 argc--;
280 argv++;
281 dpiX = strtol(argv[1], &cp, 0);
282 if (*cp == ':') {
283 cp++;
284 dpiY = strtol(cp, NULL, 0);
285 } else {
286 dpiY = dpiX;
288 tpdX = TPD_X(dpiX);
289 tpdY = TPD_Y(dpiY);
290 continue;
295 if ((argc != 4) && (argc != 5))
297 fprintf(stderr, "Wrong number of arguments\n");
298 cleanup("Usage: ilbmtoicon [--png] [--no-argb] [--no-iff] icondescription image1 [image2] filename", 1);
301 if (argc == 4)
303 infilename = argv[1];
304 image1option = argv[2];
305 outfilename = argv[3];
307 else if (argc == 5)
309 infilename = argv[1];
310 image1option = argv[2];
311 image2option = argv[3];
312 outfilename = argv[4];
316 /****************************************************************************************/
318 static char *skipblanks(char *s)
320 while ((*s == ' ') || (*s == '\t')) s++;
322 return s;
325 /****************************************************************************************/
327 static char *skipword(char *s)
329 while((*s != ' ') &&
330 (*s != '\t') &&
331 (*s != '\0') &&
332 (*s != '\n'))
334 s++;
337 return s;
340 /****************************************************************************************/
342 static char *checkquotes(char *s)
344 char *s2;
345 static char s3[256];
346 BOOL escaped = 0;
347 int i = 0;
349 if (*s != '"')
351 s2 = skipword(s);
352 *s2 = '\0';
354 return s;
357 s++;
360 while ((i < 256) && (s3[i] = *s))
362 if (!escaped)
364 if (*s == '\\')
366 escaped = !escaped;
367 i--;
369 else if (*s == '"')
370 break;
372 else
373 escaped = !escaped;
374 i++;
375 s++;
377 s3[i] = '\0';
378 s = s3;
380 return s;
383 /****************************************************************************************/
385 #define KEYWORD_STRING 0
386 #define KEYWORD_INTEGER 1
387 #define KEYWORD_STRINGARRAY 2
388 #define KEYWORD_CYCLE 3
390 #define MAX_ARRAY_SIZE 200
392 /****************************************************************************************/
394 struct cycle
396 char *keyword;
397 LONG value;
400 struct cycle typecycles[] =
402 {"DISK" , 1},
403 {"DRAWER" , 2},
404 {"TOOL" , 3},
405 {"PROJECT" , 4},
406 {"GARBAGE" , 5},
407 {"DEVICE" , 6},
408 {"KICK" , 7},
409 {"APPICON" , 8},
412 struct cycle showcycles[] =
414 {"DEFAULT" , 0},
415 {"ICONS" , 1},
416 {"ALL" , 2},
417 {NULL , 0}
421 struct cycle showascycles[] =
423 {"DEFAULT" , 0},
424 {"ICON" , 1},
425 {"TEXT_NAME", 2},
426 {"TEXT_DATE", 3},
427 {"TEXT_SIZE", 4},
428 {"TEXT_TYPE", 5},
429 {NULL , 0}
434 /****************************************************************************************/
436 struct keyword
438 WORD type;
439 char *keyword;
440 APTR store;
441 APTR extra;
443 keywordtable[] =
445 {KEYWORD_STRING , "DEFAULTTOOL" , &defaulttooloption , NULL },
446 {KEYWORD_STRING , "DRAWERDATA" , &drawerdataoption , NULL },
447 {KEYWORD_CYCLE , "TYPE" , &typeoption , typecycles },
448 {KEYWORD_STRINGARRAY, "TOOLTYPE" , &tooltypesoption , NULL },
449 {KEYWORD_INTEGER , "STACK" , &stackoption , NULL },
450 {KEYWORD_INTEGER , "ICONLEFTPOS" , &iconleftoption , NULL },
451 {KEYWORD_INTEGER , "ICONTOPPOS" , &icontopoption , NULL },
452 {KEYWORD_INTEGER , "DRAWERLEFTPOS" , &drawerleftoption , NULL },
453 {KEYWORD_INTEGER , "DRAWERTOPPOS" , &drawertopoption , NULL },
454 {KEYWORD_INTEGER , "DRAWERWIDTH" , &drawerwidthoption , NULL },
455 {KEYWORD_INTEGER , "DRAWERHEIGHT" , &drawerheightoption , NULL },
456 {KEYWORD_INTEGER , "DRAWERVIEWLEFT" , &drawervleftoption , NULL },
457 {KEYWORD_INTEGER , "DRAWERVIEWTOP" , &drawervtopoption , NULL },
458 {KEYWORD_CYCLE , "DRAWERSHOW" , &drawershowoption , showcycles },
459 {KEYWORD_CYCLE , "DRAWERSHOWAS" , &drawershowoption , showascycles },
460 {KEYWORD_INTEGER , "TRANSPARENT" , &transparentoption , NULL },
461 {0 , NULL , NULL }
465 /****************************************************************************************/
467 static void handleoption(char *keyword, char *keyvalue)
469 struct keyword *kw;
470 struct cycle *cy;
472 D(printf("Keyword %s, value %s\n", keyword, keyvalue));
474 for(kw = keywordtable; kw->keyword; kw++)
476 if (strcasecmp(kw->keyword, keyword) == 0)
478 switch(kw->type)
480 case KEYWORD_STRING:
481 *(char **)kw->store = strdup(keyvalue);
482 if (!(*(char **)kw->store)) cleanup("Out of memory!", 1);
483 break;
485 case KEYWORD_INTEGER:
486 *(LONG *)kw->store = strtol(keyvalue, 0, 0);
487 break;
489 case KEYWORD_CYCLE:
490 for(cy = (struct cycle *)kw->extra; cy->keyword; cy++)
492 if (strcasecmp(keyvalue, cy->keyword) == 0)
494 *(LONG *)kw->store = cy->value;
495 break;
498 break;
500 case KEYWORD_STRINGARRAY:
501 if (!(*(char ***)kw->store))
503 *(char ***)kw->store = (char **)malloc(MAX_ARRAY_SIZE * sizeof(char *));
504 if (!(*(char ***)kw->store)) cleanup("Out of memory!", 1);
506 memset(*(char ***)kw->store, 0, MAX_ARRAY_SIZE * sizeof(char *));
510 char *dupvalue;
511 char **strarray = *(char ***)kw->store;
512 WORD i = 0;
514 dupvalue = strdup(keyvalue);
515 if (!dupvalue) cleanup("Out of memory!", 1);
517 while(*strarray)
519 strarray++;
520 i++;
523 if (i >= MAX_ARRAY_SIZE - 1) cleanup("Array overflow!", 1);
525 *strarray = dupvalue;
528 } /* switch(kw->type) */
530 break;
532 } /* if (strcasecmp(kw->keyword, keyword) == 0) */
534 } /* for(kw = keywordtable; kw->keyword; kw++) */
538 /****************************************************************************************/
540 static void parseline(char *s)
542 char *keyword;
543 char *keyvalue = NULL;
545 s = skipblanks(s);
547 if (*s == '#') return;
548 if (*s == ';') return;
550 keyword = s;
552 s = skipword(s);
553 if (*s == '\0') return;
555 *s = '\0';
556 s = skipblanks(s + 1);
558 if (*s == '=') s = skipblanks(s + 1);
559 if (*s == '\0') return;
561 keyvalue = checkquotes(s);
563 handleoption(keyword, keyvalue);
566 /****************************************************************************************/
568 static void parseiconsource(void)
570 char s[256];
572 infile = fopen(infilename, "r");
573 if (infile)
575 while(fgets(s, sizeof(s), infile))
577 D(printf("Read line: %s\n", s));
578 parseline(s);
581 fclose(infile);
582 infile = 0;
586 /****************************************************************************************/
588 static void showoptions(void)
590 char **strarray;
592 printf("image1: %s\n", image1option ? image1option : "(NULL)");
593 printf("image2: %s\n", image2option ? image2option : "(NULL)");
594 printf("type: %ld\n", typeoption);
596 strarray = tooltypesoption;
597 if (strarray)
599 printf("tooltypes:\n");
600 while(*strarray)
602 printf(" %s\n", *strarray++);
607 /****************************************************************************************/
609 static ULONG getlong(void)
611 ULONG ret;
613 if (filepos > filesize - 4) cleanup("Tried to read over file end!", 1);
615 ret = filebuffer[filepos++] * 0x1000000;
616 ret += filebuffer[filepos++] * 0x10000;
617 ret += filebuffer[filepos++] * 0x100;
618 ret += filebuffer[filepos++];
620 return ret;
623 /****************************************************************************************/
625 static UWORD getword(void)
627 UWORD ret;
629 if (filepos > filesize - 2) cleanup("Tried to read over file end!", 1);
631 ret = filebuffer[filepos++] * 0x100;
632 ret += filebuffer[filepos++];
634 return ret;
637 /****************************************************************************************/
639 static UBYTE getbyte(void)
641 ULONG ret;
643 if (filepos > filesize - 1) cleanup("Tried to read over file end!", 1);
644 ret = filebuffer[filepos++];
646 return ret;
649 /****************************************************************************************/
651 static void skipbytes(ULONG howmany)
653 filepos += howmany;
656 /****************************************************************************************/
658 static void openimage(struct ILBMImage *img)
660 file = fopen(filename, "rb");
661 if (!file) cleanup("Can't open file!", 1);
663 fseek(file, 0, SEEK_END);
664 filesize = ftell(file);
666 if (filesize < 12) cleanup("Bad file size!", 1);
668 //fprintf(stderr, "Filesize is %d\n", filesize);
670 fseek(file, 0, SEEK_SET);
672 filebuffer = malloc(filesize + 10);
673 if (!filebuffer) cleanup("Memory allocation for file buffer failed!", 1);
675 if (fread(filebuffer, 1, filesize, file) != filesize)
676 cleanup("Error reading file!", 1);
678 fclose(file); file = NULL;
681 /****************************************************************************************/
683 static void checkimage(struct ILBMImage *img)
685 static UBYTE pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
687 ULONG id;
688 ULONG size;
690 if (dualpng) {
691 img->png = dualpngstart;
692 img->png_size = filesize - (dualpngstart - filebuffer);
693 return;
696 if (memcmp(filebuffer, pngsig, 8) == 0)
698 is_png = 1;
699 img->png = filebuffer;
701 /* search for second image */
704 dualpngstart = filebuffer + 8 ;
705 dualpngstart < filebuffer + filesize - 8 ;
706 dualpngstart++
709 if (memcmp(dualpngstart, pngsig, 8) == 0)
711 dualpng = 1;
712 break;
715 if (dualpng)
716 img->png_size = dualpngstart - filebuffer;
717 else
718 img->png_size = filesize;
720 else if (is_png == 0)
722 id = getlong();
723 if (id != ID_FORM) cleanup("File is not an IFF file!", 1);
725 size = getlong();
726 if (size != filesize - 8) cleanup("File is IFF, but has bad size in IFF header!", 1);
728 id = getlong();
729 if (id != ID_ILBM) cleanup("File is IFF, but not of type ILBM!", 1);
731 else if (is_png == 1)
733 cleanup("Second image must be a PNG image, too!", 1);
738 /****************************************************************************************/
740 static void my_read_fn(png_structp png_ptr, png_bytep data, png_size_t length)
742 png_bytep *pdata = png_get_io_ptr(png_ptr);
744 if (*pdata-filebuffer >= filesize)
745 png_error(png_ptr, "Read past end of file");
747 memcpy(data, *pdata, length);
748 *pdata += length;
751 static UBYTE findcolor(struct Palette *pal, ULONG r, ULONG g, ULONG b, BOOL notrans);
753 static void loadpng(struct ILBMImage *img, struct Palette *pal)
755 png_structp png_ptr;
756 png_infop info_ptr, end_info;
757 png_bytep fpos, *row_pointers;
758 UBYTE *chunkrow;
759 UWORD width, height;
760 int x, y;
762 if (png_sig_cmp(img->png, 0, img->png_size) != 0)
763 cleanup("I thought it was a PNG, but I was wrong.", 1);
765 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
766 0, /* error ptr */
769 if (!png_ptr)
770 cleanup("png_create_read_struct() failed", 1);
772 info_ptr = png_create_info_struct(png_ptr);
773 if (!info_ptr) {
774 png_destroy_read_struct(&png_ptr, NULL, NULL);
775 cleanup("png_create_info_struct() failed", 1);
778 end_info = png_create_info_struct(png_ptr);
779 if (!end_info) {
780 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
781 cleanup("png_create_info_struct() failed", 1);
784 fpos = img->png;
785 png_set_read_fn(png_ptr, &fpos, my_read_fn);
787 if (setjmp(png_jmpbuf(png_ptr))) {
788 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
789 cleanup("png read failed", 1);
792 /* Read the PNG as RGBA */
793 png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
794 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_STRIP_16, NULL);
796 row_pointers = png_get_rows(png_ptr, info_ptr);
798 width = png_get_image_width(png_ptr, info_ptr);
799 height = png_get_image_height(png_ptr, info_ptr);
801 img->bmh.bmh_Width = width;
802 img->bmh.bmh_Height = height;
803 img->bmh.bmh_Left = 0;
804 img->bmh.bmh_Top = 0;
805 img->bmh.bmh_Depth = 8;
806 img->bmh.bmh_Masking = MSK_HASTRANS;
807 img->bmh.bmh_Compression = CMP_NONE;
808 img->bmh.bmh_Pad = 0;
809 img->bmh.bmh_XAspect = 1;
810 img->bmh.bmh_YAspect = 1;
811 img->bmh.bmh_PageWidth = 320;
812 img->bmh.bmh_PageHeight = 200;
814 img->planarbmh;
815 img->bpr = ((img->bmh.bmh_Width + 15) & ~15) / 8;
816 img->totdepth = 0;
818 /* Transform the RGBA data into chunky */
819 img->cmapentries = pal->numentries;
820 memcpy(img->rgb, pal->rgb, sizeof(img->rgb[0])*pal->numentries);
822 img->chunkybuffer = malloc(width * height * sizeof(UBYTE));
823 if (!img->chunkybuffer)
824 cleanup("Can't allocate the chunky buffer", 1);
826 chunkrow = img->chunkybuffer;
827 img->argb_size = width * height * sizeof(UBYTE) * 4;
828 img->argb = malloc(img->argb_size);
829 if (!img->argb)
830 cleanup("Can't allocate the ARGB buffer", 1);
832 for (y = 0; y < height; y++) {
833 png_bytep row = row_pointers[y];
834 UBYTE *ap = img->argb + (width * sizeof(UBYTE) * 4) * y;
835 for (x = 0; x < width; x++, row += 4, ap += 4, chunkrow++) {
836 UBYTE r,g,b;
838 ap[0] = row[3];
839 ap[1] = row[0];
840 ap[2] = row[1];
841 ap[3] = row[2];
843 /* Opacity of 0? Use the transparency color */
844 if (row[3] == 0) {
845 if (transparentoption < 0)
846 transparentoption = 0;
847 *chunkrow = transparentoption;
848 } else {
849 r = row[0];
850 g = row[1];
851 b = row[2];
853 *chunkrow = findcolor(pal, r, g, b, TRUE);
858 img->bmh.bmh_Transparent = transparentoption;
860 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
864 /****************************************************************************************/
866 static void scanimage(struct ILBMImage *img)
868 WORD i;
870 have_bmhd = 0;
871 have_cmap = 0;
872 have_body = 0;
874 if (img->png) {
875 /* Load the PNG, using the Scalos 16-color pallette,
876 * into the Chunky buffer.
878 loadpng(img, &scalos16colpal);
879 return;
882 for(;;)
884 ULONG id;
885 ULONG size;
887 id = getlong();
888 size = getlong();
890 //fprintf(stderr, "Chunk: %c%c%c%c Size: %d\n", id >> 24, id >> 16, id >> 8, id, size);
892 switch(id)
894 case ID_BMHD:
895 if (size != 20) cleanup("Bad BMHD chunk size!", 1);
897 img->bmh.bmh_Width = getword();
898 img->bmh.bmh_Height = getword();
899 img->bmh.bmh_Left = (WORD)getword();
900 img->bmh.bmh_Top = (WORD)getword();
901 img->bmh.bmh_Depth = getbyte();
902 img->bmh.bmh_Masking = getbyte();
903 img->bmh.bmh_Compression = getbyte();
904 img->bmh.bmh_Pad = getbyte();
905 img->bmh.bmh_Transparent = getword();
906 img->bmh.bmh_XAspect = getbyte();
907 img->bmh.bmh_YAspect = getbyte();
908 img->bmh.bmh_PageWidth = (WORD)getword();
909 img->bmh.bmh_PageHeight = (WORD)getword();
911 if (img->bmh.bmh_Depth > 8) cleanup("ILBM file has too many colors!", 1);
912 if ((img->bmh.bmh_Compression != CMP_NONE) && (img->bmh.bmh_Compression != CMP_BYTERUN1)) cleanup("Compression method unsupported!", 1);
914 have_bmhd = 1;
916 img->totdepth = img->bmh.bmh_Depth + ((img->bmh.bmh_Masking == MSK_HASMASK) ? 1 : 0);
918 img->bpr = ((img->bmh.bmh_Width + 15) & ~15) / 8;
920 /*fprintf(stderr, "BMHD: %d x %d x %d (%d)\n", img->bmh.bmh_Width,
921 img->bmh.bmh_Height,
922 img->bmh.bmh_Depth,
923 img->totdepth);*/
924 img->planarbmh = img->bmh;
925 break;
927 case ID_CMAP:
928 if (!have_bmhd) cleanup("CMAP chunk before BMHD chunk (or no BMHD chunk at all!", 1);
930 img->cmapentries = size / 3;
931 if (size & 1) size++;
933 if ((img->cmapentries < 2) || (img->cmapentries > 256)) cleanup("CMAP chunk has bad number of entries!", 1);
935 for(i = 0; i < img->cmapentries; i++)
937 img->rgb[i][0] = getbyte();
938 img->rgb[i][1] = getbyte();
939 img->rgb[i][2] = getbyte();
940 size -= 3;
943 skipbytes(size);
945 have_cmap = 1;
947 break;
949 case ID_BODY:
950 if (!have_bmhd) cleanup("BODY chunk before BMHD chunk (or no BMHD chunk at all!", 1);
951 body = &filebuffer[filepos];
952 bodysize = size;
954 if (img->bmh.bmh_Compression == CMP_NONE)
956 LONG shouldbesize = img->totdepth * img->bpr * img->bmh.bmh_Height;
957 if (bodysize != shouldbesize) cleanup("BODY chunk size seems to be wrong!", 1);
960 have_body = 1;
961 /* Fall through */
963 default:
964 if (size & 1) size++;
965 skipbytes(size);
966 break;
969 if (filepos == filesize) break;
970 if (have_bmhd && have_body && have_cmap) break;
973 if (!have_bmhd) cleanup("BMHD chunk missing!", 1);
974 if (!have_body) cleanup("BODY chunk missing!", 1);
977 /****************************************************************************************/
979 static unsigned char *unpack_byterun1(unsigned char *source, unsigned char *dest, LONG unpackedsize)
981 unsigned char r;
982 signed char c;
984 for(;;)
986 c = (signed char)(*source++);
987 if (c >= 0)
989 while(c-- >= 0)
991 *dest++ = *source++;
992 if (--unpackedsize <= 0) return source;
995 else if (c != -128)
997 c = -c;
998 r = *source++;
1000 while(c-- >= 0)
1002 *dest++ = r;
1003 if (--unpackedsize <= 0) return source;
1010 /****************************************************************************************/
1012 static BOOL norm1(LONG count, unsigned char **source_backup,
1013 unsigned char **dest, LONG *checksize)
1015 //if (count >= 0) fprintf(stderr, "XX: non packable %d\n",count);
1017 while(count >= 0)
1019 LONG step = count;
1021 if (step > 127) step = 127;
1023 *checksize -= step;
1024 *checksize -= 2;
1026 if (*checksize <= 0) return 0;
1028 count -= step;
1030 *(*dest)++ = step;
1033 while(step-- >= 0)
1035 *(*dest)++ = *(*source_backup)++;
1038 count--;
1042 return 1;
1045 static BOOL copy1(unsigned char r, LONG count, unsigned char **dest, LONG *checksize)
1047 //if (count >= 1) fprintf(stderr, "XX: repeat %02x x %d\n", r, count);
1049 while(--count >= 0)
1051 LONG step = count;
1053 if (step > 127) step = 127;
1055 count -= step;
1056 step = -step;
1057 *checksize -= 2;
1058 if (*checksize <= 0) return 0;
1060 *(*dest)++ = (unsigned char)step;
1061 *(*dest)++ = r;
1064 return 1;
1067 static BOOL pack_byterun1(unsigned char *source, unsigned char *dest,
1068 LONG size, LONG check_size, LONG *packsize)
1070 unsigned char *source_backup, *dest_backup;
1071 LONG samebytes_counter, samebytes, count;
1072 LONG checksize = check_size;
1073 unsigned char oldbyte, actbyte;
1075 if (checksize < 0) checksize = 0x7FFFFFFF;
1077 oldbyte = *source;
1078 samebytes_counter = 0;
1079 source_backup = source;
1080 dest_backup = dest;
1082 for(;;)
1084 //fprintf(stderr, "size = %d. checksize = %d\n", size, checksize);
1085 if (--size < 0) break;
1086 actbyte = *source++;
1087 if (actbyte == oldbyte)
1089 samebytes_counter++;
1090 continue;
1093 oldbyte = actbyte;
1095 samebytes = samebytes_counter;
1096 samebytes_counter = 1;
1098 if (samebytes < 3) continue;
1100 count = (LONG)(source - source_backup - samebytes - 2);
1101 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1103 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
1105 source_backup = source - 1;
1107 //fprintf(stderr, "done\n");
1109 if (samebytes_counter >= 3)
1111 samebytes = samebytes_counter;
1112 count = (LONG)(source - source_backup - samebytes - 1);
1113 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1114 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
1116 else
1118 count = (LONG)(source - source_backup - 1);
1119 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1121 //fprintf(stderr, "realdone\n");
1123 if (packsize) *packsize = (LONG)(dest - dest_backup);
1125 return 1;
1128 /****************************************************************************************/
1130 static void p2c(unsigned char *source, unsigned char *dest, LONG width, LONG height,
1131 LONG totplanes, LONG wantplanes, LONG chunkybpr)
1133 LONG alignedwidth, x, y, p, bpr, bpl;
1135 alignedwidth = (width + 15) & ~15;
1136 bpr = alignedwidth / 8;
1137 bpl = bpr * totplanes;
1139 for(y = 0; y < height; y++)
1141 for(x = 0; x < width; x++)
1143 LONG mask = 0x80 >> (x & 7);
1144 LONG offset = x / 8;
1145 unsigned char chunkypix = 0;
1147 for(p = 0; p < wantplanes; p++)
1149 if (source[p * bpr + offset] & mask) chunkypix |= (1 << p);
1151 dest[x] = chunkypix;
1154 source += bpl;
1155 dest += chunkybpr;
1161 /****************************************************************************************/
1163 static void c2p(unsigned char *source, unsigned char *dest, LONG width, LONG height, LONG planes)
1165 LONG alignedwidth, x, y, p, bpr, bpl;
1167 alignedwidth = (width + 15) & ~15;
1168 bpr = alignedwidth / 8;
1169 bpl = bpr * planes;
1171 for(y = 0; y < height; y++)
1173 for(x = 0; x < width; x++)
1175 LONG mask = 0x80 >> (x & 7);
1176 LONG offset = x / 8;
1177 unsigned char chunkypix = source[x];
1179 for(p = 0; p < planes; p++)
1181 if (chunkypix & (1 << p))
1182 dest[p * bpr + offset] |= mask;
1183 else
1184 dest[p * bpr + offset] &= ~mask;
1188 source += width;
1189 dest += bpl;
1194 /****************************************************************************************/
1196 static void convertbody(struct ILBMImage *img)
1198 LONG unpackedsize = img->bpr * img->bmh.bmh_Height * img->totdepth;
1200 if (is_png)
1201 return;
1203 img->planarbuffer = malloc(unpackedsize);
1204 if (!img->planarbuffer) cleanup("Memory allocation for planar buffer failed!", 1);
1206 if (img->bmh.bmh_Compression == CMP_NONE)
1208 memcpy(img->planarbuffer, body, unpackedsize);
1210 else
1212 unpack_byterun1(body, img->planarbuffer, unpackedsize);
1215 img->chunkybuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
1216 if (!img->chunkybuffer) cleanup("Memory allocation for chunky buffer failed!", 1);
1218 p2c(img->planarbuffer,
1219 img->chunkybuffer,
1220 img->bmh.bmh_Width,
1221 img->bmh.bmh_Height,
1222 img->totdepth,
1223 img->bmh.bmh_Depth,
1224 img->bmh.bmh_Width);
1227 /****************************************************************************************/
1229 static UBYTE findcolor(struct Palette *pal, ULONG r, ULONG g, ULONG b, BOOL notrans)
1231 ULONG dist, bestdist = 0xFFFFFFFF;
1232 UBYTE i, besti = 0;
1234 for(i = 0; i < pal->numentries; i++)
1236 LONG r1, g1, b1, r2, g2, b2, dr, dg, db;
1238 if (notrans && i == transparentoption)
1239 continue;
1241 r1 = (LONG)r;
1242 g1 = (LONG)g;
1243 b1 = (LONG)b;
1245 r2 = (LONG)pal->rgb[i][0];
1246 g2 = (LONG)pal->rgb[i][1];
1247 b2 = (LONG)pal->rgb[i][2];
1249 dr = r1 - r2;
1250 dg = g1 - g2;
1251 db = b1 - b2;
1253 dist = (dr * dr) + (dg * dg) + (db * db);
1254 if (dist < bestdist)
1256 bestdist = dist;
1257 besti = i;
1262 return besti;
1265 /****************************************************************************************/
1267 static void remapplanar(struct ILBMImage *img, struct Palette *pal)
1269 UBYTE *remapbuffer;
1270 LONG i, x, y, highestcol = 0, newdepth = 0;
1272 remapbuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
1273 if (!remapbuffer) cleanup("Error allocating remap buffer!", 1);
1275 for(i = 0; i < img->cmapentries; i++)
1277 img->remaptable[i] = findcolor(pal, img->rgb[i][0], img->rgb[i][1], img->rgb[i][2], FALSE);
1280 for(i = 0; i < img->bmh.bmh_Width * img->bmh.bmh_Height; i++)
1282 remapbuffer[i] = img->remaptable[img->chunkybuffer[i]];
1284 if (remapbuffer[i] > highestcol)
1285 highestcol = remapbuffer[i];
1288 for(i = highestcol; i; i >>= 1) newdepth++;
1289 if (newdepth == 0) newdepth = 1;
1291 if (newdepth > img->totdepth)
1293 if (img->planarbuffer)
1294 free(img->planarbuffer);
1296 img->planarbuffer = malloc(img->bpr * img->bmh.bmh_Height * newdepth);
1297 if (!img->planarbuffer)
1299 free(remapbuffer);
1300 cleanup("Error re-allocating planar buffer!", 1);
1304 img->planarbmh.bmh_Width = img->bmh.bmh_Width;
1305 img->planarbmh.bmh_Height= img->bmh.bmh_Height;
1306 img->planarbmh.bmh_Depth = newdepth;
1308 memset(img->planarbuffer, 0, img->bpr * img->bmh.bmh_Height * newdepth);
1310 c2p(remapbuffer, img->planarbuffer, img->bmh.bmh_Width, img->bmh.bmh_Height, newdepth);
1312 free(remapbuffer);
1315 /****************************************************************************************/
1317 static void loadimage(char *name, struct ILBMImage *img)
1319 freeimage(img);
1321 filename = name;
1323 openimage(img);
1324 checkimage(img);
1325 scanimage(img);
1326 convertbody(img);
1329 /****************************************************************************************/
1331 struct diskobject
1333 UBYTE do_magic[2];
1334 UBYTE do_version[2];
1335 UBYTE do_gadget_nextgadget[4];
1336 UBYTE do_gadget_leftedge[2];
1337 UBYTE do_gadget_topedge[2];
1338 UBYTE do_gadget_width[2];
1339 UBYTE do_gadget_height[2];
1340 UBYTE do_gadget_flags[2];
1341 UBYTE do_gadget_activation[2];
1342 UBYTE do_gadget_gadgettype[2];
1343 UBYTE do_gadget_gadgetrender[4];
1344 UBYTE do_gadget_selectrender[4];
1345 UBYTE do_gadget_gadgettext[4];
1346 UBYTE do_gadget_mutualexclude[4];
1347 UBYTE do_gadget_specialinfo[4];
1348 UBYTE do_gadget_gadgetid[2];
1349 UBYTE do_gadget_userdata[4];
1350 UBYTE do_type;
1351 UBYTE do_pad;
1352 UBYTE do_defaulttool[4];
1353 UBYTE do_tooltypes[4];
1354 UBYTE do_currentx[4];
1355 UBYTE do_currenty[4];
1356 UBYTE do_drawerdata[4];
1357 UBYTE do_toolwindow[4];
1358 UBYTE do_stacksize[4];
1361 /****************************************************************************************/
1363 struct olddrawerdata
1365 UBYTE dd_newwindow_leftedge[2];
1366 UBYTE dd_newwindow_topedge[2];
1367 UBYTE dd_newwindow_width[2];
1368 UBYTE dd_newwindow_height[2];
1369 UBYTE dd_newwindow_detailpen;
1370 UBYTE dd_newwindow_blockpen;
1371 UBYTE dd_newwindow_idcmpflags[4];
1372 UBYTE dd_newwindow_flags[4];
1373 UBYTE dd_newwindow_firstgadget[4];
1374 UBYTE dd_newwindow_checkmark[4];
1375 UBYTE dd_newwindow_title[4];
1376 UBYTE dd_newwindow_screen[4];
1377 UBYTE dd_newwindow_bitmap[4];
1378 UBYTE dd_newwindow_minwidth[2];
1379 UBYTE dd_newwindow_minheight[2];
1380 UBYTE dd_newwindow_maxwidth[2];
1381 UBYTE dd_newwindow_maxheight[2];
1382 UBYTE dd_newwindow_type[2];
1383 UBYTE dd_currentx[4];
1384 UBYTE dd_currenty[4];
1387 /****************************************************************************************/
1389 struct newdrawerdata
1391 UBYTE dd_flags[4];
1392 UBYTE dd_viewmodes[2];
1395 /****************************************************************************************/
1397 struct image
1399 UBYTE leftedge[2];
1400 UBYTE topedge[2];
1401 UBYTE width[2];
1402 UBYTE height[2];
1403 UBYTE depth[2];
1404 UBYTE imagedata[4];
1405 UBYTE planepick;
1406 UBYTE planeonoff;
1407 UBYTE nextimage[4];
1410 /****************************************************************************************/
1412 #define SET_BYTE(field,value) \
1413 ACT_STRUCT.field = value
1415 #define SET_WORD(field, value) \
1416 ACT_STRUCT.field[0] = ((value) >> 8) & 0xFF; \
1417 ACT_STRUCT.field[1] = (value) & 0xFF;
1419 #define SET_LONG(field,value) \
1420 ACT_STRUCT.field[0] = ((value) >> 24) & 0xFF; \
1421 ACT_STRUCT.field[1] = ((value) >> 16) & 0xFF; \
1422 ACT_STRUCT.field[2] = ((value) >> 8) & 0xFF; \
1423 ACT_STRUCT.field[3] = (value) & 0xFF;
1425 #define BOOL_YES 0x2A2A2A2A
1426 #define BOOL_NO 0x00000000
1428 static void writediskobject(void)
1430 struct diskobject dobj;
1432 if (typeoption == 2) /* DRAWER */
1434 drawerdataoption = "YES";
1437 #define ACT_STRUCT dobj
1439 SET_WORD(do_magic, 0xE310);
1440 SET_WORD(do_version, 1);
1441 SET_LONG(do_gadget_nextgadget, 0);
1442 SET_WORD(do_gadget_leftedge, 0);
1443 SET_WORD(do_gadget_topedge, 0);
1444 SET_WORD(do_gadget_width, img1.bmh.bmh_Width);
1445 SET_WORD(do_gadget_height, img1.bmh.bmh_Height);
1447 if (image2option)
1449 /* GFLG_GADGHIMAGE + GFLG_GADGIMAGE */
1450 SET_WORD(do_gadget_flags, 4 + 2);
1452 else
1454 /* GFLG_GADGIMAGE */
1455 SET_WORD(do_gadget_flags, 4);
1458 SET_WORD(do_gadget_activation, 1);
1459 SET_WORD(do_gadget_gadgettype, 1);
1460 SET_LONG(do_gadget_gadgetrender, BOOL_YES);
1462 if (image2option)
1464 SET_LONG(do_gadget_selectrender, BOOL_YES);
1466 else
1468 SET_LONG(do_gadget_selectrender, BOOL_NO);
1471 SET_LONG(do_gadget_gadgettext, 0);
1472 SET_LONG(do_gadget_mutualexclude, (1 << 31) | (tpdX << 8) | (tpdY << 0));
1473 SET_LONG(do_gadget_specialinfo, 0);
1474 SET_WORD(do_gadget_gadgetid, 0);
1475 SET_LONG(do_gadget_userdata, 1); /* full drawer data */
1477 SET_BYTE(do_type, typeoption);
1478 SET_BYTE(do_pad, 0);
1480 if (defaulttooloption)
1482 SET_LONG(do_defaulttool, BOOL_YES);
1484 else
1486 SET_LONG(do_defaulttool, BOOL_NO);
1489 if (tooltypesoption)
1491 SET_LONG(do_tooltypes, BOOL_YES);
1493 else
1495 SET_LONG(do_tooltypes, BOOL_NO);
1498 SET_LONG(do_currentx, iconleftoption);
1499 SET_LONG(do_currenty, icontopoption);
1501 if (drawerdataoption)
1503 SET_LONG(do_drawerdata, BOOL_YES);
1505 else
1507 SET_LONG(do_drawerdata, BOOL_NO);
1511 SET_LONG(do_toolwindow, 0);
1512 SET_LONG(do_stacksize, stackoption);
1514 if (fwrite(&dobj, 1, sizeof(dobj), outfile) != sizeof(dobj))
1516 cleanup("Error writing diskobject structure to outfile!", 1);
1520 /****************************************************************************************/
1522 static void writeolddrawerdata(void)
1524 struct olddrawerdata dd;
1526 if (!drawerdataoption) return;
1528 #undef ACT_STRUCT
1529 #define ACT_STRUCT dd
1531 SET_WORD(dd_newwindow_leftedge, drawerleftoption);
1532 SET_WORD(dd_newwindow_topedge, drawertopoption);
1533 SET_WORD(dd_newwindow_width, drawerwidthoption);
1534 SET_WORD(dd_newwindow_height, drawerheightoption);
1535 SET_BYTE(dd_newwindow_detailpen, 255);
1536 SET_BYTE(dd_newwindow_blockpen, 255);
1537 SET_LONG(dd_newwindow_idcmpflags, 0);
1538 SET_LONG(dd_newwindow_flags, 0x240027f);
1539 SET_LONG(dd_newwindow_firstgadget, 0);
1540 SET_LONG(dd_newwindow_checkmark, 0);
1541 SET_LONG(dd_newwindow_title, 0);
1542 SET_LONG(dd_newwindow_screen, 0);
1543 SET_LONG(dd_newwindow_bitmap, 0);
1544 SET_WORD(dd_newwindow_minwidth, 90);
1545 SET_WORD(dd_newwindow_minheight, 40);
1546 SET_WORD(dd_newwindow_maxwidth, 65535);
1547 SET_WORD(dd_newwindow_maxheight, 65535);
1548 SET_WORD(dd_newwindow_type, 1);
1549 SET_LONG(dd_currentx, drawervleftoption);
1550 SET_LONG(dd_currenty, drawervtopoption);
1552 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1554 cleanup("Error writing olddrawerdata structure to outfile!", 1);
1560 /****************************************************************************************/
1562 static void writenewdrawerdata(void)
1564 struct newdrawerdata dd;
1566 if (!drawerdataoption) return;
1568 #undef ACT_STRUCT
1569 #define ACT_STRUCT dd
1571 SET_LONG(dd_flags, drawershowoption);
1572 SET_WORD(dd_viewmodes, drawershowasoption);
1574 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1576 cleanup("Error writing newdrawerdata structure to outfile!", 1);
1581 /****************************************************************************************/
1583 static void writeword(WORD l)
1585 UBYTE f[2];
1587 f[1] = (l >> 8) & 0xFF;
1588 f[2] = l & 0xFF;
1590 if (fwrite(f, 1, 2, outfile) != 2)
1592 cleanup("Error writing word value!", 1);
1597 /****************************************************************************************/
1599 static void writelong(LONG l)
1601 UBYTE f[4];
1603 f[0] = (l >> 24) & 0xFF;
1604 f[1] = (l >> 16) & 0xFF;
1605 f[2] = (l >> 8) & 0xFF;
1606 f[3] = l & 0xFF;
1608 if (fwrite(f, 1, 4, outfile) != 4)
1610 cleanup("Error writing long value!", 1);
1615 /****************************************************************************************/
1617 static void writenormalstring(char *s)
1619 int len = strlen(s) + 1;
1621 if (fwrite(s, 1, len, outfile) != len)
1623 cleanup("Error writing string!", 1);
1628 /****************************************************************************************/
1630 static void writestring(char *s)
1632 int len = strlen(s) + 1;
1634 D(printf("String: \"%s\", length %d\n", s, len));
1636 writelong(len);
1638 if (fwrite(s, 1, len, outfile) != len)
1640 cleanup("Error writing string!", 1);
1645 /****************************************************************************************/
1647 static void writeimage(struct ILBMImage *img)
1649 struct image i;
1650 LONG d, y;
1652 #undef ACT_STRUCT
1653 #define ACT_STRUCT i
1655 SET_WORD(leftedge, 0);
1656 SET_WORD(topedge, 0);
1657 SET_WORD(width, img->planarbmh.bmh_Width);
1658 SET_WORD(height, img->planarbmh.bmh_Height);
1659 SET_WORD(depth, img->planarbmh.bmh_Depth);
1660 SET_LONG(imagedata, BOOL_YES);
1661 SET_BYTE(planepick, (1 << img->planarbmh.bmh_Depth) - 1);
1662 SET_BYTE(planeonoff, 0);
1663 SET_LONG(nextimage, 0);
1665 if (fwrite(&i, 1, sizeof(i), outfile) != sizeof(i))
1667 cleanup("Error writing image structure to outfile!", 1);
1670 for(d = 0; d < img->planarbmh.bmh_Depth; d++)
1672 UBYTE *dat = img->planarbuffer + img->bpr * d;
1674 for(y = 0; y < img->planarbmh.bmh_Height; y++)
1676 if(fwrite(dat, 1, img->bpr, outfile) != img->bpr)
1678 cleanup("Error writing image data to outfile!", 1);
1680 dat += (img->planarbmh.bmh_Depth * img->bpr);
1686 /****************************************************************************************/
1688 struct facechunk
1690 UBYTE fc_width;
1691 UBYTE fc_height;
1692 UBYTE fc_flags;
1693 UBYTE fc_aspect;
1694 UBYTE fc_maxpalettebytes[2];
1697 /****************************************************************************************/
1699 struct imagchunk
1701 UBYTE ic_transparentcolour;
1702 UBYTE ic_numcolours;
1703 UBYTE ic_flags;
1704 UBYTE ic_imageformat;
1705 UBYTE ic_paletteformat;
1706 UBYTE ic_depth;
1707 UBYTE ic_numimagebytes[2];
1708 UBYTE ic_numpalettebytes[2];
1711 /****************************************************************************************/
1713 static LONG writefacechunk(void)
1715 struct facechunk fc;
1716 LONG palbytes;
1718 #undef ACT_STRUCT
1719 #define ACT_STRUCT fc
1721 writelong(ID_FACE);
1722 writelong(sizeof(struct facechunk));
1724 SET_BYTE(fc_width, img1.bmh.bmh_Width - 1);
1725 SET_BYTE(fc_height, img1.bmh.bmh_Height - 1);
1726 SET_BYTE(fc_flags, 0);
1727 SET_BYTE(fc_aspect, 0); // 0x11);
1729 palbytes = (img1.cmapentries > img2.cmapentries) ? img1.cmapentries : img2.cmapentries;
1730 palbytes = palbytes * 3;
1732 SET_WORD(fc_maxpalettebytes, palbytes - 1);
1734 if (fwrite(&fc, 1, sizeof(fc), outfile) != sizeof(fc))
1736 cleanup("Error writing face chunk!", 1);
1739 return sizeof(struct facechunk) + 8;
1742 /****************************************************************************************/
1744 /* createrle() based on ModifyIcon source by Dirk Stöcker */
1746 /****************************************************************************************/
1748 static char * createrle(unsigned long depth, unsigned char *dtype, LONG *dsize, unsigned long size,
1749 unsigned char *src)
1751 int i, j, k;
1752 unsigned long bitbuf, numbits;
1753 unsigned char *buf;
1754 long ressize, numcopy, numequal;
1756 buf = malloc(size * 2);
1757 if (!buf) return NULL;
1759 numcopy = 0;
1760 numequal = 1;
1761 bitbuf = 0;
1762 numbits = 0;
1763 ressize = 0;
1764 k = 0; /* the really output pointer */
1765 for(i = 1; numequal || numcopy;)
1767 if(i < size && numequal && (src[i-1] == src[i]))
1769 ++numequal; ++i;
1771 else if(i < size && numequal*depth <= 16)
1773 numcopy += numequal; numequal = 1; ++i;
1775 else
1777 /* care for end case, where it maybe better to join the two */
1778 if(i == size && numcopy + numequal <= 128 && (numequal-1)*depth <= 8)
1780 numcopy += numequal; numequal = 0;
1782 if(numcopy)
1784 if((j = numcopy) > 128) j = 128;
1785 bitbuf = (bitbuf<<8) | (j-1);
1786 numcopy -= j;
1788 else
1790 if((j = numequal) > 128) j = 128;
1791 bitbuf = (bitbuf<<8) | (256-(j-1));
1792 numequal -= j;
1793 k += j-1;
1794 j = 1;
1796 buf[ressize++] = (bitbuf >> numbits);
1797 while(j--)
1799 numbits += depth;
1800 bitbuf = (bitbuf<<depth) | src[k++];
1801 if(numbits >= 8)
1803 numbits -= 8;
1804 buf[ressize++] = (bitbuf >> numbits);
1807 if(i < size && !numcopy && !numequal)
1809 numequal = 1; ++i;
1813 if(numbits)
1814 buf[ressize++] = bitbuf << (8-numbits);
1816 if(ressize > size) /* no RLE */
1818 ressize = size;
1819 *dtype = 0;
1820 for(i = 0; i < size; ++i)
1821 buf[i]= src[i];
1823 else
1824 *dtype = 1;
1826 *dsize = ressize;
1828 return buf;
1831 /****************************************************************************************/
1833 static LONG writeimagchunk(struct ILBMImage *img)
1835 struct imagchunk ic;
1836 LONG imagsize;
1837 UBYTE skippalette = 0;
1838 UBYTE *pal, *gfx;
1839 LONG palsize, gfxsize;
1840 UBYTE palpacked, gfxpacked;
1842 imagsize = sizeof(struct imagchunk);
1844 /* if this is second image check whether palette is identical to
1845 the one of first image */
1847 if (img == &img2)
1849 if (img1.cmapentries == img2.cmapentries)
1851 WORD i;
1853 for (i = 0; i < img1.cmapentries; i++)
1855 if (img1.rgb[i][0] != img2.rgb[i][0]) break;
1856 if (img1.rgb[i][1] != img2.rgb[i][1]) break;
1857 if (img1.rgb[i][2] != img2.rgb[i][2]) break;
1860 if (i == img1.cmapentries) skippalette = 1;
1864 if (!skippalette)
1866 pal = createrle(8,
1867 &palpacked,
1868 &palsize,
1869 img->cmapentries * 3,
1870 (unsigned char *)img->rgb);
1872 imagsize += palsize;
1875 gfx = createrle(img->bmh.bmh_Depth,
1876 &gfxpacked,
1877 &gfxsize,
1878 img->bmh.bmh_Width * img->bmh.bmh_Height,
1879 img->chunkybuffer);
1881 imagsize += gfxsize;
1883 #undef ACT_STRUCT
1884 #define ACT_STRUCT ic
1886 SET_BYTE(ic_transparentcolour, transparentoption);
1887 if (skippalette)
1889 SET_BYTE(ic_numcolours, 0);
1890 SET_BYTE(ic_flags, (transparentoption != -1) ? 1 : 0); /* 1 = HasTransparentColour */
1891 SET_BYTE(ic_paletteformat, 0);
1892 SET_WORD(ic_numpalettebytes, 0);
1894 else
1896 SET_BYTE(ic_numcolours, img->cmapentries - 1);
1897 SET_BYTE(ic_flags, (transparentoption != -1) ? 3 : 2); /* 2 = HasPalette */
1898 SET_BYTE(ic_paletteformat, palpacked);
1899 SET_WORD(ic_numpalettebytes, palsize - 1);
1902 SET_BYTE(ic_imageformat, gfxpacked);
1903 SET_BYTE(ic_depth, img->bmh.bmh_Depth);
1904 SET_WORD(ic_numimagebytes, gfxsize - 1);
1906 writelong(ID_IMAG);
1907 writelong(imagsize);
1909 if (fwrite(&ic, 1, sizeof(ic), outfile) != sizeof(ic))
1911 cleanup("Error writing imag chunk!", 1);
1914 if (fwrite(gfx, 1, gfxsize, outfile) != gfxsize)
1916 cleanup("Error write gfx data in imag chunk!", 1);
1919 if (!skippalette)
1921 if (fwrite(pal, 1, palsize, outfile) != palsize)
1923 cleanup("Error write palette data in imag chunk!", 1);
1927 if (imagsize & 1)
1929 UBYTE dummy = 0;
1931 if (fwrite(&dummy, 1, 1, outfile) != 1)
1933 cleanup("Error writing imag chunk!", 1);
1936 imagsize++;
1939 return imagsize + 8;
1942 /****************************************************************************************/
1943 static LONG writeargb(APTR argb, ULONG argb_size)
1945 LONG formsize = 10;
1946 struct ARGB35_Header {
1947 ULONG ztype; /* Always 1 */
1948 ULONG zsize; /* Compressed size, or -1 */
1949 UWORD resv; /* Always 0 */
1950 } ahdr;
1951 Bytef *zdest;
1952 uLongf zsize, size;
1953 int err;
1955 zsize = size = argb_size;
1957 zdest = malloc(zsize);
1958 if (!zdest)
1959 return 0;
1961 err = compress(zdest, &zsize, argb, size);
1962 if (err != Z_OK) {
1963 free(zdest);
1964 return 0;
1967 writelong(ID_ARGB);
1968 formsize = 10 + zsize;
1969 if (formsize & 1)
1970 formsize++;
1971 writelong(formsize);
1972 writelong(1);
1973 writelong(zsize);
1974 writeword(0);
1975 fwrite(zdest, 1, zsize, outfile);
1976 if (zsize & 1) {
1977 char c = 0;
1978 fwrite(&c, 1, 1, outfile);
1981 free(zdest);
1983 return 8 + formsize;
1986 /****************************************************************************************/
1988 static void write35data(void)
1990 LONG formsize = 4;
1991 LONG formsizeseek;
1993 if (nosaveIFF)
1994 return;
1996 writelong(ID_FORM);
1997 formsizeseek = ftell(outfile);
1998 writelong(0x12345678);
1999 writelong(ID_ICON);
2001 formsize += writefacechunk();
2002 formsize += writeimagchunk(&img1);
2003 if (image2option) formsize += writeimagchunk(&img2);
2005 if (!nosaveARGB && img1.argb) {
2006 formsize += writeargb(img1.argb, img1.argb_size);
2009 if (!nosaveARGB && img2.argb) {
2010 formsize += writeargb(img2.argb, img2.argb_size);
2013 if (!nosavePNG && img1.png) {
2014 writelong(ID_PNG);
2015 writelong(img1.png_size);
2016 fwrite(img1.png, 1, img1.png_size, outfile);
2017 if (img1.png_size & 1) {
2018 char c = 0;
2019 fwrite(&c, 1, 1, outfile);
2020 img1.png_size++;
2022 formsize += 8 + img1.png_size;
2025 if (!nosavePNG && img2.png) {
2026 writelong(ID_PNG);
2027 writelong(img2.png_size);
2028 fwrite(img2.png, 1, img2.png_size, outfile);
2029 if (img2.png_size & 1) {
2030 char c = 0;
2031 fwrite(&c, 1, 1, outfile);
2032 img2.png_size++;
2034 formsize += 8 + img2.png_size;
2037 fseek(outfile, formsizeseek, SEEK_SET);
2038 writelong(formsize);
2041 /****************************************************************************************/
2043 static void writeicon(void)
2045 struct diskobject dobj;
2047 outfile = fopen(outfilename, "wb");
2048 if (!outfile) cleanup("Can't open output file for writing!", 1);
2050 writediskobject();
2051 writeolddrawerdata();
2052 writeimage(&img1);
2054 if (image2option) writeimage(&img2);
2056 if (defaulttooloption) writestring(defaulttooloption);
2058 if (tooltypesoption)
2060 char **strarray;
2061 LONG numtooltypes = 0;
2063 for(strarray = tooltypesoption; *strarray; strarray++, numtooltypes++);
2065 writelong((numtooltypes + 1) * 4);
2067 for(strarray = tooltypesoption; *strarray; strarray++)
2069 writestring(*strarray);
2074 /* toolwindow would have to be saved in between here if there is any */
2076 writenewdrawerdata();
2078 write35data();
2082 /****************************************************************************************/
2084 static void remapicon(void)
2086 remapplanar(&img1, &std4colpal);
2087 if (image2option) remapplanar(&img2, &std4colpal);
2090 /****************************************************************************************/
2092 int main(int argc, char **argv)
2094 getarguments(argc, argv);
2095 parseiconsource();
2096 loadimage(image1option, &img1);
2097 if (image2option) loadimage(image2option, &img2);
2098 remapicon();
2099 writeicon();
2101 cleanup(0, 0);
2104 /****************************************************************************************/