/************************************************************************\
 *                                                                      *
 *  writepcx.c                                                          *
 *                                                                      *
 *  This file is part of PICTURE MAN image file converter/processor     *
 *                                                                      *
 *  1992 Potapov WORKS, STOIK Ltd.                                      *
 *                                                                      *
 *  This file contains source code for PCX file writer                  *
 *                                                                      *
 *  Compiler: MS C v.6.00A                                              *
 *                                                                      *
 *  You may use, modify and distribute this text freely                 *
 *                                                                      *
\************************************************************************/
#include <windows.h>
#include "custconv.h"
  
#define SEEK_SET    0
#define SEEK_CUR    1
#define SEEK_END    2
  
#define BUFSIZE 4096
  

typedef struct {
        char         manuf;     /* Always =10 for Paintbrush   */
        char         hard;      /* Version information         */
        char         encod;     /* Run-length encoding (=1)    */
        char         bitpx;     /* Bits per pixel              */
        unsigned     x1;        /* Picture dimensions (incl)   */
        unsigned     y1;
        unsigned     x2;
        unsigned     y2;
        unsigned     hres;      /* Display horiz resolution    */
        unsigned     vres;      /* Display vert  resolution    */
        char         clrma[48]; /* Pallete                     */
        char         vmode;     /* (ignored)                   */
        char         nplanes;   /* Number of planes (ver 2.5=0)*/
        unsigned     bplin;     /* Bytes per line              */
        unsigned     palinfo;   /* Palette Info (1=col, 2=gray)*/
        unsigned     shres;     /* Scanner resolution          */
        unsigned     svres;     /*                             */
        char         xtra[54];  /* Extra space (filler)        */
       } PCXhdr;


typedef struct{
               int file;
               BOOL PCXpalette;
               PAL pal;
               BYTE buffer[BUFSIZE];
               WORD pos;
					PCXhdr hdr;
				  }PCXStruct;
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: int FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg,       *
 *                                 WORD cbHeapSize, LPSTR lpszCmdLine)  *
 * PURPOSE: DLL entry point.                                            *
 *                                                                      *
\************************************************************************/
int FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg,
WORD cbHeapSize, LPSTR lpszCmdLine)
{
    return 1;
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: int FAR PASCAL WEP(int bSystemExit)                         *
 *                                                                      *
 * PURPOSE: DLL exit procedure                                          *
 *                                                                      *
\************************************************************************/
int FAR PASCAL WEP(int bSystemExit)
{
    return 1;
}
  
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: WORD FAR PASCAL Magic(void)                                 *
 *                                                                      *
 * PURPOSE: Identification routine                                      *
 * RETURNS: 'Magic number' SRC_MAGIC                                    *
 *                                                                      *
\************************************************************************/
WORD FAR PASCAL Magic(void)
{
    return DST_MAGIC;
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: void FAR PASCAL GetDescription(LPSTR str)                   *
 *                                                                      *
 * PURPOSE: Sets format name                                            *
 *                                                                      *
 * PARAMETERS: LPSTR str - pointer for format name storage. The length  *
 *             name must be less than 40!                               *
 *                                                                      *
\************************************************************************/
void FAR PASCAL GetDescription(LPSTR str)
{
    lstrcpy(str,"ZSoft PaintBrush PCX");
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: void FAR PASCAL GetExtension(LPSTR str)                     *
 *                                                                      *
 * PURPOSE: Sets format file extension                                  *
 *                                                                      *
 * PARAMETERS: LPSTR str - pointer for format file extension.           *
 *                                                                      *
\************************************************************************/
void FAR PASCAL GetExtension(LPSTR str)
{
    lstrcpy(str,"PCX");
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: DWORD FAR PASCAL GetFlags(void)                             *
 *                                                                      *
 * PURPOSE: Sets flag for converter capabilities                        *
 *                                                                      *
 * PARAMETERS: None                                                     *
 *                                                                      *
 * RETURNS: Flags                                                       *
 *  Color info bits                                                     *
 *  INFO_COLOR      // Image is colored                                 *
 *  INFO_PALETTE    // Image is paletted                                *
 *  INFO_NEGATIVE   // Image is negative                                *
 *  File organization bits                                              *
 *  INFO_TEMPFILE   // Only using temporary file                        *
 *  INFO_COMPRESSED // Image is compressed                              *
 *  INFO_FORWARD    // Up to down                                       *
 *  INFO_BACKWARD   // Down to up                                       *
 *  INFO_RANDOM     // Random access is allowed                         *
 *  Row organization bits                                               *
 *  INFO_PACKED     // (bps < 8) bits are shifted together              *
 *  INFO_SEPARATE   // (bps !=8) bitplanes are separated                *
 *                                                                      *
 *  Bits for GetFlags()                                                 *
 *  Destination capabilites bits                                        *
 *  INFO_1BPS       // Accepts 1-bit data                               *
 *  INFO_4BPS       // Accepts 4-bit data                               *
 *  INFO_8BPS       // Accepts 8-bit data                               *
 *  INFO_24BPS      // Accepts 24-bit data                              *
 *  INFO_GRAY       // Accepts true gray data                           *
 *  INFO_STDPAL     // Requires std. EGA/VGA palette                    *
 *  INFO_ANYPAL     // Accepts any palette                              *
 *  Source/Destination capabilites bits                                 *
 *  INFO_HASOPTIONS // Has SetOptions()                                 *
 *  INFO_NOFILE     // Do not open src/dst file                         *
 *                                                                      *
 *  ALL OTHER BITS ARE RESERVED                                         *
 *                                                                      *
\************************************************************************/
DWORD FAR PASCAL GetFlags(void)
{
    return ( INFO_COMPRESSED | INFO_FORWARD | INFO_1BPS | \
    INFO_4BPS | INFO_8BPS | INFO_24BPS | INFO_STDPAL | INFO_ANYPAL );
}
/************************************************************************\
 *                                                                      *
 * ROUTINE: int FAR PASCAL GetPrivateSize()                             *
 *                                                                      *
 * PURPOSE: Returns size of private memory block                        *
 *                                                                      *
 *                                                                      *
\************************************************************************/
int FAR PASCAL GetPrivateSize()
{
   return sizeof(PCXStruct);
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: int   FAR PASCAL WriteHeader(LPINFO p, void far * lpPrivate)*
 *                                                                      *
 * PURPOSE: Writes image header.                                        *
 *                                                                      *
 * PARAMETERS: LPINFO p - pointer to INFO structure                     *
 *             void far * lpPrivate - pointer to                        *
 *             custom structure to store private data                   *
 *                                                                      *
 * RETURNS:                                                             *
 * OK         - Success                                                 *
 * BADFORMAT  - Bad signature                                           *
 * UNSUPPORTED- Unsupported subformat                                   *
 * BADFILE    - Error in file structure                                 *
 * CANNOTOPEN - Cannot open src/dest                                    *
 * INTERNAL   - Reserved                                                *
 * BADDLL     - Error initializing DLL                                  *
 * BADREQUEST - Unsupported type of conversion                          *
 * BADTEMPFILE- Error creating/reading tempfile                         *
 * NOMEMORY   - No enough global heap                                   *
 * NODISK     - No enough disk space                                    *
 * USERABORT  - Cancelled by user                                       *
 * BADPARMS   - Conflicting parameters                                  *
 *                                                                      *
\************************************************************************/
int   FAR PASCAL WriteHeader(LPINFO p, void far *lpPrivate)
{
    int i,j;
	 PCXStruct far * lpPCXStruct = lpPrivate;


         lpPCXStruct->hdr.manuf = 10;   // manuf
         lpPCXStruct->hdr.hard  = 5;    // hard
         lpPCXStruct->hdr.encod = 1;    // encod
         lpPCXStruct->hdr.bitpx = 1;    // bitpix ***
         lpPCXStruct->hdr.x1    = 0;    // x1, y1
         lpPCXStruct->hdr.y1    = 0;    
         lpPCXStruct->hdr.x2    = 0;    
         lpPCXStruct->hdr.y2    = 0;    
         lpPCXStruct->hdr.hres  = 640 ;
         lpPCXStruct->hdr.vres  = 480;  
         lpPCXStruct->hdr.vmode = 0;     
         lpPCXStruct->hdr.nplanes = 1;  
         lpPCXStruct->hdr.bplin  = 0;   
         lpPCXStruct->hdr.palinfo= 0;   
         lpPCXStruct->hdr.shres = 300;  
         lpPCXStruct->hdr.svres = 300;  
  
    lpPCXStruct->hdr.x2 = p->w - 1;
    lpPCXStruct->hdr.y2 = p->h - 1;
    if( p->resunit == RES_SCREEN )
    {
        lpPCXStruct->hdr.hres = (WORD)p->xres; lpPCXStruct->hdr.vres = (WORD)p->yres;
    }
    switch( p->bps )
    {
        case 1:
            lpPCXStruct->hdr.bitpx = 1;
            lpPCXStruct->hdr.nplanes = 1;
            if( p->resunit != RES_SCREEN )
            {
                lpPCXStruct->hdr.hres = 640; lpPCXStruct->hdr.vres = 480;
            }
            lpPCXStruct->PCXpalette = 0;
            lpPCXStruct->hdr.clrma[0] = lpPCXStruct->hdr.clrma[1] = lpPCXStruct->hdr.clrma[2] = 0;
            lpPCXStruct->hdr.clrma[3] = lpPCXStruct->hdr.clrma[4] = lpPCXStruct->hdr.clrma[5] = 0xFF;
            break;
  
        case 4:
            lpPCXStruct->hdr.bitpx = 1;
            lpPCXStruct->hdr.nplanes = 4;
            if( p->resunit != RES_SCREEN )
            {
                lpPCXStruct->hdr.hres = 640; lpPCXStruct->hdr.vres = 480;
            }
            lpPCXStruct->PCXpalette = 0;
            for( i = 0; i < 16; i++ )
                for( j = 0; j < 3; j++ )
                    lpPCXStruct->hdr.clrma[i*3+j] = p->pal[j][i];
            break;
  
        case 8:
            lpPCXStruct->hdr.bitpx = 8;
            lpPCXStruct->hdr.nplanes = 1;
            if( p->resunit != RES_SCREEN )
            {
                lpPCXStruct->hdr.hres = 320; lpPCXStruct->hdr.vres = 200;
            }
            lpPCXStruct->PCXpalette = 1;
            for( i = 0; i < 3; i++ )
                for( j = 0; j < 256; j++ )
                    lpPCXStruct->pal[i][j] = p->pal[i][j];
				break;
        case 24:
            lpPCXStruct->hdr.bitpx = 8;
            lpPCXStruct->hdr.nplanes = 3;
            if( p->resunit != RES_SCREEN )
            {
                lpPCXStruct->hdr.hres = 640; lpPCXStruct->hdr.vres = 480;
            }
				break;
    }
    lpPCXStruct->file = p->file;
    p->nplanes = lpPCXStruct->hdr.nplanes;
    p->bplin = lpPCXStruct->hdr.bplin =
    (WORD)( ( (DWORD)lpPCXStruct->hdr.bitpx * (DWORD)p->w + 15lu ) / 16lu ) * 2;
    p->flags |= INFO_COMPRESSED | INFO_FORWARD | INFO_1BPS | \
    INFO_4BPS | INFO_8BPS | INFO_24BPS | INFO_STDPAL | INFO_ANYPAL | \
	 INFO_COLOR | INFO_PALETTE;
    if( lpPCXStruct->hdr.bitpx != 8 )   p->flags |= INFO_PACKED;
    if( lpPCXStruct->hdr.nplanes != 1 ) p->flags |= INFO_SEPARATE;
  
    lpPCXStruct->pos = 0;
    if(_lwrite( lpPCXStruct->file,(LPSTR)&(lpPCXStruct->hdr),sizeof(lpPCXStruct->hdr)) != sizeof(lpPCXStruct->hdr)) return NODISK;
    return OK;
}
  
/************************************************************************/
/************************************************************************/
/************************************************************************/
/* useful macros */
#define BufByte(x) ((lpPCXStruct->pos < BUFSIZE) ? ((lpPCXStruct->buffer[lpPCXStruct->pos++] = x),OK) : putbuf(x,lpPCXStruct))
  
/* useful subfunctions */
int putbuf(BYTE b,PCXStruct far *lpPCXStruct)
{
    if( _lwrite(lpPCXStruct->file,lpPCXStruct->buffer,BUFSIZE) != BUFSIZE ) return NODISK;
    lpPCXStruct->buffer[0] = b; lpPCXStruct->pos = 1;
    return OK;
}
  
/************************************************************************/
/************************************************************************/
/************************************************************************/
int FlushOutBuf(PCXStruct far *lpPCXStruct)
{
    if( !lpPCXStruct->pos ) return OK;
    return ( _lwrite(lpPCXStruct->file,lpPCXStruct->buffer,lpPCXStruct->pos) != lpPCXStruct->pos ) ? NODISK : OK;
}
  
  
/************************************************************************/
/************************************************************************/
/************************************************************************/
static int PCXpack(LPBYTE buf, WORD len, void far *lpPrivate)
{
    int PCXcount,ret;
    BYTE PCXbyte;
	 PCXStruct far * lpPCXStruct = lpPrivate;
  
    PCXcount = 0;
    while(len)
    {
        if(!PCXcount)
        {
            PCXcount = 1;
            PCXbyte  = *buf++;
            len --;
        }
        while(len && PCXcount < 0x3F && *buf == PCXbyte)
        {
            PCXcount++; buf++; len--;
        }
  
        if(!len) /* return OK; */ break;
  
        if(PCXcount == 1 && (PCXbyte & 0xC0) != 0xC0 )
        {
            if(ret = BufByte(PCXbyte)) return ret;
        }
        else
        {
            if(ret = BufByte((BYTE)(PCXcount | 0xC0))) return ret;
            if(ret = BufByte(PCXbyte)) return ret;
        }
  
        PCXcount = 0;
    }
  
    if(PCXcount)
    {
        if(PCXcount == 1 && (PCXbyte & 0xC0) != 0xC0 )
        {
            if(ret = BufByte(PCXbyte)) return ret;
        }
        else
        {
            if(ret = BufByte((BYTE)(PCXcount | 0xC0))) return ret;
            if(ret = BufByte(PCXbyte)) return ret;
        }
        PCXcount = 0;
    }
    return OK;
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: int FAR PASCAL EndWrite(void far * lpPrivate)               *
 *             void far * lpPrivate - pointer to                        *
 *             custom structure to store private data                   *
 *                                                                      *
 * PURPOSE: Terminates conversion.                                      *
 *                                                                      *
 * RETURNS:                                                             *
 * OK         - Success                                                 *
 * BADFORMAT  - Bad signature                                           *
 * UNSUPPORTED- Unsupported subformat                                   *
 * BADFILE    - Error in file structure                                 *
 * CANNOTOPEN - Cannot open src/dest                                    *
 * INTERNAL   - Reserved                                                *
 * BADDLL     - Error initializing DLL                                  *
 * BADREQUEST - Unsupported type of conversion                          *
 * BADTEMPFILE- Error creating/reading tempfile                         *
 * NOMEMORY   - No enough global heap                                   *
 * NODISK     - No enough disk space                                    *
 * USERABORT  - Cancelled by user                                       *
 * BADPARMS   - Conflicting parameters                                  *
 *                                                                      *
\************************************************************************/
int FAR PASCAL EndWrite(void far *lpPrivate)
{
    WORD i;
	 PCXStruct far * lpPCXStruct = lpPrivate;
  
    if(lpPCXStruct->PCXpalette)
    {
        if(BufByte(0x0C)) return NODISK;
        for(i = 0; i<256; i++)
        {
            if( BufByte(lpPCXStruct->pal[0][i]) ||
                BufByte(lpPCXStruct->pal[1][i]) ||
                BufByte(lpPCXStruct->pal[2][i]) ) return NODISK;
        }
    }
    return FlushOutBuf(lpPCXStruct);
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: int FAR PASCAL WriteRow(int row, LPBYTE p,                  *
 *                                           void far * lpPrivate)      *
 *                                                                      *
 * PURPOSE: Writes image row.                                           *
 *                                                                      *
 * PARAMETERS: int row - the number of row to read                      *
 *             LPBYTE p - pointer to buffer to store image row          *
 *             void far * lpPrivate - pointer to                        *
 *             custom structure to store private data                   *
 *                                                                      *
 * RETURNS:                                                             *
 * OK         - Success                                                 *
 * BADFORMAT  - Bad signature                                           *
 * UNSUPPORTED- Unsupported subformat                                   *
 * BADFILE    - Error in file structure                                 *
 * CANNOTOPEN - Cannot open src/dest                                    *
 * INTERNAL   - Reserved                                                *
 * BADDLL     - Error initializing DLL                                  *
 * BADREQUEST - Unsupported type of conversion                          *
 * BADTEMPFILE- Error creating/reading tempfile                         *
 * NOMEMORY   - No enough global heap                                   *
 * NODISK     - No enough disk space                                    *
 * USERABORT  - Cancelled by user                                       *
 * BADPARMS   - Conflicting parameters                                  *
 *                                                                      *
\************************************************************************/
int FAR PASCAL WriteRow(int row,LPBYTE buf,void far *lpPrivate)
{
    int i;
  	 PCXStruct far *lpPCXStruct = lpPrivate;

    for( i = 0; i < (int)lpPCXStruct->hdr.nplanes; i++ )
    {
        if( PCXpack(buf,lpPCXStruct->hdr.bplin,lpPrivate) ) return NODISK;
        buf += lpPCXStruct->hdr.bplin;
    }
    return OK;
}
  
/************************************************************************\
 *                                                                      *
 * ROUTINE: void FAR PASCAL CleanUp(void far *lpPrivate)                *
 *             void far * lpPrivate - pointer to                        *
 *             custom structure to store private data                   *
 *                                                                      *
 * PURPOSE: Frees all auxiliary buffers.                                *
 *                                                                      *
\************************************************************************/
void FAR PASCAL CleanUp(void far *lpPrivate)
{
}

