Added type conversion to red, green and blue components, otherwise
[AROS.git] / tools / ilbmtoc / ilbmtoc.c
blobdef244be5006152e66d21905a064f6dd4a62259a
1 /*
2 Copyright © 1995-2010, The AROS Development Team. All rights reserved.
3 $Id$
5 Desc: Tool to convert IFF ILBM images into C source.
7 Lang:
9 */
11 /****************************************************************************************/
13 #include <stdio.h>
14 #include <string.h>
15 #include <stdlib.h>
16 #include <ctype.h>
18 /****************************************************************************************/
20 #define MAKE_ID(a,b,c,d) (((a)<<24) | ((b)<<16) | ((c)<<8) | ((d)))
22 #define ID_FORM MAKE_ID('F','O','R','M')
23 #define ID_ILBM MAKE_ID('I','L','B','M')
24 #define ID_CMAP MAKE_ID('C','M','A','P')
25 #define ID_BODY MAKE_ID('B','O','D','Y')
26 #define ID_BMHD MAKE_ID('B','M','H','D')
28 #define CMP_NONE 0
29 #define CMP_BYTERUN1 1
31 #define MSK_HASMASK 1
33 /****************************************************************************************/
35 /* For this tool it does not really matter if the following types
36 have a bigger sizeof() than on Amiga */
38 #ifndef __AROS__
39 typedef unsigned long ULONG;
40 typedef long LONG;
41 typedef unsigned short UWORD;
42 typedef short WORD;
43 typedef short BOOL;
44 typedef unsigned char UBYTE;
45 #else
46 #include <exec/types.h>
47 #endif
49 /****************************************************************************************/
51 struct BitMapHeader
53 UWORD bmh_Width;
54 UWORD bmh_Height;
55 WORD bmh_Left;
56 WORD bmh_Top;
57 UBYTE bmh_Depth;
58 UBYTE bmh_Masking;
59 UBYTE bmh_Compression;
60 UBYTE bmh_Pad;
61 UWORD bmh_Transparent;
62 UBYTE bmh_XAspect;
63 UBYTE bmh_YAspect;
64 WORD bmh_PageWidth;
65 WORD bmh_PageHeight;
68 /****************************************************************************************/
70 static char *filename;
71 static FILE *file;
72 static unsigned char *filebuffer, *body, *planarbuffer, *chunkybuffer;
73 static unsigned char *planarbuffer_packed, *chunkybuffer_packed;
74 static long filesize, bodysize, bodysize_packed;
75 static long filepos;
76 static struct BitMapHeader bmh;
77 static LONG cmapentries, totdepth, bpr;
78 static BOOL have_bmhd, have_cmap, have_body;
79 static UBYTE red[256], green[256], blue[256];
80 static char imagename[1000];
81 static char bigimagename[1000];
82 static BOOL brush2c; // compatibility with brush2c from MUI SDK
83 static BOOL brush2pix; // compatibility with brush2pix from JabberWocky
85 /****************************************************************************************/
87 static void cleanup(char *msg, int rc)
89 if (msg) fprintf(stderr, "ilbmtoc: %s\n", msg);
91 if (chunkybuffer_packed) free(chunkybuffer_packed);
92 if (planarbuffer_packed) free(planarbuffer_packed);
93 if (chunkybuffer) free(chunkybuffer);
94 if (planarbuffer) free(planarbuffer);
95 if (filebuffer) free(filebuffer);
97 if (file) fclose(file);
99 exit(rc);
102 /****************************************************************************************/
104 static void getarguments(int argc, char **argv)
106 char *imagenamestart, *sp;
107 WORD i;
108 unsigned int narg = 1;
110 if (!strcasecmp(argv[1], "-b2c"))
112 brush2c = 1;
113 narg++;
115 else if (!strcasecmp(argv[1], "-b2p"))
117 brush2pix = 1;
118 narg++;
121 if (argc > narg)
122 filename = argv[narg++];
123 else
124 cleanup("Usage: ilbmtoc [-b2c|-b2p] filename [imagename]", 1);
126 if (argc > narg)
127 imagenamestart = argv[narg];
128 else
130 imagenamestart = filename;
131 for(;;)
133 sp = strchr(imagenamestart + 1, '/');
134 if (!sp) sp = strchr(imagenamestart + 1, '\\');
135 if (!sp) sp = strchr(imagenamestart + 1, ':');
136 if (!sp) break;
138 imagenamestart = sp + 1;
142 if (strlen(imagename) >= sizeof(imagename)) cleanup("Image name too long!", 1);
144 strcpy(imagename, imagenamestart);
145 if ((sp = strchr(imagename, '.'))) *sp = 0;
147 for(i = 0; i < strlen(imagename); i++) bigimagename[i] = toupper(imagename[i]);
150 /****************************************************************************************/
152 static ULONG getlong(void)
154 ULONG ret;
156 if (filepos > filesize - 4) cleanup("Tried to read over file end!", 1);
158 ret = filebuffer[filepos++] * 0x1000000;
159 ret += filebuffer[filepos++] * 0x10000;
160 ret += filebuffer[filepos++] * 0x100;
161 ret += filebuffer[filepos++];
163 return ret;
166 /****************************************************************************************/
168 static UWORD getword(void)
170 UWORD ret;
172 if (filepos > filesize - 2) cleanup("Tried to read over file end!", 1);
174 ret = filebuffer[filepos++] * 0x100;
175 ret += filebuffer[filepos++];
177 return ret;
180 /****************************************************************************************/
182 static UBYTE getbyte(void)
184 ULONG ret;
186 if (filepos > filesize - 1) cleanup("Tried to read over file end!", 1);
187 ret = filebuffer[filepos++];
189 return ret;
192 /****************************************************************************************/
194 static void skipbytes(ULONG howmany)
196 filepos += howmany;
199 /****************************************************************************************/
201 static void openfile(void)
203 file = fopen(filename, "rb");
204 if (!file) cleanup("Can't open file!", 1);
206 fseek(file, 0, SEEK_END);
207 filesize = ftell(file);
209 if (filesize < 12) cleanup("Bad file size!", 1);
211 fprintf(stderr, "Filesize is %ld\n", filesize);
213 fseek(file, 0, SEEK_SET);
215 filebuffer = malloc(filesize + 10);
216 if (!filebuffer) cleanup("Memory allocation for file buffer failed!", 1);
218 if (fread(filebuffer, 1, filesize, file) != filesize)
219 cleanup("Error reading file!", 1);
221 fclose(file); file = NULL;
224 /****************************************************************************************/
226 static void checkfile(void)
228 ULONG id;
229 ULONG size;
231 id = getlong();
232 if (id != ID_FORM) cleanup("File is not an IFF file!", 1);
234 size = getlong();
235 if (size != filesize - 8) cleanup("File is IFF, but has bad size in IFF header!", 1);
237 id = getlong();
238 if (id != ID_ILBM) cleanup("File is IFF, but not of type ILBM!", 1);
241 /****************************************************************************************/
243 static void scanfile(void)
245 WORD i;
247 for(;;)
249 ULONG id;
250 ULONG size;
252 id = getlong();
253 size = getlong();
255 /* Cast the IFF identifier to 4 ASCII chars:
256 (Use unsigned as i ANSI-C the cast to signed is implementation-dependent.) */
257 fprintf( stderr, "Chunk: %c%c%c%c Size: %ld\n"
258 , (unsigned char) (id >> 24)
259 , (unsigned char) (id >> 16)
260 , (unsigned char) (id >> 8)
261 , (unsigned char) (id)
262 , size
265 switch(id)
267 case ID_BMHD:
268 if (size != 20) cleanup("Bad BMHD chunk size!", 1);
270 bmh.bmh_Width = getword();
271 bmh.bmh_Height = getword();
272 bmh.bmh_Left = (WORD)getword();
273 bmh.bmh_Top = (WORD)getword();
274 bmh.bmh_Depth = getbyte();
275 bmh.bmh_Masking = getbyte();
276 bmh.bmh_Compression = getbyte();
277 bmh.bmh_Pad = getbyte();
278 bmh.bmh_Transparent = getword();
279 bmh.bmh_XAspect = getbyte();
280 bmh.bmh_YAspect = getbyte();
281 bmh.bmh_PageWidth = (WORD)getword();
282 bmh.bmh_PageHeight = (WORD)getword();
284 if (bmh.bmh_Depth > 8) cleanup("ILBM file has too many colors!", 1);
285 if ((bmh.bmh_Compression != CMP_NONE) && (bmh.bmh_Compression != CMP_BYTERUN1)) cleanup("Compression method unsupported!", 1);
287 have_bmhd = 1;
289 totdepth = bmh.bmh_Depth + ((bmh.bmh_Masking == MSK_HASMASK) ? 1 : 0);
291 bpr = ((bmh.bmh_Width + 15) & ~15) / 8;
293 fprintf(stderr, "BMHD: %d x %d x %d (%ld)\n", bmh.bmh_Width,
294 bmh.bmh_Height,
295 bmh.bmh_Depth,
296 totdepth);
297 break;
299 case ID_CMAP:
300 if (!have_bmhd) cleanup("CMAP chunk before BMHD chunk (or no BMHD chunk at all!", 1);
302 cmapentries = size / 3;
303 if (size & 1) size++;
305 if ((cmapentries < 2) || (cmapentries > 256)) cleanup("CMAP chunk has bad number of entries!", 1);
307 for(i = 0; i < cmapentries; i++)
309 red[i] = getbyte();
310 green[i] = getbyte();
311 blue[i] = getbyte();
312 size -= 3;
315 skipbytes(size);
317 have_cmap = 1;
319 break;
321 case ID_BODY:
322 if (!have_bmhd) cleanup("BODY chunk before BMHD chunk (or no BMHD chunk at all!", 1);
323 body = &filebuffer[filepos];
324 bodysize = size;
326 if (bmh.bmh_Compression == CMP_NONE)
328 LONG shouldbesize = totdepth * bpr * bmh.bmh_Height;
329 if (bodysize != shouldbesize) cleanup("BODY chunk size seems to be wrong!", 1);
332 have_body = 1;
333 /* Fall through */
335 default:
336 if (size & 1) size++;
337 skipbytes(size);
338 break;
341 if (filepos == filesize) break;
342 if (have_bmhd && have_body && have_cmap) break;
345 if (!have_bmhd) cleanup("BMHD chunk missing!", 1);
346 if (!have_body) cleanup("BODY chunk missing!", 1);
349 /****************************************************************************************/
351 static unsigned char *unpack_byterun1(unsigned char *source, unsigned char *dest, LONG unpackedsize)
353 unsigned char r;
354 signed char c;
356 for(;;)
358 c = (signed char)(*source++);
359 if (c >= 0)
361 while(c-- >= 0)
363 *dest++ = *source++;
364 if (--unpackedsize <= 0) return source;
367 else if (c != -128)
369 c = -c;
370 r = *source++;
372 while(c-- >= 0)
374 *dest++ = r;
375 if (--unpackedsize <= 0) return source;
382 /****************************************************************************************/
384 static BOOL norm1(LONG count, unsigned char **source_backup,
385 unsigned char **dest, LONG *checksize)
387 //if (count >= 0) fprintf(stderr, "XX: non packable %d\n",count);
389 while(count >= 0)
391 LONG step = count;
393 if (step > 127) step = 127;
395 *checksize -= step;
396 *checksize -= 2;
398 if (*checksize <= 0) return 0;
400 count -= step;
402 *(*dest)++ = step;
405 while(step-- >= 0)
407 *(*dest)++ = *(*source_backup)++;
410 count--;
414 return 1;
417 static BOOL copy1(unsigned char r, LONG count, unsigned char **dest, LONG *checksize)
419 //if (count >= 1) fprintf(stderr, "XX: repeat %02x x %d\n", r, count);
421 while(--count >= 0)
423 LONG step = count;
425 if (step > 127) step = 127;
427 count -= step;
428 step = -step;
429 *checksize -= 2;
430 if (*checksize <= 0) return 0;
432 *(*dest)++ = (unsigned char)step;
433 *(*dest)++ = r;
436 return 1;
439 static BOOL pack_byterun1(unsigned char *source, unsigned char *dest,
440 LONG size, LONG check_size, LONG *packsize)
442 unsigned char *source_backup, *dest_backup;
443 LONG samebytes_counter, samebytes, count;
444 LONG checksize = check_size;
445 unsigned char oldbyte, actbyte;
447 if (checksize < 0) checksize = 0x7FFFFFFF;
449 oldbyte = *source;
450 samebytes_counter = 0;
451 source_backup = source;
452 dest_backup = dest;
454 for(;;)
456 //fprintf(stderr, "size = %d. checksize = %d\n", size, checksize);
457 if (--size < 0) break;
458 actbyte = *source++;
459 if (actbyte == oldbyte)
461 samebytes_counter++;
462 continue;
465 oldbyte = actbyte;
467 samebytes = samebytes_counter;
468 samebytes_counter = 1;
470 if (samebytes < 3) continue;
472 count = (LONG)(source - source_backup - samebytes - 2);
473 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
475 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
477 source_backup = source - 1;
479 //fprintf(stderr, "done\n");
481 if (samebytes_counter >= 3)
483 samebytes = samebytes_counter;
484 count = (LONG)(source - source_backup - samebytes - 1);
485 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
486 if (!copy1(source[-2], samebytes, &dest, &checksize)) return 0;
488 else
490 count = (LONG)(source - source_backup - 1);
491 if (!norm1(count, &source_backup, &dest, &checksize)) return 0;
493 //fprintf(stderr, "realdone\n");
495 if (packsize) *packsize = (LONG)(dest - dest_backup);
497 return 1;
500 /****************************************************************************************/
502 static void p2c(unsigned char *source, unsigned char *dest, LONG width, LONG height,
503 LONG totplanes, LONG wantplanes, LONG chunkybpr)
505 LONG alignedwidth, x, y, p, bpr, bpl;
507 alignedwidth = (width + 15) & ~15;
508 bpr = alignedwidth / 8;
509 bpl = bpr * totplanes;
511 for(y = 0; y < height; y++)
513 for(x = 0; x < width; x++)
515 LONG mask = 1 << (7 - (x & 7));
516 LONG offset = x / 8;
517 unsigned char chunkypix = 0;
519 for(p = 0; p < wantplanes; p++)
521 if (source[p * bpr + offset] & mask) chunkypix |= (1 << p);
523 dest[x] = chunkypix;
526 source += bpl;
527 dest += chunkybpr;
533 /****************************************************************************************/
535 static void convertbody(void)
537 LONG unpackedsize = bpr * bmh.bmh_Height * totdepth;
539 planarbuffer = malloc(unpackedsize);
540 if (!planarbuffer) cleanup("Memory allocation for planar buffer failed!", 1);
542 if (bmh.bmh_Compression == CMP_NONE)
544 memcpy(planarbuffer, body, unpackedsize);
546 else
548 unpack_byterun1(body, planarbuffer, unpackedsize);
551 chunkybuffer = malloc(bmh.bmh_Width * bmh.bmh_Height);
552 if (!chunkybuffer) cleanup("Memory allocation for chunky buffer failed!", 1);
554 p2c(planarbuffer,
555 chunkybuffer,
556 bmh.bmh_Width,
557 bmh.bmh_Height,
558 totdepth,
559 bmh.bmh_Depth,
560 bmh.bmh_Width);
563 /****************************************************************************************/
565 static void packdata(void)
567 LONG chunkysize = (LONG)bmh.bmh_Width * (LONG)bmh.bmh_Height;
568 BOOL success;
570 chunkybuffer_packed = malloc(chunkysize);
572 if (!chunkybuffer_packed) cleanup("Memory allocation for packed chunky buffer failed!", 1);
574 fprintf(stderr, "Starting packing\n");
576 success = pack_byterun1(chunkybuffer, chunkybuffer_packed,
577 chunkysize, chunkysize, &bodysize_packed);
579 fprintf(stderr, "Done packing. Success = %d\n", success);
580 if (!success)
582 free(chunkybuffer_packed); chunkybuffer_packed = 0;
586 /****************************************************************************************/
588 static void gensource(void)
590 unsigned char *buffer;
591 LONG i, x, buffersize;
593 printf("#include <exec/types.h>\n");
594 printf("\n");
595 printf("#define %s_WIDTH %d\n", bigimagename, bmh.bmh_Width);
596 printf("#define %s_HEIGHT %d\n", bigimagename, bmh.bmh_Height);
597 printf("#define %s_PACKED %d\n", bigimagename, (chunkybuffer_packed || planarbuffer_packed) ? 1 : 0);
598 printf("#define %s_PLANES %d\n", bigimagename, bmh.bmh_Depth);
599 if (have_cmap)
600 printf("#define %s_COLORS %ld\n", bigimagename, cmapentries);
602 printf("\n");
604 if (have_cmap)
606 printf("const ULONG %s_pal[%ld] =\n", imagename, cmapentries);
607 printf("{\n");
608 for(i = 0; i < cmapentries; i++)
610 ULONG col = (((ULONG)red[i]) << 16) +
611 (((ULONG)green[i]) << 8) +
612 ((ULONG)blue[i]);
614 printf(" 0x%06lx", col);
615 if (i == cmapentries - 1)
616 printf("\n");
617 else
618 printf(",\n");
620 printf("};\n\n");
624 if (chunkybuffer_packed)
626 buffer = chunkybuffer_packed;
627 buffersize = bodysize_packed;
629 else
631 buffer = chunkybuffer;
632 buffersize = bodysize;
635 printf("const UBYTE %s_data[%ld] =\n", imagename, buffersize);
636 printf("{");
638 i = 0;
640 for(x = 0; x < buffersize; x++)
642 if ((i++ % 20) == 0) printf("\n ");
643 printf("0x%02x", buffer[x]);
644 if (!(x == buffersize - 1)) printf(",");
647 printf("\n");
648 printf("};\n");
651 /****************************************************************************************/
653 static void genbrush2csource(void)
655 int i;
657 if (have_cmap)
659 printf("#ifdef USE_%s_COLORS\n", bigimagename);
660 printf("const ULONG %s_colors[%ld] =\n{\n", imagename, cmapentries * 3);
661 for (i = 0; i < cmapentries; i++)
663 printf("\t0x%08lx,0x%08lx,0x%08lx,\n",
664 (long) ((ULONG)red[i] << 24 | (ULONG)red[i] << 16 | (ULONG)red[i] << 8 | (ULONG)red[i]),
665 (long) ((ULONG)green[i] << 24 | (ULONG)green[i] << 16 | (ULONG)green[i] << 8 | (ULONG)green[i]),
666 (long) ((ULONG)blue[i] << 24 | (ULONG)blue[i] << 16 | (ULONG)blue[i] << 8 | (ULONG)blue[i]));
668 printf("};\n");
669 printf("#endif\n\n");
672 if (have_body)
674 printf("#define %s_WIDTH %3d\n", bigimagename, bmh.bmh_Width);
675 printf("#define %s_HEIGHT %3d\n", bigimagename, bmh.bmh_Height);
676 printf("#define %s_DEPTH %3d\n", bigimagename, bmh.bmh_Depth);
677 printf("#define %s_COMPRESSION %3d\n", bigimagename, bmh.bmh_Compression);
678 printf("#define %s_MASKING %3d\n", bigimagename, bmh.bmh_Masking);
679 printf("\n");
681 printf("#ifdef USE_%s_HEADER\n", bigimagename);
682 printf("const struct BitMapHeader %s_header =\n{ %ld,%ld,%ld,%ld,%ld,%ld,%ld,0,%ld,%ld,%ld,%ld,%ld };\n",
683 imagename, (long)bmh.bmh_Width, (long)bmh.bmh_Height, (long)bmh.bmh_Left, (long)bmh.bmh_Top,
684 (long)bmh.bmh_Depth, (long)bmh.bmh_Masking, (long)bmh.bmh_Compression, (long)bmh.bmh_Transparent,
685 (long)bmh.bmh_XAspect, (long)bmh.bmh_YAspect, (long)bmh.bmh_PageWidth, (long)bmh.bmh_PageHeight);
686 printf("#endif\n\n");
688 printf("#ifdef USE_%s_BODY\n", bigimagename);
689 printf("const UBYTE %s_body[%ld] = {\n", imagename, bodysize);
690 for (i = 0; i < bodysize; i++)
692 printf("0x%02lx,", (long)(body[i]));
693 if (!((i + 1) % 15)) printf("\n");
695 printf(" };\n");
696 printf("#endif\n");
700 /****************************************************************************************/
702 static void genbrush2pixsource(void)
704 int i;
706 if (have_cmap)
708 printf("const ULONG %s_colors[%ld] =\n{\n", imagename, cmapentries * 3);
709 for (i = 0; i < cmapentries; i++)
711 printf("\t0x%08lx,0x%08lx,0x%08lx,\n",
712 (long)((ULONG)red[i] << 24 | (ULONG)red[i] << 16 | (ULONG)red[i] << 8 | (ULONG)red[i]),
713 (long)((ULONG)green[i] << 24 | (ULONG)green[i] << 16 | (ULONG)green[i] << 8 | (ULONG)green[i]),
714 (long)((ULONG)blue[i] << 24 | (ULONG)blue[i] << 16 | (ULONG)blue[i] << 8 | (ULONG)blue[i]));
716 printf("};\n\n");
719 if (have_body)
721 printf("#define %s_WIDTH %3d\n", bigimagename, bmh.bmh_Width);
722 printf("#define %s_HEIGHT %3d\n", bigimagename, bmh.bmh_Height);
723 printf("#define %s_DEPTH %3d\n", bigimagename, bmh.bmh_Depth);
724 printf("#define %s_COMPRESSION %3d\n", bigimagename, bmh.bmh_Compression);
725 printf("#define %s_MASKING %3d\n", bigimagename, bmh.bmh_Masking);
726 printf("\n");
728 printf("const UBYTE %s_body[%ld] = {\n", imagename, bodysize);
729 for (i = 0; i < bodysize; i++)
731 printf("0x%02lx,", (long)(body[i]));
732 if (!((i + 1) % 15)) printf("\n");
734 printf(" };\n");
737 if (have_cmap && have_body)
739 printf("\nmuidefpix %s_defpix =\n{\n", imagename);
740 printf("\t%s_body,\n", imagename);
741 printf("\t%s_colors,\n", imagename);
742 printf("\t%s_WIDTH, %s_HEIGHT, %s_DEPTH,\n", bigimagename, bigimagename, bigimagename);
743 printf("\t%s_COMPRESSION, %s_MASKING \n", bigimagename, bigimagename);
744 printf("};\n");
748 /****************************************************************************************/
750 int main(int argc, char **argv)
752 getarguments(argc, argv);
753 openfile();
754 checkfile();
755 scanfile();
757 if (brush2c)
759 genbrush2csource();
761 else if (brush2pix)
763 genbrush2pixsource();
765 else
767 convertbody();
768 packdata();
769 gensource();
772 cleanup(0, 0);
775 /****************************************************************************************/