Source file: /~heha/hs/dos/hp2xx_hs.zip/to_pcl.c

/* Copyright (c) 1991 - 1994 Heinz W. Werntges.  All rights reserved.
   Parts Copyright (c) 1999  Martin Kroeker  All rights reserved.
*/

/** to_pcl.c: PCL converter part of project "hp2xx"
 **
 ** 91/01/19  V 1.00  HWW  Reorganized
 ** 91/01/29  V 1.01  HWW  Tested on SUN
 ** 91/02/01  V 1.02  HWW  Deskjet specials acknowledged
 ** 91/02/15  V 1.03  HWW  VAX_C support added
 ** 91/02/20  V 1.04b HWW  x & y positioning: Now absolute!
 **			   Some VAX_C changes
 ** 91/06/09  V 1.05  HWW  New options added
 ** 91/10/15  V 1.06  HWW  ANSI_C
 ** 91/10/25  V 1.07  HWW  VAX: fopen() augmentations used, open() removed
 ** 92/05/17  V 1.07b HWW  Output to stdout if outfile == '-'
 ** 92/05/19  V 1.07c HWW  Abort if color mode
 ** 92/12/23  V 1.08a HWW  Color for Deskjet (beginning)
 ** 93/04/02  V 1.08b HWW  DotBlock --> Byte
 ** 93/04/13  V 1.09a HWW  CMYK supported
 ** 93/04/25  V 1.09b HWW  End-of-raster-graphics code fixed: now ESC*rbC
 **                        This conforms with DJ550C doc. I hope it is
 **			   still compatible with other DJ models.
 **			   Please tell me if not -- I don't have all doc's.
 ** 93/07/18  V 1.10a HWW  TIFF compression
 ** 94/01/01  V 1.10b HWW  init_printer(), start_graphmode():
 **			   L. Lowe's modifications
 ** 94/02/14  V 1.20a HWW  Adapted to changes in hp2xx.h
 ** 97/12/1           MK   add initialization code for A3 paper size
 ** 99/05/10         RS/MK autoselect A4/A3/A2 paper, reduce margins
 **/

#include <stdio.h>
#include <stdlib.h>
#include "bresnham.h"
#include "pendef.h"
#include "hp2xx.h"



#define	PCL_FIRST 	1			/* Bit mask! 	*/
#define	PCL_LAST 	2			/* Bit mask!	*/


/**
 ** Used for compression ON/off switch:
 **/
static	int	Deskjet_specials = FALSE;


/**
 ** Buffers for color treatment
 **/
static	Byte	*p_K, *p_C, *p_M, *p_Y;		/* Buffer ptrs (CMYK bits) */



/**
 ** Data & functions for (TIFF) compression:
 **
 ** Note: Usually, the buffer p_B receives less data than the
 **	  original (i.e., < nb). However, "temporary" increases
 **	  are possible. To allow for them, we allocate a few extra bytes.
 **	  If the buffer eventually really grows, we won't use compression!
 **	  "n_B" keeps track of the amount of extra buffer space left.
 **/
#define	B_EXTRASPACE	16
static	Byte	*p_B;				/* Buffer for compression  */
static	int	n_B;				/* Counter for extra space */


int TIFF_n_repeats(Byte *p1, int nb) {
/**
 **	There are "nb" bytes in buffer "p1"
 **	Return number of identical bytes in a sequence (0, 2 ... nb)
 **/
 int	i;
 Byte	*p2;

 p2 = p1+1;
 if (nb < 2 || *p2 != *p1) return 0;
 for (i=1; i < nb && *p1 == *p2; p1++, p2++) i++;
 return i;
}

int TIFF_n_irregs (Byte *p1, int nb) {
/**
 **	There are "nb" bytes in buffer "p1"
 **	Return number of irregular (non-identical) bytes
 **	   in a sequence (0, 1, 2 ... nb)
 **/
 int	i;
 Byte	*p2;

 if (nb < 2) return nb;	/* 0 or 1 */
 p2 = p1+1;
 for (i=1; i < nb && *p1 != *p2; p1++, p2++) i++;
 return (i == nb) ? nb : i-1;
}

int TIFF_compress (Byte *src, Byte *dst, int nb) {
  /**
   ** Either there is a block of repetitions or non-repeating bytes
   ** at the buffer start. If repetitions, compress them. If not,
   ** buffer them and compress next block of repetitions.
   **/
 int	i, l, count=0;

 l = TIFF_n_repeats (src, nb);	/* l == 0 or  l >= 2	*/
 while (l > 128 ) {
  *dst++ = (-127);	/* 128 repetitions	*/
  *dst++ = *src;
  count += 2;
  l   -= 128;
  nb  -= 128;
  src += 128;
  n_B += 126;		/* 128 bytes coded as 2	*/
 }
 if (l > 0) {
  *dst++ = (Byte)(1 - l);	/* l repetitions	*/
  *dst++ = *src;
  count += 2;
  src += l;
  nb  -= l;
  n_B += (l - 2);		/* l bytes coded as 2	*/
 }
 if (nb < 0) return -1;		/* should never happen	*/
 if (nb == 0) return count;	/* "count" bytes buffered*/

  /* Irregular sequence	*/

 l = TIFF_n_irregs (src, nb);	/* l == 0 or  l >= 2	*/
 while (l > 128 ) {
  n_B -= 1;
  if (n_B < 0) return -1;	/* Buffer overflow!	*/
  *dst++ = 127;		/* 128 repetitions	*/
  for (i=0; i < 128; i++) *dst++ = *src++;
  count += 129;
  l   -= 128;
  nb  -= 128;
 }
 if (l > 0) {
  n_B -= 1;
  if (n_B < 0) return -1;	/* Buffer overflow!	*/
  *dst++ = (Byte)(l-1);		/* l repetitions	*/
  for (i=0; i < l; i++)	*dst++ = *src++;
  count += (l+1);
  nb  -= l;
 }
 if (nb < 0) return -1;		/* should never happen		*/
 if (nb == 0) {			/* At end-of-buffer: evaluate	*/
  if (n_B > B_EXTRASPACE)	/* Regular exit: Return		*/
    return count;		/* number of compressed bytes	*/
  else return -1;		/* Nothing gained !		*/
 }
 i = TIFF_compress (src, dst, nb);	/* Recursion for rest	*/
 return (i == -1) ? -1 : i + count;
}


/**
 ** PCL data compression method #2 (TIFF)
 **
 ** Compress data in buf; leave compressed data there.
 ** Return number of valid bytes in buf of OK.
 ** Return -1 if no compression done.
 **/

int compress_buf_TIFF (Byte *buf, int nb) {
 if (Deskjet_specials == FALSE)	return -1;
				/* Plain PLC L3 does not support compression! */
 if (p_B == NULL) return -1;	/* No buffer for compression!	*/

 n_B = B_EXTRASPACE;		/* Init. extra space counter	*/
 return TIFF_compress (buf, p_B, nb);	/* Recursive function!	*/
}

void Buf_to_PCL (Byte *buf, int nb, int mode, FILE *fd) {
/**
 ** Output the raw bit stream
 **   (This should be an ideal place for data compression)
 **/
 int	ncb;	/* Number of compressed bytes	*/
 Byte	*p;	/* Buffer pointer		*/

 if (mode & PCL_FIRST) fprintf(fd,"\033*b");

 ncb = compress_buf_TIFF (buf, nb);
 if (ncb == -1) {
  ncb = nb;
  p = buf;		/* Use original buffer & length	*/
  fprintf(fd,"0m");	/* No compression		*/
 }else{
  p = p_B;		/* Use compression buffer	*/
  fprintf(fd,"2m");	/* Compression method 2 (TIFF)	*/
 }
 if (mode & PCL_LAST) fprintf(fd,"%dW", ncb);
 else fprintf(fd,"%dv", ncb);

 fwrite (p, ncb, 1, fd);
}


void KCMY_Buf_to_PCL (int nb, int is_KCMY, FILE *fd) {
 if (is_KCMY) {
  Buf_to_PCL (p_K, nb, PCL_FIRST, fd);
  Buf_to_PCL (p_C, nb, 0,         fd);
 } else			/* is only CMY:	*/
   Buf_to_PCL (p_C, nb, PCL_FIRST, fd);
 Buf_to_PCL (p_M, nb, 0,        fd);
 Buf_to_PCL (p_Y, nb, PCL_LAST, fd);
}

void KCMY_to_K (int nb) {
/**
 ** Color -> B/W conversion:
 ** Any set bit will show up black
 **/
 int	i;
 Byte	*pK=p_K, *pC=p_C, *pM=p_M, *pY=p_Y;

 for (i=0; i < nb; i++)	*pK++|=((*pC++|*pM++)|*pY++);
}

void K_to_CMY(int nb) {
/**
 ** CMYK-to-CMY conversion:
 ** Any set bit in the "black" layer sets all C,M,Y bits to emulate "black"
 **/
 int	i;
 Byte	*pK=p_K, *pC=p_C, *pM=p_M, *pY=p_Y;

 for (i=0; i < nb; i++, pK++) {
  *pC++ |= *pK;
  *pM++ |= *pK;
  *pY++ |= *pK;
 }
}

void init_printer (const OUT_PAR *po, FILE *fd) {
 int size;
 double x,y;

 size=26; /* default to A4 paper */
 x=po->width;
 y=po->height;
 if (x<y) {
  double t=x; x=y; y=t;	/* always assume Landscape (with x>y) */
 }
 if (x>297.||y>210.) size=27; /* A3 format */
 if (x>420.||y>297.) size=28; /* A2 format */
 if (x>584.||y>420.) size=29; /* A1 format */
 if (x>820.||y>584.) size=30; /* A0 format :-) */

 fprintf(fd,
   "\033" "E"		/* reset printer            */
   "\033" "&l%dA"	/* select paper size        */
   "\033" "&l0L"	/* perforation skip off     */
   "\033" "&l0E"	/* no top margin            */
   "\033" "9"		/* no side margins          */
   "\033" "&a0V",size);	/* vertical position  0     */
}

void start_graphmode (const OUT_PAR *po, FILE *fd) {
/**
 ** X & Y offsets: Use "decipoints" as unit to stick to PCL level 3
 **		1 dpt = 0.1 pt = 1/720 in
 **/
 if (po->yoff != 0.0)
   fprintf(fd,"\033&a+%dV",(int)(po->yoff * 720.0 / 25.4) );
 if (po->xoff != 0.0)
   fprintf(fd,"\033&a+%dH",(int)(po->xoff * 720.0 / 25.4) );
 fprintf(stderr,"xoff, yoff: %f %f\n",po->xoff,po->yoff);
/**
 ** Set Graphics Resolution (300 / 150 / 100 / 75):
 ** This is NO PCL level 3 feature, but LaserjetII and compatibles
 ** seem to accept it.
 **/
 fprintf(fd,"\033*t%dR", po->dpi_x);

/**
 ** Set Raster Width (in dots)
 **	Deskjet feature, good for saving internal memory!
 **/
 if (po->specials) {
  fprintf(fd,"\033*r%dS", po->picbuf->pext.x);
  switch (po->specials)	{
   case 4: fprintf(fd,"\033*r-4U"); break;	/* KCMY */
   case 3: fprintf(fd,"\033*r-3U"); break;	/* CMY	*/
   default: fprintf(fd,"\033*r1U");		/* Single color plane */
  }
 }

/**
 ** Start Raster Graphics at current position
 ** This is NO PCL level 3 feature, but LaserjetII and compatibles
 ** seem to accept it.
 **/
 fprintf(fd,"\033*r1A");
}

void end_graphmode(FILE *fd) {
/**
 ** End Raster Graphics
 **/
 fprintf(fd,"\033*rbC");	/* fix: *rB --> *rbC	*/
}


int PicBuf_to_PCL (const GEN_PAR *pg, const OUT_PAR *po) {
/**
 ** Main interface routine
 **/
 FILE	*fd = stdout;
 DevPt	p;
 int	i,offset,err,linelen,mode,x;
 Byte	color_index,mask,*line;
 PicBuf *pb=po->picbuf;

 err = 0;
 if (!pg->quiet) Eprintf ("\nWriting PCL output\n");

 if (pb->depth>1 && po->specials<3)
  Eprintf ("\nWARNING: Monochrome output despite active colors selected!\n");

 Deskjet_specials = (po->specials != 0) ? TRUE : FALSE;

  /**
   ** Allocate buffers for CMYK conversion
   **/
 if (po->picbuf->depth > 1) {
  p_K = calloc (po->picbuf->nb, sizeof(Byte));
  p_C = calloc (po->picbuf->nb, sizeof(Byte));
  p_M = calloc (po->picbuf->nb, sizeof(Byte));
  p_Y = calloc (po->picbuf->nb, sizeof(Byte));
  if (p_K == NULL || p_C == NULL || p_M == NULL || p_Y == NULL) {
   Eprintf ("\nCannot 'calloc' CMYK memory -- sorry, use B/W!\n");
   goto PCL_exit;
  }
 }
  /**
   ** Optional memory; for compression
   **/
 n_B = B_EXTRASPACE;
 p_B = calloc (po->picbuf->nb + n_B, sizeof(Byte));


 if (*po->outfile != '-') {
  fd=FOPEN(po->outfile, WRITE_BIN);
  if(!fd) {
   PError ("hp2xx -- opening output file");
   goto PCL_exit;
  }
 }

 if (po->init_p) init_printer (po, fd);

 start_graphmode (po, fd);

  /**
   ** Loop for all rows:
   ** Counting back since highest index is lowest line on paper...
   **/

 for (p.y = po->picbuf->pext.y - 1; p.y >= 0; p.y--) {
  if (!pg->quiet) ShowPercent(pb->pext.y-1-p.y, pb->pext.y-1);

  mode=PCL_FIRST;
  for (p.x=0; p.x<pb->pext.x; p.x+=pb->ksi) {
   line=GetTileLine(pb,&p,&linelen);

   if (pb->depth==1) {
    if (p.x+pb->ksi>=pb->pext.x) mode|=PCL_LAST;
    Buf_to_PCL(line,linelen, mode, fd);
    mode&=~PCL_FIRST;
   }else{
    for (x=0; x<pb->ksi; x++) p_K[x] = p_C[x] = p_M[x] = p_Y[x] = 0;

    for (x=offset=0; x < (po->picbuf->nb << 3); x++, offset = (x >> 3))	{
     color_index=GetPixel_from_PicBuf(pb,&p);	// fehlt: p.x setzen!
     if (color_index == xxBackground) continue;
     else{
      mask = 0x80;
      if ((i = x & 0x07) != 0) mask >>= i;

      if (pt.clut[color_index][0]
	 +pt.clut[color_index][1]
	 +pt.clut[color_index][2] == 0){
       *(p_K +offset) |= mask;
      }else{
       *(p_C + offset ) |= ( mask ^ ( pt.clut[color_index][0] & mask ) );
       *(p_M + offset ) |= ( mask ^ ( pt.clut[color_index][1] & mask ) );
       *(p_Y + offset ) |= ( mask ^ ( pt.clut[color_index][2] & mask ) );
      }
/*
				switch (color_index)
				{
				  case xxForeground:
					*(p_K + offset) |= mask;
					break;
				  case xxRed:
					*(p_M + offset) |= mask;
					*(p_Y + offset) |= mask;
					break;
				  case xxGreen:
					*(p_C + offset) |= mask;
					*(p_Y + offset) |= mask;
					break;
				  case xxBlue:
					*(p_C + offset) |= mask;
					*(p_M + offset) |= mask;
					break;
				  case xxCyan:
					*(p_C + offset) |= mask;
					break;
				  case xxMagenta:
					*(p_M + offset) |= mask;
					break;
				  case xxYellow:
					*(p_Y + offset) |= mask;
					break;
				  default:
					break;
				}
*/
     }
    }
    switch (po->specials) {
     case 3:	K_to_CMY (pb->nb);
			/* drop thru	*/
     case 4:	KCMY_Buf_to_PCL (pb->nb, (po->specials == 4), fd);
			break;
     default:	KCMY_to_K (po->picbuf->nb);
		Buf_to_PCL (p_K, po->picbuf->nb, PCL_FIRST | PCL_LAST, fd);
			break;
    }
   }
  }
 }

 end_graphmode (fd);
 if (po->formfeed) putc (FF, fd);
 if (!pg->quiet) Eprintf ("\n");
 if (fd != stdout) fclose (fd);

PCL_exit:
 if (p_Y != NULL) free(p_Y);
 if (p_M != NULL) free(p_M);
 if (p_C != NULL) free(p_C);
 if (p_K != NULL) free(p_K);

 if (p_B != NULL) free(p_B);

 p_K = p_C = p_M = p_Y = NULL;
 return err;
}
Detected encoding: ASCII (7 bit)2