[comp.sys.handhelds] How does one print out a GROB from a PC?

b3300876@rick.cs.ubc.ca (george kai yee chow) (01/25/91)

I seem to recall seeing the answer to this question. After browsing thru my
various capture and files, I came across a EPSPRINT.LIB and PCLPRINT.LIB. Are
these the only way to print to a printer? Ie, with a connection between the
48sx and the printer? I thought there was a converter somewhere that allowed
me to print a GROB out on any printer (in my case, an Epson clone on the 
parallel port). I don't have any graphics program so translation from GROB to
anything else isn't gonna help much. Any help on this would be appreciated.
(BTW, this is for an assignment that's due next Wednesday so if you're reading
this after Jan 30, the whole issue is kinda mote. But do answer anyways just
in case I can use it for the next assignment. ;)

George

rrd@hpfcso.HP.COM (Ray Depew) (01/25/91)

George,

If you're wanting to print grobs on a Mac, then it's a cinch.  You just have
to pick up the GROBber from the HPBBS.  If you're wanting to print grobs on
an MS-DOS machine, it's almost as easy, except that you say you have no way
to play with graphics on your machine.  The program GROB2TIF.EXE on the HPBBS
allows you to convert GROBs to TIFF files.  TIFF files can be imported by
any decent word-processing program (insult to other WP's was intentional)
and printed in the documents thus created.

It's not hard to write a program on your PC that will convert a grob to
printer control commands, and print it out directly.  It's just that nobody
has bothered doing it yet.  Since you have until the 30th to complete your
assignment, you have time.  It should take you a couple of hours on Saturday,
with nobody around to interrupt you.

Basically, the program is just string manipulation.  When you transfer the 
grob to the PC in ASCII mode, you get a string of the form

     GROB x y bitmap

where 'x' is the width in pixels, 'y' is the height in pixels, and 'bitmap'
is a hex bitmap of the grob, row by row.  Bear in mind:

1)  The 48 rounds each row bitmap up to a multiple of 8 bits.  If your grob
    is 11 pixels wide, the 48 will use 16 bits (or 2 bytes, or 4 characters)
    to define each row.
2)  Each nybble in the bitmap is backwards from what you think it should be.
    This means that the pixel pattern 1100, or hex C, is represented in the
    grob bitmap as hex 3, or what should be 0011.  Knowing this, you should
    be able to translate all nybbles:  0 stays 0, 1 becomes 8, 2 becomes 4,
    et cetera.

Like I said, a good Saturday afternoon project.  Good luck.

Ray
rrd@hpfitst1.hp.com
Disclaimer:  Hey, I don't make 'em, I just use 'em, same as you.

akcs.rkb@hpcvbbs.UUCP (Robert Brunner) (01/27/91)

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');
}