Path: funic!news.funet.fi!sunic!uupsi!rice!cs.utexas.edu!sdd.hp.com!hp-pcd!hpcvra.cv.hp.com!rnews!hpcvbbs!akcs.rkb
From: akcs.rkb@hpcvbbs.UUCP (Robert Brunner)
Newsgroups: comp.sys.handhelds
Subject: Re: How does one print out a GROB from a PC?
Keywords: GROB, PC printing
Message-ID: <27a26d9b:1803.2comp.sys.handhelds;1@hpcvbbs.UUCP>
Date: 27 Jan 91 06:40:07 GMT
References: <1991Jan24.182436.20395@rick.cs.ubc.ca> <7360058@hpfcso.HP.COM>
Lines: 255

I've been meaning to write a program to print out GROBs
for some time.  Reading  the previous posts motivated
me to finally do it.  The program runs on PC-compatibles
under MS-DOS.  Some directions for use can be found in the
comments for the program.  I'm only posting the source code
(written in Turbo C) here, but I will also post the executable
on hpcvbbs in user.programs.  I hope this helps you out.
By the way, this program was written and tested in one Saturday 
afternoon, so it probably includes some bugs (at no extra charge :-))
I'd be interested if others add more options; please get back
to me if you do.

             Robert Brunner
                   brunner@uirvld.csl.uiuc.edu

/*
/
**  grob2eps.c   version 1.0
**  Robert Brunner
**  1-26-91
**
**  Translate a GROB to a file which can be copied to an Epson
**  printer.  The GROB is sent from the HP-48 to the PC using
**  ASCII mode.  The program is then run with the command:
**
**  C>grob2eps grob_file print_file
**
**  and the results can be printed with the MS-DOS copy command:
**
**  C>copy print_file /b prn
**
**  If either filename is omitted, stdin or stdout are used.
**  Therefore, another way to execute the command is:
**
**  C>grob2eps grob_file >prn
**
**  Bugs:
**  1) Specifying PRN for the print_file sends garbage to the printer
**  2) The program is slow as molasses
**
**  This program was developed for MS-DOS with Turbo C 2.0, although
**  no machine-specific are used, so it may be usable on other
**  systems.
*/
 
#include <stdio.h>
 
#define GROBTYP     "GROB"
#define ESC         27
 
main(argc,argv)
int argc;
char *argv[];
{
  FILE *fp_in, *fp_out;
  char ftyp[5], *grobmap;
  unsigned char *bmap;
  int realwidth,width,realheight,height,i;
  long grobsize;
 
  /*
  **  Open files from the command line, or use stdin and stdout
  */
  if (argc>=2) {
    if ((fp_in=fopen(argv[1],"r"))==NULL)  {
      fprintf(stderr,"Can't open grob file\n");
      exit(1);
    }
  } else fp_in=stdin;
  if (argc>=3) {
    if ((fp_out=fopen(argv[2],"wb"))==NULL)  {
      fprintf(stderr,"Can't open print file\n");
      exit(2);
    }
  } else fp_out=stdout;
 
  /*
  **  Find the first occurence of GROB and print out this.
  **  This gets the file pointer past the %%HP junk.
  */
  while (!feof(fp_in)) {
    fscanf(fp_in,"%5s",ftyp);
    if (strcmp(GROBTYP,ftyp)==0)
      break;
  }
  if (feof(fp_in)) {
    fprintf(stderr,"Unexpected eof\n");
    exit(3);
  }
 
  /*
  **  Get the GROB size and the actual grob data
  **  Notice that the width is rounded up to the next multiple
  **  of eight, since this is how they are transmitted.
  **  The real width is saved for printing because the
  **  lines are completed with 1's
  */
  fscanf(fp_in,"%d %d ",&realwidth,&realheight);
  if (realwidth%8==0)
    width=realwidth;
  else width=((realwidth/8)+1)*8;
  if (realheight%8==0)
    height=realheight;
  else height=((realheight/8)+1)*8;
  grobmap=(char *)malloc(sizeof(char)*(width/4)*height+1);
  if (grobmap==NULL) {
    fprintf(stderr,"GROB too big.  Exiting\n");
    exit(4);
  }
  fgets(grobmap,(width/4)*height+1,fp_in);
 
  /*
  **  Create memory space for a bitmap and clear that memory
  **  to zero
  */
  bmap=(unsigned char *)malloc(sizeof(char)*width*(height/8));
  if (bmap==NULL) {
    fprintf(stderr,"GROB too big.  Exiting\n");
    exit(4);
  }
  for(i=0;i<width*(height/8);i++)
    bmap[i]=0;
 
  /*
  **  Translate the grob string to a bitmap where each byte
  **  represents 8 rows from 1 column.  This makes printing
  **  upright images easier.
  */
  generate_bmap(grobmap,width,bmap);
 
  /*
  **  Print out the bitmap
  */
  print_out(bmap,width,realwidth,height,fp_out);
 
  /*
  **  Clean up and exit
  */
  free(grobmap);
  free(bmap);
  fclose(fp_in);
  fclose(fp_out);
  exit(0);
}
 
int generate_bmap(grobmap,width,bmap)
char *grobmap;
int width;
unsigned char *bmap;
{
  int i,j,bmaprow,bmapcol,bitrow;
  char ch,*chptr;
  unsigned char val,*bmap_indx,maptable0[16][8],maptable1[16][8],
    maptable2[16][8],maptable3[16][8];
 
  /*
  **  Initialize maptable#[hexnum][rownum] This array gives the
  **  table which tells which columns (0-3) are 1 or 0 for each hex digit
  **  and each row in the bitmap.
  **  Note that the order of the bits is reversed since the HP-48 sends
  **  the grobs this way, ie.  bit 0 is the leftmost bit and 3
  **  the rightmost bit
  */
  for(i=1;i<16;i++)
    for(j=0;j<8;j++) {
      maptable0[i][j]=((i & 0x1) > 0) << j;
      maptable1[i][j]=((i & 0x2) > 0) << j;
      maptable2[i][j]=((i & 0x4) > 0) << j;
      maptable3[i][j]=((i & 0x8) > 0) << j;
    }
 
  /*
  **  Scan the string, setting the appropriate bits in bmap.
  **  Note that the MS bit of bmap is the top row.
  */
  bmaprow=0;
  bitrow=7;
  bmapcol=0;
  chptr=grobmap;
  for(i=0;i<strlen(grobmap); i++,bmapcol+=4,chptr++) {
    /*
    **  Calculate the value represented by the hex character
    */
    ch=*chptr;
    if ((ch>='0') && (ch<='9'))
      val=ch-'0';
    else  {
      ch=toupper(ch);
      if ((ch>='A') && (ch<='F'))
val=ch-'A'+10;
      else val=0;
    }
    /*
    **  Increment the current bit or column at the end of each row
    */
    if (bmapcol>=width) {
      bmapcol-=width;
      bitrow--;
    }
    if (bitrow<0)  {
      bitrow=7;
      bmaprow++;
    }
    /*
    **  Skip a bit if there is a zero
    */
    if (val==0)
      continue;
    /*
    **  bitwise-or each pixel column with the appropriate value
    */
    bmap_indx=bmap+bmapcol+width*bmaprow;
    *bmap_indx++ |= maptable0[val][bitrow];
    *bmap_indx++ |= maptable1[val][bitrow];
    *bmap_indx++ |= maptable2[val][bitrow];
    *bmap_indx   |= maptable3[val][bitrow];
  }
}
 
int print_out(bmap,width,realwidth,height,fp_out)
unsigned char *bmap;
int width,realwidth,height;
FILE *fp_out;
{
  /*
  **  Print out the bitmap.  This routine uses 8-bit single
  **  density mode for epson printers.  On a 9-pin printer
  **  the output is 60(H)x72(V) dpi. or 60(H)x60(V) dpi on
  **  a 24-pin printer.  A normal size GROB will be pretty
  **  small, but the calculator can produce larger ones
  **  which will have better resolution
  */
 
  int i,j;
  /*
  **  Set the line spacing
  */
  fprintf(fp_out,"%c%c%c",ESC,'3',24);
 
  for(j=0;j<(height/8);j++) {
    /*
    **  Print out one line of points
    */
    fprintf(fp_out,"%c%c%c%c",ESC,'K',realwidth%256,realwidth/256);
    for(i=0;i<realwidth;i++)
      fputc(*(bmap+j*width+i),fp_out);
    /*
    **  End of line - CR,LF
    */
    fprintf(fp_out,"%c%c",13,10);
  }
  /*
  **  Restore the printer line spacing to 1/6 inch.
  */
  fprintf(fp_out,"%c%c",ESC,'2');
}
