/* pbmtomacp.c - read a portable bitmap and produce a MacPaint bitmap file
**
** Copyright (C) 1988 by Douwe vand der Schaaf.
**
** 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 <string.h>

#include "pm_c_util.h"
#include "pbm.h"
#include "macp.h"

#define TRUE		1
#define FALSE		0
#define EQUAL		1
#define UNEQUAL		0

#define MIN3(a,b,c)     (MIN((MIN((a),(b))),(c)))

static void fillbits ARGS(( bit **bits, bit **bitsr, int top, int left, int bottom, int right ));
static void writemacp ARGS(( bit **bits ));
static int packit ARGS(( bit *pb, bit *bits ));
static void filltemp ARGS(( bit *dest, bit *src ));
static void sendbytes ARGS(( bit *pb, register int npb ));
static void header ARGS(( void ));

static FILE *fdout;

int
main(argc, argv)
int argc;
char *argv[];
{ FILE *ifp;
  register bit **bits, **bitsr;
  int argn, rows, cols;
  int left,bottom,right,top;
  int lflg, rflg, tflg, bflg;
  const char * const usage = "[-l left] [-r right] [-b bottom] [-t top] [pbmfile]";


  pbm_init( &argc, argv );

  argn = 1;
  fdout = stdout;
  lflg = rflg = tflg = bflg = 0;
  left = right = top = bottom = 0;  /* To quiet compiler warning */

  while ( argn < argc && argv[argn][0] == '-' && argv[argn][1] != '\0' )
  { switch ( argv[argn][1] )
    { case 'l':
      lflg++;
      argn++;
      left = atoi( argv[argn] );
      break;

      case 'r':
      rflg++;
      argn++;
      right = atoi( argv[argn] );
      break;

      case 't':
      tflg++;
      argn++;
      top = atoi( argv[argn] );
      break;

      case 'b':
      bflg++;
      argn++;
      bottom = atoi( argv[argn] );
      break;

      case '?':
      default:
      pm_usage( usage );
    }
    ++argn;
  }

  if ( argn == argc )
  { ifp = stdin;
  }
  else
  { ifp = pm_openr( argv[argn] );
    ++argn;
  }

  if ( argn != argc )
    pm_usage( usage );

  bitsr = pbm_readpbm( ifp, &cols, &rows );

  pm_close( ifp );

  bits = pbm_allocarray( MAX_COLS, MAX_LINES );

  if( !lflg )
    left = 0;

  if( rflg )
    right = MIN3( right, cols - 1, left + MAX_COLS - 1 );
  else
    right = MIN( cols - 1,  left + MAX_COLS - 1 );

  if( !tflg )
    top = 0;

  if( bflg )
    bottom = MIN3( bottom, rows - 1, top + MAX_LINES - 1);
  else
    bottom = MIN( rows - 1, top + MAX_LINES - 1 );

    if( right <= left || left < 0 || right - left + 1 > MAX_COLS )
      pm_error("error in right (= %d) and/or left (=%d)",right,left );
    if( bottom <= top || top < 0 || bottom - top + 1 > MAX_LINES )
      pm_error("error in bottom (= %d) and/or top (=%d)",bottom,top );

  fillbits( bits, bitsr, top, left, bottom, right );

  writemacp( bits );

  exit( 0 );

}

/* - - - - - - - - - - - - - - - - - - - - - - - - - - */

/* centreer het over te zenden plaatje in het MacPaint document
 *
 * Het plaatje wordt vanaf al of niet opgegeven (left, bottom)
 * in een pbm bitmap van de juist macpaint afmetingen gezet,
 * en eventueel afgekapt.
 */
static void
fillbits( bits, bitsr, top, left, bottom, right )
bit **bits, **bitsr;
int top, left, bottom, right;
{ register bit *bi, *bir;
  register int i, j;
  register int bottomr, leftr, topr, rightr;
  int width, height;

  width = right - left + 1;
  leftr = (MAX_COLS - width) / 2;
  rightr = leftr + width - 1;

  height = bottom - top + 1;
  topr = ( MAX_LINES - height ) / 2;
  bottomr = topr + height - 1;

  for( i = 0; i < topr; i++ )
  { bi = bits[i];
    for( j = 0; j < MAX_COLS; j++ )
      *bi++ = 0;
  }

  for( i = topr; i <= bottomr; i++ )
  { bi = bits[i];
    { for( j = 0; j < leftr; j++ )
	*bi++ = 0;
      bir = bitsr[ i - topr + top ];
      for( j = leftr; j <= rightr; j++ )
	*bi++ = bir[j - leftr + left];
      for( j = rightr + 1; j < MAX_COLS; j++ )
	*bi++ = 0;
  } }

  for( i = bottomr + 1; i < MAX_LINES; i++ )
  { bi = bits[i];
    for( j = 0; j < MAX_COLS; j++ )
      *bi++ = 0;
  }
} /* fillbits */
      
/* - - - - - - - - - - - - - - - - - - - - - - - - - - */

static void
writemacp( bits )
bit **bits;
{ register int i;
  bit pb[MAX_COLS * 2];
  int npb;

  header();
  for( i=0; i < MAX_LINES; i++ )
  { npb = packit( pb, bits[i] );
    sendbytes( pb, npb );
  }
} /* writemacp */

/* - - - - - - - - - - - - - - - - - - - - - - - - - - */

/* pack regel van MacPaint doc in Apple's format
 * return value = # of bytes in pb 
 */
static int
packit( pb, bits )
     bit *pb, *bits;
{ register int charcount, npb, newcount, flg;
  bit temp[72];
  bit *count, *srcb, *destb, save;

  srcb = bits; destb = temp;
  filltemp( destb, srcb );
  srcb = temp;
  destb = pb;
  npb = 0;
  charcount = BYTES_WIDE;
  flg = EQUAL;
  while( charcount ) { 
      save = *srcb++;
      charcount--;
      newcount = 1;
      while( charcount && (*srcb == save) ) { 
          srcb++;
          newcount++;
          charcount--;
      }
      if( newcount > 2 ) { 
          count = destb++;
          *count = 257 - newcount;
          *destb++ = save;
          npb += 2;
          flg = EQUAL;
      } else { 
          if( flg == EQUAL ) { 
              count = destb++;
              *count = newcount - 1;
              npb++;
          } else
            *count += newcount;
          while( newcount-- ) { 
              *destb++ = save;
              npb++;
          }
          flg = UNEQUAL;
      } 
  }
  return npb;
} /* packit */

/* - - - - - - - - - - - - - - - - - - - - - - - - - - */

static void
filltemp( dest, src )
bit *dest, *src;
{ register unsigned char ch, zero, acht;
  register int i, j;

  zero = '\0';
  acht = 8;
  i = BYTES_WIDE;
  while( i-- )
  { ch = zero; 
    j = acht;
    while( j-- )
    { ch <<= 1;
      if( *src++ )
	ch++;
    }
    *dest++ = ch;
  }
} /* filltemp */

/* - - - - - - - - - - - - - - - - - - - - - - - - - - */

static void
sendbytes( pb, npb )
bit *pb;
register int npb;
{ register bit *b;

  b = pb;
  while( npb-- )
    (void) putc( *b++, fdout );
} /* sendbytes */

/* - - - - - - - - - - - - - - - - - - - - - - - - - - */

static void
header()
{ register int i;
  register char ch;

  /* header contains nothing ... */
  ch = '\0';
  for(i = 0; i < HEADER_LENGTH; i++ )
    (void) putc( ch, fdout );
} /* header */
