/*  bmp2gray, utility to convert 16-grayscale BMPs to 8-grayscale 85s
    by Magnus Svedin (gy95msv@t.du.se).
    Feel free to use this however you like EXCEPT ANY KIND OF PORTING
    OR RUNNING ON A mac. If you want to discuss this, mail me.
*/
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <conio.h>

#define uchar unsigned char

struct p
{
  uchar index;
  uchar col;
};

uchar convcol(struct p *colors, uchar index);

int main(int numarg, char *arg[])
{
  FILE *f;
  int a,b;
  char *filename;
  struct p colors[16];
  unsigned int chsum;
	uchar curbit, curbyte, *rawpic, *tipic;
  uchar header[]=  {0x2A, 0x2A, 0x54, 0x49, 0x38, 0x35, 0x2A, 0x2A, 0x1A, 0x0C, 0x00, 0x4D, 0x61, 0x63, 0x68, 0x69,
                    0x6E, 0x65, 0x20, 0x63, 0x6F, 0x64, 0x65, 0x20, 0x73, 0x74, 0x6F, 0x72, 0x65, 0x64, 0x20, 0x61,
                    0x73, 0x20, 0x61, 0x20, 0x73, 0x74, 0x72, 0x69, 0x6E, 0x67, 0x2E, 0x20, 0x20, 0x20, 0x20, 0x20,
										0x20, 0x20, 0x5A, 0x53, 0x34, 0x14, 0x0C, 0x0B, 0x00, 0x05, 0x0c, 0x0c, 0x07,
                    0x47, 0x72, 0x61, 0x79, 0x50, 0x69, 0x63, 0x05, 0x0c, 0x03, 0x0c, 0x00, 0x7f};
  printf("bmp2gray v2.0 by Magnus Svedin\n");
	if(numarg!=2)
	{
		printf("Usage: bmp2gray [bitmapfile]\n");
		printf("       Creates GrayPic.85s\n");
		exit(1);
	}
	rawpic=(uchar *)malloc(4096*sizeof(uchar));
	tipic=(uchar *)malloc(128*64*sizeof(uchar));
  b=0;
  for(a=0;arg[1][a]!='\0';a++)
    if(arg[1][a]=='.')
      b=1;
  if(b==0)
  {
    filename=(char *)malloc(15*sizeof(char));
    strcpy(filename, arg[1]); 
    strcat(filename, ".bmp");    
    f=fopen(filename, "rb");   
    free(filename);
  }
  else
    f=fopen(arg[1], "rb");
	if(!f)
	{
		printf("Unable to open file: %s\n", arg[1]);
		exit(1);
	}
  fread(rawpic, 0x20, 1, f);
  if(rawpic[0]!=0x42 || rawpic[1]!=0x4d || rawpic[3]!=0x10 || rawpic[18]!=0x80 || rawpic[22] != 0x40)
  {
    printf("Input file doesn't appear to be a 128x64 16-grays RGB-encoded BMP-file, continue anyway(Y/n)?\n");
    a=getch();
    if(a!='y' && a!='Y')
    {
      fclose(f);
      exit(1);
    }
  }
  fseek(f, 0x3a, SEEK_SET);  /* Creating table to convert 16 grays to 8 grays */
  for(a=0;a<16;a++)
  {
    colors[a].index=(uchar)a;
    fread(&colors[a].col, 1, 1, f);
    fseek(f, 0x3, SEEK_CUR);
  }

  fseek(f, 0x76, SEEK_SET); /* Reading and reversing data to rawpic */
	for(a=63;a>=0;a--)
	{
		fread(tipic, 64, 1, f);
		for(b=0;b<64;b++)
		  rawpic[b+a*64]=tipic[b];
	}
	fclose(f);

  for(a=0;a<8192;a=a+2)  /* Converting rawpic to tipic (16 to 8 grays) */
	{
    tipic[a+1]=convcol(colors, (rawpic[a/2] & 0xf));
    tipic[a]=convcol(colors, (rawpic[a/2] >> 4)); /* was >> 4 */
	}
	free(rawpic);
  f=fopen("GrayPic.85s", "wb");  /* Writing GrayPic.85s */
	if(!f)
	{
		printf("Unable to write file GrayPic.85s.\n");
		exit(1);
	}
	fwrite(header, 1, 0x4a, f);
  chsum=0x37d; /* or 0x305 0x2fa */
	for(curbit=0x04;curbit!=0;curbit=curbit>>1)
	{
		for(b=0;b<1024;b++)
		{
			curbyte=0;
      for(a=0;a<8;a++)
			{
        if((tipic[b*8+a] & curbit) != 0)
          curbyte+=(((uchar)1)<<(7-a));
			}
			fwrite(&curbyte, 1, 1, f);
			chsum+=(unsigned int)curbyte;
		}
	}
	free(tipic);
  curbyte=0;
  fwrite(&curbyte, 1, 1, f); /* not quite sure why, but it works :) */
  curbyte=(uchar)(chsum&0xff);
	fwrite(&curbyte, 1, 1, f);
	curbyte=(uchar)(chsum>>8);
	fwrite(&curbyte, 1, 1, f);
	fclose(f);
	printf("GrayPic.85s written ok.\n");
	return(0);
}

uchar convcol(struct p *colors, uchar index)
{
  int a=0;
  while(colors[a].index != index)
    a++;
  return(8-(colors[a].col/32));
}
