2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
5 Desc: Tool to convert IFF ILBM images into C source.
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')
30 #define CMP_BYTERUN1 1
34 /****************************************************************************************/
36 /* For this tool it does not really matter if the following types
37 have a bigger sizeof() than on Amiga */
40 typedef unsigned long ULONG
;
42 typedef unsigned short UWORD
;
45 typedef unsigned char UBYTE
;
47 #include <exec/types.h>
50 /****************************************************************************************/
60 UBYTE bmh_Compression
;
62 UWORD bmh_Transparent
;
69 /****************************************************************************************/
71 static char *filename
;
73 static unsigned char *filebuffer
, *body
, *planarbuffer
, *chunkybuffer
;
74 static unsigned char *planarbuffer_packed
, *chunkybuffer_packed
;
75 static long filesize
, bodysize
, bodysize_packed
;
77 static struct BitMapHeader bmh
;
78 static LONG cmapentries
, totdepth
, bpr
;
79 static BOOL have_bmhd
, have_cmap
, have_body
;
80 static UBYTE red
[256], green
[256], blue
[256];
81 static char imagename
[1000];
82 static char bigimagename
[1000];
83 static BOOL brush2c
; // compatibility with brush2c from MUI SDK
84 static BOOL brush2pix
; // compatibility with brush2pix from JabberWocky
86 /****************************************************************************************/
88 static void cleanup(char *msg
, int rc
)
90 if (msg
) fprintf(stderr
, "ilbmtoc: %s\n", msg
);
92 if (chunkybuffer_packed
) free(chunkybuffer_packed
);
93 if (planarbuffer_packed
) free(planarbuffer_packed
);
94 if (chunkybuffer
) free(chunkybuffer
);
95 if (planarbuffer
) free(planarbuffer
);
96 if (filebuffer
) free(filebuffer
);
98 if (file
) fclose(file
);
103 /****************************************************************************************/
105 static void getarguments(int argc
, char **argv
)
107 char *imagenamestart
, *sp
;
110 if (argc
== 3 && !strcasecmp(argv
[1], "-b2c"))
115 else if (argc
== 3 && !strcasecmp(argv
[1], "-b2p"))
126 cleanup("Usage: ilbmtoc [-b2c|-b2p] filename", 1);
129 if (strlen(filename
) >= sizeof(imagename
)) cleanup("Filename too long!", 1);
131 imagenamestart
= filename
;
134 sp
= strchr(imagenamestart
+ 1, '/');
135 if (!sp
) sp
= strchr(imagenamestart
+ 1, '\\');
136 if (!sp
) sp
= strchr(imagenamestart
+ 1, ':');
139 imagenamestart
= sp
+ 1;
142 strcpy(imagename
, imagenamestart
);
143 if ((sp
= strchr(imagename
, '.'))) *sp
= 0;
145 for(i
= 0; i
< strlen(imagename
); i
++) bigimagename
[i
] = toupper(imagename
[i
]);
148 /****************************************************************************************/
150 static ULONG
getlong(void)
154 if (filepos
> filesize
- 4) cleanup("Tried to read over file end!", 1);
156 ret
= filebuffer
[filepos
++] * 0x1000000;
157 ret
+= filebuffer
[filepos
++] * 0x10000;
158 ret
+= filebuffer
[filepos
++] * 0x100;
159 ret
+= filebuffer
[filepos
++];
164 /****************************************************************************************/
166 static UWORD
getword(void)
170 if (filepos
> filesize
- 2) cleanup("Tried to read over file end!", 1);
172 ret
= filebuffer
[filepos
++] * 0x100;
173 ret
+= filebuffer
[filepos
++];
178 /****************************************************************************************/
180 static UBYTE
getbyte(void)
184 if (filepos
> filesize
- 1) cleanup("Tried to read over file end!", 1);
185 ret
= filebuffer
[filepos
++];
190 /****************************************************************************************/
192 static void skipbytes(ULONG howmany
)
197 /****************************************************************************************/
199 static void openfile(void)
201 file
= fopen(filename
, "rb");
202 if (!file
) cleanup("Can't open file!", 1);
204 fseek(file
, 0, SEEK_END
);
205 filesize
= ftell(file
);
207 if (filesize
< 12) cleanup("Bad file size!", 1);
209 fprintf(stderr
, "Filesize is %ld\n", filesize
);
211 fseek(file
, 0, SEEK_SET
);
213 filebuffer
= malloc(filesize
+ 10);
214 if (!filebuffer
) cleanup("Memory allocation for file buffer failed!", 1);
216 if (fread(filebuffer
, 1, filesize
, file
) != filesize
)
217 cleanup("Error reading file!", 1);
219 fclose(file
); file
= NULL
;
222 /****************************************************************************************/
224 static void checkfile(void)
230 if (id
!= ID_FORM
) cleanup("File is not an IFF file!", 1);
233 if (size
!= filesize
- 8) cleanup("File is IFF, but has bad size in IFF header!", 1);
236 if (id
!= ID_ILBM
) cleanup("File is IFF, but not of type ILBM!", 1);
239 /****************************************************************************************/
241 static void scanfile(void)
253 /* Cast the IFF identifier to 4 ASCII chars:
254 (Use unsigned as i ANSI-C the cast to signed is implementation-dependent.) */
255 fprintf( stderr
, "Chunk: %c%c%c%c Size: %ld\n"
256 , (unsigned char) (id
>> 24)
257 , (unsigned char) (id
>> 16)
258 , (unsigned char) (id
>> 8)
259 , (unsigned char) (id
)
266 if (size
!= 20) cleanup("Bad BMHD chunk size!", 1);
268 bmh
.bmh_Width
= getword();
269 bmh
.bmh_Height
= getword();
270 bmh
.bmh_Left
= (WORD
)getword();
271 bmh
.bmh_Top
= (WORD
)getword();
272 bmh
.bmh_Depth
= getbyte();
273 bmh
.bmh_Masking
= getbyte();
274 bmh
.bmh_Compression
= getbyte();
275 bmh
.bmh_Pad
= getbyte();
276 bmh
.bmh_Transparent
= getword();
277 bmh
.bmh_XAspect
= getbyte();
278 bmh
.bmh_YAspect
= getbyte();
279 bmh
.bmh_PageWidth
= (WORD
)getword();
280 bmh
.bmh_PageHeight
= (WORD
)getword();
282 if (bmh
.bmh_Depth
> 8) cleanup("ILBM file has too many colors!", 1);
283 if ((bmh
.bmh_Compression
!= CMP_NONE
) && (bmh
.bmh_Compression
!= CMP_BYTERUN1
)) cleanup("Compression method unsupported!", 1);
287 totdepth
= bmh
.bmh_Depth
+ ((bmh
.bmh_Masking
== MSK_HASMASK
) ? 1 : 0);
289 bpr
= ((bmh
.bmh_Width
+ 15) & ~15) / 8;
291 fprintf(stderr
, "BMHD: %d x %d x %d (%ld)\n", bmh
.bmh_Width
,
298 if (!have_bmhd
) cleanup("CMAP chunk before BMHD chunk (or no BMHD chunk at all!", 1);
300 cmapentries
= size
/ 3;
301 if (size
& 1) size
++;
303 if ((cmapentries
< 2) || (cmapentries
> 256)) cleanup("CMAP chunk has bad number of entries!", 1);
305 for(i
= 0; i
< cmapentries
; i
++)
308 green
[i
] = getbyte();
320 if (!have_bmhd
) cleanup("BODY chunk before BMHD chunk (or no BMHD chunk at all!", 1);
321 body
= &filebuffer
[filepos
];
324 if (bmh
.bmh_Compression
== CMP_NONE
)
326 LONG shouldbesize
= totdepth
* bpr
* bmh
.bmh_Height
;
327 if (bodysize
!= shouldbesize
) cleanup("BODY chunk size seems to be wrong!", 1);
334 if (size
& 1) size
++;
339 if (filepos
== filesize
) break;
340 if (have_bmhd
&& have_body
&& have_cmap
) break;
343 if (!have_bmhd
) cleanup("BMHD chunk missing!", 1);
344 if (!have_body
) cleanup("BODY chunk missing!", 1);
347 /****************************************************************************************/
349 static unsigned char *unpack_byterun1(unsigned char *source
, unsigned char *dest
, LONG unpackedsize
)
356 c
= (signed char)(*source
++);
362 if (--unpackedsize
<= 0) return source
;
373 if (--unpackedsize
<= 0) return source
;
380 /****************************************************************************************/
382 static BOOL
norm1(LONG count
, unsigned char **source_backup
,
383 unsigned char **dest
, LONG
*checksize
)
385 //if (count >= 0) fprintf(stderr, "XX: non packable %d\n",count);
391 if (step
> 127) step
= 127;
396 if (*checksize
<= 0) return 0;
405 *(*dest
)++ = *(*source_backup
)++;
415 static BOOL
copy1(unsigned char r
, LONG count
, unsigned char **dest
, LONG
*checksize
)
417 //if (count >= 1) fprintf(stderr, "XX: repeat %02x x %d\n", r, count);
423 if (step
> 127) step
= 127;
428 if (*checksize
<= 0) return 0;
430 *(*dest
)++ = (unsigned char)step
;
437 static BOOL
pack_byterun1(unsigned char *source
, unsigned char *dest
,
438 LONG size
, LONG check_size
, LONG
*packsize
)
440 unsigned char *source_backup
, *dest_backup
;
441 LONG samebytes_counter
, samebytes
, count
;
442 LONG checksize
= check_size
;
443 unsigned char oldbyte
, actbyte
;
445 if (checksize
< 0) checksize
= 0x7FFFFFFF;
448 samebytes_counter
= 0;
449 source_backup
= source
;
454 //fprintf(stderr, "size = %d. checksize = %d\n", size, checksize);
455 if (--size
< 0) break;
457 if (actbyte
== oldbyte
)
465 samebytes
= samebytes_counter
;
466 samebytes_counter
= 1;
468 if (samebytes
< 3) continue;
470 count
= (LONG
)(source
- source_backup
- samebytes
- 2);
471 if (!norm1(count
, &source_backup
, &dest
, &checksize
)) return 0;
473 if (!copy1(source
[-2], samebytes
, &dest
, &checksize
)) return 0;
475 source_backup
= source
- 1;
477 //fprintf(stderr, "done\n");
479 if (samebytes_counter
>= 3)
481 samebytes
= samebytes_counter
;
482 count
= (LONG
)(source
- source_backup
- samebytes
- 1);
483 if (!norm1(count
, &source_backup
, &dest
, &checksize
)) return 0;
484 if (!copy1(source
[-2], samebytes
, &dest
, &checksize
)) return 0;
488 count
= (LONG
)(source
- source_backup
- 1);
489 if (!norm1(count
, &source_backup
, &dest
, &checksize
)) return 0;
491 //fprintf(stderr, "realdone\n");
493 if (packsize
) *packsize
= (LONG
)(dest
- dest_backup
);
498 /****************************************************************************************/
500 static void p2c(unsigned char *source
, unsigned char *dest
, LONG width
, LONG height
,
501 LONG totplanes
, LONG wantplanes
, LONG chunkybpr
)
503 LONG alignedwidth
, x
, y
, p
, bpr
, bpl
;
505 alignedwidth
= (width
+ 15) & ~15;
506 bpr
= alignedwidth
/ 8;
507 bpl
= bpr
* totplanes
;
509 for(y
= 0; y
< height
; y
++)
511 for(x
= 0; x
< width
; x
++)
513 LONG mask
= 1 << (7 - (x
& 7));
515 unsigned char chunkypix
= 0;
517 for(p
= 0; p
< wantplanes
; p
++)
519 if (source
[p
* bpr
+ offset
] & mask
) chunkypix
|= (1 << p
);
531 /****************************************************************************************/
533 static void convertbody(void)
535 LONG unpackedsize
= bpr
* bmh
.bmh_Height
* totdepth
;
537 planarbuffer
= malloc(unpackedsize
);
538 if (!planarbuffer
) cleanup("Memory allocation for planar buffer failed!", 1);
540 if (bmh
.bmh_Compression
== CMP_NONE
)
542 memcpy(planarbuffer
, body
, unpackedsize
);
546 unpack_byterun1(body
, planarbuffer
, unpackedsize
);
549 chunkybuffer
= malloc(bmh
.bmh_Width
* bmh
.bmh_Height
);
550 if (!chunkybuffer
) cleanup("Memory allocation for chunky buffer failed!", 1);
561 /****************************************************************************************/
563 static void packdata(void)
565 LONG chunkysize
= (LONG
)bmh
.bmh_Width
* (LONG
)bmh
.bmh_Height
;
568 chunkybuffer_packed
= malloc(chunkysize
);
570 if (!chunkybuffer_packed
) cleanup("Memory allocation for packed chunky buffer failed!", 1);
572 fprintf(stderr
, "Starting packing\n");
574 success
= pack_byterun1(chunkybuffer
, chunkybuffer_packed
,
575 chunkysize
, chunkysize
, &bodysize_packed
);
577 fprintf(stderr
, "Done packing. Success = %d\n", success
);
580 free(chunkybuffer_packed
); chunkybuffer_packed
= 0;
584 /****************************************************************************************/
586 static void gensource(void)
588 unsigned char *buffer
;
589 LONG i
, x
, y
, buffersize
;
591 printf("#include <exec/types.h>\n");
593 printf("#define %s_WIDTH %d\n", bigimagename
, bmh
.bmh_Width
);
594 printf("#define %s_HEIGHT %d\n", bigimagename
, bmh
.bmh_Height
);
595 printf("#define %s_PACKED %d\n", bigimagename
, (chunkybuffer_packed
|| planarbuffer_packed
) ? 1 : 0);
596 printf("#define %s_PLANES %d\n", bigimagename
, bmh
.bmh_Depth
);
598 printf("#define %s_COLORS %ld\n", bigimagename
, cmapentries
);
604 printf("ULONG %s_pal[%ld] =\n", imagename
, cmapentries
);
606 for(i
= 0; i
< cmapentries
; i
++)
608 ULONG col
= (((ULONG
)red
[i
]) << 16) +
609 (((ULONG
)green
[i
]) << 8) +
612 printf(" 0x%06lx", col
);
613 if (i
== cmapentries
- 1)
622 if (chunkybuffer_packed
)
624 buffer
= chunkybuffer_packed
;
625 buffersize
= bodysize_packed
;
629 buffer
= chunkybuffer
;
630 buffersize
= bodysize
;
633 printf("UBYTE %s_data[%ld] =\n", imagename
, buffersize
);
638 for(x
= 0; x
< buffersize
; x
++)
640 if ((i
++ % 20) == 0) printf("\n ");
641 printf("0x%02x", buffer
[x
]);
642 if (!(x
== buffersize
- 1)) printf(",");
649 /****************************************************************************************/
651 static void genbrush2csource(void)
657 printf("#ifdef USE_%s_COLORS\n", bigimagename
);
658 printf("const ULONG %s_colors[%ld] =\n{\n", imagename
, cmapentries
* 3);
659 for (i
= 0; i
< cmapentries
; i
++)
661 printf("\t0x%08lx,0x%08lx,0x%08lx,\n",
662 (long) (red
[i
] << 24 | red
[i
] << 16 | red
[i
] << 8 | red
[i
]),
663 (long) (green
[i
] << 24 | green
[i
] << 16 | green
[i
] << 8 | green
[i
]),
664 (long) (blue
[i
] << 24 | blue
[i
] << 16 | blue
[i
] << 8 | blue
[i
]));
667 printf("#endif\n\n");
672 printf("#define %s_WIDTH %3d\n", bigimagename
, bmh
.bmh_Width
);
673 printf("#define %s_HEIGHT %3d\n", bigimagename
, bmh
.bmh_Height
);
674 printf("#define %s_DEPTH %3d\n", bigimagename
, bmh
.bmh_Depth
);
675 printf("#define %s_COMPRESSION %3d\n", bigimagename
, bmh
.bmh_Compression
);
676 printf("#define %s_MASKING %3d\n", bigimagename
, bmh
.bmh_Masking
);
679 printf("#ifdef USE_%s_HEADER\n", bigimagename
);
680 printf("const struct BitMapHeader %s_header =\n{ %ld,%ld,%ld,%ld,%ld,%ld,%ld,0,%ld,%ld,%ld,%ld,%ld };\n",
681 imagename
, (long)bmh
.bmh_Width
, (long)bmh
.bmh_Height
, (long)bmh
.bmh_Left
, (long)bmh
.bmh_Top
,
682 (long)bmh
.bmh_Depth
, (long)bmh
.bmh_Masking
, (long)bmh
.bmh_Compression
, (long)bmh
.bmh_Transparent
,
683 (long)bmh
.bmh_XAspect
, (long)bmh
.bmh_YAspect
, (long)bmh
.bmh_PageWidth
, (long)bmh
.bmh_PageHeight
);
684 printf("#endif\n\n");
686 printf("#ifdef USE_%s_BODY\n", bigimagename
);
687 printf("const UBYTE %s_body[%ld] = {\n", imagename
, bodysize
);
688 for (i
= 0; i
< bodysize
; i
++)
690 printf("0x%02lx,", (long)(body
[i
]));
691 if (!((i
+ 1) % 15)) printf("\n");
698 /****************************************************************************************/
700 static void genbrush2pixsource(void)
706 printf("const ULONG %s_colors[%ld] =\n{\n", imagename
, cmapentries
* 3);
707 for (i
= 0; i
< cmapentries
; i
++)
709 printf("\t0x%08lx,0x%08lx,0x%08lx,\n",
710 (long)(red
[i
] << 24 | red
[i
] << 16 | red
[i
] << 8 | red
[i
]),
711 (long)(green
[i
] << 24 | green
[i
] << 16 | green
[i
] << 8 | green
[i
]),
712 (long)(blue
[i
] << 24 | blue
[i
] << 16 | blue
[i
] << 8 | blue
[i
]));
719 printf("#define %s_WIDTH %3d\n", bigimagename
, bmh
.bmh_Width
);
720 printf("#define %s_HEIGHT %3d\n", bigimagename
, bmh
.bmh_Height
);
721 printf("#define %s_DEPTH %3d\n", bigimagename
, bmh
.bmh_Depth
);
722 printf("#define %s_COMPRESSION %3d\n", bigimagename
, bmh
.bmh_Compression
);
723 printf("#define %s_MASKING %3d\n", bigimagename
, bmh
.bmh_Masking
);
726 printf("const UBYTE %s_body[%ld] = {\n", imagename
, bodysize
);
727 for (i
= 0; i
< bodysize
; i
++)
729 printf("0x%02lx,", (long)(body
[i
]));
730 if (!((i
+ 1) % 15)) printf("\n");
735 if (have_cmap
&& have_body
)
737 printf("\nmuidefpix %s_defpix =\n{\n", imagename
);
738 printf("\t%s_body,\n", imagename
);
739 printf("\t%s_colors,\n", imagename
);
740 printf("\t%s_WIDTH, %s_HEIGHT, %s_DEPTH,\n", bigimagename
, bigimagename
, bigimagename
);
741 printf("\t%s_COMPRESSION, %s_MASKING \n", bigimagename
, bigimagename
);
746 /****************************************************************************************/
748 int main(int argc
, char **argv
)
750 getarguments(argc
, argv
);
761 genbrush2pixsource();
773 /****************************************************************************************/