/*DDK*************************************************************************/
/*                                                                           */
/* COPYRIGHT    Copyright (C) 1995 IBM Corporation                           */
/*                                                                           */
/*    The following IBM OS/2 WARP source code is provided to you solely for  */
/*    the purpose of assisting you in your development of OS/2 WARP device   */
/*    drivers. You may use this code in accordance with the IBM License      */
/*    Agreement provided in the IBM Device Driver Source Kit for OS/2. This  */
/*    Copyright statement may not be removed.                                */
/*                                                                           */
/*****************************************************************************/

/**************************************************************************
 *
 * SOURCE FILE NAME = Compress.c
 *
 * DESCRIPTIVE NAME = BITMAP COMPRESSION ROUTINES
 *
 *
 *
 * VERSION =   V2.1
 *
 * DATE        01/11/94
 *
 * DESCRIPTION BITMAP COMPRESSION PLOTTER DRIVER SOURCE FILE
 *
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/
#define INCL_GENPLIB_COMPRESS             /* genplib compression */
#include "plotters.h"
#include "compress.h"
#include "utils.h"
#include "init.h"
#define   MAXBLOCKSIZE  127



/****************************************************************************/
/* Function:    compress_any_supported_mode Row based compression           */
/*                                                                          */
/*                                                                          */
/* Description: Function will select the best                               */
/*              compression supported by the device select the mode         */
/*              and output the data. This function will work for both       */
/*              RTL and PCL devices                                         */
/*                                                                          */
/*  Return:     TRUE = success                                              */
/*                                                                          */
/*       PDDC    pDDC - drivers instance data pointer                       */
/*       PBYTE   pbBuffer - ptr to data to compress                         */
/*       INT     iBytesInArray - # of bytes in pbBuffer                     */
/*       PBYTE   pbLastLine - ptr to last lines uncompressed data           */
/*       PBYTE   pbCompress - buffer to compress data into. This buffer     */
/*                            is used as a scratch buffer for each line.    */
/*       ULONG   ulMaxCompress - length of pbCompress                       */
/*       PINT    piCurrentCompressMode - ptr to current compress mode       */
/*       ULONG   fulGplCompressModes - flags of supported Genplib           */
/*                                     compression routines                 */
/*       PUSHORT pusDelta - ptr to an array of USHORTS. This array is       */
/*                          used by GplCompressChooseMode as an area        */
/*                          to put hints for the choosen compression        */
/*                          routine.                                        */
/*                          Note: That pusDelta must have a length          */
/*                          equal to the length + 1  of                     */
/*                          Row Length to hold the pDelta  output.          */
/*                          There is no check on the the limit.             */
/*                                                                          */
/****************************************************************************/
BOOL compress_any_supported_mode( PDDC    pDDC,
                                  PBYTE   pbBuffer,
                                  INT     iBytesInArray,
                                  PBYTE   pbLastLine,
                                  PBYTE   pbCompress,
                                  ULONG   ulMaxCompress,
                                  PINT    piCurrentCompressMode,
                                  ULONG   fulGplCompressModes,
                                  PUSHORT pusDelta )
{
     INT iCompressMode, iCompressed;

     // Check for "best" compression mode for this scanline here
     // DBPRINTIF((TRUE, "fulGplCompressModes = %d", fulGplCompressModes));


     if (fulGplCompressModes != 0)
        iCompressMode = GplCompressChooseMode(pbBuffer, pbLastLine,
                                              iBytesInArray,
                                              fulGplCompressModes,
                                              pusDelta);
     else
        iCompressMode = 0;

     if (*piCurrentCompressMode != iCompressMode )
     {
        /*
        ** Set the compression mode
        */
        output_bytes(pDDC,"\033*b");
        output_number(pDDC, iCompressMode);
        output_bytes(pDDC,"M");

        *piCurrentCompressMode = iCompressMode;
     }


     /*
     ** Compress the data in the mode returned by GplCompChooseMode
     */
     switch (iCompressMode)
     {
        case 0:           // no compression
            iCompressed = iBytesInArray;
            CopyMem( pbCompress, pbBuffer, iBytesInArray);
            if (fulGplCompressModes >= GPLCOMPRESS_DELTAROW)
                 CopyMem( pbLastLine, pbBuffer, iBytesInArray);
            break;

        case 1:           // mode 1 = RLL compression
             iCompressed = GplCompressRLL (pbBuffer,
                                           iBytesInArray,
                                           pbCompress,
                                           ulMaxCompress);
            ASSERTT(iCompressed == -1 );
            if (fulGplCompressModes >= GPLCOMPRESS_DELTAROW)
                 CopyMem( pbLastLine, pbBuffer, iBytesInArray);
            break;

        case 2:           // mode 2 = TIFF compression
            iCompressed = GplCompressTIFF (pbBuffer,
                                           iBytesInArray,
                                           pbCompress,
                                           ulMaxCompress);
            ASSERTT(iCompressed == -1 );
            if (fulGplCompressModes >= GPLCOMPRESS_DELTAROW)
                 CopyMem( pbLastLine, pbBuffer, iBytesInArray);
            break;

        case 3:           // mode 3 = Delta Row compression
            iCompressed = GplCompressDeltaRow (iBytesInArray,
                                              pbBuffer,
                                              pbLastLine,
                                              ulMaxCompress,
                                              pbCompress,
                                              pusDelta );


            assertT(iCompressed == -1);
            if (iCompressed != 0)        // current and last line are different
              CopyMem( pbLastLine, pbBuffer, iBytesInArray);
            break;

         case 9:           // mode 9 = Enhanced Delta Row compression
            iCompressed = GplCompressRLLDeltaRow(iBytesInArray,
                                                 pbBuffer,
                                                 pbLastLine,
                                                 ulMaxCompress,
                                                 pbCompress,
                                                 pusDelta );
            if (iCompressed != 0)     // current and last line are different
              CopyMem( pbLastLine, pbBuffer, iBytesInArray);
            break;

        default:
           assertstring("Bad compression type");    // should never execute
           break;
      }

      /*
      ** Write raster data transfer header
      */
      output_bytes(pDDC,"\033*b");
      output_number(pDDC, iCompressed);
      output_bytes(pDDC,"W");

      /*
      ** Send a scanline
      */
      if (iCompressed > 0)
        bin_output_bytes(pDDC, pbCompress, (ULONG)iCompressed);

     return TRUE;
}
/***************************************************************************/
/* Function:    compress_adaptive- Block based adaptive                     */
/*              compression for RTL                                         */
/*                                                                          */
/* Description: Function will compress using an intelligent adaptive        */
/*              compression algorithm and then put in the control byte to   */
/*              tell whether we chose mode 0, 2, or 3. Then we follow that  */
/*              with the compressed size of the row.                        */
/*                                                                          */
/*  Return:     We return the control bytes and the compressed data in the  */
/*              buffer passed to us, PBRETURN, then we function return value*/
/*              is the number of bytes, including control bytes in this row */
/*              of data.                                                    */
/*                                                                          */
/****************************************************************************/
ULONG compress_adaptive(PBYTE   pbBits,
                        ULONG   ulcbDataIn,
                        PBYTE   pbLastLine,
                        PBYTE   pbReturn,
                        ULONG   ulcbDataOut,
                        ULONG   fulGplCompressModes,
                        PUSHORT pusDelta)
{

    ULONG    i,            /* Index Variable                                */
             ulTemp,       /* Temporary variable for output Count           */
             mode3size,
             mode2size;

   /*-----------------------------------------------------------------------*/
   /* Decide which mode to use and put control byte in buffer               */
   /*-----------------------------------------------------------------------*/
   switch (*pbReturn++ = (BYTE)GplCompressChooseMode(pbBits, pbLastLine,
                                                     ulcbDataIn,
                                                     fulGplCompressModes,
                                                     pusDelta))

   {
      case 0:  /* Don't use compression.                               */
               /* Insert number of bytes, high-order byte first.       */

               *pbReturn++ = (BYTE)(ulcbDataIn >> 8);
               *pbReturn++ = (BYTE)ulcbDataIn;

               /* Copy bits to return buffer and last line buffer.          */

               CopyMem( pbReturn, pbBits, ulcbDataIn );
               CopyMem( pbLastLine, pbBits, ulcbDataIn );

               /* Add 3 to return because 3 control bytes must be sent down.*/
               return (ulcbDataIn+3);

      case 1:  /* Use mode 1, it should do best for this line.     */
               /* Compress in Mode 1 and save number of bytes.     */

               ulTemp = GplCompressRLL ( pbBits, ulcbDataIn,
                                         pbReturn+2, ulcbDataOut-2 );

               /* Insert number of bytes, high-order byte first.   */
               *pbReturn++ = (BYTE)(ulTemp >> 8);
               *pbReturn++ = (BYTE)ulTemp;

               /* copy uncompressed data to the Last line buffer   */
               CopyMem( pbLastLine, pbBits, ulcbDataIn );

               /* Add 3 to return because 3 control bytes must be sent down.*/
               return (ulTemp+3);

      case 2:  /* Use mode 2, it should do best for this line.     */
               /* Compress in Mode 2 and save number of bytes.     */

               //ulTemp = OutputMode2 (pbBits, pbReturn+2, ulcbDataIn);
               ulTemp = GplCompressTIFF ( pbBits, ulcbDataIn,
                                          pbReturn+2, ulcbDataOut-2 );

               /* Insert number of bytes, high-order byte first.   */
               *pbReturn++ = (BYTE)(ulTemp >> 8);
               *pbReturn++ = (BYTE)ulTemp;

               /* copy uncompressed data to the Last line buffer   */
               CopyMem( pbLastLine, pbBits, ulcbDataIn );

               /* Add 3 to return because 3 control bytes must be sent down.*/
               return (ulTemp+3);

      case 3:  /* Use mode 3, it should be best for this line.     */
               /* Compress in Mode 3 and save number of bytes.     */

               ulTemp =  GplCompressDeltaRow( ulcbDataIn,     // bytes in scan
                                              pbBits,         // raster data
                                              pbLastLine,     // previous line
                                              ulcbDataOut-2,  // output size
                                              pbReturn+2,     // output
                                              pusDelta);      // delta hints

               /* Insert number of bytes, high-order byte first.   */
               *pbReturn++ = (BYTE)(ulTemp >> 8);
               *pbReturn++ = (BYTE)ulTemp;

               /* Add 3 to return because 3 control bytes must be sent down.*/
               /* copy uncompressed data to the Last line buffer   */
               CopyMem( pbLastLine, pbBits, ulcbDataIn );

               return (ulTemp+3);
   }
}
