Expand 8bit grayscale image data to rgba. (NicJA)
[AROS.git] / tools / ilbmtoicon / ilbmtoicon.c
blob94bd1004bc83f02a674d771e2302333834f7bf79
1 /*
2 Copyright © 1995-2019, 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;
173 #if (0)
174 static long bodysize_packed;
175 #endif
176 static long filepos;
177 static struct ILBMImage img1, img2;
178 static BOOL have_bmhd, have_cmap, have_body, is_png;
180 /* 'ticks' per dot, corresponding to ~72dpi */
181 static ULONG tpdX = TPD_X(72), tpdY = TPD_Y(72);
182 static char *image1option;
183 static char *image2option;
184 static char *defaulttooloption;
185 static char *drawerdataoption;
186 static char **tooltypesoption;
187 static LONG typeoption = 3; /* WBTOOL */
188 static LONG iconleftoption = 0x80000000; /* NO_ICON_POSITION */
189 static LONG icontopoption = 0x80000000; /* NO_ICON_POSITION */
190 static LONG stackoption = 4096;
191 static LONG drawerleftoption = 50;
192 static LONG drawertopoption = 50;
193 static LONG drawerwidthoption = 400;
194 static LONG drawerheightoption = 100;
195 static LONG drawervleftoption = 0;
196 static LONG drawervtopoption = 0;
197 static LONG drawershowoption = 0;
198 static LONG drawershowasoption = 0;
199 static LONG transparentoption = -1;
201 static BOOL dualpng; /* png file contains second image */
202 static unsigned char *dualpngstart; /* address of 2nd image in filebuffer */
203 static BOOL nosavePNG; /* Don't save the original PNG data */
204 static BOOL nosaveARGB; /* Don't ARGB data */
205 static BOOL nosaveIFF; /* Don't save any IFF data */
207 /****************************************************************************************/
209 static void freeimage(struct ILBMImage *img)
211 if (img->chunkybuffer)
213 free(img->chunkybuffer);
214 img->chunkybuffer = NULL;
217 if (img->planarbuffer)
219 free(img->planarbuffer);
220 img->planarbuffer = NULL;
223 if (img->argb)
225 free(img->argb);
226 img->argb = NULL;
229 if (filebuffer)
231 free(filebuffer);
232 filebuffer = NULL;
235 if (file)
237 fclose(file);
238 file = NULL;
241 filepos = 0;
244 /****************************************************************************************/
246 static void cleanup(char *msg, int rc)
248 if (msg) fprintf(stderr, "ilbmtoicon: %s\n", msg);
250 freeimage(&img1);
251 freeimage(&img2);
253 if (outfile) fclose(outfile);
254 if (infile) fclose(infile);
256 exit(rc);
259 /****************************************************************************************/
261 static void getarguments(int argc, char **argv)
263 #if (0)
264 WORD i;
265 #endif
267 nosavePNG = 1;
269 for (; argc > 1 && argv[1][0] == '-'; argc--, argv++) {
270 if (strcmp(argv[1],"--png") == 0) {
271 nosavePNG = 0;
272 continue;
274 if (strcmp(argv[1],"--no-iff") == 0) {
275 nosaveIFF = 1;
276 continue;
278 if (strcmp(argv[1],"--no-argb") == 0) {
279 nosaveIFF = 1;
280 continue;
282 if (strcmp(argv[1],"--dpi") == 0) {
283 char *cp;
284 long dpiX, dpiY;
285 argc--;
286 argv++;
287 dpiX = strtol(argv[1], &cp, 0);
288 if (*cp == ':') {
289 cp++;
290 dpiY = strtol(cp, NULL, 0);
291 } else {
292 dpiY = dpiX;
294 tpdX = TPD_X(dpiX);
295 tpdY = TPD_Y(dpiY);
296 continue;
301 if ((argc != 4) && (argc != 5))
303 fprintf(stderr, "Wrong number of arguments\n");
304 cleanup("Usage: ilbmtoicon [--png] [--no-argb] [--no-iff] icondescription image1 [image2] filename", 1);
307 if (argc == 4)
309 infilename = argv[1];
310 image1option = argv[2];
311 outfilename = argv[3];
313 else if (argc == 5)
315 infilename = argv[1];
316 image1option = argv[2];
317 image2option = argv[3];
318 outfilename = argv[4];
322 /****************************************************************************************/
324 static char *skipblanks(char *s)
326 while ((*s == ' ') || (*s == '\t')) s++;
328 return s;
331 /****************************************************************************************/
333 static char *skipword(char *s)
335 while((*s != ' ') &&
336 (*s != '\t') &&
337 (*s != '\0') &&
338 (*s != '\n'))
340 s++;
343 return s;
346 /****************************************************************************************/
348 static char *checkquotes(char *s)
350 char *s2;
351 static char s3[256];
352 BOOL escaped = 0;
353 int i = 0;
355 if (*s != '"')
357 s2 = skipword(s);
358 *s2 = '\0';
360 return s;
363 s++;
366 while ((i < 256) && (s3[i] = *s))
368 if (!escaped)
370 if (*s == '\\')
372 escaped = !escaped;
373 i--;
375 else if (*s == '"')
376 break;
378 else
379 escaped = !escaped;
380 i++;
381 s++;
383 s3[i] = '\0';
384 s = s3;
386 return s;
389 /****************************************************************************************/
391 #define KEYWORD_STRING 0
392 #define KEYWORD_INTEGER 1
393 #define KEYWORD_STRINGARRAY 2
394 #define KEYWORD_CYCLE 3
396 #define MAX_ARRAY_SIZE 200
398 /****************************************************************************************/
400 struct cycle
402 char *keyword;
403 LONG value;
406 struct cycle typecycles[] =
408 {"DISK" , 1},
409 {"DRAWER" , 2},
410 {"TOOL" , 3},
411 {"PROJECT" , 4},
412 {"GARBAGE" , 5},
413 {"DEVICE" , 6},
414 {"KICK" , 7},
415 {"APPICON" , 8},
418 struct cycle showcycles[] =
420 {"DEFAULT" , 0},
421 {"ICONS" , 1},
422 {"ALL" , 2},
423 {NULL , 0}
427 struct cycle showascycles[] =
429 {"DEFAULT" , 0},
430 {"ICON" , 1},
431 {"TEXT_NAME", 2},
432 {"TEXT_DATE", 3},
433 {"TEXT_SIZE", 4},
434 {"TEXT_TYPE", 5},
435 {NULL , 0}
440 /****************************************************************************************/
442 struct keyword
444 WORD type;
445 char *keyword;
446 APTR store;
447 APTR extra;
449 keywordtable[] =
451 {KEYWORD_STRING , "DEFAULTTOOL" , &defaulttooloption , NULL },
452 {KEYWORD_STRING , "DRAWERDATA" , &drawerdataoption , NULL },
453 {KEYWORD_CYCLE , "TYPE" , &typeoption , typecycles },
454 {KEYWORD_STRINGARRAY, "TOOLTYPE" , &tooltypesoption , NULL },
455 {KEYWORD_INTEGER , "STACK" , &stackoption , NULL },
456 {KEYWORD_INTEGER , "ICONLEFTPOS" , &iconleftoption , NULL },
457 {KEYWORD_INTEGER , "ICONTOPPOS" , &icontopoption , NULL },
458 {KEYWORD_INTEGER , "DRAWERLEFTPOS" , &drawerleftoption , NULL },
459 {KEYWORD_INTEGER , "DRAWERTOPPOS" , &drawertopoption , NULL },
460 {KEYWORD_INTEGER , "DRAWERWIDTH" , &drawerwidthoption , NULL },
461 {KEYWORD_INTEGER , "DRAWERHEIGHT" , &drawerheightoption , NULL },
462 {KEYWORD_INTEGER , "DRAWERVIEWLEFT" , &drawervleftoption , NULL },
463 {KEYWORD_INTEGER , "DRAWERVIEWTOP" , &drawervtopoption , NULL },
464 {KEYWORD_CYCLE , "DRAWERSHOW" , &drawershowoption , showcycles },
465 {KEYWORD_CYCLE , "DRAWERSHOWAS" , &drawershowoption , showascycles },
466 {KEYWORD_INTEGER , "TRANSPARENT" , &transparentoption , NULL },
467 {0 , NULL , NULL }
471 /****************************************************************************************/
473 static void handleoption(char *keyword, char *keyvalue)
475 struct keyword *kw;
476 struct cycle *cy;
478 D(printf("Keyword %s, value %s\n", keyword, keyvalue));
480 for(kw = keywordtable; kw->keyword; kw++)
482 if (strcasecmp(kw->keyword, keyword) == 0)
484 switch(kw->type)
486 case KEYWORD_STRING:
487 *(char **)kw->store = strdup(keyvalue);
488 if (!(*(char **)kw->store)) cleanup("Out of memory!", 1);
489 break;
491 case KEYWORD_INTEGER:
492 *(LONG *)kw->store = strtol(keyvalue, 0, 0);
493 break;
495 case KEYWORD_CYCLE:
496 for(cy = (struct cycle *)kw->extra; cy->keyword; cy++)
498 if (strcasecmp(keyvalue, cy->keyword) == 0)
500 *(LONG *)kw->store = cy->value;
501 break;
504 break;
506 case KEYWORD_STRINGARRAY:
507 if (!(*(char ***)kw->store))
509 *(char ***)kw->store = (char **)malloc(MAX_ARRAY_SIZE * sizeof(char *));
510 if (!(*(char ***)kw->store)) cleanup("Out of memory!", 1);
512 memset(*(char ***)kw->store, 0, MAX_ARRAY_SIZE * sizeof(char *));
516 char *dupvalue;
517 char **strarray = *(char ***)kw->store;
518 WORD i = 0;
520 dupvalue = strdup(keyvalue);
521 if (!dupvalue) cleanup("Out of memory!", 1);
523 while(*strarray)
525 strarray++;
526 i++;
529 if (i >= MAX_ARRAY_SIZE - 1) cleanup("Array overflow!", 1);
531 *strarray = dupvalue;
534 } /* switch(kw->type) */
536 break;
538 } /* if (strcasecmp(kw->keyword, keyword) == 0) */
540 } /* for(kw = keywordtable; kw->keyword; kw++) */
544 /****************************************************************************************/
546 static void parseline(char *s)
548 char *keyword;
549 char *keyvalue = NULL;
551 s = skipblanks(s);
553 if (*s == '#') return;
554 if (*s == ';') return;
556 keyword = s;
558 s = skipword(s);
559 if (*s == '\0') return;
561 *s = '\0';
562 s = skipblanks(s + 1);
564 if (*s == '=') s = skipblanks(s + 1);
565 if (*s == '\0') return;
567 keyvalue = checkquotes(s);
569 handleoption(keyword, keyvalue);
572 /****************************************************************************************/
574 static void parseiconsource(void)
576 char s[256];
578 infile = fopen(infilename, "r");
579 if (infile)
581 while(fgets(s, sizeof(s), infile))
583 D(printf("Read line: %s\n", s));
584 parseline(s);
587 fclose(infile);
588 infile = 0;
592 /****************************************************************************************/
594 #if (0)
595 static void showoptions(void)
597 char **strarray;
599 printf("image1: %s\n", image1option ? image1option : "(NULL)");
600 printf("image2: %s\n", image2option ? image2option : "(NULL)");
601 printf("type: %ld\n", typeoption);
603 strarray = tooltypesoption;
604 if (strarray)
606 printf("tooltypes:\n");
607 while(*strarray)
609 printf(" %s\n", *strarray++);
613 #endif
615 /****************************************************************************************/
617 static ULONG getlong(void)
619 ULONG ret;
621 if (filepos > filesize - 4) cleanup("Tried to read over file end!", 1);
623 ret = filebuffer[filepos++] * 0x1000000;
624 ret += filebuffer[filepos++] * 0x10000;
625 ret += filebuffer[filepos++] * 0x100;
626 ret += filebuffer[filepos++];
628 return ret;
631 /****************************************************************************************/
633 static UWORD getword(void)
635 UWORD ret;
637 if (filepos > filesize - 2) cleanup("Tried to read over file end!", 1);
639 ret = filebuffer[filepos++] * 0x100;
640 ret += filebuffer[filepos++];
642 return ret;
645 /****************************************************************************************/
647 static UBYTE getbyte(void)
649 ULONG ret;
651 if (filepos > filesize - 1) cleanup("Tried to read over file end!", 1);
652 ret = filebuffer[filepos++];
654 return ret;
657 /****************************************************************************************/
659 static void skipbytes(ULONG howmany)
661 filepos += howmany;
664 /****************************************************************************************/
666 static void openimage(struct ILBMImage *img)
668 file = fopen(filename, "rb");
669 if (!file) cleanup("Can't open file!", 1);
671 fseek(file, 0, SEEK_END);
672 filesize = ftell(file);
674 if (filesize < 12) cleanup("Bad file size!", 1);
676 //fprintf(stderr, "Filesize is %d\n", filesize);
678 fseek(file, 0, SEEK_SET);
680 filebuffer = malloc(filesize + 10);
681 if (!filebuffer) cleanup("Memory allocation for file buffer failed!", 1);
683 if (fread(filebuffer, 1, filesize, file) != filesize)
684 cleanup("Error reading file!", 1);
686 fclose(file); file = NULL;
689 /****************************************************************************************/
691 static void checkimage(struct ILBMImage *img)
693 static UBYTE pngsig[8] = {137, 80, 78, 71, 13, 10, 26, 10};
695 ULONG id;
696 ULONG size;
698 if (dualpng) {
699 img->png = dualpngstart;
700 img->png_size = filesize - (dualpngstart - filebuffer);
701 return;
704 if (memcmp(filebuffer, pngsig, 8) == 0)
706 is_png = 1;
707 img->png = filebuffer;
709 /* search for second image */
712 dualpngstart = filebuffer + 8 ;
713 dualpngstart < filebuffer + filesize - 8 ;
714 dualpngstart++
717 if (memcmp(dualpngstart, pngsig, 8) == 0)
719 dualpng = 1;
720 break;
723 if (dualpng)
724 img->png_size = dualpngstart - filebuffer;
725 else
726 img->png_size = filesize;
728 else if (is_png == 0)
730 id = getlong();
731 if (id != ID_FORM) cleanup("File is not an IFF file!", 1);
733 size = getlong();
734 if (size != filesize - 8) cleanup("File is IFF, but has bad size in IFF header!", 1);
736 id = getlong();
737 if (id != ID_ILBM) cleanup("File is IFF, but not of type ILBM!", 1);
739 else if (is_png == 1)
741 cleanup("Second image must be a PNG image, too!", 1);
746 /****************************************************************************************/
748 static void my_read_fn(png_structp png_ptr, png_bytep data, png_size_t length)
750 png_bytep *pdata = png_get_io_ptr(png_ptr);
752 if (*pdata-filebuffer >= filesize)
753 png_error(png_ptr, "Read past end of file");
755 memcpy(data, *pdata, length);
756 *pdata += length;
759 static UBYTE findcolor(struct Palette *pal, ULONG r, ULONG g, ULONG b, BOOL notrans);
761 static void loadpng(struct ILBMImage *img, struct Palette *pal)
763 png_structp png_ptr;
764 png_infop info_ptr, end_info;
765 png_bytep fpos, *row_pointers;
766 UBYTE *chunkrow;
767 UWORD width, height;
768 int x, y;
770 if (png_sig_cmp(img->png, 0, img->png_size) != 0)
771 cleanup("I thought it was a PNG, but I was wrong.", 1);
773 png_ptr = png_create_read_struct(PNG_LIBPNG_VER_STRING,
774 0, /* error ptr */
777 if (!png_ptr)
778 cleanup("png_create_read_struct() failed", 1);
780 info_ptr = png_create_info_struct(png_ptr);
781 if (!info_ptr) {
782 png_destroy_read_struct(&png_ptr, NULL, NULL);
783 cleanup("png_create_info_struct() failed", 1);
786 end_info = png_create_info_struct(png_ptr);
787 if (!end_info) {
788 png_destroy_read_struct(&png_ptr, &info_ptr, NULL);
789 cleanup("png_create_info_struct() failed", 1);
792 fpos = img->png;
793 png_set_read_fn(png_ptr, &fpos, my_read_fn);
795 if (setjmp(png_jmpbuf(png_ptr))) {
796 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
797 cleanup("png read failed", 1);
800 /* Read the PNG as RGBA */
801 png_set_add_alpha(png_ptr, 255, PNG_FILLER_AFTER);
802 png_read_png(png_ptr, info_ptr, PNG_TRANSFORM_EXPAND | PNG_TRANSFORM_GRAY_TO_RGB | PNG_TRANSFORM_STRIP_16, NULL);
804 row_pointers = png_get_rows(png_ptr, info_ptr);
806 width = png_get_image_width(png_ptr, info_ptr);
807 height = png_get_image_height(png_ptr, info_ptr);
809 img->bmh.bmh_Width = width;
810 img->bmh.bmh_Height = height;
811 img->bmh.bmh_Left = 0;
812 img->bmh.bmh_Top = 0;
813 img->bmh.bmh_Depth = 8;
814 img->bmh.bmh_Masking = MSK_HASTRANS;
815 img->bmh.bmh_Compression = CMP_NONE;
816 img->bmh.bmh_Pad = 0;
817 img->bmh.bmh_XAspect = 1;
818 img->bmh.bmh_YAspect = 1;
819 img->bmh.bmh_PageWidth = 320;
820 img->bmh.bmh_PageHeight = 200;
822 #if (0)
823 img->planarbmh;
824 #endif
825 img->bpr = ((img->bmh.bmh_Width + 15) & ~15) / 8;
826 img->totdepth = 0;
828 /* Transform the RGBA data into chunky */
829 img->cmapentries = pal->numentries;
830 memcpy(img->rgb, pal->rgb, sizeof(img->rgb[0])*pal->numentries);
832 img->chunkybuffer = malloc(width * height * sizeof(UBYTE));
833 if (!img->chunkybuffer)
834 cleanup("Can't allocate the chunky buffer", 1);
836 chunkrow = img->chunkybuffer;
837 img->argb_size = width * height * sizeof(UBYTE) * 4;
838 img->argb = malloc(img->argb_size);
839 if (!img->argb)
840 cleanup("Can't allocate the ARGB buffer", 1);
842 for (y = 0; y < height; y++) {
843 png_bytep row = row_pointers[y];
844 UBYTE *ap = img->argb + (width * sizeof(UBYTE) * 4) * y;
845 for (x = 0; x < width; x++, row += 4, ap += 4, chunkrow++) {
846 UBYTE r,g,b;
848 ap[0] = row[3];
849 ap[1] = row[0];
850 ap[2] = row[1];
851 ap[3] = row[2];
853 /* Opacity of 0? Use the transparency color */
854 if (row[3] == 0) {
855 if (transparentoption < 0)
856 transparentoption = 0;
857 *chunkrow = transparentoption;
858 } else {
859 r = row[0];
860 g = row[1];
861 b = row[2];
863 *chunkrow = findcolor(pal, r, g, b, TRUE);
868 img->bmh.bmh_Transparent = transparentoption;
870 png_destroy_read_struct(&png_ptr, &info_ptr, &end_info);
874 /****************************************************************************************/
876 static void scanimage(struct ILBMImage *img)
878 WORD i;
880 have_bmhd = 0;
881 have_cmap = 0;
882 have_body = 0;
884 if (img->png) {
885 /* Load the PNG, using the Scalos 16-color pallette,
886 * into the Chunky buffer.
888 loadpng(img, &scalos16colpal);
889 return;
892 for(;;)
894 ULONG id;
895 ULONG size;
897 id = getlong();
898 size = getlong();
900 //fprintf(stderr, "Chunk: %c%c%c%c Size: %d\n", id >> 24, id >> 16, id >> 8, id, size);
902 switch(id)
904 case ID_BMHD:
905 if (size != 20) cleanup("Bad BMHD chunk size!", 1);
907 img->bmh.bmh_Width = getword();
908 img->bmh.bmh_Height = getword();
909 img->bmh.bmh_Left = (WORD)getword();
910 img->bmh.bmh_Top = (WORD)getword();
911 img->bmh.bmh_Depth = getbyte();
912 img->bmh.bmh_Masking = getbyte();
913 img->bmh.bmh_Compression = getbyte();
914 img->bmh.bmh_Pad = getbyte();
915 img->bmh.bmh_Transparent = getword();
916 img->bmh.bmh_XAspect = getbyte();
917 img->bmh.bmh_YAspect = getbyte();
918 img->bmh.bmh_PageWidth = (WORD)getword();
919 img->bmh.bmh_PageHeight = (WORD)getword();
921 if (img->bmh.bmh_Depth > 8) cleanup("ILBM file has too many colors!", 1);
922 if ((img->bmh.bmh_Compression != CMP_NONE) && (img->bmh.bmh_Compression != CMP_BYTERUN1)) cleanup("Compression method unsupported!", 1);
924 have_bmhd = 1;
926 img->totdepth = img->bmh.bmh_Depth + ((img->bmh.bmh_Masking == MSK_HASMASK) ? 1 : 0);
928 img->bpr = ((img->bmh.bmh_Width + 15) & ~15) / 8;
930 /*fprintf(stderr, "BMHD: %d x %d x %d (%d)\n", img->bmh.bmh_Width,
931 img->bmh.bmh_Height,
932 img->bmh.bmh_Depth,
933 img->totdepth);*/
934 img->planarbmh = img->bmh;
935 break;
937 case ID_CMAP:
938 if (!have_bmhd) cleanup("CMAP chunk before BMHD chunk (or no BMHD chunk at all!", 1);
940 img->cmapentries = size / 3;
941 if (size & 1) size++;
943 if ((img->cmapentries < 2) || (img->cmapentries > 256)) cleanup("CMAP chunk has bad number of entries!", 1);
945 for(i = 0; i < img->cmapentries; i++)
947 img->rgb[i][0] = getbyte();
948 img->rgb[i][1] = getbyte();
949 img->rgb[i][2] = getbyte();
950 size -= 3;
953 skipbytes(size);
955 have_cmap = 1;
957 break;
959 case ID_BODY:
960 if (!have_bmhd) cleanup("BODY chunk before BMHD chunk (or no BMHD chunk at all!", 1);
961 body = &filebuffer[filepos];
962 bodysize = size;
964 if (img->bmh.bmh_Compression == CMP_NONE)
966 LONG shouldbesize = img->totdepth * img->bpr * img->bmh.bmh_Height;
967 if (bodysize != shouldbesize) cleanup("BODY chunk size seems to be wrong!", 1);
970 have_body = 1;
971 /* Fall through */
973 default:
974 if (size & 1) size++;
975 skipbytes(size);
976 break;
979 if (filepos == filesize) break;
980 if (have_bmhd && have_body && have_cmap) break;
983 if (!have_bmhd) cleanup("BMHD chunk missing!", 1);
984 if (!have_body) cleanup("BODY chunk missing!", 1);
987 /****************************************************************************************/
989 static unsigned char *unpack_byterun1(unsigned char *source, unsigned char *dest, LONG unpackedsize)
991 unsigned char r;
992 signed char c;
994 for(;;)
996 c = (signed char)(*source++);
997 if (c >= 0)
999 while(c-- >= 0)
1001 *dest++ = *source++;
1002 if (--unpackedsize <= 0) return source;
1005 else if (c != -128)
1007 c = -c;
1008 r = *source++;
1010 while(c-- >= 0)
1012 *dest++ = r;
1013 if (--unpackedsize <= 0) return source;
1020 /****************************************************************************************/
1022 #if (0)
1023 static BOOL norm1(LONG count, unsigned char **source_backup,
1024 unsigned char **dest, LONG *checksize)
1026 //if (count >= 0) fprintf(stderr, "XX: non packable %d\n",count);
1028 while(count >= 0)
1030 LONG step = count;
1032 if (step > 127) step = 127;
1034 *checksize -= step;
1035 *checksize -= 2;
1037 if (*checksize <= 0) return 0;
1039 count -= step;
1041 *(*dest)++ = step;
1044 while(step-- >= 0)
1046 *(*dest)++ = *(*source_backup)++;
1049 count--;
1053 return 1;
1056 static BOOL copy1(unsigned char r, LONG count, unsigned char **dest, LONG *checksize)
1058 //if (count >= 1) fprintf(stderr, "XX: repeat %02x x %d\n", r, count);
1060 while(--count >= 0)
1062 LONG step = count;
1064 if (step > 127) step = 127;
1066 count -= step;
1067 step = -step;
1068 *checksize -= 2;
1069 if (*checksize <= 0) return 0;
1071 *(*dest)++ = (unsigned char)step;
1072 *(*dest)++ = r;
1075 return 1;
1078 static BOOL pack_byterun1(unsigned char *source, unsigned char *dest,
1079 LONG size, LONG check_size, LONG *packsize)
1081 unsigned char *source_backup, *dest_backup;
1082 LONG samebytes_counter, samebytes, count;
1083 LONG checksize = check_size;
1084 unsigned char oldbyte, actbyte;
1086 if (checksize < 0) checksize = 0x7FFFFFFF;
1088 oldbyte = *source;
1089 samebytes_counter = 0;
1090 source_backup = source;
1091 dest_backup = dest;
1093 for(;;)
1095 //fprintf(stderr, "size = %d. checksize = %d\n", size, checksize);
1096 if (--size < 0) break;
1097 actbyte = *source++;
1098 if (actbyte == oldbyte)
1100 samebytes_counter++;
1101 continue;
1104 oldbyte = actbyte;
1106 samebytes = samebytes_counter;
1107 samebytes_counter = 1;
1109 if (samebytes < 3) continue;
1111 count = (LONG)(source - source_backup - samebytes - 2);
1112 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1114 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
1116 source_backup = source - 1;
1118 //fprintf(stderr, "done\n");
1120 if (samebytes_counter >= 3)
1122 samebytes = samebytes_counter;
1123 count = (LONG)(source - source_backup - samebytes - 1);
1124 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1125 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
1127 else
1129 count = (LONG)(source - source_backup - 1);
1130 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
1132 //fprintf(stderr, "realdone\n");
1134 if (packsize) *packsize = (LONG)(dest - dest_backup);
1136 return 1;
1138 #endif
1140 /****************************************************************************************/
1142 static void p2c(unsigned char *source, unsigned char *dest, LONG width, LONG height,
1143 LONG totplanes, LONG wantplanes, LONG chunkybpr)
1145 LONG alignedwidth, x, y, p, bpr, bpl;
1147 alignedwidth = (width + 15) & ~15;
1148 bpr = alignedwidth / 8;
1149 bpl = bpr * totplanes;
1151 for(y = 0; y < height; y++)
1153 for(x = 0; x < width; x++)
1155 LONG mask = 0x80 >> (x & 7);
1156 LONG offset = x / 8;
1157 unsigned char chunkypix = 0;
1159 for(p = 0; p < wantplanes; p++)
1161 if (source[p * bpr + offset] & mask) chunkypix |= (1 << p);
1163 dest[x] = chunkypix;
1166 source += bpl;
1167 dest += chunkybpr;
1173 /****************************************************************************************/
1175 static void c2p(unsigned char *source, unsigned char *dest, LONG width, LONG height, LONG planes)
1177 LONG alignedwidth, x, y, p, bpr, bpl;
1179 alignedwidth = (width + 15) & ~15;
1180 bpr = alignedwidth / 8;
1181 bpl = bpr * planes;
1183 for(y = 0; y < height; y++)
1185 for(x = 0; x < width; x++)
1187 LONG mask = 0x80 >> (x & 7);
1188 LONG offset = x / 8;
1189 unsigned char chunkypix = source[x];
1191 for(p = 0; p < planes; p++)
1193 if (chunkypix & (1 << p))
1194 dest[p * bpr + offset] |= mask;
1195 else
1196 dest[p * bpr + offset] &= ~mask;
1200 source += width;
1201 dest += bpl;
1206 /****************************************************************************************/
1208 static void convertbody(struct ILBMImage *img)
1210 LONG unpackedsize = img->bpr * img->bmh.bmh_Height * img->totdepth;
1212 if (is_png)
1213 return;
1215 img->planarbuffer = malloc(unpackedsize);
1216 if (!img->planarbuffer) cleanup("Memory allocation for planar buffer failed!", 1);
1218 if (img->bmh.bmh_Compression == CMP_NONE)
1220 memcpy(img->planarbuffer, body, unpackedsize);
1222 else
1224 unpack_byterun1(body, img->planarbuffer, unpackedsize);
1227 img->chunkybuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
1228 if (!img->chunkybuffer) cleanup("Memory allocation for chunky buffer failed!", 1);
1230 p2c(img->planarbuffer,
1231 img->chunkybuffer,
1232 img->bmh.bmh_Width,
1233 img->bmh.bmh_Height,
1234 img->totdepth,
1235 img->bmh.bmh_Depth,
1236 img->bmh.bmh_Width);
1239 /****************************************************************************************/
1241 static UBYTE findcolor(struct Palette *pal, ULONG r, ULONG g, ULONG b, BOOL notrans)
1243 ULONG dist, bestdist = 0xFFFFFFFF;
1244 UBYTE i, besti = 0;
1246 for(i = 0; i < pal->numentries; i++)
1248 LONG r1, g1, b1, r2, g2, b2, dr, dg, db;
1250 if (notrans && i == transparentoption)
1251 continue;
1253 r1 = (LONG)r;
1254 g1 = (LONG)g;
1255 b1 = (LONG)b;
1257 r2 = (LONG)pal->rgb[i][0];
1258 g2 = (LONG)pal->rgb[i][1];
1259 b2 = (LONG)pal->rgb[i][2];
1261 dr = r1 - r2;
1262 dg = g1 - g2;
1263 db = b1 - b2;
1265 dist = (dr * dr) + (dg * dg) + (db * db);
1266 if (dist < bestdist)
1268 bestdist = dist;
1269 besti = i;
1274 return besti;
1277 /****************************************************************************************/
1279 static void remapplanar(struct ILBMImage *img, struct Palette *pal)
1281 UBYTE *remapbuffer;
1282 #if (0)
1283 LONG x,y;
1284 #endif
1285 LONG i, highestcol = 0, newdepth = 0;
1287 remapbuffer = malloc(img->bmh.bmh_Width * img->bmh.bmh_Height);
1288 if (!remapbuffer) cleanup("Error allocating remap buffer!", 1);
1290 for(i = 0; i < img->cmapentries; i++)
1292 img->remaptable[i] = findcolor(pal, img->rgb[i][0], img->rgb[i][1], img->rgb[i][2], FALSE);
1295 for(i = 0; i < img->bmh.bmh_Width * img->bmh.bmh_Height; i++)
1297 remapbuffer[i] = img->remaptable[img->chunkybuffer[i]];
1299 if (remapbuffer[i] > highestcol)
1300 highestcol = remapbuffer[i];
1303 for(i = highestcol; i; i >>= 1) newdepth++;
1304 if (newdepth == 0) newdepth = 1;
1306 if (newdepth > img->totdepth)
1308 if (img->planarbuffer)
1309 free(img->planarbuffer);
1311 img->planarbuffer = malloc(img->bpr * img->bmh.bmh_Height * newdepth);
1312 if (!img->planarbuffer)
1314 free(remapbuffer);
1315 cleanup("Error re-allocating planar buffer!", 1);
1319 img->planarbmh.bmh_Width = img->bmh.bmh_Width;
1320 img->planarbmh.bmh_Height= img->bmh.bmh_Height;
1321 img->planarbmh.bmh_Depth = newdepth;
1323 memset(img->planarbuffer, 0, img->bpr * img->bmh.bmh_Height * newdepth);
1325 c2p(remapbuffer, img->planarbuffer, img->bmh.bmh_Width, img->bmh.bmh_Height, newdepth);
1327 free(remapbuffer);
1330 /****************************************************************************************/
1332 static void loadimage(char *name, struct ILBMImage *img)
1334 freeimage(img);
1336 filename = name;
1338 openimage(img);
1339 checkimage(img);
1340 scanimage(img);
1341 convertbody(img);
1344 /****************************************************************************************/
1346 struct diskobject
1348 UBYTE do_magic[2];
1349 UBYTE do_version[2];
1350 UBYTE do_gadget_nextgadget[4];
1351 UBYTE do_gadget_leftedge[2];
1352 UBYTE do_gadget_topedge[2];
1353 UBYTE do_gadget_width[2];
1354 UBYTE do_gadget_height[2];
1355 UBYTE do_gadget_flags[2];
1356 UBYTE do_gadget_activation[2];
1357 UBYTE do_gadget_gadgettype[2];
1358 UBYTE do_gadget_gadgetrender[4];
1359 UBYTE do_gadget_selectrender[4];
1360 UBYTE do_gadget_gadgettext[4];
1361 UBYTE do_gadget_mutualexclude[4];
1362 UBYTE do_gadget_specialinfo[4];
1363 UBYTE do_gadget_gadgetid[2];
1364 UBYTE do_gadget_userdata[4];
1365 UBYTE do_type;
1366 UBYTE do_pad;
1367 UBYTE do_defaulttool[4];
1368 UBYTE do_tooltypes[4];
1369 UBYTE do_currentx[4];
1370 UBYTE do_currenty[4];
1371 UBYTE do_drawerdata[4];
1372 UBYTE do_toolwindow[4];
1373 UBYTE do_stacksize[4];
1376 /****************************************************************************************/
1378 struct olddrawerdata
1380 UBYTE dd_newwindow_leftedge[2];
1381 UBYTE dd_newwindow_topedge[2];
1382 UBYTE dd_newwindow_width[2];
1383 UBYTE dd_newwindow_height[2];
1384 UBYTE dd_newwindow_detailpen;
1385 UBYTE dd_newwindow_blockpen;
1386 UBYTE dd_newwindow_idcmpflags[4];
1387 UBYTE dd_newwindow_flags[4];
1388 UBYTE dd_newwindow_firstgadget[4];
1389 UBYTE dd_newwindow_checkmark[4];
1390 UBYTE dd_newwindow_title[4];
1391 UBYTE dd_newwindow_screen[4];
1392 UBYTE dd_newwindow_bitmap[4];
1393 UBYTE dd_newwindow_minwidth[2];
1394 UBYTE dd_newwindow_minheight[2];
1395 UBYTE dd_newwindow_maxwidth[2];
1396 UBYTE dd_newwindow_maxheight[2];
1397 UBYTE dd_newwindow_type[2];
1398 UBYTE dd_currentx[4];
1399 UBYTE dd_currenty[4];
1402 /****************************************************************************************/
1404 struct newdrawerdata
1406 UBYTE dd_flags[4];
1407 UBYTE dd_viewmodes[2];
1410 /****************************************************************************************/
1412 struct image
1414 UBYTE leftedge[2];
1415 UBYTE topedge[2];
1416 UBYTE width[2];
1417 UBYTE height[2];
1418 UBYTE depth[2];
1419 UBYTE imagedata[4];
1420 UBYTE planepick;
1421 UBYTE planeonoff;
1422 UBYTE nextimage[4];
1425 /****************************************************************************************/
1427 #define SET_BYTE(field,value) \
1428 ACT_STRUCT.field = value
1430 #define SET_WORD(field, value) \
1431 ACT_STRUCT.field[0] = ((value) >> 8) & 0xFF; \
1432 ACT_STRUCT.field[1] = (value) & 0xFF;
1434 #define SET_LONG(field,value) \
1435 ACT_STRUCT.field[0] = ((value) >> 24) & 0xFF; \
1436 ACT_STRUCT.field[1] = ((value) >> 16) & 0xFF; \
1437 ACT_STRUCT.field[2] = ((value) >> 8) & 0xFF; \
1438 ACT_STRUCT.field[3] = (value) & 0xFF;
1440 #define BOOL_YES 0x2A2A2A2A
1441 #define BOOL_NO 0x00000000
1443 static void writediskobject(void)
1445 struct diskobject dobj;
1447 if (typeoption == 2) /* DRAWER */
1449 drawerdataoption = "YES";
1452 #define ACT_STRUCT dobj
1454 SET_WORD(do_magic, 0xE310);
1455 SET_WORD(do_version, 1);
1456 SET_LONG(do_gadget_nextgadget, 0);
1457 SET_WORD(do_gadget_leftedge, 0);
1458 SET_WORD(do_gadget_topedge, 0);
1459 SET_WORD(do_gadget_width, img1.bmh.bmh_Width);
1460 SET_WORD(do_gadget_height, img1.bmh.bmh_Height);
1462 if (image2option)
1464 /* GFLG_GADGHIMAGE + GFLG_GADGIMAGE */
1465 SET_WORD(do_gadget_flags, 4 + 2);
1467 else
1469 /* GFLG_GADGIMAGE */
1470 SET_WORD(do_gadget_flags, 4);
1473 SET_WORD(do_gadget_activation, 1);
1474 SET_WORD(do_gadget_gadgettype, 1);
1475 SET_LONG(do_gadget_gadgetrender, BOOL_YES);
1477 if (image2option)
1479 SET_LONG(do_gadget_selectrender, BOOL_YES);
1481 else
1483 SET_LONG(do_gadget_selectrender, BOOL_NO);
1486 SET_LONG(do_gadget_gadgettext, 0);
1487 SET_LONG(do_gadget_mutualexclude, (1 << 31) | (tpdX << 8) | (tpdY << 0));
1488 SET_LONG(do_gadget_specialinfo, 0);
1489 SET_WORD(do_gadget_gadgetid, 0);
1490 SET_LONG(do_gadget_userdata, 1); /* full drawer data */
1492 SET_BYTE(do_type, typeoption);
1493 SET_BYTE(do_pad, 0);
1495 if (defaulttooloption)
1497 SET_LONG(do_defaulttool, BOOL_YES);
1499 else
1501 SET_LONG(do_defaulttool, BOOL_NO);
1504 if (tooltypesoption)
1506 SET_LONG(do_tooltypes, BOOL_YES);
1508 else
1510 SET_LONG(do_tooltypes, BOOL_NO);
1513 SET_LONG(do_currentx, iconleftoption);
1514 SET_LONG(do_currenty, icontopoption);
1516 if (drawerdataoption)
1518 SET_LONG(do_drawerdata, BOOL_YES);
1520 else
1522 SET_LONG(do_drawerdata, BOOL_NO);
1526 SET_LONG(do_toolwindow, 0);
1527 SET_LONG(do_stacksize, stackoption);
1529 if (fwrite(&dobj, 1, sizeof(dobj), outfile) != sizeof(dobj))
1531 cleanup("Error writing diskobject structure to outfile!", 1);
1535 /****************************************************************************************/
1537 static void writeolddrawerdata(void)
1539 struct olddrawerdata dd;
1541 if (!drawerdataoption) return;
1543 #undef ACT_STRUCT
1544 #define ACT_STRUCT dd
1546 SET_WORD(dd_newwindow_leftedge, drawerleftoption);
1547 SET_WORD(dd_newwindow_topedge, drawertopoption);
1548 SET_WORD(dd_newwindow_width, drawerwidthoption);
1549 SET_WORD(dd_newwindow_height, drawerheightoption);
1550 SET_BYTE(dd_newwindow_detailpen, 255);
1551 SET_BYTE(dd_newwindow_blockpen, 255);
1552 SET_LONG(dd_newwindow_idcmpflags, 0);
1553 SET_LONG(dd_newwindow_flags, 0x240027f);
1554 SET_LONG(dd_newwindow_firstgadget, 0);
1555 SET_LONG(dd_newwindow_checkmark, 0);
1556 SET_LONG(dd_newwindow_title, 0);
1557 SET_LONG(dd_newwindow_screen, 0);
1558 SET_LONG(dd_newwindow_bitmap, 0);
1559 SET_WORD(dd_newwindow_minwidth, 90);
1560 SET_WORD(dd_newwindow_minheight, 40);
1561 SET_WORD(dd_newwindow_maxwidth, 65535);
1562 SET_WORD(dd_newwindow_maxheight, 65535);
1563 SET_WORD(dd_newwindow_type, 1);
1564 SET_LONG(dd_currentx, drawervleftoption);
1565 SET_LONG(dd_currenty, drawervtopoption);
1567 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1569 cleanup("Error writing olddrawerdata structure to outfile!", 1);
1575 /****************************************************************************************/
1577 static void writenewdrawerdata(void)
1579 struct newdrawerdata dd;
1581 if (!drawerdataoption) return;
1583 #undef ACT_STRUCT
1584 #define ACT_STRUCT dd
1586 SET_LONG(dd_flags, drawershowoption);
1587 SET_WORD(dd_viewmodes, drawershowasoption);
1589 if (fwrite(&dd, 1, sizeof(dd), outfile) != sizeof(dd))
1591 cleanup("Error writing newdrawerdata structure to outfile!", 1);
1596 /****************************************************************************************/
1598 static void writeword(WORD l)
1600 UBYTE f[2];
1602 f[0] = (l >> 8) & 0xFF;
1603 f[1] = l & 0xFF;
1605 if (fwrite(f, 1, 2, outfile) != 2)
1607 cleanup("Error writing word value!", 1);
1612 /****************************************************************************************/
1614 static void writelong(LONG l)
1616 UBYTE f[4];
1618 f[0] = (l >> 24) & 0xFF;
1619 f[1] = (l >> 16) & 0xFF;
1620 f[2] = (l >> 8) & 0xFF;
1621 f[3] = l & 0xFF;
1623 if (fwrite(f, 1, 4, outfile) != 4)
1625 cleanup("Error writing long value!", 1);
1630 /****************************************************************************************/
1632 #if (0)
1633 static void writenormalstring(char *s)
1635 int len = strlen(s) + 1;
1637 if (fwrite(s, 1, len, outfile) != len)
1639 cleanup("Error writing string!", 1);
1642 #endif
1644 /****************************************************************************************/
1646 static void writestring(char *s)
1648 int len = strlen(s) + 1;
1650 D(printf("String: \"%s\", length %d\n", s, len));
1652 writelong(len);
1654 if (fwrite(s, 1, len, outfile) != len)
1656 cleanup("Error writing string!", 1);
1661 /****************************************************************************************/
1663 static void writeimage(struct ILBMImage *img)
1665 struct image i;
1666 LONG d, y;
1668 #undef ACT_STRUCT
1669 #define ACT_STRUCT i
1671 SET_WORD(leftedge, 0);
1672 SET_WORD(topedge, 0);
1673 SET_WORD(width, img->planarbmh.bmh_Width);
1674 SET_WORD(height, img->planarbmh.bmh_Height);
1675 SET_WORD(depth, img->planarbmh.bmh_Depth);
1676 SET_LONG(imagedata, BOOL_YES);
1677 SET_BYTE(planepick, (1 << img->planarbmh.bmh_Depth) - 1);
1678 SET_BYTE(planeonoff, 0);
1679 SET_LONG(nextimage, 0);
1681 if (fwrite(&i, 1, sizeof(i), outfile) != sizeof(i))
1683 cleanup("Error writing image structure to outfile!", 1);
1686 for(d = 0; d < img->planarbmh.bmh_Depth; d++)
1688 UBYTE *dat = img->planarbuffer + img->bpr * d;
1690 for(y = 0; y < img->planarbmh.bmh_Height; y++)
1692 if(fwrite(dat, 1, img->bpr, outfile) != img->bpr)
1694 cleanup("Error writing image data to outfile!", 1);
1696 dat += (img->planarbmh.bmh_Depth * img->bpr);
1702 /****************************************************************************************/
1704 struct facechunk
1706 UBYTE fc_width;
1707 UBYTE fc_height;
1708 UBYTE fc_flags;
1709 UBYTE fc_aspect;
1710 UBYTE fc_maxpalettebytes[2];
1713 /****************************************************************************************/
1715 struct imagchunk
1717 UBYTE ic_transparentcolour;
1718 UBYTE ic_numcolours;
1719 UBYTE ic_flags;
1720 UBYTE ic_imageformat;
1721 UBYTE ic_paletteformat;
1722 UBYTE ic_depth;
1723 UBYTE ic_numimagebytes[2];
1724 UBYTE ic_numpalettebytes[2];
1727 /****************************************************************************************/
1729 static LONG writefacechunk(void)
1731 struct facechunk fc;
1732 LONG palbytes;
1734 #undef ACT_STRUCT
1735 #define ACT_STRUCT fc
1737 writelong(ID_FACE);
1738 writelong(sizeof(struct facechunk));
1740 SET_BYTE(fc_width, img1.bmh.bmh_Width - 1);
1741 SET_BYTE(fc_height, img1.bmh.bmh_Height - 1);
1742 SET_BYTE(fc_flags, 0);
1743 SET_BYTE(fc_aspect, 0); // 0x11);
1745 palbytes = (img1.cmapentries > img2.cmapentries) ? img1.cmapentries : img2.cmapentries;
1746 palbytes = palbytes * 3;
1748 SET_WORD(fc_maxpalettebytes, palbytes - 1);
1750 if (fwrite(&fc, 1, sizeof(fc), outfile) != sizeof(fc))
1752 cleanup("Error writing face chunk!", 1);
1755 return sizeof(struct facechunk) + 8;
1758 /****************************************************************************************/
1760 /* createrle() based on ModifyIcon source by Dirk Stöcker */
1762 /****************************************************************************************/
1764 static char * createrle(unsigned long depth, unsigned char *dtype, LONG *dsize, unsigned long size,
1765 unsigned char *src)
1767 int i, j, k;
1768 unsigned long bitbuf, numbits;
1769 unsigned char *buf;
1770 long ressize, numcopy, numequal;
1772 buf = malloc(size * 2);
1773 if (!buf) return NULL;
1775 numcopy = 0;
1776 numequal = 1;
1777 bitbuf = 0;
1778 numbits = 0;
1779 ressize = 0;
1780 k = 0; /* the really output pointer */
1781 for(i = 1; numequal || numcopy;)
1783 if(i < size && numequal && (src[i-1] == src[i]))
1785 ++numequal; ++i;
1787 else if(i < size && numequal*depth <= 16)
1789 numcopy += numequal; numequal = 1; ++i;
1791 else
1793 /* care for end case, where it maybe better to join the two */
1794 if(i == size && numcopy + numequal <= 128 && (numequal-1)*depth <= 8)
1796 numcopy += numequal; numequal = 0;
1798 if(numcopy)
1800 if((j = numcopy) > 128) j = 128;
1801 bitbuf = (bitbuf<<8) | (j-1);
1802 numcopy -= j;
1804 else
1806 if((j = numequal) > 128) j = 128;
1807 bitbuf = (bitbuf<<8) | (256-(j-1));
1808 numequal -= j;
1809 k += j-1;
1810 j = 1;
1812 buf[ressize++] = (bitbuf >> numbits);
1813 while(j--)
1815 numbits += depth;
1816 bitbuf = (bitbuf<<depth) | src[k++];
1817 if(numbits >= 8)
1819 numbits -= 8;
1820 buf[ressize++] = (bitbuf >> numbits);
1823 if(i < size && !numcopy && !numequal)
1825 numequal = 1; ++i;
1829 if(numbits)
1830 buf[ressize++] = bitbuf << (8-numbits);
1832 if(ressize > size) /* no RLE */
1834 ressize = size;
1835 *dtype = 0;
1836 for(i = 0; i < size; ++i)
1837 buf[i]= src[i];
1839 else
1840 *dtype = 1;
1842 *dsize = ressize;
1844 return buf;
1847 /****************************************************************************************/
1849 static LONG writeimagchunk(struct ILBMImage *img)
1851 struct imagchunk ic;
1852 LONG imagsize;
1853 UBYTE skippalette = 0;
1854 UBYTE *pal, *gfx;
1855 LONG palsize, gfxsize;
1856 UBYTE palpacked, gfxpacked;
1858 imagsize = sizeof(struct imagchunk);
1860 /* if this is second image check whether palette is identical to
1861 the one of first image */
1863 if (img == &img2)
1865 if (img1.cmapentries == img2.cmapentries)
1867 WORD i;
1869 for (i = 0; i < img1.cmapentries; i++)
1871 if (img1.rgb[i][0] != img2.rgb[i][0]) break;
1872 if (img1.rgb[i][1] != img2.rgb[i][1]) break;
1873 if (img1.rgb[i][2] != img2.rgb[i][2]) break;
1876 if (i == img1.cmapentries) skippalette = 1;
1880 if (!skippalette)
1882 pal = createrle(8,
1883 &palpacked,
1884 &palsize,
1885 img->cmapentries * 3,
1886 (unsigned char *)img->rgb);
1888 imagsize += palsize;
1891 gfx = createrle(img->bmh.bmh_Depth,
1892 &gfxpacked,
1893 &gfxsize,
1894 img->bmh.bmh_Width * img->bmh.bmh_Height,
1895 img->chunkybuffer);
1897 imagsize += gfxsize;
1899 #undef ACT_STRUCT
1900 #define ACT_STRUCT ic
1902 SET_BYTE(ic_transparentcolour, transparentoption);
1903 if (skippalette)
1905 SET_BYTE(ic_numcolours, 0);
1906 SET_BYTE(ic_flags, (transparentoption != -1) ? 1 : 0); /* 1 = HasTransparentColour */
1907 SET_BYTE(ic_paletteformat, 0);
1908 SET_WORD(ic_numpalettebytes, 0);
1910 else
1912 SET_BYTE(ic_numcolours, img->cmapentries - 1);
1913 SET_BYTE(ic_flags, (transparentoption != -1) ? 3 : 2); /* 2 = HasPalette */
1914 SET_BYTE(ic_paletteformat, palpacked);
1915 SET_WORD(ic_numpalettebytes, palsize - 1);
1918 SET_BYTE(ic_imageformat, gfxpacked);
1919 SET_BYTE(ic_depth, img->bmh.bmh_Depth);
1920 SET_WORD(ic_numimagebytes, gfxsize - 1);
1922 writelong(ID_IMAG);
1923 writelong(imagsize);
1925 if (fwrite(&ic, 1, sizeof(ic), outfile) != sizeof(ic))
1927 cleanup("Error writing imag chunk!", 1);
1930 if (fwrite(gfx, 1, gfxsize, outfile) != gfxsize)
1932 cleanup("Error write gfx data in imag chunk!", 1);
1935 if (!skippalette)
1937 if (fwrite(pal, 1, palsize, outfile) != palsize)
1939 cleanup("Error write palette data in imag chunk!", 1);
1943 if (imagsize & 1)
1945 UBYTE dummy = 0;
1947 if (fwrite(&dummy, 1, 1, outfile) != 1)
1949 cleanup("Error writing imag chunk!", 1);
1952 imagsize++;
1955 return imagsize + 8;
1958 /****************************************************************************************/
1959 static LONG writeargb(APTR argb, ULONG argb_size)
1961 LONG formsize = 10;
1962 #if (0)
1963 struct ARGB35_Header {
1964 ULONG ztype; /* Always 1 */
1965 ULONG zsize; /* Compressed size, or -1 */
1966 UWORD resv; /* Always 0 */
1967 } ahdr;
1968 #endif
1969 Bytef *zdest;
1970 uLongf zsize, size;
1971 int err;
1973 zsize = size = argb_size;
1975 zdest = malloc(zsize);
1976 if (!zdest)
1977 return 0;
1979 err = compress(zdest, &zsize, argb, size);
1980 if (err != Z_OK) {
1981 free(zdest);
1982 return 0;
1985 D(printf("ARGB: Compressed %d => %d\n", size, zsize));
1987 writelong(ID_ARGB);
1988 formsize = 10 + zsize;
1989 writelong(formsize);
1990 writelong(1);
1991 writelong(zsize);
1992 writeword(0);
1993 fwrite(zdest, 1, zsize, outfile);
1994 if (zsize & 1) {
1995 char c = 0;
1996 fwrite(&c, 1, 1, outfile);
1999 free(zdest);
2001 if (formsize & 1)
2002 formsize++;
2003 return 8 + formsize;
2006 /****************************************************************************************/
2008 static void write35data(void)
2010 LONG formsize = 4;
2011 LONG formsizeseek;
2013 if (nosaveIFF)
2014 return;
2016 writelong(ID_FORM);
2017 formsizeseek = ftell(outfile);
2018 writelong(0x12345678);
2019 writelong(ID_ICON);
2021 formsize += writefacechunk();
2022 formsize += writeimagchunk(&img1);
2023 if (image2option) formsize += writeimagchunk(&img2);
2025 if (!nosaveARGB && img1.argb) {
2026 formsize += writeargb(img1.argb, img1.argb_size);
2029 if (!nosaveARGB && img2.argb) {
2030 formsize += writeargb(img2.argb, img2.argb_size);
2033 if (!nosavePNG && img1.png) {
2034 writelong(ID_PNG);
2035 writelong(img1.png_size);
2036 fwrite(img1.png, 1, img1.png_size, outfile);
2037 if (img1.png_size & 1) {
2038 char c = 0;
2039 fwrite(&c, 1, 1, outfile);
2040 img1.png_size++;
2042 formsize += 8 + img1.png_size;
2045 if (!nosavePNG && img2.png) {
2046 writelong(ID_PNG);
2047 writelong(img2.png_size);
2048 fwrite(img2.png, 1, img2.png_size, outfile);
2049 if (img2.png_size & 1) {
2050 char c = 0;
2051 fwrite(&c, 1, 1, outfile);
2052 img2.png_size++;
2054 formsize += 8 + img2.png_size;
2057 fseek(outfile, formsizeseek, SEEK_SET);
2058 writelong(formsize);
2061 /****************************************************************************************/
2063 static void writeicon(void)
2065 #if (0)
2066 struct diskobject dobj;
2067 #endif
2069 D(printf("Writing %s\n", outfilename));
2070 outfile = fopen(outfilename, "wb");
2071 if (!outfile) cleanup("Can't open output file for writing!", 1);
2073 writediskobject();
2074 writeolddrawerdata();
2075 writeimage(&img1);
2077 if (image2option) writeimage(&img2);
2079 if (defaulttooloption) writestring(defaulttooloption);
2081 if (tooltypesoption)
2083 char **strarray;
2084 LONG numtooltypes = 0;
2086 for(strarray = tooltypesoption; *strarray; strarray++, numtooltypes++);
2088 writelong((numtooltypes + 1) * 4);
2090 for(strarray = tooltypesoption; *strarray; strarray++)
2092 writestring(*strarray);
2097 /* toolwindow would have to be saved in between here if there is any */
2099 writenewdrawerdata();
2101 write35data();
2105 /****************************************************************************************/
2107 static void remapicon(void)
2109 remapplanar(&img1, &std4colpal);
2110 if (image2option) remapplanar(&img2, &std4colpal);
2113 /****************************************************************************************/
2115 int main(int argc, char **argv)
2117 getarguments(argc, argv);
2118 parseiconsource();
2119 loadimage(image1option, &img1);
2120 if (image2option) {
2121 loadimage(image2option, &img2);
2122 if ((img2.bmh.bmh_Width && img2.bmh.bmh_Width != img1.bmh.bmh_Width) ||
2123 (img2.bmh.bmh_Height && img2.bmh.bmh_Height != img1.bmh.bmh_Height)) {
2124 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);
2128 remapicon();
2129 writeicon();
2131 cleanup(0, 0);
2133 return 0;
2136 /****************************************************************************************/