2 Copyright © 1995-2008, The AROS Development Team. All rights reserved.
5 Desc: Tool to convert IFF ILBM images into Amiga icon file.
11 /****************************************************************************************/
19 /****************************************************************************************/
21 #define MAKE_ID(a,b,c,d) (((a)<<24) | ((b)<<16) | ((c)<<8) | ((d)))
23 #define ID_FORM MAKE_ID('F','O','R','M')
24 #define ID_ILBM MAKE_ID('I','L','B','M')
25 #define ID_CMAP MAKE_ID('C','M','A','P')
26 #define ID_BODY MAKE_ID('B','O','D','Y')
27 #define ID_BMHD MAKE_ID('B','M','H','D')
29 #define ID_ICON MAKE_ID('I','C','O','N')
30 #define ID_FACE MAKE_ID('F','A','C','E')
31 #define ID_IMAG MAKE_ID('I','M','A','G')
34 #define CMP_BYTERUN1 1
38 /****************************************************************************************/
40 /* For this tool it does not really matter if the following types
41 have a bigger sizeof() than on Amiga */
45 typedef unsigned long ULONG
;
47 typedef unsigned short UWORD
;
50 typedef unsigned char UBYTE
;
52 #include <exec/types.h>
55 /****************************************************************************************/
65 UBYTE bmh_Compression
;
67 UWORD bmh_Transparent
;
74 /****************************************************************************************/
78 struct BitMapHeader bmh
;
79 struct BitMapHeader planarbmh
;
80 unsigned char *planarbuffer
, *chunkybuffer
;
81 LONG cmapentries
, bpr
, totdepth
;
83 UBYTE remaptable
[256];
86 /****************************************************************************************/
94 /****************************************************************************************/
96 struct Palette std4colpal
=
107 /****************************************************************************************/
109 static char *filename
, *outfilename
, *infilename
;
110 static unsigned char *filebuffer
, *body
;
111 static FILE *file
, *outfile
, *infile
;
112 static long filesize
, bodysize
, bodysize_packed
;
114 static struct ILBMImage img1
, img2
;
115 static BOOL have_bmhd
, have_cmap
, have_body
, is_png
;
117 static char *image1option
;
118 static char *image2option
;
119 static char *defaulttooloption
;
120 static char *drawerdataoption
;
121 static char **tooltypesoption
;
122 static LONG typeoption
= 3; /* WBTOOL */
123 static LONG iconleftoption
= 0x80000000; /* NO_ICON_POSITION */
124 static LONG icontopoption
= 0x80000000; /* NO_ICON_POSITION */
125 static LONG stackoption
= 4096;
126 static LONG drawerleftoption
= 0;
127 static LONG drawertopoption
= 20;
128 static LONG drawerwidthoption
= 300;
129 static LONG drawerheightoption
= 100;
130 static LONG drawervleftoption
= 0;
131 static LONG drawervtopoption
= 0;
132 static LONG drawershowoption
= 0;
133 static LONG drawershowasoption
= 0;
134 static LONG transparentoption
= 0;
136 static BOOL dualpng
; /* png file contains second image */
137 static unsigned char *dualpngstart
; /* address of 2nd image in filebuffer */
139 /****************************************************************************************/
141 static void freeimage(struct ILBMImage
*img
)
143 if (img
->chunkybuffer
)
145 free(img
->chunkybuffer
);
146 img
->chunkybuffer
= NULL
;
149 if (img
->planarbuffer
)
151 free(img
->planarbuffer
);
152 img
->planarbuffer
= NULL
;
170 /****************************************************************************************/
172 static void cleanup(char *msg
, int rc
)
174 if (msg
) fprintf(stderr
, "ilbmtoicon: %s\n", msg
);
179 if (outfile
) fclose(outfile
);
180 if (infile
) fclose(infile
);
185 /****************************************************************************************/
187 static void getarguments(int argc
, char **argv
)
191 if ((argc
!= 4) && (argc
!= 5))
193 fprintf(stderr
, "Wrong number of arguments\n");
194 cleanup("Usage: ilbmtoicon icondescription image1 [image2] filename", 1);
199 infilename
= argv
[1];
200 image1option
= argv
[2];
201 outfilename
= argv
[3];
205 infilename
= argv
[1];
206 image1option
= argv
[2];
207 image2option
= argv
[3];
208 outfilename
= argv
[4];
212 /****************************************************************************************/
214 static char *skipblanks(char *s
)
216 while ((*s
== ' ') || (*s
== '\t')) s
++;
221 /****************************************************************************************/
223 static char *skipword(char *s
)
236 /****************************************************************************************/
238 static char *checkquotes(char *s
)
253 while((*s2
!= '"') && (*s2
!= '\0')) s2
++;
259 /****************************************************************************************/
261 #define KEYWORD_STRING 0
262 #define KEYWORD_INTEGER 1
263 #define KEYWORD_STRINGARRAY 2
264 #define KEYWORD_CYCLE 3
266 #define MAX_ARRAY_SIZE 200
268 /****************************************************************************************/
276 struct cycle typecycles
[] =
288 struct cycle showcycles
[] =
297 struct cycle showascycles
[] =
310 /****************************************************************************************/
321 {KEYWORD_STRING
, "DEFAULTTOOL" , &defaulttooloption
, NULL
},
322 {KEYWORD_STRING
, "DRAWERDATA" , &drawerdataoption
, NULL
},
323 {KEYWORD_CYCLE
, "TYPE" , &typeoption
, typecycles
},
324 {KEYWORD_STRINGARRAY
, "TOOLTYPE" , &tooltypesoption
, NULL
},
325 {KEYWORD_INTEGER
, "STACK" , &stackoption
, NULL
},
326 {KEYWORD_INTEGER
, "ICONLEFTPOS" , &iconleftoption
, NULL
},
327 {KEYWORD_INTEGER
, "ICONTOPPOS" , &icontopoption
, NULL
},
328 {KEYWORD_INTEGER
, "DRAWERLEFTPOS" , &drawerleftoption
, NULL
},
329 {KEYWORD_INTEGER
, "DRAWERTOPPOS" , &drawertopoption
, NULL
},
330 {KEYWORD_INTEGER
, "DRAWERWIDTH" , &drawerwidthoption
, NULL
},
331 {KEYWORD_INTEGER
, "DRAWERHEIGHT" , &drawerheightoption
, NULL
},
332 {KEYWORD_INTEGER
, "DRAWERVIEWLEFT" , &drawervleftoption
, NULL
},
333 {KEYWORD_INTEGER
, "DRAWERVIEWTOP" , &drawervtopoption
, NULL
},
334 {KEYWORD_CYCLE
, "DRAWERSHOW" , &drawershowoption
, showcycles
},
335 {KEYWORD_CYCLE
, "DRAWERSHOWAS" , &drawershowoption
, showascycles
},
336 {KEYWORD_INTEGER
, "TRANSPARENT" , &transparentoption
, NULL
},
341 /****************************************************************************************/
343 static void handleoption(char *keyword
, char *keyvalue
)
348 for(kw
= keywordtable
; kw
->keyword
; kw
++)
350 if (strcasecmp(kw
->keyword
, keyword
) == 0)
355 *(char **)kw
->store
= strdup(keyvalue
);
356 if (!(*(char **)kw
->store
)) cleanup("Out of memory!", 1);
359 case KEYWORD_INTEGER
:
360 *(LONG
*)kw
->store
= strtol(keyvalue
, 0, 0);
364 for(cy
= (struct cycle
*)kw
->extra
; cy
->keyword
; cy
++)
366 if (strcasecmp(keyvalue
, cy
->keyword
) == 0)
368 *(LONG
*)kw
->store
= cy
->value
;
374 case KEYWORD_STRINGARRAY
:
375 if (!(*(char ***)kw
->store
))
377 *(char ***)kw
->store
= (char **)malloc(MAX_ARRAY_SIZE
* sizeof(char *));
378 if (!(*(char ***)kw
->store
)) cleanup("Out of memory!", 1);
380 memset(*(char ***)kw
->store
, 0, MAX_ARRAY_SIZE
* sizeof(char *));
385 char **strarray
= *(char ***)kw
->store
;
388 dupvalue
= strdup(keyvalue
);
389 if (!dupvalue
) cleanup("Out of memory!", 1);
397 if (i
>= MAX_ARRAY_SIZE
- 1) cleanup("Array overflow!", 1);
399 *strarray
= dupvalue
;
402 } /* switch(kw->type) */
406 } /* if (strcasecmp(kw->keyword, keyword) == 0) */
408 } /* for(kw = keywordtable; kw->keyword; kw++) */
412 /****************************************************************************************/
414 static void parseline(char *s
)
417 char *keyvalue
= NULL
;
421 if (*s
== '#') return;
422 if (*s
== ';') return;
427 if (*s
== '\0') return;
430 s
= skipblanks(s
+ 1);
432 if (*s
== '=') s
= skipblanks(s
+ 1);
433 if (*s
== '\0') return;
435 keyvalue
= checkquotes(s
);
437 handleoption(keyword
, keyvalue
);
440 /****************************************************************************************/
442 static void parseiconsource(void)
446 infile
= fopen(infilename
, "r");
449 while(fgets(s
, sizeof(s
), infile
))
459 /****************************************************************************************/
461 static void showoptions(void)
465 printf("image1: %s\n", image1option
? image1option
: "(NULL)");
466 printf("image2: %s\n", image2option
? image2option
: "(NULL)");
467 printf("type: %ld\n", typeoption
);
469 strarray
= tooltypesoption
;
472 printf("tooltypes:\n");
475 printf(" %s\n", *strarray
++);
480 /****************************************************************************************/
482 static ULONG
getlong(void)
486 if (filepos
> filesize
- 4) cleanup("Tried to read over file end!", 1);
488 ret
= filebuffer
[filepos
++] * 0x1000000;
489 ret
+= filebuffer
[filepos
++] * 0x10000;
490 ret
+= filebuffer
[filepos
++] * 0x100;
491 ret
+= filebuffer
[filepos
++];
496 /****************************************************************************************/
498 static UWORD
getword(void)
502 if (filepos
> filesize
- 2) cleanup("Tried to read over file end!", 1);
504 ret
= filebuffer
[filepos
++] * 0x100;
505 ret
+= filebuffer
[filepos
++];
510 /****************************************************************************************/
512 static UBYTE
getbyte(void)
516 if (filepos
> filesize
- 1) cleanup("Tried to read over file end!", 1);
517 ret
= filebuffer
[filepos
++];
522 /****************************************************************************************/
524 static void skipbytes(ULONG howmany
)
529 /****************************************************************************************/
531 static void openimage(struct ILBMImage
*img
)
533 file
= fopen(filename
, "rb");
534 if (!file
) cleanup("Can't open file!", 1);
536 fseek(file
, 0, SEEK_END
);
537 filesize
= ftell(file
);
539 if (filesize
< 12) cleanup("Bad file size!", 1);
541 //fprintf(stderr, "Filesize is %d\n", filesize);
543 fseek(file
, 0, SEEK_SET
);
545 filebuffer
= malloc(filesize
+ 10);
546 if (!filebuffer
) cleanup("Memory allocation for file buffer failed!", 1);
548 if (fread(filebuffer
, 1, filesize
, file
) != filesize
)
549 cleanup("Error reading file!", 1);
551 fclose(file
); file
= NULL
;
554 /****************************************************************************************/
556 static void checkimage(struct ILBMImage
*img
)
558 static UBYTE pngsig
[8] = {137, 80, 78, 71, 13, 10, 26, 10};
563 if (memcmp(filebuffer
, pngsig
, 8) == 0)
567 /* search for second image */
570 dualpngstart
= filebuffer
+ 8 ;
571 dualpngstart
< filebuffer
+ filesize
- 8 ;
575 if (memcmp(dualpngstart
, pngsig
, 8) == 0)
582 else if (is_png
== 0)
585 if (id
!= ID_FORM
) cleanup("File is not an IFF file!", 1);
588 if (size
!= filesize
- 8) cleanup("File is IFF, but has bad size in IFF header!", 1);
591 if (id
!= ID_ILBM
) cleanup("File is IFF, but not of type ILBM!", 1);
593 else if (is_png
== 1)
595 cleanup("Second image must be a PNG image, too!", 1);
599 /****************************************************************************************/
601 static void scanimage(struct ILBMImage
*img
)
617 //fprintf(stderr, "Chunk: %c%c%c%c Size: %d\n", id >> 24, id >> 16, id >> 8, id, size);
622 if (size
!= 20) cleanup("Bad BMHD chunk size!", 1);
624 img
->bmh
.bmh_Width
= getword();
625 img
->bmh
.bmh_Height
= getword();
626 img
->bmh
.bmh_Left
= (WORD
)getword();
627 img
->bmh
.bmh_Top
= (WORD
)getword();
628 img
->bmh
.bmh_Depth
= getbyte();
629 img
->bmh
.bmh_Masking
= getbyte();
630 img
->bmh
.bmh_Compression
= getbyte();
631 img
->bmh
.bmh_Pad
= getbyte();
632 img
->bmh
.bmh_Transparent
= getword();
633 img
->bmh
.bmh_XAspect
= getbyte();
634 img
->bmh
.bmh_YAspect
= getbyte();
635 img
->bmh
.bmh_PageWidth
= (WORD
)getword();
636 img
->bmh
.bmh_PageHeight
= (WORD
)getword();
638 if (img
->bmh
.bmh_Depth
> 8) cleanup("ILBM file has too many colors!", 1);
639 if ((img
->bmh
.bmh_Compression
!= CMP_NONE
) && (img
->bmh
.bmh_Compression
!= CMP_BYTERUN1
)) cleanup("Compression method unsupported!", 1);
643 img
->totdepth
= img
->bmh
.bmh_Depth
+ ((img
->bmh
.bmh_Masking
== MSK_HASMASK
) ? 1 : 0);
645 img
->bpr
= ((img
->bmh
.bmh_Width
+ 15) & ~15) / 8;
647 /*fprintf(stderr, "BMHD: %d x %d x %d (%d)\n", img->bmh.bmh_Width,
651 img
->planarbmh
= img
->bmh
;
655 if (!have_bmhd
) cleanup("CMAP chunk before BMHD chunk (or no BMHD chunk at all!", 1);
657 img
->cmapentries
= size
/ 3;
658 if (size
& 1) size
++;
660 if ((img
->cmapentries
< 2) || (img
->cmapentries
> 256)) cleanup("CMAP chunk has bad number of entries!", 1);
662 for(i
= 0; i
< img
->cmapentries
; i
++)
664 img
->rgb
[i
][0] = getbyte();
665 img
->rgb
[i
][1] = getbyte();
666 img
->rgb
[i
][2] = getbyte();
677 if (!have_bmhd
) cleanup("BODY chunk before BMHD chunk (or no BMHD chunk at all!", 1);
678 body
= &filebuffer
[filepos
];
681 if (img
->bmh
.bmh_Compression
== CMP_NONE
)
683 LONG shouldbesize
= img
->totdepth
* img
->bpr
* img
->bmh
.bmh_Height
;
684 if (bodysize
!= shouldbesize
) cleanup("BODY chunk size seems to be wrong!", 1);
691 if (size
& 1) size
++;
696 if (filepos
== filesize
) break;
697 if (have_bmhd
&& have_body
&& have_cmap
) break;
700 if (!have_bmhd
) cleanup("BMHD chunk missing!", 1);
701 if (!have_body
) cleanup("BODY chunk missing!", 1);
704 /****************************************************************************************/
706 static unsigned char *unpack_byterun1(unsigned char *source
, unsigned char *dest
, LONG unpackedsize
)
713 c
= (signed char)(*source
++);
719 if (--unpackedsize
<= 0) return source
;
730 if (--unpackedsize
<= 0) return source
;
737 /****************************************************************************************/
739 static BOOL
norm1(LONG count
, unsigned char **source_backup
,
740 unsigned char **dest
, LONG
*checksize
)
742 //if (count >= 0) fprintf(stderr, "XX: non packable %d\n",count);
748 if (step
> 127) step
= 127;
753 if (*checksize
<= 0) return 0;
762 *(*dest
)++ = *(*source_backup
)++;
772 static BOOL
copy1(unsigned char r
, LONG count
, unsigned char **dest
, LONG
*checksize
)
774 //if (count >= 1) fprintf(stderr, "XX: repeat %02x x %d\n", r, count);
780 if (step
> 127) step
= 127;
785 if (*checksize
<= 0) return 0;
787 *(*dest
)++ = (unsigned char)step
;
794 static BOOL
pack_byterun1(unsigned char *source
, unsigned char *dest
,
795 LONG size
, LONG check_size
, LONG
*packsize
)
797 unsigned char *source_backup
, *dest_backup
;
798 LONG samebytes_counter
, samebytes
, count
;
799 LONG checksize
= check_size
;
800 unsigned char oldbyte
, actbyte
;
802 if (checksize
< 0) checksize
= 0x7FFFFFFF;
805 samebytes_counter
= 0;
806 source_backup
= source
;
811 //fprintf(stderr, "size = %d. checksize = %d\n", size, checksize);
812 if (--size
< 0) break;
814 if (actbyte
== oldbyte
)
822 samebytes
= samebytes_counter
;
823 samebytes_counter
= 1;
825 if (samebytes
< 3) continue;
827 count
= (LONG
)(source
- source_backup
- samebytes
- 2);
828 if (!norm1(count
, &source_backup
, &dest
, &checksize
)) return 0;
830 if (!copy1(source
[-2], samebytes
, &dest
, &checksize
)) return 0;
832 source_backup
= source
- 1;
834 //fprintf(stderr, "done\n");
836 if (samebytes_counter
>= 3)
838 samebytes
= samebytes_counter
;
839 count
= (LONG
)(source
- source_backup
- samebytes
- 1);
840 if (!norm1(count
, &source_backup
, &dest
, &checksize
)) return 0;
841 if (!copy1(source
[-2], samebytes
, &dest
, &checksize
)) return 0;
845 count
= (LONG
)(source
- source_backup
- 1);
846 if (!norm1(count
, &source_backup
, &dest
, &checksize
)) return 0;
848 //fprintf(stderr, "realdone\n");
850 if (packsize
) *packsize
= (LONG
)(dest
- dest_backup
);
855 /****************************************************************************************/
857 static void p2c(unsigned char *source
, unsigned char *dest
, LONG width
, LONG height
,
858 LONG totplanes
, LONG wantplanes
, LONG chunkybpr
)
860 LONG alignedwidth
, x
, y
, p
, bpr
, bpl
;
862 alignedwidth
= (width
+ 15) & ~15;
863 bpr
= alignedwidth
/ 8;
864 bpl
= bpr
* totplanes
;
866 for(y
= 0; y
< height
; y
++)
868 for(x
= 0; x
< width
; x
++)
870 LONG mask
= 0x80 >> (x
& 7);
872 unsigned char chunkypix
= 0;
874 for(p
= 0; p
< wantplanes
; p
++)
876 if (source
[p
* bpr
+ offset
] & mask
) chunkypix
|= (1 << p
);
888 /****************************************************************************************/
890 static void c2p(unsigned char *source
, unsigned char *dest
, LONG width
, LONG height
, LONG planes
)
892 LONG alignedwidth
, x
, y
, p
, bpr
, bpl
;
894 alignedwidth
= (width
+ 15) & ~15;
895 bpr
= alignedwidth
/ 8;
898 for(y
= 0; y
< height
; y
++)
900 for(x
= 0; x
< width
; x
++)
902 LONG mask
= 0x80 >> (x
& 7);
904 unsigned char chunkypix
= source
[x
];
906 for(p
= 0; p
< planes
; p
++)
908 if (chunkypix
& (1 << p
))
909 dest
[p
* bpr
+ offset
] |= mask
;
911 dest
[p
* bpr
+ offset
] &= ~mask
;
921 /****************************************************************************************/
923 static void convertbody(struct ILBMImage
*img
)
925 LONG unpackedsize
= img
->bpr
* img
->bmh
.bmh_Height
* img
->totdepth
;
927 img
->planarbuffer
= malloc(unpackedsize
);
928 if (!img
->planarbuffer
) cleanup("Memory allocation for planar buffer failed!", 1);
930 if (img
->bmh
.bmh_Compression
== CMP_NONE
)
932 memcpy(img
->planarbuffer
, body
, unpackedsize
);
936 unpack_byterun1(body
, img
->planarbuffer
, unpackedsize
);
939 img
->chunkybuffer
= malloc(img
->bmh
.bmh_Width
* img
->bmh
.bmh_Height
);
940 if (!img
->chunkybuffer
) cleanup("Memory allocation for chunky buffer failed!", 1);
942 p2c(img
->planarbuffer
,
951 /****************************************************************************************/
953 static UBYTE
findcolor(struct Palette
*pal
, ULONG r
, ULONG g
, ULONG b
)
955 ULONG dist
, bestdist
= 0xFFFFFFFF;
958 for(i
= 0; i
< pal
->numentries
; i
++)
960 LONG r1
, g1
, b1
, r2
, g2
, b2
, dr
, dg
, db
;
966 r2
= (LONG
)pal
->rgb
[i
][0];
967 g2
= (LONG
)pal
->rgb
[i
][1];
968 b2
= (LONG
)pal
->rgb
[i
][2];
974 dist
= (dr
* dr
) + (dg
* dg
) + (db
* db
);
986 /****************************************************************************************/
988 static void remapplanar(struct ILBMImage
*img
, struct Palette
*pal
)
991 LONG i
, x
, y
, highestcol
= 0, newdepth
= 0;
993 remapbuffer
= malloc(img
->bmh
.bmh_Width
* img
->bmh
.bmh_Height
);
994 if (!remapbuffer
) cleanup("Error allocating remap buffer!", 1);
996 for(i
= 0; i
< img
->cmapentries
; i
++)
998 img
->remaptable
[i
] = findcolor(pal
, img
->rgb
[i
][0], img
->rgb
[i
][1], img
->rgb
[i
][2]);
1001 for(i
= 0; i
< img
->bmh
.bmh_Width
* img
->bmh
.bmh_Height
; i
++)
1003 remapbuffer
[i
] = img
->remaptable
[img
->chunkybuffer
[i
]];
1005 if (remapbuffer
[i
] > highestcol
)
1006 highestcol
= remapbuffer
[i
];
1009 for(i
= highestcol
; i
; i
>>= 1) newdepth
++;
1010 if (newdepth
== 0) newdepth
= 1;
1012 if (newdepth
> img
->totdepth
)
1014 free(img
->planarbuffer
);
1016 img
->planarbuffer
= malloc(img
->bpr
* img
->bmh
.bmh_Height
* newdepth
);
1017 if (!img
->planarbuffer
)
1020 cleanup("Error re-allocating planar buffer!", 1);
1024 img
->planarbmh
.bmh_Depth
= newdepth
;
1026 memset(img
->planarbuffer
, 0, img
->bpr
* img
->bmh
.bmh_Height
* newdepth
);
1028 c2p(remapbuffer
, img
->planarbuffer
, img
->bmh
.bmh_Width
, img
->bmh
.bmh_Height
, newdepth
);
1033 /****************************************************************************************/
1035 static void loadimage(char *name
, struct ILBMImage
*img
)
1050 /****************************************************************************************/
1055 UBYTE do_version
[2];
1056 UBYTE do_gadget_nextgadget
[4];
1057 UBYTE do_gadget_leftedge
[2];
1058 UBYTE do_gadget_topedge
[2];
1059 UBYTE do_gadget_width
[2];
1060 UBYTE do_gadget_height
[2];
1061 UBYTE do_gadget_flags
[2];
1062 UBYTE do_gadget_activation
[2];
1063 UBYTE do_gadget_gadgettype
[2];
1064 UBYTE do_gadget_gadgetrender
[4];
1065 UBYTE do_gadget_selectrender
[4];
1066 UBYTE do_gadget_gadgettext
[4];
1067 UBYTE do_gadget_mutualexclude
[4];
1068 UBYTE do_gadget_specialinfo
[4];
1069 UBYTE do_gadget_gadgetid
[2];
1070 UBYTE do_gadget_userdata
[4];
1073 UBYTE do_defaulttool
[4];
1074 UBYTE do_tooltypes
[4];
1075 UBYTE do_currentx
[4];
1076 UBYTE do_currenty
[4];
1077 UBYTE do_drawerdata
[4];
1078 UBYTE do_toolwindow
[4];
1079 UBYTE do_stacksize
[4];
1082 /****************************************************************************************/
1084 struct olddrawerdata
1086 UBYTE dd_newwindow_leftedge
[2];
1087 UBYTE dd_newwindow_topedge
[2];
1088 UBYTE dd_newwindow_width
[2];
1089 UBYTE dd_newwindow_height
[2];
1090 UBYTE dd_newwindow_detailpen
;
1091 UBYTE dd_newwindow_blockpen
;
1092 UBYTE dd_newwindow_idcmpflags
[4];
1093 UBYTE dd_newwindow_flags
[4];
1094 UBYTE dd_newwindow_firstgadget
[4];
1095 UBYTE dd_newwindow_checkmark
[4];
1096 UBYTE dd_newwindow_title
[4];
1097 UBYTE dd_newwindow_screen
[4];
1098 UBYTE dd_newwindow_bitmap
[4];
1099 UBYTE dd_newwindow_minwidth
[2];
1100 UBYTE dd_newwindow_minheight
[2];
1101 UBYTE dd_newwindow_maxwidth
[2];
1102 UBYTE dd_newwindow_maxheight
[2];
1103 UBYTE dd_newwindow_type
[2];
1104 UBYTE dd_currentx
[4];
1105 UBYTE dd_currenty
[4];
1108 /****************************************************************************************/
1110 struct newdrawerdata
1113 UBYTE dd_viewmodes
[2];
1116 /****************************************************************************************/
1131 /****************************************************************************************/
1133 #define SET_BYTE(field,value) \
1134 ACT_STRUCT.field = value
1136 #define SET_WORD(field, value) \
1137 ACT_STRUCT.field[0] = ((value) >> 8) & 0xFF; \
1138 ACT_STRUCT.field[1] = (value) & 0xFF;
1140 #define SET_LONG(field,value) \
1141 ACT_STRUCT.field[0] = ((value) >> 24) & 0xFF; \
1142 ACT_STRUCT.field[1] = ((value) >> 16) & 0xFF; \
1143 ACT_STRUCT.field[2] = ((value) >> 8) & 0xFF; \
1144 ACT_STRUCT.field[3] = (value) & 0xFF;
1146 #define BOOL_YES 0x2A2A2A2A
1147 #define BOOL_NO 0x00000000
1149 static void writediskobject(void)
1151 struct diskobject dobj
;
1153 #define ACT_STRUCT dobj
1155 SET_WORD(do_magic
, 0xE310);
1156 SET_WORD(do_version
, 1);
1157 SET_LONG(do_gadget_nextgadget
, 0);
1158 SET_WORD(do_gadget_leftedge
, 0);
1159 SET_WORD(do_gadget_topedge
, 0);
1160 SET_WORD(do_gadget_width
, img1
.bmh
.bmh_Width
);
1161 SET_WORD(do_gadget_height
, img1
.bmh
.bmh_Height
);
1165 /* GFLG_GADGHIMAGE + GFLG_GADGIMAGE */
1166 SET_WORD(do_gadget_flags
, 4 + 2);
1170 /* GFLG_GADGIMAGE */
1171 SET_WORD(do_gadget_flags
, 4);
1174 SET_WORD(do_gadget_activation
, 0);
1175 SET_WORD(do_gadget_gadgettype
, 0);
1176 SET_LONG(do_gadget_gadgetrender
, BOOL_YES
);
1180 SET_LONG(do_gadget_selectrender
, BOOL_YES
);
1184 SET_LONG(do_gadget_selectrender
, BOOL_NO
);
1187 SET_LONG(do_gadget_gadgettext
, 0);
1188 SET_LONG(do_gadget_mutualexclude
, 0);
1189 SET_LONG(do_gadget_specialinfo
, 0);
1190 SET_WORD(do_gadget_gadgetid
, 0);
1191 SET_LONG(do_gadget_userdata
, 1); /* full drawer data */
1193 SET_BYTE(do_type
, typeoption
);
1194 SET_BYTE(do_pad
, 0);
1196 if (defaulttooloption
)
1198 SET_LONG(do_defaulttool
, BOOL_YES
);
1202 SET_LONG(do_defaulttool
, BOOL_NO
);
1205 if (tooltypesoption
)
1207 SET_LONG(do_tooltypes
, BOOL_YES
);
1211 SET_LONG(do_tooltypes
, BOOL_NO
);
1214 SET_LONG(do_currentx
, iconleftoption
);
1215 SET_LONG(do_currenty
, icontopoption
);
1217 if (drawerdataoption
)
1219 SET_LONG(do_drawerdata
, BOOL_YES
);
1223 SET_LONG(do_drawerdata
, BOOL_NO
);
1227 SET_LONG(do_toolwindow
, 0);
1228 SET_LONG(do_stacksize
, stackoption
);
1230 if (fwrite(&dobj
, 1, sizeof(dobj
), outfile
) != sizeof(dobj
))
1232 cleanup("Error writing diskobject structure to outfile!", 1);
1236 /****************************************************************************************/
1238 static void writeolddrawerdata(void)
1240 struct olddrawerdata dd
;
1242 if (!drawerdataoption
) return;
1245 #define ACT_STRUCT dd
1247 SET_WORD(dd_newwindow_leftedge
, drawerleftoption
);
1248 SET_WORD(dd_newwindow_topedge
, drawertopoption
);
1249 SET_WORD(dd_newwindow_width
, drawerwidthoption
);
1250 SET_WORD(dd_newwindow_height
, drawerheightoption
);
1251 SET_BYTE(dd_newwindow_detailpen
, 0);
1252 SET_BYTE(dd_newwindow_blockpen
, 0);
1253 SET_LONG(dd_newwindow_idcmpflags
, 0);
1254 SET_LONG(dd_newwindow_flags
, 0);
1255 SET_LONG(dd_newwindow_firstgadget
, 0);
1256 SET_LONG(dd_newwindow_checkmark
, 0);
1257 SET_LONG(dd_newwindow_title
, 0);
1258 SET_LONG(dd_newwindow_screen
, 0);
1259 SET_LONG(dd_newwindow_bitmap
, 0);
1260 SET_WORD(dd_newwindow_minwidth
, 0);
1261 SET_WORD(dd_newwindow_minheight
, 0);
1262 SET_WORD(dd_newwindow_maxwidth
, 0);
1263 SET_WORD(dd_newwindow_maxheight
, 0);
1264 SET_WORD(dd_newwindow_type
, 0);
1265 SET_LONG(dd_currentx
, drawervleftoption
);
1266 SET_LONG(dd_currenty
, drawervtopoption
);
1268 if (fwrite(&dd
, 1, sizeof(dd
), outfile
) != sizeof(dd
))
1270 cleanup("Error writing olddrawerdata structure to outfile!", 1);
1276 /****************************************************************************************/
1278 static void writenewdrawerdata(void)
1280 struct newdrawerdata dd
;
1282 if (!drawerdataoption
) return;
1285 #define ACT_STRUCT dd
1287 SET_LONG(dd_flags
, drawershowoption
);
1288 SET_WORD(dd_viewmodes
, drawershowasoption
);
1290 if (fwrite(&dd
, 1, sizeof(dd
), outfile
) != sizeof(dd
))
1292 cleanup("Error writing newdrawerdata structure to outfile!", 1);
1297 /****************************************************************************************/
1299 static void writelong(LONG l
)
1303 f
[0] = (l
>> 24) & 0xFF;
1304 f
[1] = (l
>> 16) & 0xFF;
1305 f
[2] = (l
>> 8) & 0xFF;
1308 if (fwrite(f
, 1, 4, outfile
) != 4)
1310 cleanup("Error writing string long value!", 1);
1315 /****************************************************************************************/
1317 static void writenormalstring(char *s
)
1319 int len
= strlen(s
) + 1;
1321 if (fwrite(s
, 1, len
, outfile
) != len
)
1323 cleanup("Error writing string!", 1);
1328 /****************************************************************************************/
1330 static void writestring(char *s
)
1332 int len
= strlen(s
) + 1;
1336 if (fwrite(s
, 1, len
, outfile
) != len
)
1338 cleanup("Error writing string!", 1);
1343 /****************************************************************************************/
1345 static void writeimage(struct ILBMImage
*img
)
1351 #define ACT_STRUCT i
1353 SET_WORD(leftedge
, 0);
1354 SET_WORD(topedge
, 0);
1355 SET_WORD(width
, img
->planarbmh
.bmh_Width
);
1356 SET_WORD(height
, img
->planarbmh
.bmh_Height
);
1357 SET_WORD(depth
, img
->planarbmh
.bmh_Depth
);
1358 SET_LONG(imagedata
, BOOL_YES
);
1359 SET_BYTE(planepick
, (1 << img
->planarbmh
.bmh_Depth
) - 1);
1360 SET_BYTE(planeonoff
, 0);
1361 SET_LONG(nextimage
, 0);
1363 if (fwrite(&i
, 1, sizeof(i
), outfile
) != sizeof(i
))
1365 cleanup("Error writing image structure to outfile!", 1);
1368 for(d
= 0; d
< img
->planarbmh
.bmh_Depth
; d
++)
1370 UBYTE
*dat
= img
->planarbuffer
+ img
->bpr
* d
;
1372 for(y
= 0; y
< img
->planarbmh
.bmh_Height
; y
++)
1374 if(fwrite(dat
, 1, img
->bpr
, outfile
) != img
->bpr
)
1376 cleanup("Error writing image data to outfile!", 1);
1378 dat
+= (img
->planarbmh
.bmh_Depth
* img
->bpr
);
1384 /****************************************************************************************/
1392 UBYTE fc_maxpalettebytes
[2];
1395 /****************************************************************************************/
1399 UBYTE ic_transparentcolour
;
1400 UBYTE ic_numcolours
;
1402 UBYTE ic_imageformat
;
1403 UBYTE ic_paletteformat
;
1405 UBYTE ic_numimagebytes
[2];
1406 UBYTE ic_numpalettebytes
[2];
1409 /****************************************************************************************/
1411 static LONG
writefacechunk(void)
1413 struct facechunk fc
;
1417 #define ACT_STRUCT fc
1420 writelong(sizeof(struct facechunk
));
1422 SET_BYTE(fc_width
, img1
.bmh
.bmh_Width
- 1);
1423 SET_BYTE(fc_height
, img1
.bmh
.bmh_Height
- 1);
1424 SET_BYTE(fc_flags
, 0);
1425 SET_BYTE(fc_aspect
, 0); // 0x11);
1427 palbytes
= (img1
.cmapentries
> img2
.cmapentries
) ? img1
.cmapentries
: img2
.cmapentries
;
1428 palbytes
= palbytes
* 3;
1430 SET_WORD(fc_maxpalettebytes
, palbytes
- 1);
1432 if (fwrite(&fc
, 1, sizeof(fc
), outfile
) != sizeof(fc
))
1434 cleanup("Error writing face chunk!", 1);
1437 return sizeof(struct facechunk
) + 8;
1440 /****************************************************************************************/
1442 /* createrle() based on ModifyIcon source by Dirk Stöcker */
1444 /****************************************************************************************/
1446 static char * createrle(unsigned long depth
, unsigned char *dtype
, LONG
*dsize
, unsigned long size
,
1450 unsigned long bitbuf
, numbits
;
1452 long ressize
, numcopy
, numequal
;
1454 buf
= malloc(size
* 2);
1455 if (!buf
) return NULL
;
1462 k
= 0; /* the really output pointer */
1463 for(i
= 1; numequal
|| numcopy
;)
1465 if(i
< size
&& numequal
&& (src
[i
-1] == src
[i
]))
1469 else if(i
< size
&& numequal
*depth
<= 16)
1471 numcopy
+= numequal
; numequal
= 1; ++i
;
1475 /* care for end case, where it maybe better to join the two */
1476 if(i
== size
&& numcopy
+ numequal
<= 128 && (numequal
-1)*depth
<= 8)
1478 numcopy
+= numequal
; numequal
= 0;
1482 if((j
= numcopy
) > 128) j
= 128;
1483 bitbuf
= (bitbuf
<<8) | (j
-1);
1488 if((j
= numequal
) > 128) j
= 128;
1489 bitbuf
= (bitbuf
<<8) | (256-(j
-1));
1494 buf
[ressize
++] = (bitbuf
>> numbits
);
1498 bitbuf
= (bitbuf
<<depth
) | src
[k
++];
1502 buf
[ressize
++] = (bitbuf
>> numbits
);
1505 if(i
< size
&& !numcopy
&& !numequal
)
1512 buf
[ressize
++] = bitbuf
<< (8-numbits
);
1514 if(ressize
> size
) /* no RLE */
1518 for(i
= 0; i
< size
; ++i
)
1529 /****************************************************************************************/
1531 static LONG
writeimagchunk(struct ILBMImage
*img
)
1533 struct imagchunk ic
;
1535 UBYTE skippalette
= 0;
1537 LONG palsize
, gfxsize
;
1538 UBYTE palpacked
, gfxpacked
;
1540 imagsize
= sizeof(struct imagchunk
);
1542 /* if this is second image check whether palette is identical to
1543 the one of first image */
1547 if (img1
.cmapentries
== img2
.cmapentries
)
1551 for (i
= 0; i
< img1
.cmapentries
; i
++)
1553 if (img1
.rgb
[i
][0] != img2
.rgb
[i
][0]) break;
1554 if (img1
.rgb
[i
][1] != img2
.rgb
[i
][1]) break;
1555 if (img1
.rgb
[i
][2] != img2
.rgb
[i
][2]) break;
1558 if (i
== img1
.cmapentries
) skippalette
= 1;
1567 img
->cmapentries
* 3,
1568 (unsigned char *)img
->rgb
);
1570 imagsize
+= palsize
;
1573 gfx
= createrle(img
->bmh
.bmh_Depth
,
1576 img
->bmh
.bmh_Width
* img
->bmh
.bmh_Height
,
1579 imagsize
+= gfxsize
;
1582 #define ACT_STRUCT ic
1584 SET_BYTE(ic_transparentcolour
, transparentoption
);
1587 SET_BYTE(ic_numcolours
, 0);
1588 SET_BYTE(ic_flags
, (transparentoption
!= -1) ? 1 : 0); /* 1 = HasTransparentColour */
1589 SET_BYTE(ic_paletteformat
, 0);
1590 SET_WORD(ic_numpalettebytes
, 0);
1594 SET_BYTE(ic_numcolours
, img
->cmapentries
- 1);
1595 SET_BYTE(ic_flags
, (transparentoption
!= -1) ? 3 : 2); /* 2 = HasPalette */
1596 SET_BYTE(ic_paletteformat
, palpacked
);
1597 SET_WORD(ic_numpalettebytes
, palsize
- 1);
1600 SET_BYTE(ic_imageformat
, gfxpacked
);
1601 SET_BYTE(ic_depth
, img
->bmh
.bmh_Depth
);
1602 SET_WORD(ic_numimagebytes
, gfxsize
- 1);
1605 writelong(imagsize
);
1607 if (fwrite(&ic
, 1, sizeof(ic
), outfile
) != sizeof(ic
))
1609 cleanup("Error writing imag chunk!", 1);
1612 if (fwrite(gfx
, 1, gfxsize
, outfile
) != gfxsize
)
1614 cleanup("Error write gfx data in imag chunk!", 1);
1619 if (fwrite(pal
, 1, palsize
, outfile
) != palsize
)
1621 cleanup("Error write palette data in imag chunk!", 1);
1629 if (fwrite(&dummy
, 1, 1, outfile
) != 1)
1631 cleanup("Error writing imag chunk!", 1);
1637 return imagsize
+ 8;
1640 /****************************************************************************************/
1642 static void write35data(void)
1648 formsizeseek
= ftell(outfile
);
1649 writelong(0x12345678);
1652 formsize
+= writefacechunk();
1653 formsize
+= writeimagchunk(&img1
);
1654 if (image2option
) formsize
+= writeimagchunk(&img2
);
1656 fseek(outfile
, formsizeseek
, SEEK_SET
);
1657 writelong(formsize
);
1660 /****************************************************************************************/
1662 static void writeicon(void)
1664 struct diskobject dobj
;
1666 outfile
= fopen(outfilename
, "wb");
1667 if (!outfile
) cleanup("Can't open output file for writing!", 1);
1670 writeolddrawerdata();
1673 if (image2option
) writeimage(&img2
);
1675 if (defaulttooloption
) writestring(defaulttooloption
);
1677 if (tooltypesoption
)
1680 LONG numtooltypes
= 0;
1682 for(strarray
= tooltypesoption
; *strarray
; strarray
++, numtooltypes
++);
1684 writelong((numtooltypes
+ 1) * 4);
1686 for(strarray
= tooltypesoption
; *strarray
; strarray
++)
1688 writestring(*strarray
);
1693 /* toolwindow would have to be saved in between here if there is any */
1695 writenewdrawerdata();
1701 /****************************************************************************************/
1703 /* Table of CRCs of all 8-bit messages. */
1704 unsigned long crc_table
[256];
1706 /* Flag: has the table been computed? Initially false. */
1707 int crc_table_computed
= 0;
1709 /* Make the table for a fast CRC. */
1710 void make_crc_table(void)
1715 for (n
= 0; n
< 256; n
++)
1717 c
= (unsigned long) n
;
1718 for (k
= 0; k
< 8; k
++)
1721 c
= 0xedb88320L
^ (c
>> 1);
1727 crc_table_computed
= 1;
1730 /* Update a running CRC with the bytes buf[0..len-1]--the CRC
1731 should be initialized to all 1's, and the transmitted value
1732 is the 1's complement of the final running CRC (see the
1733 crc() routine below)). */
1735 unsigned long update_crc(unsigned long crc
, unsigned char *buf
,
1738 unsigned long c
= crc
;
1741 if (!crc_table_computed
)
1744 for (n
= 0; n
< len
; n
++)
1746 c
= crc_table
[(c
^ buf
[n
]) & 0xff] ^ (c
>> 8);
1751 /* Return the CRC of the bytes buf[0..len-1]. */
1752 unsigned long crc(unsigned char *buf
, int len
)
1754 return update_crc(0xffffffffL
, buf
, len
) ^ 0xffffffffL
;
1757 /****************************************************************************************/
1759 static void writepngiconattr(ULONG id
, ULONG val
, ULONG
*chunksize
, ULONG
*crc
)
1775 *crc
= update_crc(*crc
, buf
, 8);
1778 /****************************************************************************************/
1780 static void writepngiconstrattr(ULONG id
, char *val
, ULONG
*chunksize
, ULONG
*crc
)
1783 int len
= strlen(val
) + 1;
1791 *crc
= update_crc(*crc
, buf
, 4);
1794 writenormalstring(val
);
1795 *crc
= update_crc(*crc
, val
, len
);
1797 *chunksize
+= 4 + len
;
1801 /****************************************************************************************/
1803 static void writepngiconchunk(void)
1805 ULONG crc
= 0xffffffff;
1806 ULONG chunksize
= 0;
1807 ULONG sizeseek
= ftell(outfile
);
1808 UBYTE iconid
[] = {'i', 'c', 'O', 'n'};
1810 writelong(0x12345678);
1811 writelong(MAKE_ID('i', 'c', 'O', 'n'));
1813 crc
= update_crc(crc
, iconid
, 4);
1815 if (iconleftoption
!= 0x80000000)
1817 writepngiconattr(0x80001001, iconleftoption
, &chunksize
, &crc
);
1820 if (icontopoption
!= 0x80000000)
1822 writepngiconattr(0x80001002, icontopoption
, &chunksize
, &crc
);
1825 if (drawerdataoption
)
1829 writepngiconattr(0x80001003, drawerleftoption
, &chunksize
, &crc
);
1830 writepngiconattr(0x80001004, drawertopoption
, &chunksize
, &crc
);
1831 writepngiconattr(0x80001005, drawerwidthoption
, &chunksize
, &crc
);
1832 writepngiconattr(0x80001006, drawerheightoption
, &chunksize
, &crc
);
1834 if (drawershowoption
== 2) flags
|= 1;
1836 if (drawershowasoption
< 2)
1842 flags
|= ((drawershowasoption
- 2) << 2);
1844 writepngiconattr(0x80001007, flags
, &chunksize
, &crc
);
1847 writepngiconattr(0x80001009, stackoption
, &chunksize
, &crc
);
1849 if (defaulttooloption
)
1851 writepngiconstrattr(0x8000100a, defaulttooloption
, &chunksize
, &crc
);
1854 if (tooltypesoption
)
1858 for(tt
= tooltypesoption
; *tt
; tt
++)
1860 writepngiconstrattr(0x8000100b, *tt
, &chunksize
, &crc
);
1864 writelong(crc
^ 0xffffffff);
1865 fseek(outfile
, sizeseek
, SEEK_SET
);
1866 writelong(chunksize
);
1867 fseek(outfile
, 0, SEEK_END
);
1871 /****************************************************************************************/
1873 static void writepngicon(void)
1878 outfile
= fopen(outfilename
, "wb");
1879 if (!outfile
) cleanup("Can't open output file for writing!", 1);
1881 if (fwrite(filebuffer
, 1, 8, outfile
) != 8)
1883 cleanup("Error writing PNG signature!", 1);
1886 filepos
= filebuffer
+ 8;
1890 ULONG chunksize
= (filepos
[0] << 24) | (filepos
[1] << 16) |
1891 (filepos
[2] << 8) | filepos
[3];
1892 ULONG chunktype
= (filepos
[4] << 24) | (filepos
[5] << 16) |
1893 (filepos
[6] << 8) | filepos
[7];
1897 if (chunktype
== MAKE_ID('I', 'E', 'N', 'D'))
1899 writepngiconchunk();
1903 if (chunktype
!= MAKE_ID('i', 'c', 'O', 'n'))
1905 if (fwrite(filepos
, 1, chunksize
, outfile
) != chunksize
)
1907 cleanup("Error writing PNG icon file!", 1);
1911 filepos
+= chunksize
;
1914 /* Create icons with two images */
1915 if (image2option
&& strcasecmp(image1option
, image2option
))
1917 /* If filenames are different, cat/attach the 2nd
1918 file onto the first one. */
1922 loadimage(image2option
, &img2
);
1924 if (fwrite(filebuffer
, 1, filesize
, outfile
) != filesize
)
1926 cleanup("Error writing 2nd PNG Image!", 1);
1931 /* Handle the case where 2 PNG images are just joined together
1933 long bytecnt
= filebuffer
+ filesize
- dualpngstart
;
1934 if (fwrite(dualpngstart
, 1, bytecnt
, outfile
) != bytecnt
)
1936 cleanup("Error writing dual PNG icon file!", 1);
1941 /****************************************************************************************/
1943 static void remapicon(void)
1945 remapplanar(&img1
, &std4colpal
);
1946 if (image2option
) remapplanar(&img2
, &std4colpal
);
1949 /****************************************************************************************/
1951 int main(int argc
, char **argv
)
1953 getarguments(argc
, argv
);
1955 loadimage(image1option
, &img1
);
1958 if (image2option
) loadimage(image2option
, &img2
);
1970 /****************************************************************************************/