/*--------------------------------------------------------------
	Make Primitive-Rectangles        makepr v2.7
		Written  by H.Goto , Jan 1995
		Modified by H.Goto , May 1996
		Modified by H.Goto , Jun 1996
		Modified by H.Goto , Feb 1997
		Modified by H.Goto , Apr 1997
		Modified by H.Goto , May 2002
--------------------------------------------------------------*/

/*--------------------------------------------------------------------
  Copyright (C) 1995-2002  Hideaki Goto

        All Rights Reserved

  Permission to use, copy, modify, and distribute this software and
  its documentation for any purpose is hereby granted without fee,
  provided that (i) the above copyright notice and this permission
  notice appear in all copies and in supporting documentation, (ii)
  the name of the author, Hideaki Goto, may not be used in any
  advertising or otherwise to promote the sale, use or other
  dealings in this software without prior written authorization
  from the author, (iii) this software may not be used for
  commercial products without prior written permission from the
  author, and (iv) the notice of modification is specified in cases
  where modified copies of this software are distributed.

  THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND.
  THE AUTHOR WILL NOT BE RESPONSIBLE FOR ANY DAMAGE CAUSED BY THIS
  SOFTWARE.
--------------------------------------------------------------------*/


#define		DefaultColumnWidth	16

#define		RECT_INCSTEP		512

#include	<stdio.h>
#include	<stdlib.h>
#include	<string.h>
#include	<memory.h>
#include	<unistd.h>

#include	"ufilep.h"
#include	"imgobj.h"

#include	<utypes.h>



/*------------------------------------------------------
	CC list file export class
------------------------------------------------------*/

class CCEXP : public D4SAVE, D8SAVE{
    private:
	d4file		d4header;
	d4pac		d4p;
	d8file		d8header;
	d8pac		d8p;
	int		mode;
	int		open(char *fname,int x0,int x1,int y0,int y1, \
				int width0,int width1,int height0,int height1);
	int		open(char *fname,int x0,int x1,int y0,int y1, \
				int width0,int width1,int height0,int height1, \
				long count0,long count1);
	int		close(void);
    public:
	int		writeccdata(char *fname,int x0,int x1,int y0,int y1, \
				int width0,int width1,int height0,int height1, \
				int ccs,CRects *CR,int mode);
};


int CCEXP :: writeccdata(char *fname,int x0,int x1,int y0,int y1, \
			int width0,int width1,int height0,int height1, \
			int ccs,CRects *CR,int mode){
	int	ix;
	CRect	*ccr;
	long	sum;
	if ( fname == 0 )  return(0);
	CCEXP::mode = mode;
	for ( ix=0 ; ix<8 ; ix++ )  d8p.d8_data[ix] = 0;
	if ( mode == 0 ){
		if ( 0 != open(fname,x0,x1,y0,y1,width0,width1,height0,height1) ){
			fprintf(stderr,"File creation failed : %s\n",fname);
			return (-1);
		}
	}
	else{	if ( 0 != open(fname,x0,x1,y0,y1,width0,width1, \
						height0,height1,0L,327680L) ){
			fprintf(stderr,"File creation failed : %s\n",fname);
			return (-1);
		}
	}
	for ( ix=0 ; ix<ccs ; ix++ ){
		if ( ! CR->isactive(ix) )  continue;

		ccr = CR->getrect(ix);
		if ( mode == 0 ){
			d4p.d4_data[0] = ccr->x1;
			d4p.d4_data[1] = ccr->y1;
			d4p.d4_data[2] = ccr->x2 - ccr->x1 +1;
			d4p.d4_data[3] = ccr->y2 - ccr->y1 +1;
			if ( 0 != D4SAVE::putdata(&d4p) ){
				fprintf(stderr,"File write error : %s\n",fname);
				close();
				unlink(fname);
				return (-1);
			}
		}
		else{	d8p.d8_data[0] = ccr->x1;
			d8p.d8_data[1] = ccr->y1;
			d8p.d8_data[2] = ccr->x2 - ccr->x1 +1;
			d8p.d8_data[3] = ccr->y2 - ccr->y1 +1;
			sum = (long)ccr->attr;
			d8p.d8_data[4] = (short)(sum / 65536L);
			d8p.d8_data[5] = (short)(sum % 65536L);
			if ( 0 != D8SAVE::putdata(&d8p) ){
				fprintf(stderr,"File write error : %s\n",fname);
				close();
				unlink(fname);
				return (-1);
			}
		}
	}
	if ( 0 != close() ){
		fprintf(stderr,"File write error : %s\n",fname);
		return (-1);
	}
	return(0);
}


int CCEXP :: open(char *fname,int x0,int x1,int y0,int y1, \
			int width0,int width1,int height0,int height1){
	d4header.d4_llimit[0] = x0;		d4header.d4_hlimit[0] = x1;
	d4header.d4_llimit[1] = y0;		d4header.d4_hlimit[1] = y1;
	d4header.d4_llimit[2] = width0;		d4header.d4_hlimit[2] = width1;
	d4header.d4_llimit[3] = height0;	d4header.d4_hlimit[3] = height1;
	return ( filecreat(fname,&d4header) );
}


int CCEXP :: open(char *fname,int x0,int x1,int y0,int y1, \
	int width0,int width1,int height0,int height1,long count0,long count1){
	d8header.d8_llimit[0] = x0;		d8header.d8_hlimit[0] = x1;
	d8header.d8_llimit[1] = y0;		d8header.d8_hlimit[1] = y1;
	d8header.d8_llimit[2] = width0;		d8header.d8_hlimit[2] = width1;
	d8header.d8_llimit[3] = height0;	d8header.d8_hlimit[3] = height1;
	d8header.d8_llimit[4] = 0;		d8header.d8_hlimit[4] = (short)((count1 + 65335L) / 65536L);
	d8header.d8_llimit[5] = 0;		d8header.d8_hlimit[5] = -1;
	d8header.d8_llimit[6] = 0;		d8header.d8_hlimit[6] = 0;
	d8header.d8_llimit[7] = 0;		d8header.d8_hlimit[7] = 0;
	return ( D8SAVE::creat(fname,&d8header) );
}


int CCEXP :: close(void){
	if ( mode == 0 ){
		return ( fileclose() );
	}
	else{	return ( D8SAVE::close() );
	}
}




/*------------------------------------------------------
	Image processor class
------------------------------------------------------*/

class IMPR {
    private:
	struct d4pac	d4p;
	struct d4file	d4_info;
	CRects		CRectsH,CRectsV;
	CCEXP		CCEXPH,CCEXPV;
	int		d4flag;
	int		mvec;
	int		size;
	int		height;
	int		cwidth;
	char		*fname,*fname2;
	int		*lhtbl;
	int		*lhsum0;
	long		*lhsum;
	uchar		*vlbuf;
	long		*vlsum;
	int		linecount;
	int		linecount2;
	int		op_mode;
	int		filetype;
	int		limitL,limitU;
	void		vlclear(void);
	int		vlope(uchar *buf);
	int		vlope(short *rllist);
	void		mkcolumn(uchar *src,uchar *dst,int size,int cwidth);
	void		mkcolumn(uchar *src,uchar *dst,int *sum,int size,int cwidth);
	void		mkcolumn(short *rllist,uchar *dst,int cwidth);
	void		mkcolumn(short *rllist,uchar *dst,int *sum,int cwidth);
    public:
	int		create_RL(char *src,short *dst,int size);
	void		localvector(int *src,int *dst,int size,int cwidth,int mode2);
	void		localvector(uchar *src,uchar *dst,int size,int cwidth,int mode2);
	void		localvectorV(uchar *src,uchar *dst,int size,int cwidth);
	void		revcol(uchar *src,uchar *dst,int size);
	int		lineproc_init(int size,int height,int cwidth,int op_mode, \
						int limitL,int limitU,int filetype);
	int		lineproc_close(void);
	int		lineproc(uchar *buf,short *rllist);
	int		d4_create(char *fname,char *fname2,int mvec);
			IMPR(void);
			~IMPR(void);
};


IMPR :: IMPR(void){
	lhtbl = 0;
	lhsum0 = 0;
	lhsum = 0;
	vlbuf = 0;
	vlsum = 0;
	op_mode = 0;
	d4flag = 0;
	mvec = 0;
	CRectsH.set_incstep(RECT_INCSTEP);
	CRectsV.set_incstep(RECT_INCSTEP);
}


IMPR :: ~IMPR(void){
	if ( lhtbl  != 0 )  delete []lhtbl;
	if ( lhsum0 != 0 )  delete []lhsum0;
	if ( lhsum  != 0 )  delete []lhsum;
	if ( vlbuf  != 0 )  delete []vlbuf;
	if ( vlsum  != 0 )  delete []vlsum;
	lineproc_close();
}


int IMPR :: create_RL(char *src,short *dst,int size){
	int	i,rlc,rl;
	i = rlc = 0;
	while (1){
		for ( rl = i ; i < size ; i++ ){
			if ( src[i] != 0 )  break;
		}
		rl = i - rl;
		dst[ rlc++ ] = (short)rl;
		if ( i == size )  break;
		for ( rl = i ; i < size ; i++ ){
			if ( src[i] == 0 )  break;
		}
		rl = i - rl;
		dst[ rlc++ ] = (short)rl;
		if ( i == size )  break;
	}
	dst[ rlc ] = -1;
	return(rlc);
}


void IMPR :: vlclear(void){
	int	i;
	uchar	*vlb;
	long	*vls;
	vlb = vlbuf;
	vls = vlsum;
	if ( op_mode == 0 ){
		for ( i=size ; i > 0 ; i-- )
			*vlb++ = 0;		// OR mode
	}
	else{	for ( i=size ; i > 0 ; i-- )
			*vlb++ = (uchar)0xff;	// AND mode
	}
	if ( filetype != 0 ){
		for ( i=size ; i > 0 ; i-- )  *vls++ = 0;
	}
	linecount2 = 0;
}


int IMPR :: vlope(uchar *buf){
	int	i,dc,crn;
	uchar	*vlb;
	long	*vls;
	long	s;
	vlb = vlbuf;
	vls = vlsum;
	if ( filetype == 0 ){
		if ( op_mode == 0 ){	// OR mode
			for ( i=0 ; i<size ; i++ ){
				if ( buf[i] != 0 )  vlb[i] = 0xff;
			}
		}
		else{			// AND mode
			for ( i=0 ; i<size ; i++ ){
				if ( buf[i] == 0 )  vlb[i] = 0;
			}
		}
	}
	else{	if ( op_mode == 0 ){
			for ( i=0 ; i<size ; i++ ){
				*vlb++  |= buf[i];	// OR mode
				*vls++ += (ulong)buf[i];
			}
		}
		else{	for ( i=0 ; i<size ; i++ ){
				*vlb++  &= buf[i];	// AND mode
				*vls++ += (ulong)buf[i];
			}
		}
	}
	++linecount2;
	if ( linecount2 == cwidth ){
		dc = 0;
		s = 0;
		vlb = vlbuf;
		vls = vlsum;
		for ( i=0 ; i<size ; i++ ){
			if ( vlb[i] != 0 ){
				++dc;
				s += vls[i];
				continue;
			}
			if ( dc != 0 ){
				if ( dc > limitU ){  dc = 0;  continue; }
				if ( dc < limitL ){  dc = 0;  continue; }
				if ( 0 > (crn = CRectsV.create(linecount,(i - dc), \
					(linecount +cwidth -1),(i-1))) )  return (-1);
				if ( filetype != 0 ){
					CRectsV.setattr(crn,(int)(s /255));
				}
				dc = 0;
				s = 0;
			}
		}
		if ( (dc != 0) && (dc >= limitL) && (dc <= limitU) ){
			if ( 0 > (crn = CRectsV.create(linecount,(i - dc), \
				(linecount +cwidth -1),(i-1))) )  return (-1);
			if ( filetype != 0 ){
				CRectsV.setattr(crn,(int)(s /255));
			}
		}
		vlclear();
	}
	return(0);
}


int IMPR :: vlope(short *rllist){
	int	i,dc,crn;
	uchar	*vlb;
	long	*vls;
	long	s;
	int	rlc,rl;
	vlb = vlbuf;
	vls = vlsum;
	if ( filetype == 0 ){
		if ( op_mode == 0 ){	// OR mode
			i = rlc = 0;
			while(1){
				if ( -1 == (rl = (int)rllist[rlc++]) )  break;
				i += rl;
				if ( -1 == (rl = (int)rllist[rlc++]) )  break;
				for ( ; rl > 0 ; rl--, i++ )  vlb[i] = 0xff;
			}
		}
		else{			// AND mode
			i = rlc = 0;
			while(1){
				if ( -1 == (rl = (int)rllist[rlc++]) )  break;
				for ( ; rl > 0 ; rl--, i++ )  vlb[i] = 0;
				if ( -1 == (rl = (int)rllist[rlc++]) )  break;
				i += rl;
			}
		}
	}
	else{	if ( op_mode == 0 ){	// OR mode
			i = rlc = 0;
			while(1){
				if ( -1 == (rl = (int)rllist[rlc++]) )  break;
				i += rl;
				if ( -1 == (rl = (int)rllist[rlc++]) )  break;
				for ( ; rl > 0 ; rl--, i++ ){
					vlb[i] = 0xff;
					vls[i] += 0xff;
				}
			}
		}
		else{			// AND mode
			i = rlc = 0;
			while(1){
				if ( -1 == (rl = (int)rllist[rlc++]) )  break;
				for ( ; rl > 0 ; rl--, i++ )  vlb[i] = 0;
				if ( -1 == (rl = (int)rllist[rlc++]) )  break;
				for ( ; rl > 0 ; rl--, i++ )  vls[i] += 0xff;
			}
		}
	}

	++linecount2;
	if ( linecount2 == cwidth ){
		dc = 0;
		s = 0;
		vlb = vlbuf;
		vls = vlsum;
		for ( i=0 ; i<size ; i++ ){
			if ( vlb[i] != 0 ){
				++dc;
				s += vls[i];
				continue;
			}
			if ( dc != 0 ){
				if ( dc > limitU ){  dc = 0;  continue; }
				if ( dc < limitL ){  dc = 0;  continue; }
				if ( 0 > (crn = CRectsV.create( \
					(linecount -cwidth +1), \
					(i - dc), \
					linecount, \
					(i-1) )) )  return (-1);
				if ( filetype != 0 ){
					CRectsV.setattr(crn,(int)(s /255));
				}
				dc = 0;
				s = 0;
			}
		}
		if ( (dc != 0) && (dc >= limitL) && (dc <= limitU) ){
			if ( 0 > (crn = CRectsV.create( \
				(linecount -cwidth +1), \
				(i - dc), \
				linecount, \
				(i-1) )) )  return (-1);
			if ( filetype != 0 ){
				CRectsV.setattr(crn,(int)(s /255));
			}
		}
		vlclear();
	}
	return(0);
}


int IMPR :: lineproc_init(int size,int height,int cwidth,int op_mode, \
					int limitL,int limitU,int filetype){
	int	i;
	IMPR::size = size;
	IMPR::height = height;
	IMPR::cwidth = cwidth;
	IMPR::op_mode = op_mode;
	IMPR::limitL = limitL;
	IMPR::limitU = limitU;
	IMPR::filetype = filetype;
	linecount = 0;
	if ( lhtbl  != 0 )  delete []lhtbl;
	if ( lhsum0 != 0 )  delete []lhsum0;
	if ( lhsum  != 0 )  delete []lhsum;
	if ( vlbuf  != 0 )  delete []vlbuf;
	if ( vlsum  != 0 )  delete []vlsum;
	lhtbl = new int[size];
	lhsum0 = new int[size];
	lhsum = new long[size];
	vlbuf = new uchar[size];
	vlsum = new long[size];
	if ( (lhtbl == 0) || (lhsum0 == 0) || (lhsum == 0) )  return(-1);
	if ( (vlbuf == 0) || (vlsum == 0) )  return (-1);	// Memory over
	for ( i=0 ; i<size ; i++ ){  lhtbl[i] = 0;  lhsum[i] = 0; }
	vlclear();
	return (0);
}


int IMPR :: d4_create(char *fname,char *fname2,int mvec){
	IMPR::fname  = fname;
	IMPR::fname2 = fname2;
	IMPR::mvec = mvec;
	d4flag = -1;
	return (0);
}


int IMPR :: lineproc_close(void){
	int	rc;
	if ( d4flag == -1 ){
		d4flag = 0;
		if ( mvec != 0 ){
			rc = CCEXPV.writeccdata(fname2,0,height-1,0,size-1, \
				cwidth,cwidth,1,size, \
				CRectsV.counts,&CRectsV,filetype);
			if ( rc != 0 )  return(rc);
		}
		return ( CCEXPH.writeccdata(fname,0,size-1,0,height-1, \
				cwidth,cwidth,1,height, \
				CRectsH.counts,&CRectsH,filetype) );
	}
	return (0);
}


int IMPR :: lineproc(uchar *buf,short *rllist){
	int	ix,size,cwidth,height,limitL,limitU;
	int	crn;
	int	*lhtbl;
	long	*lhsum;
	cwidth = IMPR::cwidth;
	size = IMPR::size;
	lhtbl = IMPR::lhtbl;
	lhsum = IMPR::lhsum;
	limitL = IMPR::limitL;
	limitU = IMPR::limitU;
	if ( mvec != 0 ){
//		if ( 0 != vlope(buf) )  return(-1);
		if ( 0 != vlope(rllist) )  return(-1);
	}
#if 0
	if ( filetype == 0 )	mkcolumn(buf,buf,size,cwidth);
	else			mkcolumn(buf,buf,lhsum0,size,cwidth);
#else
	if ( filetype == 0 )	mkcolumn(rllist,buf,cwidth);
	else			mkcolumn(rllist,buf,lhsum0,cwidth);
#endif
	for ( ix=0 ; ix<size ; ix+=cwidth ){
		if ( buf[ix] != 0 ){
			++lhtbl[ix];
			lhsum[ix] += (long)lhsum0[ix];
			continue;
		}
		if ( (height = lhtbl[ix]) != 0 ){
			if ( height < limitL )  continue;
			if ( height > limitU )  continue;
			if ( 0 > (crn = CRectsH.create(ix,(linecount - height), \
				(ix +cwidth -1),(linecount - 1))) )  return (-1);
			if ( filetype != 0 ){
				CRectsH.setattr(crn,(int)lhsum[ix]);
			}
			lhtbl[ix] = 0;
			lhsum[ix] = 0;
		}
	}
	++linecount;
	return (0);
}


void IMPR :: mkcolumn(uchar *src,uchar *dst,int size,int cwidth){
	int	ix,ix2;
	uchar	acc;
	if ( (cwidth & 0x03) != 0 ){
		if ( op_mode == 0 ){
			for ( ix=0 ; ix<size ; ix+=cwidth ){
				acc = 0;
				for ( ix2=cwidth ; ix2 > 0 ; ix2-- )  acc |= *src++;
				dst[ix] = acc;
			}
		}
		else{	for ( ix=0 ; ix<size ; ix+=cwidth ){
				acc = (uchar)0xff;
				for ( ix2=cwidth ; ix2 > 0 ; ix2-- )  acc &= *src++;
				dst[ix] = acc;
			}
		}
	}
	else{	if ( op_mode == 0 ){
			for ( ix=0 ; ix<size ; ix+=cwidth ){
				acc = 0;
				for ( ix2=(cwidth /4) ; ix2 > 0 ; ix2-- ){
					acc |= src[0] | src[1] | src[2] | src[3];
					src += 4;
				}
				dst[ix] = acc;
			}
		}
		else{	for ( ix=0 ; ix<size ; ix+=cwidth ){
				acc = (uchar)0xff;
				for ( ix2=(cwidth /4) ; ix2 > 0 ; ix2-- ){
					acc &= src[0] & src[1] & src[2] & src[3];
					src += 4;
				}
				dst[ix] = acc;
			}
		}
	}
}


void IMPR :: mkcolumn(uchar *src,uchar *dst,int *sum,int size,int cwidth){
	int	ix,ix2;
	uchar	acc;
	int	s;
	if ( (cwidth & 0x03) != 0 ){
		if ( op_mode == 0 ){
			for ( ix=0 ; ix<size ; ix+=cwidth ){
				acc = 0;
				s = 0;
				for ( ix2=cwidth ; ix2 > 0 ; ix2-- ){
					acc |= *src;
					s += (uint)*src++;
				}
				dst[ix] = acc;
				sum[ix] = s / 255;
			}
		}
		else{	for ( ix=0 ; ix<size ; ix+=cwidth ){
				acc = (uchar)0xff;
				s = 0;
				for ( ix2=cwidth ; ix2 > 0 ; ix2-- ){
					acc &= *src;
					s += (uint)*src++;
				}
				dst[ix] = acc;
				sum[ix] = s / 255;
			}
		}
	}
	else{	if ( op_mode == 0 ){
			for ( ix=0 ; ix<size ; ix+=cwidth ){
				acc = 0;
				s = 0;
				for ( ix2=cwidth ; ix2 > 0 ; ix2-=4 ){
					acc |= src[0] | src[1] | src[2] | src[3];
					s += (uint)src[0] + (uint)src[1] + (uint)src[2] + (uint)src[3];
					src += 4;
				}
				dst[ix] = acc;
				sum[ix] = s / 255;
			}
		}
		else{	for ( ix=0 ; ix<size ; ix+=cwidth ){
				acc = (uchar)0xff;
				s = 0;
				for ( ix2=cwidth ; ix2 > 0 ; ix2-=4 ){
					acc &= src[0] & src[1] & src[2] & src[3];
					s += (uint)src[0] + (uint)src[1] + (uint)src[2] + (uint)src[3];
					src += 4;
				}
				dst[ix] = acc;
				sum[ix] = s / 255;
			}
		}
	}
}


void IMPR :: mkcolumn(short *rllist,uchar *dst,int cwidth){
	int	rl,rc,cw,acc;
	cw = cwidth;
	rl = 0;
	rc = 0xff;
	if ( op_mode == 0 ){
		acc = 0;
		while(1){
			if ( -1 == (rl = (int)*rllist++) )  break;
			rc = 0xff - rc;
			while ( rl ){
				acc |= rc;
				if ( cw > rl ){  cw -= rl;  break; }
				else{	rl -= cw;
					*dst = acc;
					dst += cwidth;
					cw = cwidth;
					acc = 0;
				}
			}
		}
	}
	else{	acc = 0xff;
		while(1){
			if ( -1 == (rl = (int)*rllist++) )  break;
			rc = 0xff - rc;
			while ( rl ){
				acc &= rc;
				if ( cw > rl ){  cw -= rl;  break; }
				else{	rl -= cw;
					*dst = acc;
					dst += cwidth;
					cw = cwidth;
					acc = 0xff;
				}
			}
		}
	}
	if ( cw != cwidth )  *dst = acc;
}


void IMPR :: mkcolumn(short *rllist,uchar *dst,int *sum,int cwidth){
	int	rl,rc,cw,acc;
	int	s;
	cw = cwidth;
	rl = 0;
	rc = 0xff;
	s = 0;
	if ( op_mode == 0 ){
		acc = 0;
		while(1){
			if ( -1 == (rl = (int)*rllist++) )  break;
			rc = 0xff - rc;
			while ( rl ){
				acc |= rc;
				if ( cw > rl ){  cw -= rl;  s += (rl * rc);  break; }
				else{	rl -= cw;
					s += (cw * rc);
					*dst = acc;	dst += cwidth;
					*sum = s /255;	sum += cwidth;
					cw = cwidth;
					acc = 0;
					s = 0;
				}
			}
		}
	}
	else{	acc = 0xff;
		while(1){
			if ( -1 == (rl = (int)*rllist++) )  break;
			rc = 0xff - rc;
			while ( rl ){
				acc &= rc;
				if ( cw > rl ){  cw -= rl;  s += (rl * rc);  break; }
				else{	rl -= cw;
					s += (cw * rc);
					*dst = acc;	dst += cwidth;
					*sum = s /255;	sum += cwidth;
					cw = cwidth;
					acc = 0xff;
					s = 0;
				}
			}
		}
	}
	if ( cw != cwidth )  *dst = acc;
}


void IMPR :: localvector(int *src,int *dst,int size,int cwidth,int mode2){
	int	ix,ix2;
	int	acc;
	if ( op_mode == 0 ){
		for ( ix=0 ; ix<size ; ix+=cwidth ){
			acc = 0;
			for ( ix2=0 ; ix2<cwidth ; ++ix2 )  acc |= src[ix+ix2];
//			if ( acc != 0 )  acc = -1;
			dst[ix] = acc;
/*			if ( ! mode2 ){
				for ( ix2=1 ; ix2<cwidth ; ++ix2 ){
					dst[ix+ix2] = 0;
				}
			}
			else{	for ( ix2=1 ; ix2<cwidth ; ++ix2 ){
					dst[ix+ix2] = acc;
				}
			}
*/		}
	}
	else{	for ( ix=0 ; ix<size ; ix+=cwidth ){
			acc = -1;
			for ( ix2=0 ; ix2<cwidth ; ++ix2 )  acc &= src[ix+ix2];
//			if ( acc != 0 )  acc = -1;
			dst[ix] = acc;
			if ( ! mode2 ){
				for ( ix2=1 ; ix2<cwidth ; ++ix2 ){
					dst[ix+ix2] = 0;
				}
			}
			else{	for ( ix2=1 ; ix2<cwidth ; ++ix2 ){
					dst[ix+ix2] = acc;
				}
			}
		}
	}
}


void IMPR :: localvector(uchar *src,uchar *dst,int size,int cwidth,int mode2){
	int	ix,ix2;
	uchar	acc;
	if ( op_mode == 0 ){
		for ( ix=0 ; ix<size ; ix+=cwidth ){
			acc = 0;
			for ( ix2=0 ; ix2<cwidth ; ++ix2 )  acc |= src[ix+ix2];
			if ( acc != 0 )  acc = 0xff;
			dst[ix] = acc;
			if ( ! mode2 ){
				for ( ix2=1 ; ix2<cwidth ; ++ix2 ){
					dst[ix+ix2] = 0;
				}
			}
			else{	for ( ix2=1 ; ix2<cwidth ; ++ix2 ){
					dst[ix+ix2] = acc;
				}
			}
		}
	}
	else{	for ( ix=0 ; ix<size ; ix+=cwidth ){
			acc = 0xff;
			for ( ix2=0 ; ix2<cwidth ; ++ix2 )  acc &= src[ix+ix2];
			if ( acc != 0 )  acc = 0xff;
			dst[ix] = acc;
			if ( ! mode2 ){
				for ( ix2=1 ; ix2<cwidth ; ++ix2 ){
					dst[ix+ix2] = 0;
				}
			}
			else{	for ( ix2=1 ; ix2<cwidth ; ++ix2 ){
					dst[ix+ix2] = acc;
				}
			}
		}
	}
}


void IMPR :: localvectorV(uchar *src,uchar *dst,int size,int cwidth){
	int	ix,ix2;
	for ( ix=0 ; ix<size ; ++ix ){
		dst[ix] = src[ix];
	}
	for ( ix2=1 ; ix2<8 ; ++ix2 ){
		for ( ix=0 ; ix<size ; ++ix ){
			if ( op_mode == 0 )  dst[ix] |= src[ix + (ix2*size)];
			else                 dst[ix] &= src[ix + (ix2*size)];
		}
		
	}
}


void IMPR :: revcol(uchar *src,uchar *dst,int size){
	int	ix;
	for ( ix=0 ; ix<size ; ++ix ){
		*(dst++) = 255 - *(src++);
	}
}





/*------------------------------------------------------
	Message class
------------------------------------------------------*/

class MSG {
    public:
	void		usage(void);
	void		switcherr(void);
	void		readerr(char *name);
	void		writeerr(char *name);
	void		nonsupported(char *name);
	void		memoryover(void);
};
    	
    	
void MSG :: usage(void){		// Display Usage
	fputs("makepr  v2.7,  Copyright (C) 1995-2002 Hideaki Goto \n",stderr);
	fputs("Usage : makepr [-options] in_file out_file [out_file2] \n",stderr);
	fputs("	      *	-or      : OR  Mode \n",stderr);
	fputs("	      	-and     : AND Mode \n",stderr);
	fputs("		-reverse : reverse B/W for monocrome in_file \n",stderr);
	fputs("	      	-cwid n  : column width (def. n=16) \n",stderr);
	fputs("	      	-image   : create image-file instead of list-file \n",stderr);
	fputs("	      	-box     : box image     (with -image only) \n",stderr);
	fputs("		-vert    : vertical mode (with -image only) \n",stderr);
	fputs("	      	-mvec    : multi vector mode (horizontal/vertical list) \n",stderr);
	fputs("	      	-d8      : create 8-dim file \n",stderr);
	fputs("	      	-llim n  : lower limit of PR height (def. n=1) \n",stderr);
	fputs("	      	-ulim n  : upper limit of PR height (def. n=32767) \n",stderr);
}


void MSG :: switcherr(void){
	puts("Switch error.");
}


void MSG :: readerr(char *name){
	printf("Can't read %s.\n",name);
}


void MSG :: writeerr(char *name){
	printf("Can't write %s.\n",name);
}


void MSG :: nonsupported(char *name){
	printf("Non-supported file %s.\n",name);
}


void MSG :: memoryover(void){
	puts("Not enough memory.");
}




/*------------------------------------------------------
	Argument / Option class
------------------------------------------------------*/

class ARGS {
    private:
	char		*fpath[16];
	int		fpcount;
    	int		sw_verbose;
    	int		sw_reverse;
	int		sw_smode;
	int		sw_filetype;
	int		sw_vertical;
	int		sw_cwidth;
	int		sw_box;
	int		sw_list;
	int		sw_limitL;
	int		sw_limitU;
	int		sw_mvec;
	int		sw_d8;
    public:
	int		scanargv(int ac,char **av);
	int		SWverbose(void) {  return sw_verbose; }
	int		SWreverse(void) {  return sw_reverse; }
	int		SWsmode  (void) {  return sw_smode; }
	int		SWfiletype(void) {  return sw_filetype; }
	int		SWvertical(void) {  return sw_vertical; }
	int		SWcwidth(void) {  return sw_cwidth; }
	int		SWbox(void) {  return sw_box; }
	int		SWlist(void) {  return sw_list; }
	int		SWlimitL(void) {  return sw_limitL; }
	int		SWlimitU(void) {  return sw_limitU; }
	int		SWmvec(void) {  return sw_mvec; }
	int		SWd8(void) {  return sw_d8; }
	char		*infile(void);
	char		*outfile(int n);
			ARGS(void);
};


ARGS :: ARGS(void){
	sw_verbose = 0;
	sw_reverse = 0;
	sw_smode = 0;		//  0:or, 1:and
	sw_filetype = 0;
	sw_vertical = 0;
	sw_cwidth = DefaultColumnWidth;
	sw_box = 0;
	sw_list = -1;
	sw_limitL = 1;
	sw_limitU = 32767;
	sw_mvec = 0;
	sw_d8 = 0;
}


int ARGS :: scanargv(int ac,char **av){
	int	i1,err,skip;
	char	*sw;
	fpcount = err = 0;
	skip = 0;
	--ac;  if( ac >= 16 )  ac = 16;
	for( i1 = 0 ; i1 < ac ; ++i1 ){
		if( skip ){  skip = 0;  continue;  }
		if( *( sw = av[i1+1] ) == '-' ){
			++sw;
			if( 0 == strcmp(sw,"cwid") ){
				if((i1+1)<ac){
					sw_cwidth = atoi(av[i1+2]);
					skip = -1;
					continue;
				}
				else{	err = -1;  break;  }
			}
			if( 0 == strcmp(sw,"list") ){
				sw_list = -1;
				continue;
			}
			if( 0 == strcmp(sw,"image") ){
				sw_list = 0;
				continue;
			}
			if( 0 == strcmp(sw,"box") ){
				sw_list = 0;
				sw_box = -1;
				continue;
			}
			if( 0 == strcmp(sw,"vert") ){
				sw_vertical = -1;
				continue;
			}
			if( 0 == strcmp(sw,"b8") ){
				sw_filetype=1;
				continue;
			}
			if( 0 == strcmp(sw,"or") ){
				sw_smode=0;
				continue;
			}
			if( 0 == strcmp(sw,"and") ){
				sw_smode=1;
				continue;
			}
			if( 0 == strcmp(sw,"reverse") ){
				sw_reverse = -1;
				continue;
			}
			if( 0 == strcmp(sw,"ulim") ){
				if((i1+1)<ac){
					sw_limitU = atoi(av[i1+2]);
					skip = -1;
					continue;
				}
				else{	err = -1;  break;  }
			}
			if( 0 == strcmp(sw,"llim") ){
				if((i1+1)<ac){
					sw_limitL = atoi(av[i1+2]);
					skip = -1;
					continue;
				}
				else{	err = -1;  break;  }
			}
			if( 0 == strcmp(sw,"mvec") ){
				sw_mvec = -1;
				continue;
			}
			if( 0 == strcmp(sw,"d8") ){
				sw_d8 = -1;
				continue;
			}
			if( 0 == strcmp(sw,"quiet") ){
				sw_verbose = 0;
				continue;
			}
			if( 0 == strcmp(sw,"verbose") ){
				sw_verbose = -1;
				continue;
			}
			err = -1;  break;
		}
		else{	fpath[fpcount++] = av[i1+1];
		}
	}
	return(err);
}


char * ARGS :: infile(void){
	if ( fpcount < 1 )  return( "" );
	return( fpath[0] );
}


char * ARGS :: outfile(int n){
	if ( fpcount < (2 + n) )  return(0);
	return( fpath[n + 1] );
}




/*------------------------------------------------------
	Main routine
------------------------------------------------------*/

int main(int ac,char **av){
	ARGS		ARGS;
	MSG		MSG;
	PBMFILE		PBMLD,PBMSV;
	IMPR		IMPR;
	int		retcode,errflag;
	int		width,height;
	int		o_height;
	int		o_filetype;
	int		ix,iy,iy2;
	uchar		*lbuf;
	short		*rlbuf;

	if ( ac < 2 ){
		MSG.usage();
		exit(0);
	}
	if ( 0 != ARGS.scanargv(ac,av) ){
		MSG.switcherr();
		exit(1);
	}

	retcode = PBMLD.open(ARGS.infile(),"r");
	switch ( retcode ){
	  case 0:	break;
	  case -5:	MSG.nonsupported(ARGS.infile());  exit(2);
	  case -6:	MSG.memoryover();  exit(3);
	  default:	MSG.readerr(ARGS.infile());  exit(2);
	}

	width  = PBMLD.getwidth();
	o_height = height = PBMLD.getheight();
	o_filetype = PBMLD.getfiletype();
	if ( ARGS.SWfiletype() != 0 )  o_filetype = 1;
	if ( ARGS.SWvertical() )  o_height = (height / ARGS.SWcwidth())*ARGS.SWcwidth();
	if ( ARGS.SWverbose() ){
		fprintf(stderr,"Input : %s is a %dx%d ", \
					ARGS.infile(),width,height );
		if ( PBMLD.getfiletype() ==0 ){
			fputs("RawBits PBM image\n",stderr);
		}
		else{	fputs("RawBits PGM image\n",stderr);
		}
		if ( ! ARGS.SWlist() ){
			fprintf(stderr,"Output: %s is a %dx%d ", \
						ARGS.outfile(0),width,o_height );
			if ( o_filetype ==0 ){
				fputs("RawBits PBM image\n",stderr);
			}
			else{	fputs("RawBits PGM image\n",stderr);
			}
		}
		else{	fprintf(stderr,"Output: %s is a 4-dim list file\n", \
								ARGS.outfile(0));
		}
	}

	if ( ! ARGS.SWvertical() ){
		if ( NULL == (lbuf = new uchar[width]) ){
			MSG.memoryover();
			exit(3);
		}
	}
	else{	if ( NULL == (lbuf = new uchar[width*ARGS.SWcwidth()]) ){
			MSG.memoryover();
			exit(3);
		}
	}
	if ( 0 == (rlbuf = new short[2*width+2]) ){
		MSG.memoryover();
		exit(3);
	}
	rlbuf[0] = -1;


	IMPR.lineproc_init(width,height,ARGS.SWcwidth(),ARGS.SWsmode(), \
				ARGS.SWlimitL(),ARGS.SWlimitU(),ARGS.SWd8());
	if ( ! ARGS.SWlist() ){
		if ( o_filetype == 0 )  PBMSV.setsize(width,o_height,1);
		else                    PBMSV.setsize(width,o_height,8);
		retcode = PBMSV.open(ARGS.outfile(0),"w");
	}
	else{	if ( ! ARGS.SWmvec())
			retcode = IMPR.d4_create(ARGS.outfile(0),0,0);
		else	retcode = IMPR.d4_create(ARGS.outfile(0),ARGS.outfile(1),1);
	}
	switch ( retcode ){
	  case 0:	break;
	  case -3:	MSG.nonsupported(ARGS.outfile(0));  exit(2);
	  default:	MSG.writeerr(ARGS.outfile(0));  exit(2);
	}

	errflag = 0;
	PBMLD.setpal_fb(0xff,0);

	if ( ARGS.SWlist() ){
		for ( iy=0 ; iy<height ; ++iy ){
			if ( 0 != PBMLD.readline_gray(-1,lbuf) ){ errflag = -1; break; }
			if ( ARGS.SWreverse() )  IMPR.revcol(lbuf,lbuf,width);
			IMPR.create_RL((char *)lbuf,rlbuf,width);
			if ( 0 != IMPR.lineproc(lbuf,rlbuf) ){
				errflag = -1; break;
			}
		}
				/* flush */
		for ( ix=0 ; ix<width ; ix++ )  lbuf[ix] = 0;
		IMPR.create_RL((char *)lbuf,rlbuf,width);
		if ( 0 != IMPR.lineproc(lbuf,rlbuf) )  errflag = -1;
	}

	else if (! ARGS.SWvertical()){
		for ( iy=0 ; iy<height ; ++iy ){
			if ( 0 != PBMLD.readline_gray(-1,lbuf) ){ errflag = -1; break; }
			if ( ARGS.SWreverse() )  IMPR.revcol(lbuf,lbuf,width);
			IMPR.localvector(lbuf,lbuf,width,ARGS.SWcwidth(),\
								ARGS.SWbox());
			if ( o_filetype == 0 ){
				if ( 0 != PBMSV.writeline_bilevel(-1,lbuf,128) ){ errflag = -1; break; }
			}
			else{	if ( 0 != PBMSV.writeline(-1,lbuf) ){ errflag = -1; break; }
			}
		}
	}

	else{	for ( iy=0 ; iy<o_height ; iy+=ARGS.SWcwidth() ){
			for ( iy2=0 ; iy2<ARGS.SWcwidth() ; ++iy2 ){
				if ( 0 != PBMLD.readline_gray(-1,lbuf + (iy2 * width)) ){
					errflag = -1;
					break;
				}
			}
			if ( errflag )  break;
			if ( ARGS.SWreverse() )  IMPR.revcol(lbuf,lbuf,(ARGS.SWcwidth()*width));
			IMPR.localvectorV(lbuf,lbuf,width,ARGS.SWcwidth());
			for ( iy2=0 ; iy2<ARGS.SWcwidth() ; ++iy2 ){
				if ( (iy2 == 1) && (! ARGS.SWbox()) ){
					for ( ix=0 ; ix<width ; ++ix ){
						lbuf[ix] = 0;
					}
				}
				if ( o_filetype == 0 ){
					if ( 0 != PBMSV.writeline_bilevel(-1,lbuf,128) ){ errflag = -1; break; }
				}
				else{	if ( 0 != PBMSV.writeline(-1,lbuf) ){ errflag = -1; break; }
				}
			}
			if ( errflag )  break;
		}
	}

	if ( !errflag ){
		if ( ! ARGS.SWlist() ) {
			if ( 0 != PBMSV.close() ){
				MSG.writeerr(ARGS.outfile(0));
				exit(2);
			}
		}
		else{	if ( 0 != IMPR.lineproc_close() ){
				MSG.writeerr(ARGS.outfile(0));
				exit(2);
			}
		}
	}

	return(0);
}	
