/*
 * NAME
 *      pk2bm - create a bitmap from a TeX pkfont
 * SYNOPSIS:
 *	pk2bm [-bh] [-W width] [-H height] {-c char|-o octchar} pkfont 
 * DESCRIPTION
 *	This program generates a bitmap (ASCII file) which can be used
 *	to create X11 applications. The bitmap file consists of all
 *	pixels of the specified character (via the -c or -o option) from 
 *	the given pkfont. The format is described in bitmap(X11).
 *
 *	The pkfont is a packed fontfile generated by gftopk(TeX) from a 
 *	gffont. A gffont is the output of METAFONT a program to design fonts
 *	in a device independant way.
 *
 *	With the -b flag a bitmap is generated in which all black pixels are
 *	drawn as a `*' and all white bits as a `.'. With the -h flag a 
 *	hexadecimal bitmap dump is generated. 
 *
 *      The -W and/or -H options can be used to create a bitmap of
 *	respectivally `width' and `height' pixels. The pk-bitmap will in
 *	this case be centered according to these new dimensions.
 *
 *	The output is written to the standard output.
 * SEE ALSO
 *	``METAFONT'', Donald Knuth.
 *	``The PKtype processor'', belonging to the METAFONTware.
 *	bitmap(X11), gftopk(TeX), pktype(TeX), ps2pk(1)
 * AUTHOR
 *	Piet Tutelaers
 */

#ifdef HAVE_CONFIG_H
#include "c-auto.h"
#endif

#include <stdio.h>
#include "pkin.h"
#include "basics.h"

#ifdef WIN32
#include <fcntl.h>
#include <io.h>
#endif

static quarterword lsbf(quarterword u);
static void dots(quarterword u, int n);
static int atoo(char *oct);

int main(int argc, char *argv[])
{
   int done, C = 0, c, h = 0, w = 0, row, col;
   unsigned int bitmap = 0, hexmap = 0;
   halfword *word;
   chardesc cd;
   const char *myname = "pk2bm";
   char *pkname;
	
   while (--argc > 0 && (*++argv)[0] == '-') {
      done=0;
      while ((!done) && (c = *++argv[0]))	/* allow -bcK as an option */
         switch (c) {
      	 case 'c':
      	    if (*++argv[0] == '\0') {
      	       argc--;  argv++;
      	    }
      	    if (argv[0] == NULL) goto invalid;
      	    C = *argv[0];
      	    done = 1; break;
      	 case 'o':
      	    if (*++argv[0] == '\0') {
      	       argc--;  ++argv;
      	    }
      	    if (argv[0] == NULL) goto invalid;
      	    C = atoo(argv[0]);
      	    done = 1; break;
      	 case 'H':
      	    if (*++argv[0] == '\0') {
      	       argc--; argv++;
      	    }
      	    if (argv[0] == NULL) goto invalid;
      	    h = atoi(argv[0]);
            done=1;
      	    break;
      	 case 'W':
      	    if (*++argv[0] == '\0') {
      	       argc--; argv++;
      	    }
      	    if (argv[0] == NULL) goto invalid;
      	    w = atoi(argv[0]);
	    done=1;
      	    break;
      	 case 'b':
      	    bitmap = 1;
      	    break;
      	 case 'h':
      	    hexmap = 1;
      	    break;
invalid:
      	 default:
      	    printf("%s: %c invalid option\n", myname, c);
      	    exit(1);
      	 }
   }

   if (argc == 0) {
       msg  ("pk2bm (ps2pk) version " PACKAGE_VERSION " (" TL_VERSION ")\n");
       msg  ("Usage: %s [-bh] {-c char|-o octchar} [-W width -H height] pkfile\n", myname);
       fatal("\nEmail bug reports to %s.\n", PACKAGE_BUGREPORT);
   }

#ifdef WIN32
   _setmode(fileno(stdout), _O_BINARY);
#endif

   pkname = argv[0];

   if (readchar(pkname, (integer)C, &cd)) {
      int H, dh, W, dw, bitsleft;
      halfword nextword; quarterword nextbyte;

      H=cd.cheight; if (h==0) h=H; dh=(h-H)/2;
      W=cd.cwidth; if (w==0) w=W; dw=(w-W)/2;
	   
      if (bitmap || hexmap) {
         printf("character : %d (%c)\n", (int) cd.charcode, 
	         (char)cd.charcode);
         printf("   height : %d\n", (int) cd.cheight);
         printf("    width : %d\n", (int) cd.cwidth);
         printf("     xoff : %d\n", (int) cd.xoff);
         printf("     yoff : %d\n", (int) cd.yoff);
      }
      else {
         printf("#define %s_%c_width \t %d\n",
              pkname, (char)cd.charcode, (int) w);
         printf("#define %s_%c_height \t %d\n",
              pkname, (char)cd.charcode, (int) h);
         printf("#define %s_%c_xoff \t %d\n",
              pkname, (char)cd.charcode, (int) dw);
         printf("#define %s_%c_yoff \t %d\n",
              pkname, (char)cd.charcode, (int) dh);
         printf("static char %s_%c_bits[] = {", 
   	      pkname, (char)cd.charcode);
      }
      for (row=0; row<h-H-dh; row++) {
          printf("\n  ");
          for (col=0; col<w; col+=8)
             if (bitmap) dots(0, w-col>7? 8: w-col);
             else if (hexmap) printf("%02x", 0x00);
             else printf(" 0x%02x, ", 0x00);
      }
      word = cd.raster;
      for (row=h-H-dh; row<h-dh; row++) {
         bitsleft = dw; nextword = 0;
         printf("\n  ");
         for (col=0; col<w; col+=8) {
            if (bitsleft>=8) {
               nextbyte = nextword >> (bitsleft-8) & 0xff;
	       bitsleft-=8;
	       
               if (bitmap) dots(nextbyte, w-col>7? 8: w-col); 
               else if (hexmap) printf("%02x", nextbyte);
               else printf(" 0x%02x, ", lsbf(nextbyte));
	    }
	    else {
	       nextbyte = nextword << (8-bitsleft) & 0xff;
	       if (col-dw<W)
	          nextword=(*word++);
	       else nextword=0;
	       nextbyte = nextbyte | (nextword >> (16-(8-bitsleft))
		                           & 0xff);
	       bitsleft = 16 - (8-bitsleft);
	       
               if (bitmap) dots(nextbyte, w-col>7? 8: w-col);
               else if (hexmap) printf("%02x", nextbyte);
               else printf(" 0x%02x, ", lsbf(nextbyte));
	    }
	 }
      }
      for (row=h-dh; row<h; row++) {
          printf("\n  ");
	  for (col=0; col<w; col+=8)
             if (bitmap) dots(0, w-col>7? 8: w-col);
             else if (hexmap) printf("%02x", 0x00);
             else printf(" 0x%02x, ", 0x00);
      }
      if ((!bitmap) && (!hexmap)) printf("};\n");
      else putchar('\n');
   }
   return 0;
}

/*
 * lsbf() transforms a byte (least significant bit first).
 */
static quarterword
lsbf(quarterword u)
{
	int i; quarterword bit, result = 0;

	for (i=0; i<8; i++) {
	   bit = u & 001;
	   result = (result<<1) | bit;
	   u = u >> 1;
	}
	return result;
}

/*
 * dots() print byte: `*' for a black and `.' for a white pixel
 */
static void
dots(quarterword u, int n)
{
   unsigned int bit;

   bit=1<<7;
   for ( ;n>0 ;n--) {
      if (u & bit) putchar('*');
      else putchar('.');
      bit>>=1;
   }
}

static int
atoo(char *oct)
{
   int octal = 0;
   while (*oct != '\0') octal = 8*octal + (*oct++) - '0';
   return octal;
}
