/* ilbm2prt
 * This program converts a ilbm-file to a series of rgb-files that can be fed
 * separately with "copy <name> to par:" into a Mitsubishi Videoprinter
 *
 * Source-code and executable are ©'93 by
 *           Stephan Feinen
 *           Im Steinfeld 1
 *           52076 Aachen
 *           Germany
 *
 * Please send comments, criticism and suggestions to:
 *           feinen@pool.informatik.rwth-aachen.de
 *
*/

#define VERSION "1.2"
#include <stdio.h>
#include <fcntl.h>
#include <sys/file.h>
#define RowBytes(cols)  ( ( ( (int)(cols) + 15 ) >> 4 ) << 1 )
#define mskNone                 0
#define mskHasMask              1
#define mskHasTransparentColor  2
#define mskLasso                3

#define cmpNone                 0
#define cmpByteRun1             1
#define ALLOCROW( cols ) ((pixel*) malloc( cols * sizeof(pixel) ))

struct BitMapHeader
{
    unsigned short w, h;
    short x, y;
    unsigned char nPlanes, masking, compression, pad1;
    unsigned short transparentColor;
    unsigned char xAspect, yAspect;
    short pageWidth, pageHeight;
};


typedef struct
    {
    unsigned char r, g, b;
    } pixel;

char   version[25]="$VER: 1.2 (05.12.93)";
char   vers[10]=VERSION;


pixel *pixelrow;

struct BitMapHeader ilbmheader;
unsigned char   form[5],header[11];
unsigned char  *ubp,*bp;
unsigned char *runbuf;
unsigned char   *Rrow;
unsigned char   *Brow;
unsigned char   *Grow;
unsigned int    byte;
int     totbytes,row;
int col,j,plane;
long    bmsize,formsize;
unsigned char *body = 0;
unsigned long body_chunk_size;
FILE *fp;
int     fd1,fd2,fd3;
char tempname[40];

void Usage()
{
fprintf(stderr,"Usage: ilbm2prt ILBMFILE/A BASENAME/A\n");
fprintf(stderr,"ILBMFILE must be a 24-bit ILBM\n");
fprintf(stderr,"BASENAME will be expanded to BASENAME.red, BASENAME.grn, BASENAME.blu\n");
}

main( argc, argv )
int argc;
char **argv;
{
 printf("ilbm2prt %s ©1993 Stephan Feinen\n",vers);
 if (argc != 3){
   Usage();
   exit(1);
   }

 if (!(fp = fopen(argv[1],"r"))){
   fprintf(stderr,"Open of '%s' for reading failed.\n",argv[1]);
   exit(20);
   }
 puts("Opened source");
 strcpy(tempname,argv[2]);
 strcat(tempname, ".red");
 printf("tempname:%s\n",tempname);
 if ((fd1 = creat(tempname,0660)) < 0) {
   fprintf(stderr,"Open of '%s' for writing red-part failed.\n",tempname);
   exit(20);
   }
 puts("Opened red-file");
 strcpy(tempname,argv[2]);
 strcat(tempname, ".grn");
 if ((fd2 = creat(tempname,0660)) < 0) {
   fprintf(stderr,"Open of '%s' for writing green-part  failed.\n",tempname);
   exit(20);
   }
 puts("Opened green-file");
 strcpy(tempname,argv[2]);
 strcat(tempname, ".blu");
 if ((fd3 = creat(tempname,0660)) < 0) {
   fprintf(stderr,"Open of '%s' for writing blue-part failed.\n",tempname);
   exit(20);
   }
 puts("Opened blue-file");

 fread(form,4,1,fp);            /* FORM */
 if (strcmp(form,"FORM") != NULL) {
   fprintf(stderr,"'%s' is not an IFF file. Exiting.\n",argv[1]);
   fclose(fp);
   close(fd1);
   close(fd2);
   close(fd3);
   exit(20);
   }
 fread(&formsize,4,1,fp);       /* Size of whole form -4 */
 printf("%s ",form);
 fread(form,4,1,fp);            /* ILBM */
 printf("%s: (%d bytes) ",form,formsize);
 fread(form,4,1,fp);            /* BMHD */
 fread(&bmsize,4,1,fp);         /* size of BMHD */
 fread(&ilbmheader,20,1,fp);
 printf("(%dx%d) (%d planes) (Compression %s)\n",ilbmheader.w,ilbmheader.h,ilbmheader.nPlanes, ilbmheader.compression == cmpByteRun1 ? "On" : "Off");
 if (ilbmheader.nPlanes != 24) {
   fprintf(stderr,"Only IFF ILBM's of 24 bit planes are supported.\n");
   fclose(fp);
   close(fd1);
   close(fd2);
   close(fd3);
   exit(20);
   }

 fread(form,4,1,fp);            /* BODY (ANNO sometimes) */

 while ((strcmp(form,"BODY") != 0))     /* Find the damn thing */
   fread(form,4,1,fp);
        
 fread(&body_chunk_size,4,1,fp);

 pixelrow = ALLOCROW(ilbmheader.w);
 body = (unsigned char*) malloc(body_chunk_size);
 runbuf = (unsigned char*) malloc(RowBytes(ilbmheader.w));
 Rrow = (unsigned char*) malloc(ilbmheader.w);
 Grow = (unsigned char*) malloc(ilbmheader.w);
 Brow = (unsigned char*) malloc(ilbmheader.w);
 if (body == NULL || pixelrow == NULL || runbuf == NULL ||
   Rrow == NULL || Grow == NULL || Brow == NULL) {
   fprintf(stderr,"Unable to allocate all the memory I need...\n");
   fclose(fp);
   close(fd1);
   close(fd2);
   close(fd3);
   exit(20);
   }
 header[0]=27;
 header[1]=83;
 header[2]=48;
 header[3]=(ilbmheader.h) / 256;
 header[4]=(ilbmheader.h) % 256;
 header[5]=75;
 bp = body;

        /* Read in the body of the ilbm */
 fread(body, body_chunk_size, 1, fp); 
 puts("sources read\n");
 write(fd1,header,6); 
 for (row = 0; row < (int)ilbmheader.h; row++ ) {

        /* There are kind of colormappish */
/*   Only needed if planes != 24 */
   for (col = 0; col < 640 ; col++ )
     Rrow[col] = Grow[col] = Brow[col] = 0;

   for (plane = 0; plane < (int)ilbmheader.nPlanes; plane++) {
     switch (ilbmheader.compression) {

       case 0:
              ubp = bp;
              bp += RowBytes(640);
              break;
       case 1:
              ubp = runbuf;
              totbytes = RowBytes(640);
              do {
                byte = *bp++;
                if ( byte <= 127 )
                  for ( j = byte, totbytes -= j + 1; j >= 0; j--) {
                    *ubp++ = *bp++;
                    }
                else if ( byte != 128 )
                  for (j = 256 - byte, totbytes -= j + 1, byte = *bp++; j >= 0; j--) {
                    *ubp++ = byte;
                    }
                } while ( totbytes > 0 );
              ubp = runbuf;
              break;
       }

       /* Break raw row buffer up into separate rgb values */
       /* In order to understand this a little better, it might help */
       /* to know that the pixel values in an ILBM appear to be stored */
       /* bit reversed. Hence all the logical bitwise juju. */
     if ( plane < 8){
       for ( col = 0; col < 640; col++ )
         {
         if ( ubp[col >> 3] & ( 128 >> ( col & 7 ) ) )
           Rrow[col] |= 1 << plane;
         }
       }
     else if ( plane > 15 ) { /* blue */
       for ( col = 0; col < 640; col++ )
         {
         if ( ubp[col >> 3] & ( 128 >> ( col & 7 ) ) )
           Brow[col] |= 1 << (plane-16);
         }
       }
     else { /* green */
       for ( col = 0; col < 640; col++ )
         {
         if ( ubp[col >> 3] & ( 128 >> ( col & 7 ) ) )
           Grow[col] |= 1 << (plane-8);
         }
       }
     }
      /* Write out an entire row of pixel interleaved data */
     write(fd1, Rrow, 640);
     write(fd2, Grow, 640);
     write(fd3, Brow, 640);
   }
 free(Rrow);            /* Fly! Be Free!! */
 free(Grow);
 free(Brow);
 free(runbuf);
 free(body);
 fclose(fp);
 close(fd1);
 close(fd2);
 close(fd3);
 exit(0);
}
