#include "stdio.h"
#include "stdlib.h"
#include "math.h"
#include "string.h"
#define TRUE 1
#define FALSE 0

/*
   Conversion d'un fichier .BMP vers un .CIR, pour le concours du "Reporter"
   par le Club LinuX Nord-Pas de Calais
   http://clx.anet.fr/spip/article.php3?id_article=170

   Fonction de lecture du fichier BMP par Paul Bourke
   http://astronomy.swin.edu.au/~pbourke/dataformats/

*/

typedef struct {
   unsigned short int type;                 /* Magic identifier            */
   unsigned int size;                       /* File size in bytes          */
   unsigned short int reserved1, reserved2;
   unsigned int offset;                     /* Offset to image data, bytes */
} HEADER;

typedef struct {
   unsigned int size;               /* Header size in bytes      */
   int width,height;                /* Width and height of image */
   unsigned short int planes;       /* Number of colour planes   */
   unsigned short int bits;         /* Bits per pixel            */
   unsigned int compression;        /* Compression type          */
   unsigned int imagesize;          /* Image size in bytes       */
   int xresolution,yresolution;     /* Pixels per meter          */
   unsigned int ncolours;           /* Number of colours         */
   unsigned int importantcolours;   /* Important colours         */
} INFOHEADER;

typedef struct {
   unsigned char r,g,b,junk;
} COLOURINDEX;

void    ReadUShort(FILE *fptr, void *header, char toto) {
  fread(header, sizeof(short int), 1, fptr);
}

void    ReadUInt(FILE *fptr, void *header, char toto) {
  fread(header, sizeof(int), 1,fptr);
}

void exit_and_close(int value) {
  free(filename);
  exit (value);
}

char repCar[19] = "ABCDEFGH JKLMNOPQRS";

int main(int argc,char **argv)
{
   int i,j;
   int gotindex = FALSE;
   unsigned char grey,r,g,b;
   char *filename;
   HEADER header;
   INFOHEADER infoheader;
   COLOURINDEX colourindex[256];
   FILE  *fptr,
         *outfile;
   unsigned char *bmpBuff;

   if (filename=(char *)malloc(sizeof(char)*255))==NULL) {
      fprintf(stderr,"Memory allocation failed\n");
      exit(-1);
   }
   if (bmpBuff=(char *) malloc(((infoheader.width+1)*(infoheader.height+1)))==NULL) {
      fprintf(stderr,"Memory allocation failed\n");
      free(filename);
      exit(-1);
   }
   ;

   /* Check arguments */
   fprintf(stderr,"BMP 2 CIR\nUtilitaire de convertion pour le concours du \"Reporter\"\nhttp://clx.anet.fr/spip/article.php2?id_article=170\n---------------------------------------------------\n\n");
   if (argc < 2) {
      fprintf(stderr,"Usage: %s filename\n",argv[0]);
      strcpy(filename,"monaco.bmp");
      exit_and_close(-1);
   } else {
      filename=argv[1];
   }
   
   /* Open file */
   if ((fptr = fopen(filename,"r")) == NULL) {
      fprintf(stderr,"Unable to open BMP file \"%s\"\n",filename);
      exit_and_close(-1);
   }
   
   /* Read and check the header */
   ReadUShort(fptr,&header.type,FALSE);
   fprintf(stderr,"ID is: %d, should be %d to be a valid BMP file\n",header.type,'M'*256+'B');
   ReadUInt(fptr,&header.size,FALSE);
   fprintf(stderr,"File size is %d bytes\n",header.size);
   ReadUShort(fptr,&header.reserved1,FALSE);
   ReadUShort(fptr,&header.reserved2,FALSE);
   ReadUInt(fptr,&header.offset,FALSE);
   fprintf(stderr,"Offset to image data is %d bytes\n",header.offset);

   /* Read and check the information header */
   if (fread(&infoheader,sizeof(INFOHEADER),1,fptr) != 1) {
      fprintf(stderr,"Failed to read BMP info header\n");
      exit_and_close(-1);
   }
   fprintf(stderr,"Image size = %d x %d\n",infoheader.width,infoheader.height);
   fprintf(stderr,"Number of colour planes is %d\n",infoheader.planes);
   fprintf(stderr,"Bits per pixel is %d\n",infoheader.bits);
   fprintf(stderr,"Compression type is %d\n",infoheader.compression);
   fprintf(stderr,"Number of colours is %d\n",infoheader.ncolours);
   fprintf(stderr,"Number of required colours is %d\n", infoheader.importantcolours);

   if ((infoheader.width!=150) || (infoheader.height!=100) || (infoheader.bits!=4) || (infoheader.ncolours>0)) {
      fprintf(stderr,"BMP file must be 150x100 pixels, 16 colors, not indexed");
      exit_and_close(-1);
   }

   /* Read the lookup table if there is one */
   for (i=0;i<255;i++) {
      colourindex[i].r = rand() % 256;
      colourindex[i].g = rand() % 256;
      colourindex[i].b = rand() % 256;
      colourindex[i].junk = rand() % 256;
   }
   if (infoheader.ncolours > 0) {
      for (i=0;i<infoheader.ncolours;i++) {
         if (fread(&colourindex[i].b,sizeof(unsigned char),1,fptr) != 1) {
            fprintf(stderr,"Image read failed\n");
            exit_and_close(-1);
         }
         if (fread(&colourindex[i].g,sizeof(unsigned char),1,fptr) != 1) {
            fprintf(stderr,"Image read failed\n");
            exit_and_close(-1);
         }
         if (fread(&colourindex[i].r,sizeof(unsigned char),1,fptr) != 1) {
            fprintf(stderr,"Image read failed\n");
            exit_and_close(-1);
         }
         if (fread(&colourindex[i].junk,sizeof(unsigned char),1,fptr) != 1) {
            fprintf(stderr,"Image read failed\n");
            exit_and_close(-1);
         }
         fprintf(stderr,"%3d\t%3d\t%3d\t%3d\n",i,
            colourindex[i].r,colourindex[i].g,colourindex[i].b);
      }
      gotindex = TRUE;
   }

   /* Seek to the start of the image data */
   fseek(fptr,header.offset,SEEK_SET);

   /* Test if file is on true format */
   /* Read the image */
   for (j=0;j<infoheader.height;j++) {
      for (i=0;i<=infoheader.width;i++) {
         switch (infoheader.bits) {
         case 1:
            break;
         case 4:
            if (fread(&grey,sizeof(unsigned char),1,fptr) != 1) {
               fprintf(stderr,"Image read failed\n");
               exit_and_close(-1);
            }
            if (gotindex) { // indexed palette on 3 bytes
               printf("%c",colourindex[grey>>4].r);
               printf("%c",colourindex[grey>>4].g);
               printf("%c",colourindex[grey>>4].b);
               printf("%c",colourindex[grey & 0x0F].r);
               printf("%c",colourindex[grey & 0x0F].g);
               printf("%c",colourindex[grey & 0x0F].b);
               /* place here bmpBuff data if you know how to handle indexed 4 bits BMP a way useable 
                  for .cir conversion */
            } else {
               bmpBuff[i+(infoheader.width*j)]=repCar[grey>>4 & 0x0F];
               bmpBuff[i+1+(infoheader.width*j)]=repCar[grey & 0x0F];
               i++;
            }
            break;
         case 8:
            if (fread(&grey,sizeof(unsigned char),1,fptr) != 1) {
               fprintf(stderr,"Image read failed\n");
               fclose(outfile);
               exit_and_close(-1);
            }
            if (gotindex) {
               putchar(colourindex[grey].r);
               putchar(colourindex[grey].g);
               putchar(colourindex[grey].b);
               fprintf(outfile,"%c",colourindex[grey].r);
               fprintf(outfile,"%c",colourindex[grey].g);
               fprintf(outfile,"%c",colourindex[grey].b);
            } else {
               putchar(grey);
            }
            break;
         case 24:
            if (fread(&b,sizeof(unsigned char),1,fptr) != 1) {
               fprintf(stderr,"Image read failed\n");
               exit_and_close(-1);
            }
            if (fread(&g,sizeof(unsigned char),1,fptr) != 1) {
               fprintf(stderr,"Image read failed\n");
               exit_and_close(-1);
            }
            if (fread(&r,sizeof(unsigned char),1,fptr) != 1) {
               fprintf(stderr,"Image read failed\n");
               exit_and_close(-1);
            }
            putchar(r);
            putchar(g);
            putchar(b);
            break;
         }

      } /* i */
   } /* j */

  fclose(fptr);

  char * toto=strtok(filename,".");

  /* open the output file, is it there? */
  if ((outfile = fopen(strcat(filename,".cir"),"w")) == NULL)
  {
  /* gives error message if file cannot be open*/
     fprintf(stderr,"Output impossible to %s",filename);
     exit_and_close(-1);
  }

  //while(!kbhit()){}                   /* wait for a keyboard press*/

   for (i=(infoheader.height-1)*infoheader.width;i>=0;i-=infoheader.width) {
     for (j=0;j<infoheader.width;j++) {
       fprintf(outfile,"%c",bmpBuff[j+i]);
     }
     fprintf(outfile,"\n");
   }
   fprintf(stderr,"File %s succesfully wrote",filename);
   fclose(outfile);
   free (bmpBuff);
   free (filename);
   while(!kbhit()){}                   /* wait for a keyboard press*/
}

