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

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

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

/** to_pcx.c: PCX converter part of project "hp2xx"
 **
 ** 91/01/19  V 1.00  HWW  Originating: Format accepted by MS-Paintbrush,
 **                       but not by emTeX drivers
 **                       Use MS-Paintbrush "load/save" for conversion
 ** 91/02/15  V 1.01  HWW  VAX_C support added (not tested yet!)
 ** 91/02/18  V 1.02  HWW  PCX format: no zero run length allowed
 ** 91/02/20  V 1.03  HWW  Some VAX_C changes, debugged
 ** 91/06/09  V 1.04  HWW  New options added
 ** 91/06/16  V 1.05  HWW  Writing of PCX header now machine-independent
 ** 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/06/08  V 1.08a HWW  First color version
 ** 93/11/22  V 1.10a HWW  Color version based on TO_PCL.C code. CLUT still
 **                        inactive !?
 ** 93/11/25  V 1.10b RF   PCX-Version set to 2: use palette info,
 **                        colors corrected
 ** 94/02/14  V 1.20a HWW  Adapted to changes in hp2xx.h
 **
 **           NOTE: According to my tests, setting of the
 **                 color lookup table is ignored by other programs,
 **                 so this code is *preliminary* when color is used.
 **                 Correct colors appeared only if the color setting corresponded to
 **                 PC conventions...
 **
 ** 00/03/05    3.4a  MK   Write PCX version 5 truecolor files in color mode,
 **                        corrected(?) version 2 palette for b/w mode 
 **/


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


typedef enum {PCX_INIT, PCX_NORMAL, PCX_EXIT}
        PCXmode;

void RLEcode_to_file(int c, int repeat, FILE *fd) {
 if ((repeat==1) && ((c & 0xC0) != 0xC0)) {
  if (putc(c,fd)==EOF) {
   PError("RLEcode_to_file (1)");
   exit(ERROR);
  }
 }else{
  if (putc (repeat | 0xC0, fd) == EOF) {
   PError("RLEcode_to_file (2)");
   exit(ERROR);
  }
  if (putc (c, fd) == EOF) {
   PError("RLEcode_to_file (3)");
   exit(ERROR);
  }
 }
}

void byte_to_PCX(Byte b, PCXmode mode, FILE *fd) {
 static int last_b, rept;

 switch (mode) {
  case PCX_NORMAL:
  if (b == last_b) {
   if (++rept == 63) {
    RLEcode_to_file (last_b, rept, fd);
    rept = 0;
   }
  }else{
   if (rept) RLEcode_to_file (last_b, rept, fd);
   rept    = 1;
   last_b  = b;
  }break;

  case PCX_INIT:
  rept = 0;
  last_b = -2;    /* Init to impossible value     */
  break;

  case PCX_EXIT:
  if (rept) {
   RLEcode_to_file (last_b, rept, fd);
   rept = 0;
  }break;
 }
}

typedef struct {
 char    creator, version, encoding, bits;
 short   xmin, ymin, xmax, ymax, hres, vres;
 Byte    palette[16][3], vmode, planes;
 short   byteperline, paletteinfo;
 short   hscreensize, vscreensize;
 char    dummy[54];
} PCXheader;

Byte DefPalette[16][3]={
 {  0,  0,  0}, /* white */
 {255,255,255},
 {  0,128,  0},
 {128,128,  0},
 {  0,  0,128},
 {128,  0,128},
 {  0,128,128},
 {192,192,192},
 {  0,  0,  0}, /*black*/
 {255,  0,  0}, /* red*/
 {  0,255,  0}, /* green */
 {255,255,  0},
 {  0,  0,255}, /* blue */
 {255,  0,255},
 {  0,255,255},
 {255,255,255}};

#pragma argsused
int start_PCX (const OUT_PAR *po, const GEN_PAR *pg, FILE *fd) {
 PCXheader h;

 h.creator=0x0A;		/* ZSoft label			*/
 h.version=(po->picbuf->depth ==1)?(char)2:(char)5;
				/* V 2.8/3.0, with palette info	*/
				/* V5 24bit PCX			*/
 h.encoding=1;			/* RLE				*/
 h.bits=(po->picbuf->depth==1)?(char)1:(char)8;	/* Bits per pixel	*/
 h.xmin=0;			/* Range of bitmap              */
 h.ymin=0;
 h.xmax=INTELS(po->picbuf->pext.x-1);
 h.ymax=INTELS(po->picbuf->pext.y-1);
 h.hres=INTELS(po->dpi_x);	/* Resolution                   */
 h.vres=INTELS(po->dpi_y);

 if (po->picbuf->depth == 1){
  memcpy(h.palette,DefPalette,sizeof(h.palette));
 }else
  memset(h.palette,0,sizeof(h.palette));

 h.vmode       = 0;            /* Reserved                        */
 h.planes      =(Byte)(po->picbuf->depth); /* Number of color planes	   */
 h.byteperline=INTELS(po->picbuf->nb*(po->picbuf->depth==1?1:8));
 h.paletteinfo=INTELS(1);            /* 1 = color & b/w, 2 = gray scale */
 h.hscreensize=INTELS(po->picbuf->pext.x-1); /* Horizontal screen size in pixels */
 h.vscreensize=INTELS(po->picbuf->pext.y-1); /* Vertical screen size in pixels */
 memset(h.dummy,0,sizeof(h.dummy));
/**
 ** For complete machine independence, a bytewise writing of this header
 ** is mandatory. Else, fill bytes or HIGH/LOW-endian machines must be
 ** considered. A simple "fwrite(h,128,1,fd)" may not suffice!
 **/

 if (fwrite(&h,128,1,fd)!=1) goto ERROR_EXIT;
 return 0;

ERROR_EXIT:
  PError ("start_PCX");
  return ERROR;
}

void Buf_to_PCX2(int no_invert, Byte *pb, int nb, FILE *fd) {

 while (nb--) {
  Byte x=*pb++;
  if (!no_invert) x=(Byte)~x;
  byte_to_PCX (x, PCX_NORMAL, fd);
 }
}

static void Buf_to_PCX(Byte* pb, int nb, FILE* fd) {
 byte_to_PCX (0, PCX_INIT, fd);
 Buf_to_PCX2(0,pb,nb,fd);
 byte_to_PCX (0, PCX_EXIT, fd);        /* Flush        */
}

int PicBuf_to_PCX (const GEN_PAR *pg, const OUT_PAR *po) {
 FILE	*fd;
 Byte	*tileline;
 DevPt  p,max;
 int	linelen,err;
 Byte	color_index;
 Byte	*p_R=NULL, *p_G=NULL, *p_B=NULL, *p_I=NULL;

 err = 0;
 if (!pg->quiet) Eprintf ("\nWriting PCX output\n");
 if (po->outfile[0] != '-') {
  if ((fd = FOPEN(po->outfile, WRITE_BIN)) == NULL) {
   PError ("hp2xx -- opening output file");
   return ERROR;
  }
 }else fd=stdout;

 if (start_PCX (po, pg, fd)) {
  err = ERROR;
  goto PCX_exit;
 }

#if 0
  /* Backward since highest index is lowest line on screen! */
  for (row_c = po->picbuf->nr - 1; row_c >= 0; row_c--)
  {
	if ((!pg->quiet) && (row_c % 10 == 0))
		  /* For the impatient among us ...     */
		Eprintf(".");
	row = get_RowBuf (po->picbuf, row_c);
	byte_to_PCX (0, PCX_INIT, fd);
	pb = row->buf;
	for (np=0; np < picbuf->depth; np++)
		for (x=0; x < po->picbuf->nb; x++)
			byte_to_PCX (~*pb++, PCX_NORMAL, fd);
	byte_to_PCX (0, PCX_EXIT, fd);  /* Flush        */
  }
#endif

  /**
   ** Allocate buffers for temporary conversion
   **/
 if (po->picbuf->depth > 1)  {
  p_I = calloc (po->picbuf->nb, 8);
  p_B = calloc (po->picbuf->nb, 8);
  p_G = calloc (po->picbuf->nb, 8);
  p_R = calloc (po->picbuf->nb, 8);
  if (p_I == NULL || p_B == NULL || p_G == NULL || p_R == NULL)	{
   Eprintf("\nCannot 'calloc' color conversion memory -- sorry, use B/W!\n");
   err = ERROR;
   goto PCX_exit;
  }
 }
  /**
   ** Loop for all rows:
   ** Counting back since highest index is lowest line on paper...
   **/

 max.x=po->picbuf->pext.x-1;
 max.y=po->picbuf->pext.y-1;
 for (p.y=max.y; p.y>=0; p.y--) {
  if (!pg->quiet) ShowPercent(max.y-p.y,max.y);
		  /* For the impatients among us ...    */
/*fprintf(stderr,"coverting row %d (%d bytes)\n",row_c,po->picbuf->nb);*/
  byte_to_PCX (0, PCX_INIT, fd);
  if (po->picbuf->depth == 1) {
   byte_to_PCX (0, PCX_INIT, fd);
   for (p.x=0; p.x<=max.x; p.x+=po->picbuf->ksi) {
    tileline=GetTileLine(po->picbuf,&p,&linelen);
    Buf_to_PCX2(po->init_p,tileline,linelen,fd);
   }
   byte_to_PCX (0, PCX_EXIT, fd);        /* Flush        */
  }else{
   for (p.x=0; p.x<(po->picbuf->nb<<1); p.x++){
    p_I[p.x] = p_R[p.x] = p_G[p.x] = p_B[p.x] = 0;
    color_index=GetPixel_from_PicBuf(po->picbuf,&p);
/*fprintf(stderr,"color_index= %d\n",color_index);   */
    p_R[p.x] =(unsigned char)(255-pt.clut[color_index][0]);
    p_G[p.x] =(unsigned char)(255-pt.clut[color_index][1]);
    p_B[p.x] =(unsigned char)(255-pt.clut[color_index][2]);
/*
	p_R[x] = 255-pt.clut(color_index,R) ;
	p_G[x] = 255-pt.clut(color_index,G) ;
	p_B[x] = 255-pt.clut(color_index,B) ;
*/
  }
/*
for (x=0; x < po->picbuf->nb; x++)fprintf(stderr,"%d%d%d\n",p_R[x],p_G[x],p_B[x]);
*/
   Buf_to_PCX (p_R, 8*po->picbuf->nb, fd);
   Buf_to_PCX (p_G, 8*po->picbuf->nb, fd);
   Buf_to_PCX (p_B, 8*po->picbuf->nb, fd);
   Buf_to_PCX (p_I, 8*po->picbuf->nb, fd);
  }
 }
 if (!pg->quiet) Eprintf("\n");

PCX_exit:
 if (fd != stdout) fclose (fd);
 if (p_R) free(p_R);
 if (p_G) free(p_G);
 if (p_B) free(p_B);
 if (p_I) free(p_I);
 return err;
}
Detected encoding: ASCII (7 bit)2