/* pbmtoatk.c - convert portable bitmap to Andrew Toolkit raster object
**
** Copyright (C) 1991 by Bill Janssen.
**
** Permission to use, copy, modify, and distribute this software and its
** documentation for any purpose and without fee is hereby granted, provided
** that the above copyright notice appear in all copies and that both that
** copyright notice and this permission notice appear in supporting
** documentation.  This software is provided "as is" without express or
** implied warranty.
*/

#include <stdio.h>
#include <string.h>
#include "pbm.h"

static void
process_atk_byte ARGS((int *pcurcount, unsigned char *pcurbyte, 
                  FILE *file, unsigned char newbyte, int eolflag));
static void
write_atk_bytes ARGS((FILE *file, unsigned char curbyte, 
                      unsigned int curcount));
#define DEFAULTSCALE (1<<16)
#define RASTERVERSION 2
#define TRUE		1
#define FALSE		0

int
main( argc, argv )
    int argc;
    char *argv[];
    {
    FILE *ifd;
    bit *bitrow;
    register bit *bP;
    int rows, cols, format, padright, row;
    register int col;
    char name[100], *cp;
    unsigned char curbyte, newbyte;
    int curcount, gather;


    pbm_init ( &argc, argv );

    if ( argc > 2 )
	pm_usage( "[pbmfile]" );

    if ( argc == 2 )
	{
	ifd = pm_openr( argv[1] );
	strcpy( name, argv[1] );
	if ( strcmp( name, "-" ) == 0 )
	    strcpy( name, "noname" );

	if ( ( cp = index( name, '.' ) ) != 0 )
	    *cp = '\0';
	}
    else
	{
	ifd = stdin;
	strcpy( name, "noname" );
	}

    pbm_readpbminit( ifd, &cols, &rows, &format );
    bitrow = pbm_allocrow( cols );

    /* Compute padding to round cols up to the nearest multiple of 16. */
    padright = ( ( cols + 15 ) / 16 ) * 16 - cols;

    printf ("\\begindata{raster,%d}\n", 1);
    printf ("%d %d %d %d ", RASTERVERSION, 
	     0, DEFAULTSCALE, DEFAULTSCALE);
    printf ("%d %d %d %d\n",
	     0, 0, cols, rows);	/* subraster */
    printf ("bits %d %d %d\n", 1, cols, rows);

    for ( row = 0; row < rows; row++ )
	{
	  pbm_readpbmrow( ifd, bitrow, cols, format );
	  bP = bitrow;
	  gather = 0;
	  newbyte = 0;
	  curbyte = 0;
	  curcount = 0;
	  col = 0;
	  while (col < cols)
	    {
	      if (gather > 7)
		{
		  process_atk_byte (&curcount, &curbyte, stdout, newbyte, FALSE);
		  gather = 0;
		  newbyte = 0;
		}
	      newbyte = (newbyte << 1) | (*bP++);
	      gather += 1;
	      col += 1;
	    }

	  if (gather > 0)
	    {
	      newbyte = (newbyte << (8 - gather));
	      process_atk_byte (&curcount, &curbyte, stdout, newbyte, TRUE);
	    }
        }

    pm_close( ifd );
    
    printf ("\\enddata{raster, %d}\n", 1);

    exit( 0 );
  }


static void
write_atk_bytes (FILE *file, unsigned char curbyte, unsigned int curcount) {

    /* codes for data stream */
#define WHITEZERO	'f'
#define WHITETWENTY	'z'
#define BLACKZERO	'F'
#define BLACKTWENTY	'Z'
#define OTHERZERO	0x1F

#define	WHITEBYTE	0x00
#define	BLACKBYTE	0xFF

    /* WriteRow table for conversion of a byte value to two character
hex representation */

    static unsigned char hex[16] = {
	'0', '1', '2', '3', '4', '5', '6', '7',
	'8', '9', 'a', 'b', 'c', 'd', 'e', 'f'
    };

  switch (curbyte) {
  case WHITEBYTE:
    while (curcount > 20) 
      fputc(WHITETWENTY, file),
      curcount -= 20;
    fputc(WHITEZERO + curcount, file);
    break;
  case BLACKBYTE:
    while (curcount > 20) 
      fputc(BLACKTWENTY, file),
      curcount -= 20;
    fputc(BLACKZERO + curcount, file);
    break;
  default:
    while (curcount > 16)
      fputc(OTHERZERO+16, file),
      fputc(hex[curbyte / 16], file),
      fputc(hex[curbyte & 15], file),
      curcount -= 16;
    if (curcount > 1)
      fputc(OTHERZERO+curcount, file);
    else ;  /* the byte written will represent a single instance */
    fputc(hex[curbyte / 16], file);
    fputc(hex[curbyte & 15], file);
  }
}



static void
process_atk_byte (int *pcurcount, unsigned char *pcurbyte, 
                  FILE *file, unsigned char newbyte, int eolflag) {

    int curcount = *pcurcount;
    unsigned char curbyte = *pcurbyte;

    if (curcount < 1)
    {
	*pcurbyte = curbyte = newbyte;
	*pcurcount = curcount = 1;
    }
    else if (newbyte == curbyte)
    {
	*pcurcount = (curcount += 1);
    }

    if (curcount > 0 && newbyte != curbyte)
      {
	write_atk_bytes (file, curbyte, curcount);
	*pcurcount = 1;
	*pcurbyte = newbyte;
      }

    if (eolflag)
      {
	write_atk_bytes (file, *pcurbyte, *pcurcount);
	fprintf (file, " |\n");
	*pcurcount = 0;
	*pcurbyte = 0;
      }
}
