/*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.                                */
/*                                                                           */
/*****************************************************************************/
#pragma  pagesize(55)
/**************************************************************************
 *
 * SOURCE FILE NAME = BITMAP.C
 *
 * DESCRIPTIVE NAME = BITMAP PLOTTER DRIVER
 *
 *
 *
 * VERSION =   V2.0
 *
 * DATE        09/18/88
 *
 * DESCRIPTION BITMAP PLOTTER DRIVER SOURCE FILE-File contains bitmap related
 *             functions
 *
 * FUNCTIONS   Bitblt()                 Transfer bitmaps directly from memory.
 *             DeviceCreateBitmap()     Create Plotter Driver Bit map
 *             DeviceDeleteBitmap()     Delete plotter driver bit map
 *             DeviceSelectBitmap()     Select plotter driver bit map
 *             DeviceSetCursor()        Set cursor bitmap
 *             DrawBorder()             Draw border inside a rectangle
 *             GetBitmapBits()          Get bit map data
 *             GetPel()                 Get Pel from coordinates specified
 *             ImageData()              This function draws a row of image data.
 *             RestoreScreenBits()      Restore screen bits
 *             SaveScreenBits()         Save plotter driver screen bits
 *             SetBitmapBits()          Set plotter driver bit map
 *             SetPel()                 Set pel from coordinates
 *             DrawBits()               Support for MemoryDc and Bitmaps
 *
 *
 *
 *
 *
 *
 *
 *
 *
 * NOTES
 *
 *
 * STRUCTURES
 *
 * EXTERNAL REFERENCES
 *
 * EXTERNAL FUNCTIONS
 *
*/
#define  INCL_GPIBITMAPS               /* Include bitmap defs in PMDDI      */
#define  LHBITMAP      0X4000000L
#define  DESELECTED_BITMAP 0X00000001L
#define INCL_GENPLIB_COMPRESS          /* include genplib compression       */
#include "plotters.h"
#include "bitmap.h"
#include "bounds.h"
#include "clip.h"
#include "color.h"
#include "error.h"
#include "output.h"
#include "outpline.h"
#include "box.h"
#include "attribs.h"
#include "dispatch.h"
#include "utils.h"
#include "compress.h"


#define GS_PATTERN_WIDTH             8
#define GS_PATTERN_HEIGHT            8
#define COLOR_FORMAT_RGB             1    /* color array is RGB structurs */
#define COLOR_FORMAT_RGB2            2    /* color array is RGB2 structurs */

#define BM_MODE_BANDING_TOPBOTTOM   0x00010000
#define BM_MODE_ROTATE_90           0x00020000
#define BM_MODE_ROTATE_180          0x00040000
#define BM_MODE_ROTATE_270          0x00080000
/*
** Gamma correct values for 2.5
** 255*pow(pixel_value/255.0, 1/2.5)+.5)
*/
#if 0
BYTE abGamma2pt5[256] =
{
   0,  28,  37,  43,  48,  53,  57,  61,  64,  67,  70,  73,  75,  78,  80,  82,
  84,  86,  88,  90,  92,  94,  96,  97,  99, 101, 102, 104, 105, 107, 108, 110,
 111, 113, 114, 115, 117, 118, 119, 120, 122, 123, 124, 125, 126, 127, 129, 130,
 131, 132, 133, 134, 135, 136, 137, 138, 139, 140, 141, 142, 143, 144, 145, 146,
 147, 148, 149, 149, 150, 151, 152, 153, 154, 155, 155, 156, 157, 158, 159, 160,
 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168, 169, 170, 170, 171, 172,
 173, 173, 174, 175, 175, 176, 177, 177, 178, 179, 179, 180, 181, 182, 182, 183,
 183, 184, 185, 185, 186, 187, 187, 188, 189, 189, 190, 190, 191, 192, 192, 193,
 194, 194, 195, 195, 196, 197, 197, 198, 198, 199, 199, 200, 201, 201, 202, 202,
 203, 203, 204, 205, 205, 206, 206, 207, 207, 208, 208, 209, 209, 210, 211, 211,
 212, 212, 213, 213, 214, 214, 215, 215, 216, 216, 217, 217, 218, 218, 219, 219,
 220, 220, 221, 221, 222, 222, 223, 223, 224, 224, 225, 225, 226, 226, 227, 227,
 228, 228, 229, 229, 230, 230, 230, 231, 231, 232, 232, 233, 233, 234, 234, 235,
 235, 235, 236, 236, 237, 237, 238, 238, 239, 239, 240, 240, 240, 241, 241, 242,
 242, 243, 243, 243, 244, 244, 245, 245, 246, 246, 246, 247, 247, 248, 248, 248,
 249, 249, 250, 250, 251, 251, 251, 252, 252, 253, 253, 253, 254, 254, 255, 255
};
#endif
/*
**Gamma correct values for 2.0
*/
BYTE abGamma2pt0[256] =
{
  0,  16,  23,  28,  32,  36,  39,  42,  45,  48,  50,  53,  55,  58,  60,  62,
 64,  66,  68,  70,  71,  73,  75,  77,  78,  80,  81,  83,  84,  86,  87,  89,
 90,  92,  93,  94,  96,  97,  98, 100, 101, 102, 103, 105, 106, 107, 108, 109,
111, 112, 113, 114, 115, 116, 117, 118, 119, 121, 122, 123, 124, 125, 126, 127,
128, 129, 130, 131, 132, 133, 134, 135, 135, 136, 137, 138, 139, 140, 141, 142,
143, 144, 145, 145, 146, 147, 148, 149, 150, 151, 151, 152, 153, 154, 155, 156,
156, 157, 158, 159, 160, 160, 161, 162, 163, 164, 164, 165, 166, 167, 167, 168,
169, 170, 170, 171, 172, 173, 173, 174, 175, 176, 176, 177, 178, 179, 179, 180,
181, 181, 182, 183, 183, 184, 185, 186, 186, 187, 188, 188, 189, 190, 190, 191,
192, 192, 193, 194, 194, 195, 196, 196, 197, 198, 198, 199, 199, 200, 201, 201,
202, 203, 203, 204, 204, 205, 206, 206, 207, 208, 208, 209, 209, 210, 211, 211,
212, 212, 213, 214, 214, 215, 215, 216, 217, 217, 218, 218, 219, 220, 220, 221,
221, 222, 222, 223, 224, 224, 225, 225, 226, 226, 227, 228, 228, 229, 229, 230,
230, 231, 231, 232, 233, 233, 234, 234, 235, 235, 236, 236, 237, 237, 238, 238,
239, 240, 240, 241, 241, 242, 242, 243, 243, 244, 244, 245, 245, 246, 246, 247,
247, 248, 248, 249, 249, 250, 250, 251, 251, 252, 252, 253, 253, 254, 254, 255
};

RGB2 vrgb2ColorWhite = {0xFF,0xFF,0xFF,0x00};
RGB2 vrgb2ColorBlack = {0x00,0x00,0x00,0x00};

/*
**table for inverting or mirroring mono data
*/
BYTE abMonoMirrorTable[256] =
{
 0x0, 0x80, 0x40, 0xC0, 0x20, 0xA0, 0x60, 0xE0, 0x10, 0x90, 0x50,
0xD0, 0x30, 0xB0, 0x70, 0xF0,  0x8, 0x88, 0x48, 0xC8, 0x28, 0xA8,
0x68, 0xE8, 0x18, 0x98, 0x58, 0xD8, 0x38, 0xB8, 0x78, 0xF8,  0x4,
0x84, 0x44, 0xC4, 0x24, 0xA4, 0x64, 0xE4, 0x14, 0x94, 0x54, 0xD4,
0x34, 0xB4, 0x74, 0xF4,  0xC, 0x8C, 0x4C, 0xCC, 0x2C, 0xAC, 0x6C,
0xEC, 0x1C, 0x9C, 0x5C, 0xDC, 0x3C, 0xBC, 0x7C, 0xFC,  0x2, 0x82,
0x42, 0xC2, 0x22, 0xA2, 0x62, 0xE2, 0x12, 0x92, 0x52, 0xD2, 0x32,
0xB2, 0x72, 0xF2,  0xA, 0x8A, 0x4A, 0xCA, 0x2A, 0xAA, 0x6A, 0xEA,
0x1A, 0x9A, 0x5A, 0xDA, 0x3A, 0xBA, 0x7A, 0xFA,  0x6, 0x86, 0x46,
0xC6, 0x26, 0xA6, 0x66, 0xE6, 0x16, 0x96, 0x56, 0xD6, 0x36, 0xB6,
0x76, 0xF6,  0xE, 0x8E, 0x4E, 0xCE, 0x2E, 0xAE, 0x6E, 0xEE, 0x1E,
0x9E, 0x5E, 0xDE, 0x3E, 0xBE, 0x7E, 0xFE,  0x1, 0x81, 0x41, 0xC1,
0x21, 0xA1, 0x61, 0xE1, 0x11, 0x91, 0x51, 0xD1, 0x31, 0xB1, 0x71,
0xF1,  0x9, 0x89, 0x49, 0xC9, 0x29, 0xA9, 0x69, 0xE9, 0x19, 0x99,
0x59, 0xD9, 0x39, 0xB9, 0x79, 0xF9, 0x5,  0x85, 0x45, 0xC5, 0x25,
0xA5, 0x65, 0xE5, 0x15, 0x95, 0x55, 0xD5, 0x35, 0xB5, 0x75, 0xF5,
 0xD, 0x8D, 0x4D, 0xCD, 0x2D, 0xAD, 0x6D, 0xED, 0x1D, 0x9D, 0x5D,
0xDD, 0x3D, 0xBD, 0x7D, 0xFD,  0x3, 0x83, 0x43, 0xC3, 0x23, 0xA3,
0x63, 0xE3, 0x13, 0x93, 0x53, 0xD3, 0x33, 0xB3, 0x73, 0xF3,  0xB,
0x8B, 0x4B, 0xCB, 0x2B, 0xAB, 0x6B, 0xEB, 0x1B, 0x9B, 0x5B, 0xDB,
0x3B, 0xBB, 0x7B, 0xFB,  0x7, 0x87, 0x47, 0xC7, 0x27, 0xA7, 0x67,
0xE7, 0x17, 0x97, 0x57, 0xD7, 0x37, 0xB7, 0x77, 0xF7,  0xF, 0x8F,
0x4F, 0xCF, 0x2F, 0xAF, 0x6F, 0xEF, 0x1F, 0x9F, 0x5F, 0xDF, 0x3F,
0xBF, 0x7F, 0xFF
};


extern COLORTABLE DefaultColorTable[MAX_COLOR_INDEX];
extern PFNL daBitblt;
/*
** LOCAL FUNCTIONS
*/
LOCAL VOID getnextcolor(PBYTE, PBYTE, ULONG, PLONG, ULONG, ULONG, PDDC);
LOCAL BYTE getgreypattern(PBYTE, ULONG);
LOCAL VOID greyscalesourcebits(PBYTE,PBYTE,PRECTL,ULONG,ULONG,PBITMAPINFO,PDDC);
LOCAL HBITMAP getbitmaphandle(HDC);
LOCAL USHORT  locate_RFpen(PDDC, ULONG);
LOCAL VOID fill_pattern(PDDC, PBYTE, PBITMAPINFO, ULONG, LONG, RECTL);
LOCAL VOID set_palette(PDDC, ULONG, ULONG, PRGB2, ULONG);
LOCAL VOID build_palette(PDDC, ULONG, PRGB2, LONG, ULONG);
LOCAL VOID mirror_scan_line(PBYTE, PBYTE, ULONG, ULONG, LONG);
LOCAL VOID convertBGR_to_RGB(RGB*, RGB*, ULONG, ULONG, BOOL);
LOCAL VOID image_scan(PDDC,PBYTE,ULONG,LONG,ULONG,ULONG,LONG,ULONG,ULONG,ULONG,ULONG);
LOCAL BOOL end_raster_graphics(PDDC, ULONG);
LOCAL BOOL begin_raster_graphics(PDDC, ULONG, BOOL);
LOCAL BOOL set_raster_width_and_height(PDDC, ULONG, PRECTL, PRECTL, BOOL);
LOCAL BOOL set_graphics_position(PDDC, ULONG, PRECTL, ULONG,ULONG);
LOCAL BOOL return_to_HPGL2(PDDC, ULONG);
LOCAL BOOL enter_PCL_or_HPRTL(PDDC, ULONG);
LOCAL BOOL vector_bitmap(PDDC,PBYTE,ULONG,LONG,ULONG,ULONG,PRECTL,PRGB2,LONG);

/******************************************************************************/
/*  FUNCTION: getnextcolor                                                    */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This code will read source color bits and determine what the color of     */
/*  the first pel it encounters at the current position in the bits is, as    */
/*  well as the number of continuouspels of the same color. This will enable */
/*  us to greyscale as many pels of a specific color at a time as we can.     */
/*  This function returns the current RGB color as well as updating the       */
/*  pointers to the source bits, the current pel position and the total       */
/*  number of continuous pels of the current RGB color.                       */
/*                                                                            */
/*  Created : Kran                                                            */
/******************************************************************************/
LOCAL VOID getnextcolor( PBYTE      lpSrcPtr,
                         PBYTE      pRGB,
                         ULONG      ulPelsLeft,
                         PLONG      plPels,
                         ULONG      ulPelsWritten,
                         ULONG      ulBitCount,
                         PDDC       pDDC )
{

   LONG             lPels;
   ULONG            ulPelPos;
   BYTE             bSrcByte;
   BOOL             fColorsMatch;
   BYTE             ColorByte;
   PBYTE            pbNext;
   RGB              RgbNext;
   LONG             lNextBit;
   BYTE             CByte;

   /*
   **  Initialize a few things...
   */
   fColorsMatch = FALSE;              /* Assume a unique RGB...              */
   lPels        = 0;                  /* # of pels of the same color         */

   if(ulBitCount == 24)
   {
     pbNext  = lpSrcPtr + ulPelsWritten * 3;
     pRGB[0] = *pbNext++;
     pRGB[1] = *pbNext++;
     pRGB[2] = *pbNext++;
   }
   else if (ulBitCount == 8)
   {
     pbNext = lpSrcPtr + ulPelsWritten;
     pRGB[0] = ColorByte = *pbNext++;
     pRGB[1] = pRGB[2] = 0x00;
   }
   else     /* ulBitCount == 4 or 1*/
   {
     lNextBit = ulBitCount * ulPelsWritten;
     pbNext   = lpSrcPtr + (lNextBit >> 3);
     bSrcByte = *pbNext++;
     ulPelPos = lNextBit % 8;
     if (ulBitCount == 1)
     {

       switch (ulPelPos)
       {
       case 0: ColorByte = (bSrcByte & 0x80) >> 7;
               break;
         case 1: ColorByte = (bSrcByte & 0x40) >> 6;
               break;
         case 2: ColorByte = (bSrcByte & 0x20) >> 5;
               break;
         case 3: ColorByte = (bSrcByte & 0x10) >> 4;
               break;
         case 4: ColorByte = (bSrcByte & 0x08) >> 3;
               break;
         case 5: ColorByte = (bSrcByte & 0x04) >> 2;
               break;
         case 6: ColorByte = (bSrcByte & 0x02) >> 1;
               break;
         case 7: ColorByte = (bSrcByte & 0x01);
               break;
         default: break;
       }
       pRGB[0] = ColorByte;
     }
     else
     {
       pRGB[0]  = ColorByte = (ulPelPos == 0 ? bSrcByte >> 4 : bSrcByte & 0x0F);
     }
     pRGB[1] = pRGB[2] = 0x00;
     ulPelPos += ulBitCount;
   }

   /*
   **  Loop until we find a color differing from the first
   **  encountered or until we've picked up the last of the pels on
   **  this scan line...
   */
   do
   {
      /*
      **  If we have all of the pels we need, then let's get out...
      */
      if (++lPels == ulPelsLeft)
      {
          break;
      }

      switch (ulBitCount)
      {
      case 1:
          if (ulPelPos == 8)
          {
            ulPelPos = 0;
            bSrcByte = *pbNext++;
          }
          switch (ulPelPos)
          {
            case 0: CByte = (bSrcByte & 0x80) >> 7;
                    break;
            case 1: CByte = (bSrcByte & 0x40) >> 6;
                    break;
            case 2: CByte = (bSrcByte & 0x20) >> 5;
                    break;
            case 3: CByte = (bSrcByte & 0x10) >> 4;
                    break;
            case 4: CByte = (bSrcByte & 0x08) >> 3;
                    break;
            case 5: CByte = (bSrcByte & 0x04) >> 2;
                    break;
            case 6: CByte = (bSrcByte & 0x02) >> 1;
                    break;
            case 7: CByte = (bSrcByte & 0x01);
                    break;
            default: break;
          }
          fColorsMatch = ColorByte == CByte;
          ulPelPos += ulBitCount;
          break;
      case 4:
          if (ulPelPos == 8)
          {
            ulPelPos = 0;
            bSrcByte = *pbNext++;
          }
          fColorsMatch = ColorByte == (ulPelPos == 0 ? bSrcByte >> 4 : bSrcByte & 0x0F);
          ulPelPos += ulBitCount;
          break;
      case 8:
          fColorsMatch = ColorByte == *pbNext++;
          break;
      case 24:
          RgbNext.bBlue  = *pbNext++;
          RgbNext.bGreen = *pbNext++;
          RgbNext.bRed   = *pbNext++;
          fColorsMatch = compare_memory(pRGB, (PBYTE)&RgbNext, sizeof(RGB));
          break;
      default:
          return;
      }
   }
   while (fColorsMatch);

   /*
   **  Tell the calling routine how many pels we've found of the same color
   **  and return the current color too...
   */
   *plPels   = lPels;
   return;
}

/*******************************************************************************
** FUNCTION : getgreypattern
**            This function returns the pattern byte to the caller.
**
** Input  : Pointer to the rgb and yorigin
** Return : Byte pattern.
**
**
**
**
**
*******************************************************************************/
LOCAL BYTE getgreypattern(PBYTE prgb,ULONG ulY)
{
    #define HALFTONES 8         // Multiples of 2

    static BYTE bHalftone[HALFTONES][8] = {
     0xc7,   // Dense8  0x00, 0xc7, 0x38,0xc7
     0x83,   // ........0x00, 0x83, 0x7C,0x83
     0x83,   // ........0x20, 0x83, 0x7C,0x83
     0xc7,   // ..*.....0x00, 0xc7, 0x38,0xc7
     0x7c,   // ........0x00, 0x7c, 0x83,0x7c
     0x38,   //         0x00, 0x38, 0xC7,0x38
     0x38,   //         0x02, 0x38, 0xC7,0x38
     0x7c,   //         0x00, 0x7c, 0x83,0x7c

     0xc7,   // Dense7  0x00, 0xc7, 0x38,0xc7
     0x93,   // ........0x10, 0x93, 0x6C,0x93
     0xab,   // ...*....0x30, 0xab, 0x54,0xab
     0xc7,   // ..**....0x00, 0xc7, 0x38,0xc7
     0x7c,   // ........0x00, 0x7c, 0x83,0x7c
     0x39,   //         0x01, 0x39, 0xC6,0x39
     0xba,   //         0x03, 0xba, 0x45,0xba
     0x7c,   //         0x00, 0x7c, 0x83,0x7c

     0xe7,   // Dense6  0x00, 0xe7, 0x18,0xe7
     0xc3,   // ........0x10, 0xc3, 0x3C,0xc3
     0xcb,   // ...*....0x38, 0xcb, 0x34,0xcb
     0xe7,   // ..***...0x10, 0xe7, 0x18,0xe7
     0x7e,   // ...*....0x00, 0x7e, 0x81,0x7e
     0x3c,   //         0x01, 0x3c, 0xC3,0x3c
     0xbc,   //         0x83, 0xbc, 0x43,0xbc
     0x7e,   //         0x01, 0x7e, 0x81,0x7e

     0xe7,   // Dense5  0x10, 0xe7, 0x18,0xe7
     0xd3,   // ...*....0x38, 0xd3, 0x2C,0xd3
     0xdb,   // ..***...0x28, 0xdb, 0x24,0xdb
     0xe7,   // ..*.*...0x10, 0xe7, 0x18,0xe7
     0x7e,   // ...*....0x01, 0x7e, 0x81,0x7e
     0x3e,   //         0x83, 0x3e, 0xC1,0x3e
     0xbd,   //         0x82, 0xbd, 0x42,0xbd
     0x7e,   //         0x01, 0x7e, 0x81,0x7e

     0xef,   // Dense4  0x18, 0xef, 0x10,0xef
     0xc7,   // ...**...0x2c, 0xc7, 0x38,0xc7
     0xd7,   // ..*.**..0x24, 0xd7, 0x28,0xd7
     0xef,   // ..*..*..0x18, 0xef, 0x10,0xef
     0xfe,   // ...**...0x81, 0xfe, 0x01,0xfe
     0x7c,   //         0xc1, 0x7c, 0x83,0x7c
     0x7d,   //         0x42, 0x7d, 0x82,0x7d
     0xfe,   //         0x81, 0xfe, 0x01,0xfe

     0xff,   // Dense3  0x18, 0xff, 0x00,0xff
     0xef,   // ...**...0x3c, 0xef, 0x10,0xef
     0xc7,   // ..****..0x34, 0xc7, 0x38,0xc7
     0xef,   // ..**.*..0x18, 0xef, 0x10,0xef
     0xff,   // ...**...0x81, 0xff, 0x00,0xff
     0xfe,   //         0xc3, 0xfe, 0x01,0xfe
     0x7c,   //         0x43, 0x7c, 0x83,0x7c
     0xfe,   //         0x81, 0xfe, 0x01,0xfe

     0xff,   // Dense2  0x38, 0xff, 0x00,0xff
     0xef,   // ..***...0x6c, 0xef, 0x10,0xef
     0xcf,   // .**.**..0x54, 0xcf, 0x30,0xcf
     0xff,   // .*.*.*..0x38, 0xff, 0x00,0xff
     0xff,   // ..***...0x83, 0xff, 0x00,0xff
     0xfe,   //         0xc6, 0xfe, 0x01,0xfe
     0xfc,   //         0x45, 0xfc, 0x03,0xfc
     0xff,   //         0x83, 0xff, 0x00,0xff

     0xff,   // Dense1  0x38, 0xff, 0x00,0xff
     0xff,   // ..***...0x7c, 0xff, 0x00,0xff
     0xdf,   // .*****..0x7c, 0xdf, 0x20,0xdf
     0xff,   // .*****..0x38, 0xff, 0x00,0xff
     0xff,   // ..***...0x83, 0xff, 0x00,0xff
     0xff,   //         0xc7, 0xff, 0x00,0xff
     0xfd,   //         0xc7, 0xfd, 0x02,0xfd
     0xff,   //         0x83, 0xff, 0x00,0xff

    };

    BYTE Byte;

    /* average the colors to get 0-255 */
    Byte = (BYTE)(((USHORT)(prgb[0]*15 + prgb[1]*60 + prgb[2]*25)) / 100);

    if (Byte != 0x00 && Byte != 0xFF)
    {
       /* convert to index 0 - (HALFTONES-1) */
       Byte /= 256 / HALFTONES ;
        /* calculate dither pattern for y offset */
       Byte = bHalftone[Byte][ulY];
    }
    return (Byte);
}

/******************************************************************************/
/*  FUNCTION: greyscalesourcebits                                             */
/*                                                                            */
/*  PARAMETERS:                                                               */
/*                                                                            */
/*  PBYTE         pBits : Destination bitmap                                  */
/*  PBYTE         pbScan : Source bitmap                                      */
/*  PRECTL        prclDst : Destination Rectangle                             */
/*  ULONG         ulSrcBytes:number of source bytes per scan(32 bit boundary) */
/*  ULONG         ulScans : number of source scan lines                       */
/*  PBITMAPINFO   pbmi : pointer to bitmap info                               */
/*  PDDC          pDDC                                                        */
/*                                                                            */
/*                                                                            */
/*  DESCRIPTION:                                                              */
/*                                                                            */
/*  This function will take the current source bitmap                         */
/*  and convert the bitmap into a greyscaled 1,1 bits into pBits              */
/*                                                                            */
/*  Created : Kran                                                            */
/******************************************************************************/
LOCAL VOID greyscalesourcebits( PBYTE       pBits,
                                PBYTE       pbScan,
                                PRECTL      prclDst,
                                ULONG       ulSrcBytes,
                                ULONG       ulScans,
                                PBITMAPINFO pbmi,
                                PDDC        pDDC)
{
  ULONG            ulBitHeight;      /* no of scanlines                       */
  ULONG            ulSrcPels;        /* total no of pels in pSrc              */
  ULONG            ulXOrigin;        /* pattern x origin                      */
  ULONG            ulYOrigin;        /* pattern y origin                      */
  LONG             i,k;              /* loop counters                         */
  ULONG            ulPartialByte;    /* # of pels to complete last byte       */
  ULONG            ulRemains;        /* # of pels to place in target          */
  USHORT           ulFilled;         /* 8 - usPartialByte                     */
  ULONG            ulPelsWritten;    /* # of bytes written to target          */
  ULONG            ulPelPos;         /* Nibble indicator for source           */
  LONG             lPels;            /* # of pels of the same color           */
  ULONG            ulDWords;         /* # of DWORDs to place in target        */
  ULONG            ulBytes;          /* # of BYTEs to place in target         */
  ULONG            ulXDelta;         /* Adjusted pattern X-origin             */
  ULONG            ulYDelta;         /* Adjusted pattern Y-origin             */
  BYTE             bPatt;            /* Temporary greyscale pattern byte      */
  ULONG            ulXfer;           /* for dword packing                     */
  BYTE             bTemp;            /* Temporary target byte                 */
  ULONG            ulMask;
  PBYTE            pbDest;
  PBYTE            pbSrc;
  ULONG            temp;
  RGB              rgbColor;
  ULONG            ulTrgWidth;
  ULONG            ulSrcWidth;
  ULONG            ulLinesScanned;
  ULONG            ulBitCount;

  pbDest         = pBits;
  pbSrc          = pbScan;
  ulBitHeight    = ulScans;
  ulSrcPels      = pbmi->cx;
  ulTrgWidth     = (pbmi->cx + 7) >> 3; // byte aligned
  ulSrcWidth     = ulSrcBytes;          // dword aligned
  ulLinesScanned = 0;
  ulBitCount      = pbmi->cBitCount;

  /**************************************************************************/
  /*  Get the x and y origin of the pattern adjusting for the               */
  /*  target rectangle coordinates for the blit...                          */
  /**************************************************************************/
  ulXOrigin  = prclDst->xLeft % 8;
  ulYOrigin  = prclDst->yBottom % 8;

  for (i = 0; i < ulBitHeight; i++)
  {
     ulPartialByte = 0;
     ulFilled      = 0;
     ulPelsWritten = 0;

     /*
     **  Loop through all of the bytes in each scan line on a per RGB
     **  basis...
     */
     while (ulPelsWritten != ulSrcPels)
     {
        /*
        **  Find out what the next RGB color is in the source bitmap
        **  and how many consecutive pels are set to that color.
        */
        getnextcolor(pbSrc, (PBYTE) &rgbColor,
                     (USHORT)(ulSrcPels - ulPelsWritten),
                      &lPels, ulPelsWritten,ulBitCount, pDDC);
        rgbColor = pbmi->argbColor[rgbColor.bBlue];

        if ((ulPartialByte) && (lPels >= ulPartialByte))
        {
            ulDWords  = (lPels  - ulPartialByte) / 32;
            ulBytes   = ((lPels - ulPartialByte) % 32) / 8;
            ulRemains = (lPels  - ulPartialByte) % 8;
        }
        else
        {
            ulDWords  = lPels  / 32;
            ulBytes   = (lPels % 32) / 8;
            ulRemains = lPels  % 8;
        }

        ulXDelta = (ulXOrigin + ulFilled) % GS_PATTERN_WIDTH;
        ulYDelta = (ulYOrigin + i) % GS_PATTERN_HEIGHT;
        bPatt    = getgreypattern((PBYTE)&rgbColor,ulYDelta);

        ulXfer  = (ULONG)bPatt;
        ulXfer |= ulXfer << 8;
        ulMask  = (ulXfer | (ulXfer << 16));
        /* get bits that will be shifted out */
        temp = ulMask >> (32 - ulXDelta);
        ulMask = (ulMask << ulXDelta) | temp;

        /*
        **  If there was a partial byte written last time through,
        **  we need to complete it so we can get back on a DWORD
        **  or BYTE boundary...
        */
        if ((ulPartialByte) && (lPels >= ulPartialByte))
        {
           *pbDest        = (*pbDest & (0xff << ulPartialByte)) |
                            (BYTE)(((BYTE)ulMask &
                                  (0xff << ulFilled)) >> ulFilled);
           ulPelsWritten += ulPartialByte;

           /*
           **  Need to rotate the pattern by usPartialByte as we
           **  have used a portion of the pattern DWORD here and
           **  we must resynch before we go further...
           */
           temp          = ulMask >> (32 - ulPartialByte);
           ulMask        = (ulMask << ulPartialByte) | temp;
           ulPartialByte = 0;
           ulFilled      = 0;
           pbDest++;
        }
        if (ulDWords)
        {
           /*
           **  Write as many DWORDs as possible...
           */
           for (k = 0; k < ulDWords; k++)
           {
               *(PULONG)pbDest = ulMask;
               pbDest           += 4;
           }
        }
        if (ulBytes)
        {
           /*
           **  Write any remaining full BYTEs...
           */
           for (k = 0; k < ulBytes; k++)
           {
               *pbDest = (BYTE)ulMask;
               pbDest++;
           }
        }

        /*
        **  May still have a partial byte to write...
        */
        if (ulRemains)
        {
           if (ulPartialByte)
           {
              bTemp      = *pbDest & (0xff << ulPartialByte);
              bTemp     |= ((BYTE)ulMask &
                           (0xff << (8 - ulRemains))) >> ulFilled;
              bTemp     |= 0xff >> (ulFilled + ulRemains);
              *pbDest    = bTemp;
           }
           else
           {
              bTemp      = (BYTE)((BYTE)ulMask &
                                  (0xff << (8 - ulRemains)));
              bTemp     |= 0xff >> ulRemains;
              *pbDest   = bTemp;
           }
        }

        ulPelsWritten += (ulDWords * 32) + (ulBytes * 8) + ulRemains;
        if (ulRemains)
        {
           ulPartialByte = ulPartialByte ? ulPartialByte - ulRemains :
                                           8 - ulRemains;
           ulFilled      = 8 - ulPartialByte;
        }
     } /* while */
     ulLinesScanned++;
     pbDest  = pBits + ulLinesScanned * ulTrgWidth;  // go to next row
     pbSrc   = pbScan + ulLinesScanned * ulSrcWidth;

  } /* for loop */
}

/***************************************************************************
 *
 * FUNCTION NAME = getbitmaphandle
 *
 * DESCRIPTION   = Returns the bitmap handle.
 *
 * INPUT         = (hdc)
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = NONE
 *
 * RETURN-ERROR  = NONE
 *
 **************************************************************************/

LOCAL HBITMAP getbitmaphandle( HDC hdc )
{
  LONG    lResult;
  HBITMAP hbm;                         /* Source bitmap handle              */

  /*
  ** !!!CR What happens if hdc > LHBITMAP?
  */
  if ((ULONG)hdc < LHBITMAP)
  {
    /*
    ** Pop the source bitmap handle out of the source
    ** DC by selecting in a null bitmap handle and
    ** then reselecting the origional bitmap handle.
    */
    hbm = GreSelectBitmap(hdc, 0L );

    if (((LONG) hbm) <= 0)
    {
      GplErrSetError( (ERRORID)PMERR_BITMAP_NOT_FOUND );
      return( (HBITMAP)0 );
    }
    lResult = (LONG) GreSelectBitmap( hdc, hbm );

    if (lResult < 0)
    {
      GplErrSetError( (ERRORID)PMERR_BITMAP_NOT_FOUND );
      return( (HBITMAP) 0 );
    }
  }
  else
  {
    hbm = (HBITMAP) 0;
  }
  return( hbm );
}

/******************************************************************************
** FUNCTION : build_palette : Sets the PCL/RTL Palette
**
** PDDC          pDDC
** ULONG         ulBitCount : Bitmap bits per pel
** PRGB2         paRGB2 : Ptr to an array of rgb values
** LONG          flColorType : flag for color array type
** ULONG         fulOddCaps  : odd device caps
**
**
** Outputs the necessary escape sequences to the device to build the
** Color Palette in the device.
** While colors
**     output  "\033*v#a#b#c#I"
**
**
**
** Created 10/04/93 Kran
******************************************************************************/
LOCAL VOID build_palette(PDDC pDDC, ULONG ulBitCount, PRGB2 paRGB2,
                         LONG flColorType, ULONG fulOddCaps)
{
  ULONG  ulColor;
  LONG   nColors;
  LONG   lIndex = 0;
  RGB FAR  *pRGB;

  nColors = 1 << ulBitCount;
  while (nColors--)
  {
    if (fulOddCaps & OD_NEEDS_GAMMA)
    {
      ulColor = (ULONG) (abGamma2pt0[paRGB2->bRed]);
      ulColor = (ULONG) ((ulColor << 8) | abGamma2pt0[paRGB2->bGreen]);
      ulColor = (ULONG) ((ulColor << 8) | abGamma2pt0[paRGB2->bBlue]);
    }
    else
    {
      ulColor = (ULONG) (paRGB2->bRed);
      ulColor = (ULONG) ((ulColor << 8) | paRGB2->bGreen);
      ulColor = (ULONG) ((ulColor << 8) | paRGB2->bBlue);
    }

    /*
    ** Do nothing if the color is black and the index is greater than 8.
    ** PCL defaults all the indexes > 8 to BLACK .
    */
    if (((ulColor & 0xFFFFFF) == 0) && (lIndex > 8))
    {
      ;
    }
    else
    {
      output_bytes(pDDC,"\033*v");
      output_number(pDDC,(ULONG) paRGB2->bRed);
      output_bytes(pDDC,"a");
      output_number(pDDC,(ULONG) paRGB2->bGreen);
      output_bytes(pDDC,"b");
      output_number(pDDC,(ULONG) paRGB2->bBlue);
      output_bytes(pDDC,"c");
      output_number(pDDC,lIndex);
      output_bytes(pDDC,"I");
    }
    /*
    ** increment the color table pointer based on the color table type
    */
    if (flColorType & COLOR_FORMAT_RGB)
    {
      pRGB = (PVOID)paRGB2;
      pRGB++;
      paRGB2 = (PVOID)pRGB;
      /* paRGB2 = (PBYTE)paRGB2 + sizeof(RGB);  */
    }
    else
    {
      paRGB2++;
    }
    lIndex++;
  }
}
/******************************************************************************
** FUNCTION : set_palette : Controls the PCL/RTL palette
**
** PDDC          pDDC
** ULONG         ulOddCaps  : odd capabilities flag the bits
**                            tell us if this is a PCL for HPRTL
**                            device.
** ULONG         ulBitCount  : Bitmap bits per pel
** PRGB2         paRGB2      : Ptr to an array of rgb values
** LONG          flColorType : flag for color array type
**
** First saves the HPGL2 Palette, if it is not already saved.
** Sends the necessary configure image data command to the device based on the
** ulBitCount of the bitmap. Sets the number of bits per index in Configure
** Image data command. Calls the build_palette to actually build the Palette.
**
** output "\033*v6W01#888"
**     Where # is the number of bits per pel.
**
**
**
** Created : 11/03/93 Kran
******************************************************************************/
LOCAL VOID set_palette(PDDC pDDC, ULONG fulOddCaps, ULONG ulBitCount,
                       PRGB2 paRGB2, ULONG flColorType)
{
  PPDEVICE pPDevice       = pDDC->pPDevice;
  ULONG    Plotter        = pPDevice->Plotter;
  BOOL     fIsColorDevice = PlotterClass[Plotter].fsOdd & OD_COLOR;
  BYTE     pTemp[6] = {0x00,0x01,0x00,0x08,0x08,0x08};
                      // byte 0:set color model  byte 3:bits per red
                      // byte 1:pixel encoding   byte 4:bits per green
                      // byte 2:bits per index   byte 5:bits per blue

  if (fulOddCaps & (OD_PCL | OD_HPRTL))
  {
    if (fIsColorDevice)
    {
      if (!pDDC->pPDevice->bHPGL2_PalettePushed)
      {
        output_bytes (pDDC,"\033*p0P");              // Push HPGL2 Palette
        pDDC->pPDevice->bHPGL2_PalettePushed = TRUE;
      }
      /*
      ** Send configure image data command
      */
      output_bytes(pDDC, "\033*v6W");
      switch (ulBitCount)
      {
        case 1: pTemp[2] = 0x01;                     // Mono
                break;

        case 4: pTemp[2] = 0x04;                     // 4 bit per pel
                break;

        case 8: pTemp[2] = 0x08;                     // 8 bit per pel
                break;

        case 24:pTemp[1] = 0x3;                      // 24 bit per pel
                pTemp[2] = 0x24;
                break;

        default: break;
      }
      bin_output_bytes(pDDC, pTemp, 6L);             // comfigure image data

      if (ulBitCount != 24)                          // if indexed color
      {
        build_palette(pDDC, ulBitCount, paRGB2, flColorType, fulOddCaps);
      }
    }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = mirror_scan_line
 *
 * DESCRIPTION   = Because the current raster plotters do not rotate
 *                 RTL graphics we must flip and invert the bitmap
 *                 to rotate 270
 *
 * INPUT         = PBYTE pbDest,        - Pointer to the beginning of the
 *                                        destination scan line.
 *                 PBYTE pbSrc          - Pointer to the beginning of the
 *                                        source scan line.
 *                 ULONG ulBpp          - Source Bits per Pel
 *                 ULONG ulBytesPerScan - Number of bytes per row
 *                 ULONG ulWidthInPels  - Number of Pels (need for padding)
 *
 * OUTPUT        = converted scan line in pbDest
 *
 * RETURN-NORMAL = VOID
 * RETURN-ERROR  = VOID
 *
 **************************************************************************/

LOCAL VOID  mirror_scan_line(PBYTE pbDest, PBYTE pbSrc,
                             ULONG ulBpp,  ULONG ulBytesPerScan,
                             LONG lWidthInPels)
{
  ULONG ulCount = 0;
  ULONG ulShift,ulShiftCompliment;

  pbDest = pbDest+(ulBytesPerScan -1);

  if (ulBpp == 8)
  {
    while (ulCount < ulBytesPerScan)
    {
      *pbDest = *pbSrc;
      pbSrc++;
      pbDest--;
      ulCount++;
    } /* endwhile */
  }
  else
  {
    if (ulBpp == 4)
    { // First ignore padding
      while (ulCount < ulBytesPerScan)
      {
        *pbDest = (*pbSrc >> 4) | (*pbSrc << 4);
        pbSrc++;
        pbDest--;
        ulCount++;
      } /* endwhile */
    }
    else if (ulBpp == 1)
    { // Ignore padding at this point
      // and needs to invert the byte !!! What is this for ???
      while (ulCount < ulBytesPerScan)
      {
        *pbDest = abMonoMirrorTable[*pbSrc];
        pbSrc++;
        pbDest--;
        ulCount++;
      } /* endwhile */
    }

    /*
    ** Now let us take care of padding. The following code should
    ** take care of both 4Bpp and 1Bpp.
    */
    ulShift = lWidthInPels % 8;
    if (ulShift)
    {
      /*
      ** Point to the first byte.
      */
      pbDest++;

      /*
      ** For 4Bpp ulShift and ulShiftCompliment both should be 4
      */
      ulShiftCompliment = 8 - ulShift;

      ulCount = 0;
      while (ulCount < ulBytesPerScan)
      {
        *pbDest = (*pbDest << ulShift) | (*(pbDest+1) >> ulShiftCompliment);
        pbDest++;
        ulCount++;
      }
    }
  }
}

/***************************************************************************
 *
 * FUNCTION NAME = convertBGR_to_RGB
 *
 * DESCRIPTION   = Convert our BGR format to RGB order for the plotter
 *
 * INPUT         = PBYTE pRGBDest,        - Pointer to the beginning of the
 *                                        destination scan line.
 *                 PBYTE pRGBSrc          - Pointer to the beginning of the
 *                                        source scan line.
 *                 ULONG ulBytesPerScan - Number of bytes per row
 *                 ULONG fulOddCaps     - Device Odd caps
 *                 BOOL  bMirrorScan    - TRUE = Invert the scan line
 *
 * OUTPUT        = converted scan line in pRGBDest
 *
 * RETURN-NORMAL = VOID
 * RETURN-ERROR  = VOID
 *
 **************************************************************************/

LOCAL VOID  convertBGR_to_RGB(RGB* pRGBDest, RGB* pRGBSrc,
                              ULONG ulBytesPerScan, ULONG fulOddCaps,
                              BOOL  bMirrorScan)
{
  ULONG ulCount = 0;

  if (bMirrorScan) // start at the end
    pRGBSrc += ulBytesPerScan / sizeof(RGB) -1;


  if (fulOddCaps & OD_NEEDS_GAMMA)
  {
    while (ulCount < ulBytesPerScan)
    {

      pRGBDest->bBlue  = abGamma2pt0[pRGBSrc->bRed];
      pRGBDest->bGreen = abGamma2pt0[pRGBSrc->bGreen];
      pRGBDest->bRed   = abGamma2pt0[pRGBSrc->bBlue];
      if (bMirrorScan) // if inverting the scan line decrement
        pRGBSrc--;
      else
        pRGBSrc++;

      pRGBDest++;
      ulCount += sizeof(RGB);
    } /* endwhile */
  }
  else
  {
    while (ulCount < ulBytesPerScan)
    {
      pRGBDest->bBlue  = pRGBSrc->bRed;
      pRGBDest->bGreen = pRGBSrc->bGreen;
      pRGBDest->bRed   = pRGBSrc->bBlue;
      if (bMirrorScan) // if inverting the scan line decrement
        pRGBSrc--;
      else
        pRGBSrc++;
      pRGBDest++;
      ulCount += sizeof(RGB);
    } /* endwhile */
  }
}
/******************************************************************************
** FUNCTION : image_scan
**
** PDDC          pddc
** PBYTE         pbScan : Pointer to the source bits.
** ULONG         ulBytesPerScan : Number of bytes per row (dword boundary)
** LONG          lScan : Number of lines in bitmap
** ULONG         fulOddCaps : Odd capabilities
** ULONG         ulbBpp : Bits per Pel
** LONG          lWidthinPels : Width in pels used to calc padding
** ULONG         ulMix : mix mode
** ULONG         ulBltFlags : bitmap flags
** ULONG         ulModeFlags : processing mode flags
**
**
** Outputs the commands to transfer data to device and also transfers the
** data.
** We are also handling the ROP_NOTSRCCOPY here.
** We have to invert the bits in the bitmap if the device is HP600 or it is any
** other device and the number of bits per pel is one.
** Reason : We are using the display driver for bitmaps. In display driver the
** color white is represented by '1' bits and color black is represented by '0'
** bits. On our device bit '1' is black and bit '0' is white. Actually we can
** approach this problem in two ways. One is the current implementation and the
** other is to use the configure image data to switch the RGB values for indeces
** '0' and '1'. But according to the manuals configure image data command doesn't
** work on HP600.
** We are using Mode3 Compression for HP PaintJet XL 300 as addaptive compression
** is not recommended for this device.
** We are using Addaptive Compression method for both HP600 and HP650C devices.
**
**
** Note : If you change the compression mode here, then you have to change the
**        command in set_HPRTL_Mode and set_PCL_mode as well.
**
**
**
** Created 06/23/93 : Kran
*******************************************************************************/
LOCAL VOID image_scan( PDDC pDDC, PBYTE pbScan, ULONG ulBytesPerScan,
                       LONG lScan, ULONG fulOddCaps, ULONG ulBpp,
                       LONG lWidthinPels, ULONG ulMix,
                       ULONG ulBltFlags, ULONG ulModeFlags,ULONG ulOrgMask)
{
  LONG     lNBytes   = ulBytesPerScan;
  PPDEVICE pPDevice  = pDDC->pPDevice;
  PDEVICESURFACE pDS = pDDC->pDeviceSurface;
  USHORT   usPlotter = pPDevice->Plotter;
  ULONG    fulGplCompressFlags = PlotterClass[usPlotter].fulGplCompressFlags;
  ULONG    fulDrvCompressFlags = PlotterClass[usPlotter].fulDrvCompressFlags;
  PUSHORT  pusDelta;
  PBYTE    pbCurrentScan;
  PBYTE    pbScanInvert = (PBYTE)NULL;
  PBYTE    pbLastRow;
  PBYTE    pbBuff = (PBYTE)NULL;
  PBYTE    pbTemp;
  RGB*     pRGBSource;
  RGB*     pRGBDest;
  LONG     lIndex;
  BOOL     bMirror = FALSE;

  #define BLOCKSIZE 32767

  // There is no pDS for engines before WARP and our DS is always BOTTOMTOP
  // for both pcl and hprtl for this engine.
  if (!pDS)
  {
    pbCurrentScan = pbScan + (ulBytesPerScan * (lScan - 1));
    lNBytes = -lNBytes;
  }
  else
  {
    if (fulOddCaps & OD_PCL)
    {
      if (ulModeFlags & DS_BOTTOMTOP)
      {
        pbCurrentScan = pbScan + (ulBytesPerScan * (lScan - 1));
        lNBytes = -lNBytes;
      }
      else
      {
        pbCurrentScan = pbScan;
      }
    }
    else // Hprtl case.
    {
      if (pPDevice->fsTransform & DXF_PORTRAIT)
      {
         if (!(ulBltFlags & BF_DIR_BOTTOM_TOP))
         {
           pbCurrentScan = pbScan + (ulBytesPerScan * (lScan - 1));
           lNBytes = -lNBytes;
         }
         else
         {
           pbCurrentScan = pbScan;
         } /* endif */
      } // End of hprtl portrait case
      else // Hprtl Landscape
      {
         if (pDDC->lEngineVersion > RASTER_ENGINE_22)
         {
            if (!(ulBltFlags & BF_DIR_RIGHT_LEFT))
            {
              pbCurrentScan = pbScan;
            }
            else
            {
              pbCurrentScan = pbScan + (ulBytesPerScan * (lScan - 1));
              lNBytes = -lNBytes;
            } /* endif */
         }
         else
         {
            if (!(ulBltFlags & BF_DIR_RIGHT_LEFT))
            {
              pbCurrentScan = pbScan + (ulBytesPerScan * (lScan - 1));
              lNBytes = -lNBytes;
            }
            else
            {
              pbCurrentScan = pbScan;
            } /* endif */
         }
      } // End of hprtl landscape
    } // end of hprtl case
  } // end of engine greater or equal to WARP

  if ( ((ulBpp == 1) && (ulMix == ROP_NOTSRCCOPY)) ||
       (!(fulOddCaps & OD_COLOR) && (ulBpp != 1)) )
  {
    LONG  lSaveScan = lScan;
    PBYTE pbTemp = pbCurrentScan;
    while (--lSaveScan >= 0)
    {
      for (lIndex = 0; lIndex < ulBytesPerScan; lIndex++)
      {
         *(pbCurrentScan+lIndex) ^= 0xFF;
      }
      pbCurrentScan += lNBytes;
    }
    pbCurrentScan = pbTemp;
  }

  if (fulOddCaps & (OD_PCL | OD_HPRTL))
  {
    // pbLastRow is set with zeros in GplMemoryAlloc.
    pbLastRow = GplMemoryAlloc(pDDC->pPDevice->hmcbHeap, ulBytesPerScan);

    /*
    ** We need a buffer to convert RGB2 data (BGR) to (RGB) order
    */
    if (ulBpp == 24)
    {
      pbBuff = GplMemoryAlloc(pDDC->pPDevice->hmcbHeap, ulBytesPerScan);
    }
    else
    {
      /*
      ** If we need to invert the bitmap  - Note 24bit will do the invert
      ** without an extra invert buffer
      */
      if (bMirror)
      {
        pbScanInvert = GplMemoryAlloc(pDDC->pPDevice->hmcbHeap, ulBytesPerScan);
      }
    }

    /*
    **  Note that pDelta 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.
    */
    pusDelta = (PUSHORT)GplMemoryAlloc(pDDC->pPDevice->hmcbHeap,
                          ((ulBytesPerScan + 1) * sizeof(USHORT)) + 4);


    if (fulDrvCompressFlags & DRV_COMPRESS_ADAPTIVE)
    // we can use this for both 600 and 650c
    {
      PBYTE   pbCurrentBlock;
      PBYTE   pbOutBlockPtr;
      ULONG   ulBlockSize = 0;
      /*
      ** CompressionMethod   : \033*b5M  (Adaptive compression method. )
      */
      output_bytes(pDDC,"\033*b5M");

      pbOutBlockPtr  = GplMemoryAlloc(pDDC->pPDevice->hmcbHeap, BLOCKSIZE);

      pbCurrentBlock = pbOutBlockPtr;

      while (--lScan >= 0)
      {
        /*
        ** check for an abort since this takes a long time
        */
        if (!pPDevice->bEnableOutput)
          break;
        /*
        ** if this is an 24 bit per pel bitmap
        ** We need a buffer to convert RGB2 data (BGR) to (RGB) order
        */
        if (ulBpp == 24)
        {
          pRGBSource = (RGB*)pbCurrentScan;
          pRGBDest   = (RGB*)pbBuff;

          convertBGR_to_RGB(pRGBDest, pRGBSource,
                            ulBytesPerScan, fulOddCaps,
                            bMirror);
          pbTemp = pbBuff;
        }
        else
        {
          pbTemp = pbCurrentScan;
          /*
          ** if we have to invert the scan line
          */
          if (bMirror)
          {
            mirror_scan_line(pbScanInvert, pbTemp, ulBpp, ulBytesPerScan,
                             lWidthinPels);
            pbTemp = pbScanInvert;
          }
        }

        // Seed row is zeroed when raster mode is entered.
        ulBlockSize += compress_adaptive(pbTemp,
                                         ulBytesPerScan, pbLastRow,
                                         pbCurrentBlock, BLOCKSIZE-ulBlockSize,
                                         fulGplCompressFlags,
                                         pusDelta);

        pbCurrentBlock = pbOutBlockPtr + ulBlockSize;

        if ((ulBlockSize + ulBytesPerScan + 6) > BLOCKSIZE)
        {
          output_bytes(pDDC,"\033*b");
          output_number(pDDC, ulBlockSize);
          output_bytes(pDDC,"W");
          bin_output_bytes(pDDC,pbOutBlockPtr,ulBlockSize);
          setmem ((PBYTE)pbLastRow, 0, ulBytesPerScan);
          ulBlockSize = 0;
          pbCurrentBlock = pbOutBlockPtr;
        }
        pbCurrentScan += lNBytes;

      }
      if (ulBlockSize)
      {
        output_bytes(pDDC,"\033*b");
        output_number(pDDC, ulBlockSize);
        output_bytes(pDDC,"W");
        bin_output_bytes(pDDC,pbOutBlockPtr,ulBlockSize);
      }
      GplMemoryFree (pbOutBlockPtr);
    }
    else
    {
      PBYTE   pbCompressedRow;
      INT     iCurrentCompressMode = -1; //init to not set
      ULONG   ulMaxCompress = ulBytesPerScan * 2;

      pbCompressedRow = GplMemoryAlloc(pDDC->pPDevice->hmcbHeap, ulMaxCompress);

      while (--lScan >= 0)
      {
        /*
        ** check for an abort since this takes a long time
        */
        if (!pPDevice->bEnableOutput)
          break;
        /*
        ** if this is an 24 bit per pel bitmap
        ** We need a buffer to convert RGB2 data (BGR) to (RGB) order
        */
        if (ulBpp == 24)
        {
          pRGBSource = (RGB*)pbCurrentScan;
          pRGBDest   = (RGB*)pbBuff;
          convertBGR_to_RGB(pRGBDest, pRGBSource,
                            ulBytesPerScan, fulOddCaps,
                            bMirror);
          pbTemp     = pbBuff;
        }
        else
        {
          pbTemp = pbCurrentScan;
          /*
          ** if we have to invert the scan line
          */
          if (bMirror)
          {
            mirror_scan_line(pbScanInvert, pbTemp, ulBpp, ulBytesPerScan,
                             lWidthinPels);
            pbTemp = pbScanInvert;
          }
        }
        // Seed row is zeroed when raster mode is entered.

        if (ulOrgMask)
          *pbTemp &= (BYTE)ulOrgMask;

        compress_any_supported_mode(pDDC, pbTemp, ulBytesPerScan,
                                    pbLastRow,
                                    pbCompressedRow,
                                    ulMaxCompress,
                                    &iCurrentCompressMode,
                                    fulGplCompressFlags,
                                    pusDelta);

        pbCurrentScan += lNBytes;
      }
      GplMemoryFree (pbCompressedRow);

    }

    GplMemoryFree (pusDelta);
    GplMemoryFree (pbLastRow);
    if (pbScanInvert)
    {
      GplMemoryFree (pbScanInvert);
    }
    if (pbBuff)
    {
      GplMemoryFree (pbBuff);
    }
  }
  return;
}

/***************************************************************************
** FUNCTION : set_RFIndex
**
** PDDC     pDDC
** ULONG    RFindex : the current index of the user pattern defined
** ULONG    width : width of the rectangle
** ULONG    height : height of the rectangle
**
** Sets the Raster Fill index and the height and width of the rectangle
** Called from fill_pattern_use_device
**
** Created : 09/27/93 Kran
***************************************************************************/
LOCAL BOOL set_RFIndex(PDDC pDDC,ULONG RFindex,ULONG width, ULONG height)
{

  /*
  ** ReSet RFindex, if RFindex is > 8. We can not support more than 8
  ** user defined patterns.
  */

  if (RFindex > 8)
  {
    RFindex = pDDC->pPDevice->RFindex = 2;
  }

  output_bytes(pDDC,"RF");
  output_number(pDDC,RFindex);
  output_comma(pDDC);
  output_number(pDDC,width);
  output_comma(pDDC);
  output_number(pDDC,height);
  return(TRUE);

}


LOCAL USHORT locate_RFpen(PDDC pDDC, ULONG ulRGBColor)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  USHORT usPen;
  USHORT i;

  usPen = pPDevice->CurrentPen;        /* default to current pen         */


  /*
  ** look through current defined pens for our color
  */
  for (i = 0;i < pPDevice->usPensInPalette; i++)
  {
    if (pPDevice->paPaletteEntry[i].ulPenRGBColor == ulRGBColor)
    {
      /*
      ** We must mark the pen permanent to avoid having the
      ** pen redefined befor we do the raster fill
      */
      pPDevice->paPaletteEntry[i].fulPenFlags = PEN_PERMANENT;
      break;
    }
  }
  /*
  ** If the index is beyond the array
  ** we did not find a pen with the same RGB color.
  ** So, define a new one.
  */
  if (i == pPDevice->usPensInPalette)
  {
    /*
    ** Look for a pen that can be redefined starting with the
    ** least recently used
    */
    for (i = pPDevice->usLastPenDefined+1 ;i < pPDevice->usPensInPalette; i++)
    {
      if (!(pPDevice->paPaletteEntry[i].fulPenFlags & PEN_PERMANENT))
        break;
    }
    /*
    ** If the index is beyond the array
    ** we did not find and redefinable pen from the last position
    ** to the max in the array So, look at the beginning of the array.
    */
    if (i == pPDevice->usPensInPalette)
    {
      for (i = 1 ;i < pPDevice->usPensInPalette; i++)
      {
        if (!(pPDevice->paPaletteEntry[i].fulPenFlags & PEN_PERMANENT))
          break;
      }
    }
    /*
    ** Make sure we do not go above the max number of
    ** HPGL2 pens allowed for this class of device.
    ** If we are at the max we will keep redefining
    ** the last pen with the current color.
    **
    ** This can be replaced with a Least recently
    ** used algorithm in the future.
    */
    i = MIN(i, (PlotterClass[pPDevice->Plotter].usMaxHPGL2Pens - 1));
    set_pen(pDDC, i, ulRGBColor, PEN_PERMANENT);
  }

  usPen = i;

  return (usPen);
}
/***************************************************************************
** FUNCTION : rotate_8bpp_90
**            Rotates the byte matrix in pbSrc by 90 degrees and stores in
**            pbDest. This function can be called to rotate a bitmap with
**            8 bpp format by 90degrees.
**
** INPUT :    PBYTE    pbSrc  Pointer to the source bytes.
**            PBYTE    pbDest Pointer to the destination where the rotated
**                            bytes will be put.
**            ULONG    ulBytesPerLine  Number of bytes per line in source.
**            ULONG    ulScans         Number of Scan lines in Source.
**            ULONG    ulSrcPels       Currently not used.
** Assumes the pbDest points to a memory that holds ulScans * ulBytesPerLine
** number of bytes. Assumes Source is BYTE alligned.
**
** Created 09/22/94  Kran
****************************************************************************/

VOID rotate_8bpp_90(PBYTE pbSrc,PBYTE pbDest,
                          ULONG ulBytesPerLine,ULONG ulScans,ULONG ulSrcPels)
{
  LONG  lyScan = ulScans;
  LONG  lxScan = 0L;
  PBYTE pbTemp;

  while (--lyScan >= 0)
  {
    pbTemp = pbSrc + lyScan * ulBytesPerLine;
    lxScan = 0L;
    while (lxScan < ulBytesPerLine)
    {
      pbDest[ulScans * lxScan] = *(pbTemp + lxScan);
      lxScan++;
    }
    pbDest++;
  }
}
/***************************************************************************
** FUNCTION : rotate_4bpp_90
**            Rotates the 4BIT matrix in pbSrc by 90 degrees and stores in
**            pbDest. This function can be called to rotate a bitmap with
**            4 bpp format by 90degrees.
**
** INPUT :    PBYTE    pbSrc  Pointer to the source bytes.
**            PBYTE    pbDest Pointer to the destination where the rotated
**                            bytes will be put.
**            ULONG    ulBytesPerLine  Number of bytes per line in source.
**            ULONG    ulScans         Number of Scan lines in Source.
**            ULONG    ulSrcPels       Number of pels per Scan line.
** Assumes the pbDest points to a memory that holds ulScans * ulBytesPerLine
** number of bytes. Assumes Source is BYTE alligned.
**
** Created 09/22/94  Kran
****************************************************************************/
VOID rotate_4bpp_90(PBYTE pbSrc,PBYTE pbDest,
                          ULONG ulBytesPerLine,ULONG ulScans,ULONG ulSrcPels)
{
  LONG  lyScan = ulScans;
  LONG  lxScan = 0L;
  ULONG ulDestBytesPerScan = (lyScan + 1) / 2;
  LONG  lOddScans = lyScan % 2;
  PBYTE pbTemp;
  BYTE  bCurrent;
  BYTE  bNext;
  BYTE  bTemp;


  while (--lyScan > 0)
  {
    /*
    ** Go to the last row
    */
    pbTemp = pbSrc + lyScan * ulBytesPerLine;
    lxScan = 0L;

    while (lxScan < ulBytesPerLine)
    {
      /*
      ** Get the byte in the current row
      */
      bCurrent  =  bTemp = *pbTemp;

      /*
      ** Get the corresponding byte from the row above the current row.
      ** Remember we started from the last row.
      */
      bNext     = *(pbTemp - ulBytesPerLine);

      /*
      ** Exchange the nibles. if bCurrent = AB and bNext = CD then
      ** after exchange bCurrent = AC and bNext = BD
      */
      bCurrent  = (bCurrent & 0xF0) | (bNext >> 4);
      bNext     = (bNext & 0x0F) | (bTemp << 4);

      /*
      ** Put the bytes in pbDest.
      */
      pbDest[lxScan * ulDestBytesPerScan] = bCurrent;
      pbDest[(lxScan + 1) * ulDestBytesPerScan] = bNext;
      lxScan++;
    }

    /*
    ** We are Processing two rows at a time in source. So reduce lyScan
    ** here once. We do the same again at the begining of the loop.
    */
    lyScan--;

    /*
    ** Point to the next byte in the first row of pbDest. We should never
    ** cross the first row of the pbDest. Which means pbDest should not be
    ** greater than pbDest+ulDestBytesPerScan. When pbDest is
    ** pbDest+ulDestBytesPerScan+1 we should get out of the loop.
    */
    pbDest++;
  }
  /*
  ** Check if we have odd number of scans. If so we left the last scan,
  ** Which is the first scan in source, since we started from the bottom of
  ** the matrix. So just copy the bytes to our pbDest. At this point pbDest
  ** Should be pointing right where we want.
  */
  if (lOddScans)
  {
    lxScan = 0L;
    pbTemp = pbSrc;
    while (lxScan < ulBytesPerLine)
    {
      pbDest[lxScan * ulDestBytesPerScan] = *pbTemp;
      pbTemp++;
    }
  }
}
/***************************************************************************
** FUNCTION : rotate_bmap_90
**            This function calls the appropriate function to rotate a bitmap
**            by 90degrees depending on the number of bits per pel.
**
** INPUT :    PBYTE    pbSrc  Pointer to the source bytes.
**            PBYTE    pbDest Pointer to the destination where the rotated
**                            bytes will be put.
**            ULONG    ulBytesPerLine  Number of bytes per line in source.
**            ULONG    ulScans         Number of Scan lines in Source.
**            ULONG    ulBitCount      Number of bits per pel.
**            ULONG    ulSrcPels       Number of pels per Scan line.
**
** Created 10/04/94  Kran
****************************************************************************/
VOID rotate_bmap_90(PBYTE pbSrc, PBYTE pbDest,
                    ULONG ulBytesPerLine, ULONG ulScans,
                    ULONG ulBitCount, ULONG ulSrcPels)
{
   switch (ulBitCount)
   {
   case 4:  rotate_4bpp_90(pbSrc,pbDest,ulBytesPerLine,ulScans,ulSrcPels);
            break;
   case 8:
   default: rotate_8bpp_90(pbSrc,pbDest,ulBytesPerLine,ulScans,ulSrcPels);
            break;
   }
   return;
}
/***************************************************************************
** FUNCTION : fill_pattern_use_device
**            This function handles both HPGL2 and PCL to fill a rectangle
**            with patterns. Called from BitBlt for ROP_PATCOPY with user
**            defined Pattern.
**            Also called from setup_raster_fill_index to down load the pattern
**            on to the device. If the call is from setup_raster_fill_index
**            then the prclDst parameter is NULL.
**
** HDC                hdcDst
** PDDC               pDDC
** PBITMAPINFOHEADER  pbmi
** PRECTL             prclDst
** HBM                hbm
**
** Created 09/27/93  Kran
****************************************************************************/

LOCAL BOOL fill_pattern_use_device(HDC hdcDst,PDDC pDDC,PBITMAPINFOHEADER pbmi,
                                   PRECTL prclDst, HBITMAP hbm,
                                   PBITBLTATTRS pAttrs, ULONG Options)
{
  PPDEVICE     pPDevice   = pDDC->pPDevice;
  PBYTE        pBits      = 0;
  PBITMAPINFO  pbmpinfo   = 0;
  PBYTE        pbRotScan  = 0;
  PBYTE        pbPensSave = 0;
  PBYTE        pbPens     = 0;       // K2pen
  PBYTE        pbSrc;
  ULONG        ulLines;
  ULONG        nColors;
  ULONG        ulSrcPels;
  ULONG        ulPelsWritten;
  LONG         lPels;
  ULONG        ulBitCount;
  RGB          rgbColor;
  ULONG        ulrgbColor;
  LONG         Pen;
  POINTL       pPtl;
  ULONG        fulOddCaps = PlotterClass[pPDevice->Plotter].fsOdd;
  ULONG        RFindex;
  LONG         lScan;
  ULONG        ulSrcBytes;
  USHORT       TempColf;     //
  LONG         penScan;
  BOOL         flRotate = FALSE;


  DBPRINTF(("Entered fill_pattern_use_device \n"));

  /*
  ** If it is OD_QUEUED and datatype is STD then let us just getout.
  */
  if(pDDC->usDCType == OD_QUEUED && pPDevice->DataType == PM_Q_STD)
    return(TRUE);

  RFindex = ++pPDevice->RFindex;

  if (pbmi->cBitCount != 24)
    nColors = 2 << (pbmi->cBitCount - 1);
  else
    nColors = 0;

  pbmpinfo = (PBITMAPINFO)GplMemoryAlloc(pDDC->pPDevice->hmcbHeap,
                                         sizeof(BITMAPINFO)
                                         + (nColors * sizeof(LONG)));

  if (!pbmpinfo)
    return FALSE;

  pbmpinfo->cbFix     = sizeof(BITMAPINFOHEADER);
  pbmpinfo->cx        = pbmi->cx;
  pbmpinfo->cy        = pbmi->cy;
  pbmpinfo->cBitCount = pbmi->cBitCount;
  pbmpinfo->cPlanes   = pbmi->cPlanes;

  ulBitCount = pbmi->cBitCount;
  DBPRINTF (("ulBitCount = %d \n",ulBitCount));
  ulSrcBytes = ((pbmpinfo->cx * ulBitCount + 31) >> 5) << 2;
  ulSrcPels  = pbmpinfo->cx;
  lScan      = pbmpinfo->cy;

  pBits = GplMemoryAlloc(pPDevice->hmcbHeap,lScan * ulSrcBytes);

  if (!pBits)
  {
    GplMemoryFree ((PVOID)pbmpinfo);
    return(FALSE);
  }

  pbSrc = pBits;


  ulLines = GreGetBitmapBits(hdcDst,hbm,0L,pbmi->cy,pBits,pbmpinfo);

  if(ulBitCount == 1)
  {
    ULONG  ulFrgColor;
    ULONG  ulBackColor;

    ulFrgColor  = pDDC->DCState.abnd.lColor;
    ulBackColor = pDDC->DCState.abnd.lBackColor;

    if(pAttrs && (Options & BLTMODE_ATTRS_PRES))
    {
      switch (pAttrs->cSize)
      {
        case 12: ulBackColor = pAttrs->lBackColor; //Fall through
        case  8: ulFrgColor  = pAttrs->lColor;
                 break;
        default: break;
      }
    }

    ulFrgColor  = convert_color(pDDC,ulFrgColor);
    ulBackColor = convert_color(pDDC,ulBackColor);

    pbmpinfo->argbColor[0].bBlue  = (BYTE)ulBackColor;
    pbmpinfo->argbColor[0].bGreen = (BYTE)(ulBackColor >> 8);
    pbmpinfo->argbColor[0].bRed   = (BYTE)(ulBackColor >> 16);

    pbmpinfo->argbColor[1].bBlue  = (BYTE)ulFrgColor;
    pbmpinfo->argbColor[1].bGreen = (BYTE)(ulFrgColor >> 8);
    pbmpinfo->argbColor[1].bRed   = (BYTE)(ulFrgColor >> 16);
  }

  penScan    = ulSrcPels * lScan;
  pbPens     = GplMemoryAlloc(pPDevice->hmcbHeap,penScan+1);
  pbPensSave = pbPens;

  if (pPDevice->fsTransform & DXF_PORTRAIT)
    flRotate = TRUE;

  if (flRotate)
    pbRotScan = GplMemoryAlloc(pPDevice->hmcbHeap,penScan);

  /*
  **  Save color format.
  */
  TempColf = pDDC->DCState.usColorFormat;
  pDDC->DCState.usColorFormat = LCOLF_RGB;


  while (--lScan >= 0)
  {
    ulPelsWritten = 0;
    /*
    ** point to next row
    */
    pbSrc = pBits + lScan * ulSrcBytes;

    /*
    ** loop through all of the bytes in each scan line.
    */
    while (ulPelsWritten != ulSrcPels)
    {
      /*
      ** Find out what the next rgb color is and how many consecutive
      ** pels are set to that color.
      */
      getnextcolor(pbSrc,(PBYTE)&rgbColor,(ulSrcPels - ulPelsWritten),
                                     &lPels,ulPelsWritten,ulBitCount,pDDC);
      rgbColor   = pbmpinfo->argbColor[rgbColor.bBlue];
      ulrgbColor = (ULONG) rgbColor.bRed;
      ulrgbColor = (ulrgbColor << 8) | rgbColor.bGreen;

      ulrgbColor = (ulrgbColor << 8) | rgbColor.bBlue;
      DBPRINTF (("ulrgbColor = %x \n",ulrgbColor));

      /*
      ** So now we have "lPels" = number of pels with same color
      ** "rgbColor"  set in pBits.
      */
      ulPelsWritten += lPels;


      Pen = locate_RFpen(pDDC, ulrgbColor);
      DBPRINTF (("Pen : %d \n",Pen));
      //DBPRINTF (("lPels : %d \n",lPels));
      while (lPels--)
      {
        *pbPens = (BYTE) Pen;
         pbPens++;
      }

    }  // while we are not done with the line.

  }   // while we still have lines.
  /*
  ** put color format back
  */
  pDDC->DCState.usColorFormat = TempColf;

  /*
  ** Check if we have to rotate the pattern bitmap for PORTRAIT.
  ** At this point we have the pens in pbPensSave.
  */
  if (flRotate)
  {
    LONG lIndex = 0L;
    set_RFIndex(pDDC,RFindex,pbmi->cy,ulSrcPels);

    /*
    ** Rotate the pen byte matrix by 90 degrees when in portrait mode.
    */
    rotate_bmap_90(pbPensSave,pbRotScan,ulSrcPels,(ULONG)pbmpinfo->cy,8L,0L);
    //rotate_8bpp_90(pbPensSave,pbRotScan,ulSrcPels,(ULONG)pbmpinfo->cy,0L);

    while (lIndex < penScan)
    {
      output_comma(pDDC);
      output_number(pDDC,(ULONG)pbRotScan[lIndex++]);
    }
  }
  else
  {
    LONG lIndex = 0L;
    set_RFIndex(pDDC,RFindex,ulSrcPels,pbmi->cy);
    while (lIndex < penScan)
    {
      output_comma(pDDC);
      output_number(pDDC,(ULONG)pbPensSave[lIndex++]);
    }
    output_bytes(pDDC,";");
  }

  if (prclDst)
  {
    select_fill_type(pDDC,PATSYM_USERDEFINED,NULL,NULL);
    pPtl.x = prclDst->xLeft;
    pPtl.y = prclDst->yBottom;
    move_pen(pDDC,&pPtl,TRUE);

    output_bytes(pDDC,"RR");
    pPtl.x = prclDst->xRight - pPtl.x;
    pPtl.y = prclDst->yTop - pPtl.y;
    construct_point(pDDC,&pPtl,TRUE);
  }

  GplMemoryFree (pbPensSave);
  GplMemoryFree (pBits);
  GplMemoryFree ((PVOID)pbmpinfo);
  if (flRotate)
    GplMemoryFree(pbRotScan);
  return(TRUE);
}
/***************************************************************************
** FUNCTION : download_pattern
**
** Created 09/20/94  Kran
****************************************************************************/

LOCAL BOOL download_pattern(HDC hdcDst,PDDC pDDC,
                            PRGB2 prgb2PatColors, PBMAPINFO pPatBmapInfo)
{
  PPDEVICE     pPDevice = pDDC->pPDevice;
  PBYTE        pbSrc;
  ULONG        ulSrcPels;
  ULONG        ulPelsWritten;
  LONG         lPels;
  ULONG        ulBitCount;
  RGB          rgbColor;
  ULONG        ulrgbColor;
  LONG         Pen;
  ULONG        RFindex;
  LONG         lScan;
  ULONG        ulSrcBytes;
  USHORT       TempColf;
  PBYTE        pbPens;       // K2pen
  LONG         penScan;
  PBYTE        pbPensSave;
  BOOL         flRotate = FALSE;
  PBYTE        pbRotScan;
  LONG         lIndex=0L;
  LONG         lNBytes = 0L;

  DBPRINTF(("Entered download_pattern \n"));

  /*
  ** If it is OD_QUEUED and datatype is STD then let us just getout.
  */
  if(pDDC->usDCType == OD_QUEUED && pPDevice->DataType == PM_Q_STD)
    return(TRUE);

  RFindex = ++pPDevice->RFindex;

  /*
  ** Initialize some of the vars we need.
  */
  lScan = pPatBmapInfo->ulHeight;
  ulSrcPels = pPatBmapInfo->ulWidth;
  lNBytes = ulSrcBytes = pPatBmapInfo->ulBytesPerLine;
  ulBitCount = pPatBmapInfo->ulBpp;

  penScan = pPatBmapInfo->ulWidth * pPatBmapInfo->ulHeight;
  pbPens = GplMemoryAlloc(pPDevice->hmcbHeap,penScan+1);

  pbPensSave = pbPens;

  /*
  **  Save color format. This is a hack
  */
  TempColf = pDDC->DCState.usColorFormat;
  pDDC->DCState.usColorFormat = LCOLF_DEFAULT;

  if (pPDevice->fsTransform & DXF_PORTRAIT)
    flRotate = TRUE;

  if (flRotate)
    pbRotScan = GplMemoryAlloc(pPDevice->hmcbHeap,penScan);

  if (pDDC->pDeviceSurface->ulDSFlgs & DS_BOTTOMTOP)
  {
     pbSrc = (pPatBmapInfo->pBits + ((lScan - 1) * ulSrcBytes));
     lNBytes = -lNBytes;
  }
  else
     pbSrc = pPatBmapInfo->pBits;

  while (lIndex < lScan)
  {
    ulPelsWritten = 0;

    /*
    ** point to next row
    */
    //pbSrc = pPatBmapInfo->pBits + lIndex * ulSrcBytes;

    /*
    ** loop through all of the bytes in each scan line.
    */
    while (ulPelsWritten != ulSrcPels)
    {
      /*
      ** Find out what the next rgb color is and how many consecutive
      ** pels are set to that color.
      */
      getnextcolor(pbSrc,(PBYTE)&rgbColor,(ulSrcPels - ulPelsWritten),
                                     &lPels,ulPelsWritten,ulBitCount,pDDC);
      //ulrgbColor = ((PULONG)prgb2PatColors)[rgbColor.bBlue];
      ulrgbColor = (ULONG) prgb2PatColors[rgbColor.bBlue].bRed;
      ulrgbColor = (ulrgbColor << 8) | prgb2PatColors[rgbColor.bBlue].bGreen;
      ulrgbColor = (ulrgbColor << 8) | prgb2PatColors[rgbColor.bBlue].bBlue;

      DBPRINTF (("ulrgbColor = %x \n",ulrgbColor));

      /*
      ** So now we have "lPels" = number of pels with same color
      ** "rgbColor"  set in pBits.
      */
      ulPelsWritten += lPels;


      Pen = locate_RFpen(pDDC, ulrgbColor);
      DBPRINTF (("Pen : %d \n",Pen));
      while (lPels--)
      {
        *pbPens = (BYTE) Pen;
         pbPens++;
      }

    }  // while we are not done with the line.

    /*
    ** point to next row
    */
    pbSrc += lNBytes;
    lIndex++;

  }   // while we still have lines.
  pDDC->DCState.usColorFormat = TempColf;

  if (flRotate)
  {
    LONG  lIndex = 0L;

    set_RFIndex(pDDC,RFindex,pPatBmapInfo->ulHeight,ulSrcPels);

    /*
    ** Rotate the pen byte matrix by 90 degrees when in portrait mode.
    */
    rotate_bmap_90(pbPensSave,pbRotScan,ulSrcPels,pPatBmapInfo->ulHeight,8L,0L);
    //rotate_8bpp_90(pbPensSave,pbRotScan,ulSrcPels,pPatBmapInfo->ulHeight,0L);

    while (lIndex < penScan)
    {
      output_comma(pDDC);
      output_number(pDDC,(ULONG)pbRotScan[lIndex++]);
    }
  }
  else
  {
    LONG lIndex = 0L;
    set_RFIndex(pDDC,RFindex,ulSrcPels,pPatBmapInfo->ulHeight);

    while (lIndex < penScan)
    {
      output_comma(pDDC);
      output_number(pDDC,(ULONG)pbPensSave[lIndex++]);
    }
  }

  if (GplMemoryFree (pbPensSave))
     pbPensSave = NULL;

  output_bytes(pDDC,";");

  if (flRotate && GplMemoryFree(pbRotScan))
     pbRotScan = NULL;

  return(TRUE);
}


/***************************************************************************
** FUNCTION : fill_pattern
**
** PDDC        pDDC
** PBYTE       pBits
** PBITMAPINF  pbmi
** ULONG       GreyBytes
** ULONG       lScan
** RECTL       rclDst
**
** Description : Called from bitblt for ROP_PATCOPY.
**               fills a rectangle specified by the rclDst with the pattern
**               bits in pBits.
**               This function is called only when the device can not handle
**               the pattern specification with RF instruction. See comments
**               in bitblt ROP_PATCOPY.
**
**
** Created  09/23/93 : Kran
****************************************************************************/

LOCAL VOID  fill_pattern(PDDC  pDDC,PBYTE pBits, PBITMAPINFO pbmi,
                         ULONG GreyBytes, LONG lScan,RECTL rclDst)
{
  PPDEVICE pPDevice  = pDDC->pPDevice;
  USHORT   usPlotter = pPDevice->Plotter;
  ULONG    fulOddCaps = PlotterClass[usPlotter].fsOdd;
  ULONG    fulGplCompressFlags = PlotterClass[usPlotter].fulGplCompressFlags;
  ULONG    fulDrvCompressFlags = PlotterClass[usPlotter].fulDrvCompressFlags;
  LONG    lNBytes;
  ULONG   nPelsInPatRow;
  ULONG   nRowsInPat;
  LONG    lxSteps;
  LONG    lySteps;
  LONG    lxSremains;
  LONG    lySremains;
  PBYTE   pLineBuffer;
  ULONG   nPelRemains;
  PBYTE   pStartBits;
  ULONG   ulSaveScan;
  ULONG   DstWidth;
  ULONG   DstHeight;
  ULONG   ulShift;
  ULONG   ulShiftCompliment;
  LONG    ly;
  LONG    i,j;
  PBYTE   pbTemp;
  ULONG   ulBytesPerScan;
  PBYTE   pbLastRow;
  PBYTE   pbXstepPatBlock;
  PBYTE   pbPatBlock;
  PBYTE   pbBuff = NULL;
  PUSHORT pusDelta;
  RGB*    pRGBSource;
  RGB*    pRGBDest;
  LONG    lSrcBytes = (pbmi->cx * pbmi->cBitCount +7) >> 3;

  nPelsInPatRow = pbmi->cx;
  nPelRemains   = nPelsInPatRow % 8;
  nRowsInPat    = pbmi->cy;
  if ( (PlotterClass[usPlotter].fsOdd & OD_PCL) ||
       (pPDevice->fsTransform & DXF_PORTRAIT) )
  {
    DstWidth  = rclDst.xRight - rclDst.xLeft;
    DstHeight = rclDst.yTop   - rclDst.yBottom;
  }
  else
  {
    DstHeight = rclDst.xRight - rclDst.xLeft;
    DstWidth  = rclDst.yTop   - rclDst.yBottom;
  }

  lNBytes    = (DstWidth + 7) / 8;
  lxSteps    = (DstWidth + nPelsInPatRow - 1) / nPelsInPatRow;
  lySteps    = (DstHeight + nRowsInPat - 1) / nRowsInPat;
  lxSremains = DstWidth % nPelsInPatRow;
  lySremains = DstHeight % nRowsInPat;

  pStartBits = pBits;      // just save couple of things we may need later.
  ulSaveScan = lScan;

  /*
  ** Lets xor the bytes right here instead of xoring every time we write
  ** the pattern
  */
  if (!(PlotterClass[usPlotter].fsOdd & OD_COLOR))
  {
    while (--lScan >= 0)
    {
      for (i = 0;i < GreyBytes ;i++ )
        *(pBits+i) ^= 0xFF;
    }
  }

  /*
  **  To shift the bytes to take care of the padding in the last byte
  */
  ulShift = nPelRemains;
  ulShiftCompliment = 8 - ulShift;

  ulBytesPerScan = lxSteps * lSrcBytes;
  lScan  = ulSaveScan;


  // Compression support!
  // pbLastRow is set with zeros in GplMemoryAlloc.
  pbLastRow = GplMemoryAlloc(pPDevice->hmcbHeap, lNBytes);

  /*
  ** We need a buffer to convert RGB2 data (BGR) to (RGB) order
  */
  if (pbmi->cBitCount == 24)
  {
    pbBuff = GplMemoryAlloc(pPDevice->hmcbHeap, lNBytes);
  }

  /*
  **  Note that pusDelta must have a length equal to the length + 1  of
  **  Row Length to hold the pusDelta  output.  There is no check on the
  **  the limit.
  */
  pusDelta = (PUSHORT)GplMemoryAlloc(pPDevice->hmcbHeap,
                        (lNBytes + 1) * sizeof(USHORT));


  /*
  ** Allocate memory to hold lxSteps pattern Blocks and save it in pPatBlock
  ** as well.
  */
  pbXstepPatBlock = GplMemoryAlloc(pPDevice->hmcbHeap, ulBytesPerScan * lScan);
  pbPatBlock = pbXstepPatBlock;

  /*
  ** Let us just copy the whole pattern into a buffer that holds lxSteps
  ** number of patterns. Then we go through the painfull process of shifting
  ** and then compress the raster data.
  */

  while (lScan--)
  {
    for (i = 0;i < lxSteps;i++)
    {
      for (j = 0;j < lSrcBytes;j++ )
        *pbXstepPatBlock++ = pBits[j];
    }
    pBits += GreyBytes;
  }
  pBits = pStartBits;

  /*
  ** Bring back our pbXstepPatBlock to the begining of our Block and lScan
  ** to the original number
  */
  pbXstepPatBlock = pbPatBlock;
  lScan = ulSaveScan;

  /*
  ** Now we do the shifting. We do the shifting for all the lines in
  ** the pattern block if nPelRemains is true.
  */

  /*
  ** Go to the last block and shift each block backwords if
  ** we have padding in last byte of a row in pattern block.
  */
  if (nPelRemains)
  {
    LONG  nBlocks;
    LONG  ShiftBytes = 0L;

    while (lScan--)    // While we still have the lines in pattern
    {
      nBlocks = lxSteps;
      while (--nBlocks) // While we still have blocks to shift
      {
        pLineBuffer = pbXstepPatBlock + (nBlocks * lSrcBytes) - 1;
        ShiftBytes  = ShiftBytes + lSrcBytes;

        /*
        ** This byte is a special case
        */
        *pLineBuffer |= *(pLineBuffer + 1) >> ulShift;
        pLineBuffer++;

        for (i = 0;i < ShiftBytes;i++)
        {
          *pLineBuffer = (*pLineBuffer << ulShiftCompliment)  |
                                         (*(pLineBuffer + 1) >> ulShift);
           pLineBuffer++;
        }
      } // end of while nBlocks
      pbXstepPatBlock = pbXstepPatBlock + ulBytesPerScan;
    } // end of while lScan
    /*
    ** Get back our lScan and pbXstepPatBlock
    */
    pbXstepPatBlock = pbPatBlock;
    lScan = ulSaveScan;
  } // end of if nPelRemains

  /*
  ** At this point we have the lxSteps patterns coppied and shifted to
  ** currect positions in pbXstepPatBlock.

  /*
  ** Now we do the compression required and send the data to the device.
  */


  if (fulDrvCompressFlags & DRV_COMPRESS_ADAPTIVE)
     // we can use this for both 600 and 650c
  {
     PBYTE   pbCurrentBlock;
     PBYTE   pbOutBlockPtr;
     ULONG   ulBlockSize = 0;

     pLineBuffer = pbXstepPatBlock;

     /*
     ** CompressionMethod   : \033*b5M  (Adaptive compression method. )
     */
     output_bytes(pDDC,"\033*b5M");

     pbOutBlockPtr  = GplMemoryAlloc(pPDevice->hmcbHeap, BLOCKSIZE);

     pbCurrentBlock = pbOutBlockPtr;


     for (ly = 0;ly < lySteps;ly++) // as many pattern blocks
                                    // as needed in y direction
     {
        while (lScan--)
        {

          /*
          ** if this is an 24 bit per pel bitmap
          ** We need a buffer to convert RGB2 data (BGR) to (RGB) order
          */
          if (pbmi->cBitCount == 24)
          {
            pRGBSource = (RGB*)pLineBuffer;
            pRGBDest   = (RGB*)pbBuff;

            convertBGR_to_RGB(pRGBDest, pRGBSource,
                              lNBytes, fulOddCaps,
                              FALSE);
            pbTemp = pbBuff;
          }
          else
          {
            pbTemp = pLineBuffer;
          }

          // Seed row is zeroed when raster mode is entered.
          ulBlockSize += compress_adaptive(pbTemp,
                                           lNBytes, pbLastRow,
                                           pbCurrentBlock, BLOCKSIZE-ulBlockSize,
                                           fulGplCompressFlags,
                                           pusDelta);

          pbCurrentBlock = pbOutBlockPtr + ulBlockSize;

          if ((ulBlockSize + lNBytes + 6) > BLOCKSIZE)
          {
            output_bytes(pDDC,"\033*b");
            output_number(pDDC, ulBlockSize);
            output_bytes(pDDC,"W");
            bin_output_bytes(pDDC,pbOutBlockPtr,ulBlockSize);
            setmem ((PBYTE)pbLastRow, 0, lNBytes);
            ulBlockSize = 0;
            pbCurrentBlock = pbOutBlockPtr;
          }

          /*
          ** Note this addition of ulBytesPerScan instead of lNBytes is very
          ** important as we have some extra bytes at the end of each scan line.
          ** This can be removed latter.
          */
          pLineBuffer += ulBytesPerScan;

        } // End of while lScan

        /*
        ** Now get back to the starting of the patternblock
        */
        pbXstepPatBlock = pbPatBlock;
        pLineBuffer = pbXstepPatBlock;

        /*
        ** Alright now lets take care of the extra lines if we have any
        */
        if ((ly == lySteps - 2) && lySremains)
           lScan = lySremains;
        else
           lScan = ulSaveScan;

     } // End of for ly < lYsteps

     if (ulBlockSize)
     {
       output_bytes(pDDC,"\033*b");
       output_number(pDDC, ulBlockSize);
       output_bytes(pDDC,"W");
       bin_output_bytes(pDDC,pbOutBlockPtr,ulBlockSize);
     }
     GplMemoryFree (pbOutBlockPtr);
  } // End of if DRV_COMPRESS_ADAPTIVE
  else // Compression for PCL devices.
  {
     PBYTE   pbCompressedRow;
     INT     iCurrentCompressMode = -1; //init to not set
     ULONG   ulMaxCompress = lNBytes * 2;

     pbCompressedRow = GplMemoryAlloc(pDDC->pPDevice->hmcbHeap, ulMaxCompress);

     for (ly = 0;ly < lySteps;ly++) // as many pattern blocks
                                   // as needed in y direction
     {
        while ( lScan-- )
        {

           /*
           ** if this is an 24 bit per pel bitmap
           ** We need a buffer to convert RGB2 data (BGR) to (RGB) order
           */
           if (pbmi->cBitCount == 24)
           {
             pRGBSource = (RGB*)pbXstepPatBlock;
             pRGBDest   = (RGB*)pbBuff;
             convertBGR_to_RGB(pRGBDest, pRGBSource,
                               lNBytes, fulOddCaps,
                               FALSE);
             pbTemp     = pbBuff;
           }
           else
           {
             pbTemp = pbXstepPatBlock;
           }
           // Seed row is zeroed when raster mode is entered.

           compress_any_supported_mode(pDDC, pbTemp, lNBytes,
                                       pbLastRow,
                                       pbCompressedRow,
                                       ulMaxCompress,
                                       &iCurrentCompressMode,
                                       fulGplCompressFlags,
                                       pusDelta);

           pbXstepPatBlock += ulBytesPerScan;
        }   // End of while lscan

        pbXstepPatBlock = pbPatBlock;

        /*
        ** Alright now lets take care of the extra lines if we have any
        */
        if ((ly == lySteps - 2) && lySremains)
           lScan = lySremains;
        else
           lScan = ulSaveScan;

     } // End of for ly < lySteps
     GplMemoryFree (pbCompressedRow);

  }
  GplMemoryFree (pusDelta);
  GplMemoryFree (pbPatBlock);
  GplMemoryFree (pbLastRow);
  if (pbBuff)
  {
    GplMemoryFree (pbBuff);
  }
  return;
}

/***************************************************************************
 *
 * FUNCTION NAME = drawimage
 *
 * DESCRIPTION   = This routine projects an image of a rectangle on
 *                 the source DC's bitmap onto the printer.
 *                 If we want to do anything, we first need the handle to the
 *                 bitmap. If they gave us a DC as source then call the
 *                 getbitmaphandle to get the handle to the bitmap. Else they
 *                 gave us a bitmap handle as source.
 *                 Here we have to select the bitmap into our shadow DC. If we
 *                 don't we can not get the bitmap bits. But at this point we
 *                 select the bitmap into our shadow DC, only if the device
 *                 supports PCL and we are not doing any compression.
 *                 Get the bitmap parameters by calling GreGetBitmapParameters.
 *                 Now we have a problem here. For HP600 and HP650C we need to
 *                 rotate the bitmap in PORTRAIT 180 and in LANDSCAPE 270
 *                 degrees due to the way we handle orientation in HPGL/2 and
 *                 the reason that these devices can not handle the change in
 *                 print direction.
 * Note : If any of these devices can handle the change in print direction(raster)
 *        the code in this function should be chaged to reflect the device's new
 *        capability.
 *                 We also use this piece of code to do any compression or stretch
 *                 using GRE for HP600. And we use this code to compress the bitmap
 *                 for PCL and HP650C devices.
 *                 Current implementation is to use GRE for compression and do
 *                 any stretch on the device. This excludes HP600 as we have to
 *                 GreyScale the bits.
 *                 So call greyscalesourcebits for monochrome devices and then
 *                 call image_scan to actually send the bits to the device.
 *
 * INPUT         = pddc, hdcDst, hdcSrc, ulStyle, prclDst, prclSrc,
 *                 pbbAttrs, ulMix
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 *
 * RETURN-ERROR  =
 *
 * Created : Kran
 *
 **************************************************************************/

ULONG drawimage( PDDC pDDC, HDC hdcDst, HDC hdcSrc, ULONG ulStyle,
                 PRECTL prclDst, PRECTL prclSrc, PBITBLTATTRS pbbAttrs,
                 ULONG ulMix, ULONG FunN )
{
  BITMAPINFOHEADER  bmi;                   /* To hold the bitmap parameters */
  HBITMAP           hbmSrc;                /* Source bitmap handle          */
  HBITMAP           hbmDst;                /* To hold stretched bitmap      */
  LONG              nBitsPerSample;        /* no of bits                    */
  LONG              nColors;               /* no of colors in bitmap        */
  ULONG             ulBytesPerScan,ulScan; /* no of bytes in line, height   */
  ULONG             ulLinesScanned;        /* lines scanned in GetBitmapBits*/
  PBYTE             pbScan;                /* to hold the scanned bits      */
  PBITMAPINFO       pbmi;                  /* to hold the colors of bits    */
  PBYTE             pBits;                 /* holds the greyscaled bits     */
  ULONG             GreyBytesPerScan;      /* bytes per line in greyscaled bits*/
  LONG              SrcWidth,SrcHeight;    /* Source rectangle dimensions   */
  LONG              DstWidth,DstHeight;    /* Destination rectangle dimens. */
  BOOL              flComp = FALSE;        /* if needs compression          */
  ULONG             ulRet = TRUE;          /* To store Return Code          */
  HDC               hdcMemory;             /* holds shadow dc               */
  POINTL            pXY[4];                /* array to hold Dest and Srcrect*/
  PXFORM            pNEWXformData;         /* to hold new xform data        */
  PXFORM            pOLDXformData;         /* to save current xform data    */
  ULONG             Plotter = pDDC->pPDevice->Plotter; /* index into plotterclass */
  ULONG             fulOddCaps = PlotterClass[Plotter].fsOdd; /* odd caps      */
  BOOL              fIsColorDevice = fulOddCaps & OD_COLOR; /* device can handle color */
  BOOL              bScale = FALSE;        /* needs stretching              */
  HBITMAP           hbmSave;
  ULONG             ulUndo;

  DBPRINTF (("Entered DrawImage \n"));

  DstWidth  = prclDst->xRight - prclDst->xLeft;
  DstHeight = prclDst->yTop - prclDst->yBottom;
  SrcWidth  = prclSrc->xRight - prclSrc->xLeft;
  SrcHeight = prclSrc->yTop - prclSrc->yBottom;

  /*
  **  First things first. Check if we have to do any stretch or Compression.
  **  This tolerence is needed because of the GreConvert function.
  **  Lets hope no body wants to stretch or compress just by 1 or 2
  **  bits.
  */
  if ((DstWidth - SrcWidth > 2) || (DstWidth - SrcWidth < -2))
  //if ((DstWidth - SrcWidth > 2) || (DstHeight - SrcHeight > 2))
  {
    bScale = TRUE;
  }
  //else if ((DstWidth - SrcWidth < -2) || (DstHeight - SrcHeight < -2))
  else if ((DstHeight - SrcHeight > 2) || (DstHeight - SrcHeight < -2))
  {
    flComp   = TRUE;
  }
  else
  {
    DstWidth  = SrcWidth;
    DstHeight = SrcHeight;
  }

  /*
  **  If Source is a DC then get the bitmap handle
  */
  if (!(ulStyle&BLTMODE_SRC_BITMAP))
  {
    if (!(hbmSrc = getbitmaphandle(hdcSrc)))
    {
      DBPRINTF (("Drawimage : getbitmaphandle failed"));
      return( GPI_ERROR );
    }
  }
  else                         // we have a bitmap handle
  {
    hbmSrc = (HBITMAP)hdcSrc;
    if ((fulOddCaps & OD_PCL) && !flComp)
    {
      GreSelectBitmap(pDDC->hdcMemory,hbmSrc);
      hdcSrc = pDDC->hdcMemory;
    }
  }

  /*
  ** Determine the bitmap format
  */
  if (!GreGetBitmapParameters( hbmSrc, &bmi))
  {
    DBPRINTF(("Drawimage Getbitmapparameters failed"));
    return( GPI_ERROR );
  }

  /*
  **  OK. We have the bitmap handle. Now because of the handling of
  **  orientation in Vector Graphics for HP 600 and 650C we have to rotate
  **  the bitmap in
  **  Portrait Mode: 180 Degrees
  **  Landscape    : 270 Degrees
  **  We will do stretching and compression as well, using GRE for HP 600.
  **  This we do only if the device does not support PCL or it does support
  **  PCL but we have to do some compression. If the device supports PCL or the
  **  device is a color device and if we have to stretch, then we will stretch
  **  the bitmap on the device itself.
  **  This we will do in 5 steps.
  **  1. Create a bitmap and select it into our shadow DC.
  **  2. Get the transformation matrix and save it.
  **  3. Set new transformation matrix.
  **  4. Call the GreBitBlit with WC_Bitblt set.
  **  5. Set the old transformation matrix.       Kran
  */

  if (!(fulOddCaps & OD_PCL) || flComp)
  {
    hdcMemory = pDDC->hdcMemory;
    if (bScale && fIsColorDevice)  // we don't want to modify bmi for
    {                              // hp 650c stretch.
      bmi.cx = SrcWidth;
      bmi.cy = SrcHeight;
    }
    else
    {
      bmi.cx = DstWidth;
      bmi.cy = DstHeight;
    }

    if (!(fulOddCaps & OD_PCL))
    {
      pOLDXformData = (PXFORM)GplMemoryAlloc(pDDC->pPDevice->hmcbHeap,sizeof(XFORM));
      pNEWXformData = (PXFORM)GplMemoryAlloc(pDDC->pPDevice->hmcbHeap,sizeof(XFORM));

      if (pDDC->pPDevice->fsTransform & DXF_PORTRAIT)
      {
        pNEWXformData->fxM11 = MAKEFIXED(-1,0);      // cos(180)  = -1
        pNEWXformData->fxM12 = MAKEFIXED(0,0);       // sin(180)  = 0
        pNEWXformData->fxM21 = MAKEFIXED(0,0);       // -sin(180) = 0
        pNEWXformData->fxM22 = MAKEFIXED(-1,0);      // cos(180)  = -1
        pNEWXformData->lM41  = bmi.cx;               // Tx *****
        pNEWXformData->lM42  = bmi.cy;               // Ty  *****
      }
      else                  // LandScape
      {
        prclDst->xRight = prclDst->xLeft + DstHeight;
        prclDst->yTop   = prclDst->yBottom + DstWidth;

        if (bScale && fIsColorDevice)
        {                        // use source rectangle for HP 650C
          bmi.cx = SrcHeight;
          bmi.cy = SrcWidth;
        }
        else
        {
          bmi.cx = DstHeight;                                 // *********
          bmi.cy = DstWidth;                                  // *********
        }

        pNEWXformData->fxM11 = MAKEFIXED(0,0);       // cos(270)  = 0
        pNEWXformData->fxM12 = MAKEFIXED(-1,0);      // sin(270)  = -1
        pNEWXformData->fxM21 = MAKEFIXED(1,0);       // -sin(270) = 1
        pNEWXformData->fxM22 = MAKEFIXED(0,0);       // cos(270)  = 0
        pNEWXformData->lM42  = bmi.cy;               // Ty *********
      }
      GreGetModelXform(hdcMemory,pOLDXformData);
      GreSetModelXform(hdcMemory,pNEWXformData,SX_CAT_AFTER);
    } /* end of if it is not PCL or flcomp or stretch but hp650c */

    hbmDst = GreCreateBitmap(hdcMemory,&bmi,NULL,NULL,NULL);
    GreSelectBitmap(hdcMemory,hbmDst);

    pXY[0].x = 0L;
    pXY[0].y = 0L;
    pXY[2].x = prclSrc->xLeft;
    pXY[2].y = prclSrc->yBottom;
    pXY[3].x = prclSrc->xRight;
    pXY[3].y = prclSrc->yTop;

    if (bScale && fIsColorDevice) // if we are not doing any grey scaling,
    {                             // we can use device for stretching.
      pXY[1].x = SrcWidth;
      pXY[1].y = SrcHeight;
    }
    else
    {
      if (ulStyle & BBO_TARGWORLD)
      {                        // in world coords it is inclusive/exclusive
        pXY[1].x = DstWidth;   // but because of the GreTransform function
        pXY[1].y = DstHeight;  // we already have a reduced coord set.
      }
      else
      {
        pXY[1].x = DstWidth - 1;
        pXY[1].y = DstHeight - 1;
      }
    }


    ulStyle |= BBO_TARGWORLD;      // indicate target is in World Coordinates.
    if (!(ulStyle & BLTMODE_SRC_BITMAP))
    {
      DBPRINTF (("WE ARE DE SELECTING THE BITMAP"));
      // Save the original.
      hbmSave = GreSelectBitmap(hdcSrc,NULL); //deselect the bitmap. Needed for rotation
      ulUndo |= DESELECTED_BITMAP;
      ulStyle |= BLTMODE_SRC_BITMAP;// Gre doesn't handle DC as Src when rotating.
    }                               // Meaning GRE wants a bitmap as source but it
                                    // should not be selected in any DC.
    ulRet = (*daBitblt)(hdcMemory,hbmSrc,4L,pXY,ulMix,ulStyle,pbbAttrs,pDDC,FunN);

    if(ulUndo & DESELECTED_BITMAP)
    {
      GreSelectBitmap(hdcSrc,hbmSave);
      ulUndo &= ~DESELECTED_BITMAP;
      ulStyle &= ~BLTMODE_SRC_BITMAP;
      DBPRINTF (("RE SELECTED THE BITMAP"));
    }
    /*
    **  At this point we have the bitmap rotated and streched or compressed if
    **  needed. The rotated bitmap handle is hbmDst and is selected in to
    **  hdcMemory. Put them in hbmSrc and hdcSrc for convenience.
    */
    hdcSrc = hdcMemory;
    hbmSrc = hbmDst;

    if (!(fulOddCaps & OD_PCL))
    {
      prclSrc->xLeft  = prclSrc->yBottom = 0L;
      prclSrc->xRight = bmi.cx;
      prclSrc->yTop   = bmi.cy;
    }
  }

  /*
  ** Decide on which standard bitmap format to use.
  ** nBitsPerSample will be set to 1,4,8
  */
  if (bmi.cPlanes == 24 || bmi.cBitCount == 24)
  {
    if (fIsColorDevice)
    {
      nBitsPerSample = 24;
    }
    else
    {
      nBitsPerSample = 8;
    }
  }
  else if (bmi.cPlanes >= 8 || bmi.cBitCount >= 8)
  {
    nBitsPerSample = 8;
  }
  else if (bmi.cPlanes >= 4 || bmi.cBitCount >= 4)
  {
    nBitsPerSample = 4;
  }
  else
  {
    nBitsPerSample = 1;
  }

  DBPRINTF (("Number of bits per pel : %d\n",nBitsPerSample));
  /*
  ** Compute the number of color table entries.
  */
  if (nBitsPerSample != 24)
  {
    nColors = 2 << (nBitsPerSample - 1);
  }
  else
  {
    nColors = 0;
  }

  /*
  ** Find the number of bytes per scan line.
  ** The lines are in 32 bit boundary.
  */

  ulBytesPerScan = ((nBitsPerSample * bmi.cx + 31) >> 5) << 2;
  ulScan  = prclSrc->yTop - prclSrc->yBottom;

  /*
  ** Allocate memory for the entire bitmap (no of bytes per scanline * no of
  ** scan lines in bitmap).
  */
  if (!(pbScan = GplMemoryAlloc(NULL, ulBytesPerScan * ulScan)))
  {
    GplErrSetError( (ERRORID)PMERR_INSUFFICIENT_MEMORY );
    DBPRINTF(("drawimage pbscan bombed"));
    ulRet = GPI_ERROR;
    goto DrawImageExit;
  }

  /*
  ** Allocate storage for the bitmap info structure
  */
  if (!(pbmi = (PBITMAPINFO)GplMemoryAlloc(NULL,sizeof(BITMAPINFO)+nColors *sizeof
                                               (LONG))))
  {
    GplErrSetError( (ERRORID)PMERR_INSUFFICIENT_MEMORY );
    if (GplMemoryFree ((PVOID)pbScan))
       pbScan = NULL;
    ulRet = GPI_ERROR;
    goto DrawImageExit;
  }

  pbmi->cbFix = sizeof( BITMAPINFOHEADER );
  pbmi->cPlanes = 1;
  pbmi->cBitCount = nBitsPerSample;

  /*
  ** Get the bitmap colors into pbmi
  */
  ulLinesScanned = (ULONG) GreGetBitmapBits (hdcSrc, hbmSrc,
                                             prclSrc->yTop - 1,
                                             1L, pbScan,
                                             pbmi );
  assert(ulLinesScanned == 1);

  /*
  ** If the bitmap is monochrome
  */
  if(nBitsPerSample == 1)
  {
    ULONG  ulFrgColor;
    ULONG  ulBackColor;

    /*
    ** The pm specification says to use image foreground and back ground
    ** colors if the BLTMODE_ATTRS are not present.
    */
    ulFrgColor  = pDDC->DCState.ibnd.lColor;
    ulBackColor = pDDC->DCState.ibnd.lBackColor;

    /*
    ** If the Attributes are present then use them
    */
    if (ulStyle & BLTMODE_ATTRS_PRES)
    {
      switch (pbbAttrs->cSize)
      {
      case 12: ulBackColor = pbbAttrs->lBackColor;
      case 8:  ulFrgColor  = pbbAttrs->lColor;
               break;
      default: DBPRINTF(("Ooops we did't get the attrs"));
               GplErrSetError((ERRORID)PMERR_INV_LENGTH_OR_COUNT);
               if (GplMemoryFree ((PVOID)pbScan))
                  pbScan = NULL;
               if (GplMemoryFree ((PVOID)pbmi))
                  pbmi = (PBITMAPINFO)NULL;
               ulRet = GPI_ERROR;
               goto DrawImageExit;
               break;
      }
    }
    ulFrgColor = convert_color(pDDC,ulFrgColor);
    ulBackColor = convert_color(pDDC,ulBackColor);

    /*
    ** Set the background color into pbmi
    */
    pbmi->argbColor[0].bBlue = (BYTE)ulBackColor;
    pbmi->argbColor[0].bGreen = (BYTE)(ulBackColor >> 8);
    pbmi->argbColor[0].bRed   = (BYTE)(ulBackColor >> 16);

    /*
    ** Set the foreground color into pbmi
    */
    pbmi->argbColor[1].bBlue = (BYTE)ulFrgColor;
    pbmi->argbColor[1].bGreen = (BYTE)(ulFrgColor >> 8);
    pbmi->argbColor[1].bRed   = (BYTE)(ulFrgColor >> 16);

  }


  /*
  ** set up the raster transfer
  */
  enter_PCL_or_HPRTL(pDDC, fulOddCaps);
  set_palette(pDDC, fulOddCaps, pbmi->cBitCount,
              (PRGB2)pbmi->argbColor, COLOR_FORMAT_RGB);
  if (!(fulOddCaps & OD_PCL) && !fIsColorDevice )
    bScale = FALSE;
  set_raster_width_and_height(pDDC,fulOddCaps,prclSrc,prclDst,bScale);
  set_graphics_position(pDDC, fulOddCaps, prclDst,0L,0L);
  begin_raster_graphics(pDDC, fulOddCaps, bScale);

  /*
  **  Get all the bits into pbScan.
  */
  ulLinesScanned = (ULONG) GreGetBitmapBits (hdcSrc, hbmSrc,
                                              prclSrc->yBottom,
                                              ulScan, pbScan,
                                             (PBITMAPINFO)pbmi );
  assert (ulLinesScanned == ulScan);
  /*
  **  Check if our device can handle only monochrome bitmaps. If so
  **  Allocate memory to hold the GreyScaled bits and send it to
  **  GreyScaleSourceBits.
  */

  if (nBitsPerSample > 1 && !fIsColorDevice)
  {
    /*
    **  Allocate memory for pBits where we get the greyscaled bits
    */
    GreyBytesPerScan = (bmi.cx * 1 + 7) >> 3;
    if (!(pBits = GplMemoryAlloc(NULL,ulScan * GreyBytesPerScan)))
    {
      GplErrSetError( (ERRORID)PMERR_INSUFFICIENT_MEMORY );
      if (GplMemoryFree ((PVOID)pbScan ))
         pbScan = NULL;
      if (GplMemoryFree ((PVOID)pbmi))
         pbmi = (PBITMAPINFO)NULL;
      ulRet = GPI_ERROR;
      goto DrawImageExit;
    }

    setmem (pBits,0xFF,GreyBytesPerScan * ulScan);

    /*
    **  Returns the GreyScale bits in pBits. The lines in pBits are on a
    **  Byte boundary.
    */
    greyscalesourcebits(pBits,pbScan,prclDst,ulBytesPerScan,ulScan,pbmi,pDDC);
  }
  else
  {
    pBits = pbScan;
    GreyBytesPerScan = ulBytesPerScan;
  }

  /*
  **  Simply outputs the necessary output commands and then the bits in pBits.
  */
  image_scan (pDDC, pBits, GreyBytesPerScan, ulScan, fulOddCaps,
             nBitsPerSample, bmi.cx,
             ulMix, 0L, 0L,0L);
  /*
  **  We are merging the vector and Raster Graphics, Then we have
  **  to end the RasterGraphics and Enter the HPGL-2 mode.
  */
  end_raster_graphics(pDDC, fulOddCaps);
  return_to_HPGL2(pDDC, fulOddCaps);

  ulRet = TRUE;

  if (GplMemoryFree ((PVOID)pbScan))
     pbScan = NULL;
  if (GplMemoryFree ((PVOID)pbmi))
     pbmi = (PBITMAPINFO)NULL;
  if (nBitsPerSample > 1 && !fIsColorDevice)       // if it is a color device then there is no pbits.
    if (GplMemoryFree ((PVOID)pBits))
       pBits = NULL;

  DBPRINTF(("EXITING DrawImage Normally \n"));
DrawImageExit:

  if (!(fulOddCaps & OD_PCL))
  {
    GreSetModelXform(hdcMemory,pOLDXformData,SX_OVERWRITE);
    if (GplMemoryFree ((PVOID)pNEWXformData))
       pNEWXformData = (PXFORM)NULL;
    if (GplMemoryFree ((PVOID)pOLDXformData))
       pOLDXformData = (PXFORM)NULL;
  }
  if (!(fulOddCaps & OD_PCL) || flComp)
  {
    GreSelectBitmap(hdcSrc, (HBITMAP)NULL);
    GreDeleteBitmap(hbmSrc);
  }
  else if (ulStyle & BLTMODE_SRC_BITMAP)
    GreSelectBitmap(hdcSrc,(HBITMAP)NULL);

  return(ulRet);

}


/***************************************************************************
 *
 * FUNCTION NAME = DrawBits
 *
 * DESCRIPTION   = Function draws a rectangle of bits.
 *                 Supported only for memory DC.
 *                 Call back graphics engine. We should not get call to this
 *                 function for other DC types.
 * INPUT         =
 *
 *
 *
 *
 * OUTPUT        =
 *
 * RETURN-NORMAL =
 *
 * RETURN-ERROR  =
 *
 **************************************************************************/
ULONG  DrawBits (HDC hdc, PBYTE pBitmap, PBITMAPINFO pInfo, LONG  cPoints,
                      PPOINTL paptlPoint, LONG lRop, ULONG flOptions,
                      PDDC pDDC, ULONG ulFunN)
{
  ULONG ulRet;

  if (!EnterDriver (pDDC))
      return(GPI_ERROR);

  if (pDDC->usDCType == OD_MEMORY)
  {
    ulRet = InnerGreDrawBits (pDDC->hdcMemory, pBitmap, pInfo, cPoints,
                              paptlPoint, lRop, flOptions, ulFunN);
  }
  else
  {
    /*
    ** we should not come this far
    */
    ulRet = GPI_ERROR;
  }

  LeaveDriver(pDDC);
  return (ulRet);
}

/***************************************************************************
 *
 * FUNCTION NAME = Bitblt
 *
 * DESCRIPTION   = Transfer bitmaps directly from memory.
 *
 *                 The plotter driver supports Bitblt only to bypass an
 *                 optimization in the engine.  This optimization causes
 *                 the engine to use the driver's Bitblt() function to do
 *                 area fills.  So, verify that the function is the area
 *                 fill (ROP_PATCOPY) and then verify the options and
 *                 go.  Anything else is rejected as function not
 *                 installed.
 *
 * Note : This function was completely rewritten to support the Raster
 * Operations.
 *
 *
 *
 * INPUT         =  HDC hDC;
 *                  HDC hdcSrc;
 *                  LONG Count;
 *                  PPOINTL pXY;
 *                  ULONG Mix;
 *                  ULONG Options;
 *                  PBITBLTATTRS pAttrs;
 *                  PDDC pDDC;
 *                  ULONG FunN;
 *
 * The BitBlt function copies a bitmap from one presentation space to another.
 * It can also modify the bitmap within a rectangle in a presentation space.
 * The exact operation carried out by BitBlt depends on the raster
 * operation specified by the Mix parameter.
 *
 * If Mix directs BitBlt to copy a bitmap, the function copies the bitmap
 * from a source presentation space specified by hdcSrc to a target
 * presentation space specified by hDC. Each presentation space must be
 * associated with a device context for the display, for memory, or for some
 * other suitable raster device. The target and source presentation spaces
 * can be the same if desired. The pXY parameter points to an array of points
 * that specify the corners of a rectangle containing the bitmap in the source
 * presentation space as well as the corners of the rectangle in the target
 * presentation space to receive the bitmap.  If the source and target
 * rectangles are not the same, BitBlt stretches or compresses the bitmap
 * to fit the target rectangle.
 *
 * If Mix directs BitBlt to modify a bitmap, the function uses the raster
 * operation to determine how to alter the bits in a rectangle in the target
 * presentation space. Raster operations include changes such as inverting
 * target bits, replacing target bits with pattern bits, and mixing target
 * and pattern bits to create new colors.  For some raster operations,
 * the function mixes the bits of a bitmap from a source presentation space
 * with the target and/or pattern bits.
 *
 * Parameter  Description
 * ----------------------------------------------------------------------------
 * hDC        Identifies the target presentation space.
 *
 * hdcSrc     Identifies the source presentation space.
 *
 * Count      Specifies the number of points pointed to by the pXY parameter.
 *
 *            It may be one of the following values:
 *
 *            Value  Meaning
 *            -----------------------------------------------------------------
 *            2      The points specify the lower-left and upper-right corners
 *                   of the target rectangle. If 2 is given, the raster
 *                   operation specified by the Mix parameter must not include
 *                   a source.
 *
 *            3      The points specify the lower-left and upper-right corners
 *                   of the target rectangle, and the lower-left corner of the
 *                   source rectangle. The upper-right corner of the source
 *                   rectangle is computed such that the target and source
 *                   rectangles have equal width and height. Any raster
 *                   operation may be used. If the operation does not include a
 *                   source, the third point is ignored.
 *
 *            4      The points specify the lower-left and upper-right corners
 *                   of the target and the source rectangles. If the rectangles
 *                   do not have equal width and height, the source bitmap is
 *                   stretched or compressed to fit the target rectangle.
 *                   BitBlt uses the Options parameter to determine how
 *                   the bitmap should be compressed. If the raster operation
 *                   does not include a source, the source coordinates are
 *                   ignored.
 *
 * pXY        Points to an array of POINTL structures containing the number of
 *            points specified in the Count parameter. The points must be
 *            given in the following order:
 *
 *            Element index  Coordinate
 *            -----------------------------------------------------------------
 *            0              Specifies the lower-left corner of the target
 *                           rectangle.
 *
 *            1              Specifies the upper-right corner of the target
 *                           rectangle.
 *
 *            2              Specifies the lower-left corner of the source
 *                           rectangle.
 *
 *            3              Specifies the upper-right corner of the source
 *                           rectangle.
 *
 *            All points must be in device coordinates.
 *
 * Mix        Specifies the raster operation for the function. It can be any
 *            value in the range 0 through 255 or one of the following values,
 *            which represent common raster operations:
 *
 *            Value            Meaning
 *            -----------------------------------------------------------------
 *            ROP_DSTINVERT    Inverts the target.
 *
 *            ROP_MERGECOPY    Combines the source and the pattern using the
 *                             bitwise AND operator.
 *
 *            ROP_MERGEPAINT   Combines the inverse of the source and the
 *                             target using the bitwise OR operator.
 *
 *            ROP_NOTSRCCOPY   Copies the inverse of the source to the target.
 *
 *            ROP_NOTSRCERASE  Combines the inverse of the source and the
 *                             inverse of the target bitmaps using the bitwise
 *                             AND operator.
 *
 *            ROP_ONE          Sets all target pels to 1.
 *
 *            ROP_PATCOPY      Copies the pattern to the target.
 *
 *            ROP_PATINVERT    Combines the target and the pattern using the
 *                             bitwise exclusive XOR operator.
 *
 *            ROP_PATPAINT     Combines the inverse of the source, the pattern,
 *                             and target using the bitwise OR operator.
 *
 *            ROP_SRCAND       Combines the source and target bitmaps using the
 *                             bitwise AND operator.
 *
 *            ROP_SRCCOPY      Copies the source bitmap to the target.
 *
 *            ROP_SRCERASE     Combines the source and the inverse of the
 *                             target bitmaps using the bitwise AND operator.
 *
 *            ROP_SRCINVERT    Combines the source and target bitmaps using the
 *                             bitwise exclusive OR operator.
 *
 *            ROP_SRCPAINT     Combines the source and target bitmaps using the
 *                             bitwise OR operator.
 *
 *            ROP_ZERO         Sets all target pels to 0.
 *
 * Options    Specifies how to compress a bitmap if the target rectangle is
 *            smaller than the source. It can be one of the following values:
 *
 *            Value       Meaning
 *            -----------------------------------------------------------------
 *            BBO_AND     Compresses two rows or columns into one by combining
 *                        them with the bitwise AND operator. This value is
 *                        useful for compressing bitmaps
 *
 *            BBO_IGNORE  Compresses two rows or columns by throwing one out.
 *                        This value is useful for compressing color bitmaps.
 *                        that have black images on a white background.
 *
 *            BBO_OR      Compresses two rows or columns into one by combining
 *                        them with the bitwise OR operator. This value is the
 *                        default and is useful for compressing bitmaps that
 *                        have white images on a black background.
 *
 *            All values in the range 0x0100 through 0xFF00 are reserved for
 *            privately supported modes for particular devices.
 *
 * Comments
 *
 * The source and target presentation spaces may be associated with any device
 * context having raster capabilities. Some raster devices, such as banded
 * printers, can receive bitmaps but cannot supply them. These devices cannot
 * be used as a source.
 *
 * BitBlt does not affect the pels in the upper and right boundaries of the
 * target rectangle. This means the function draws up to but does not include
 * those pels.
 *
 * If Mix includes a pattern, BitBlt uses the current area color, area
 * background color, pattern set, and pattern symbol of the target presentation
 * space. Although the function may stretch or compress the bitmap, it never
 * stretches or compresses the pattern.
 *
 * If the target and source presentation spaces are associated with device
 * contexts that have different color formats, BitBlt converts the bitmap
 * color format as it copies the bitmap. This applies to bitmaps copied to or
 * from a device context having a monochrome format. To convert a monochrome
 * bitmap to a color bitmap, BitBlt converts 1 pels to the target's
 * foreground color, and 0 pels to the current area background color. To
 * convert a color bitmap to a monochrome bitmap, BitBlt converts pels with
 * the source's background color to the target's background color, and all
 * other pels to the target's foreground color.
 *
 * The bitmap associated with a source presentation space is always a finite
 * size. Although BitBlt will copy a bitmap when given a source rectangle
 * that is larger than the source bitmap or extends past the boundaries of the
 * source bitmap, any pels not associated with the source bitmap are
 * undefined.
 *
 * Implementation: We are using Shadow DC to support this function.
 * Check if we were given a source. If we have a source then check if it is a
 * bitmap handle. If it is a bitmap handle then use GetDriverInfo and get the
 * corresponding bitmap handle in Display Driver. If it is not a bitmap handle
 * then it is a handle to one of our DC. Again for this, call GetDriverInfo to
 * get the pointer to our DC and get the handle to the shadowDC from our DC
 * (pDDC->hdcMemory).
 * If the call is for OD_MEMORY then call back Graphics Engine.
 * If the Destination Rectangle coordinates are in World coordinate space then
 * convert them to Device.
 *
 * Now IF the raster operation is ROP_DSTINVERT or ~ROP_DSTINVERT it is a NOP.
 * ELSE IF the raster operation is ROP_ZERO then
 *   it means paint the destination with black color.
 *   so call draw_box with PATSYM_SOLID and ulColor set to color BLACK.
 * ELSE IF the raster operation is ROP_ONE then
 *   it means paint the destination with white color.
 *   OK. So call draw_box with PATSYM_BLANK. draw_box forces ulcolor to color
 *   white.
 * ELSE IF there is no source involved then a pattern is involved.
 *   if it is a standard pattern then
 *     check if BLTMODE_ATTRS_PRES is set in Options and if so then we have to
 *     use the colors supplied in pAttrs.
 *     else use colors in area bundle and call BoxInterior to fill the rectangle.
 *   else it is user defined pattern.
 *     The user defined pattern is defined by a bitmap.
 *     The lcid get us the bitmap handle.
 *     Call getbitmapparametes to get the details of bitmap.
 *     Check if you can blt the pattern using HPGL2 RF rasterfill command.
 *     if so then blt it and get out. See the comments in code.
 *     if not then use the brute method (call fill_pattern).
 * ELSE (all others)  (ROP_SRCCOPY and ROP_INVSRCCOPY)
 *   call drawimage to do the work. See comments in drawimage.
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = GPI_OK
 * RETURN-ERROR  = GPI_ERROR
 *
 * Created : Kran
 *
 **************************************************************************/

LONG Bitblt(HDC hDC,HDC hdcSrc,LONG Count,PPOINTL pXY,ULONG Mix,
            ULONG Options,PBITBLTATTRS pAttrs,PDDC pDDC,ULONG FunN)
{
  POINTL      aptl[2];
  POINTL      ptlOldCP;
  HDC         hSavedDC;
  RECTL       rclDst;                  /* The destination rectangle         */
  RECTL       rclSrc;                  /* The source rectangle              */
  BYTE        bMyROP;                  /* my temp copy of the ROP.          */
  ULONG       ulRet = GPI_OK;
  POINTL      SavedPos;
  ULONG       ulColor = 0;
  POINTL      pEnd;
  PPDEVICE    pPDevice = pDDC->pPDevice;
  LONG        Plotter  = pPDevice->Plotter;
  ULONG       fulOddCaps  = PlotterClass[Plotter].fsOdd; /* odd caps      */

  DBPRINTF(("ENTERED BITBLT \n"));
  DBPRINTF(("Mix is : %x\n",Mix));
  DBPRINTF(("Count is : %d\n",Count));
  DBPRINTF(("Options is : %x\n",Options));


  if (EnterDriver(pDDC) == 0)
      return(GPI_ERROR);
  if (pDDC->bJournalPlayed)
      return GPI_OK;

  /*
  ** do nothing if DRAW bit not set
  */
  if (!(FunN&COM_DRAW))
  {
    LeaveDriver( pDDC );
    return (GPI_OK);
  }

  /*
  **     Verify that what we received is somewhat acceptable...
  */
  if (Options&~(BBO_OR|BBO_AND|BBO_IGNORE|BBO_TARGWORLD|BLTMODE_SRC_BITMAP|
     BLTMODE_ATTRS_PRES))
  {
    GplErrSetError(PMERR_DEV_FUNC_NOT_INSTALLED);
    LeaveDriver(pDDC);
    return  GPI_ERROR;
  }

  if ((Options&(BBO_AND|BBO_IGNORE)) == (BBO_AND|BBO_IGNORE))
  {
    GplErrSetError(PMERR_INV_BITBLT_STYLE);
    LeaveDriver(pDDC);
    return  GPI_ERROR;
  }

  if (hdcSrc)
  {
    if (Options & BLTMODE_SRC_BITMAP)
    {
      /*
      ** Source is a bitmap
      */
      HBITMAP hbmDisplay;

      hbmDisplay = (HBITMAP) GetDriverInfo( (HBITMAP) hdcSrc, 1L, hDC );

      if (hbmDisplay != GPI_ALTERROR)
      {
        /*
        ** It is one of ours.
        */
        hdcSrc = (HDC) hbmDisplay;
      }
    }
    else
    {
      /*
      ** Source is a DC
      */
      PDDC pddcSrc;

      pddcSrc = (PDDC) GetDriverInfo( hdcSrc, 0L, hDC );

      if ((ULONG) pddcSrc != GPI_ALTERROR &&
          (pddcSrc->usDCType == OD_MEMORY) )
      {
        hdcSrc = pddcSrc->hdcMemory;
      }
    }  /* if (ulStyle & BLTMODE_SRC_BITMAP) */
  }    /* if(hdcSrc)                        */

  /*
  ** Switch on the DC type so that the body of this function
  ** is executed only if it is OD_DIRECT or OD_QUEUED.
  */

  switch ((SHORT)pDDC->usDCType)
  {
  /*
  ** in the case of an info dc, just return GPI_OK.
  */
  case OD_INFO:
       LeaveDriver( pDDC );
       return (GPI_OK);

  case OD_MEMORY:
       if (FunN & (COM_PATH | COM_AREA))
       {
         GplErrSetError( (ERRORID) PMERR_INV_IN_PATH );
         ulRet = GPI_ERROR;
       }
       else
       {
         ulRet = InnerGreBitblt( pDDC->hdcMemory, hdcSrc, Count, pXY,
                                 Mix, Options, pAttrs, FunN );
       }
       LeaveDriver( pDDC );
       return (ulRet);

  case OD_DIRECT:
  case OD_QUEUED:
       DBPRINTF (("Current ClipComplexity is : %d\n",pPDevice->ClipComplexity));
       DBPRINTF (("Number of Rectangles in clip : %d\n",pDDC->DCState.ClipComplexity));
       /*
       ** These cases fall through to the body of the function
       */
       break;

  default:
       GplErrSetError( (ERRORID) PMERR_INCORRECT_DC_TYPE );
       LeaveDriver( pDDC );
       return (GPI_ERROR);
  }

  /*
  ** Destination coordinates will be converted
  ** from world to device if the BBO_TARGWORLD is set in the usStyle.
  ** Hence, copy them from pXY to rclDst,
  ** so that the driver will sent back the points as it received.
  */
  rclDst.xLeft   = pXY[0].x;
  rclDst.yBottom = pXY[0].y;
  rclDst.xRight  = pXY[1].x;
  rclDst.yTop    = pXY[1].y;

  /*
  ** Convert the rclDst.
  */
  if (Options & BBO_TARGWORLD)
  {
    GreConvert( hDC, CVTC_WORLD, CVTC_DEVICE, (PPOINTL) &rclDst, 2L );
    rclDst.xRight += 1;
    rclDst.yTop += 1;
  }

  /*
  ** Compute the source and destination rectangles.
  */
  switch ((SHORT) Count)
  {
  case 2:
       /*
       ** If there are only two points, then there is only
       ** one rectangle so this must be a PATBLT
       ** except for ROP_DSTINVERT, ~ROP_DSTINVERT,
       ** ROP_ZERO and ROP_ONE.
       */

       if (Mix != ROP_DSTINVERT && Mix != (0x00FF & ~ROP_DSTINVERT) && Mix
           != ROP_ZERO && Mix != ROP_ONE)
       {
         Mix = ROP_PATCOPY;
       }
       break;

  case 3:
       if ((Mix == ROP_ZERO) || (Mix == ROP_ONE))
         break;
       /*
       ** With three points, the source rectangle is
       ** incomplete, so the driver assumes that its the
       ** same size as the destination rectangle.
       */
       rclSrc.xLeft = pXY[2].x;
       rclSrc.yBottom = pXY[2].y;
       rclSrc.xRight = rclSrc.xLeft + (rclDst.xRight - rclDst.xLeft);
       rclSrc.yTop = rclSrc.yBottom + (rclDst.yTop - rclDst.yBottom);
       break;

  case 4:
       if ((Mix == ROP_ZERO) || (Mix == ROP_ONE))
         break;
       /*
       ** With four points, there are two complete rectangle
       ** specifications.  Therefore, these two rectangles
       ** May be different sizes and a stretchblt will
       ** occur.
       */
       rclSrc.xLeft = pXY[2].x;
       rclSrc.yBottom = pXY[2].y;
       rclSrc.xRight = pXY[3].x;
       rclSrc.yTop = pXY[3].y;
       break;

  default:
       GplErrSetError( (ERRORID) PMERR_INV_BITMAP_DIMENSION );
       LeaveDriver( pDDC );
       return (0L);
  }

  if (Mix == ROP_DSTINVERT)           // 0x0055
  {
     DBPRINTF (("ROP_DSTINVERT\n"));
  }
  else if (Mix == (BYTE) (0x00FF & ~ROP_DSTINVERT))   // 0x00AA
  {
     DBPRINTF (("~ROP_DSTINVERT\n"));
  }
  else if (Mix == (BYTE)ROP_ZERO)
  {
     POINTL  ptlcurCP;
     DBPRINTF (("Doing ROP_ZERO \n"));
     /*
     **  Save the current logical Position
     **  filling with zero's means painting black??? hope so
     */
     GreGetCurrentPosition (hDC,&ptlOldCP);

     /*
     ** Setup current logical position to destination rectangle xleft and
     ** ybottom.
     */
     ptlcurCP.x = rclDst.xLeft;
     ptlcurCP.y = rclDst.yBottom;

     GreSetCurrentPosition (hDC,&ptlcurCP);

     /*
     ** Setup current logical position to destination rectangle xleft and
     ** ybottom.
     */

     pEnd.x = rclDst.xRight;
     pEnd.y = rclDst.yTop;

     if (pDDC->DCState.usColorFormat != LCOLF_RGB)
       ulColor = CLR_BLACK;
     else
       ulColor = COLOR_BLACK;

     /*
     ** Call draw_box to draw the rectangle with PATSYM_SOLID
     */
     draw_box(pDDC, &pEnd, ulColor, TRUE, PATSYM_SOLID);

     GreSetCurrentPosition (hDC,&ptlOldCP);

     LeaveDriver( pDDC );
     return(TRUE);
  }
  else if (Mix == (BYTE)ROP_ONE)
  {
     POINTL  ptlcurCP;

     DBPRINTF (("Doing ROP_ONE \n"));
     /*
     **  All one's is colour white.
     **  Save the current logical Position
     **  draw_box forces ulColor to CLR_WHITE or COLOR_WHITE when patsym is
     **  PATSYM_BLANK, to clear the area. If there is a change in draw_box then
     **  check the color format and set ulcolor to CLR_WHITE or COLOR_WHITE.
     **  Kran.
     */

     DBPRINTF (("rclDst.xLeft = %d\n",rclDst.xLeft));
     DBPRINTF (("rclDst.yBottom = %d\n",rclDst.yBottom));
     pEnd.x = rclDst.xRight;
     pEnd.y = rclDst.yTop;


     GreGetCurrentPosition (hDC,&ptlOldCP);

     /*
     ** Setup current logical position to destination rectangle xleft and
     ** ybottom.
     */
     ptlcurCP.x = rclDst.xLeft;
     ptlcurCP.y = rclDst.yBottom;

     GreSetCurrentPosition (hDC,&ptlcurCP);
     draw_box(pDDC, &pEnd, ulColor, TRUE, PATSYM_SOLID);
     GreSetCurrentPosition (hDC,&ptlOldCP);

     LeaveDriver( pDDC );
     return(TRUE);
  }
  else if ((Mix & 0x33) == ((Mix >> 2) & 0x33))  // pat no src
  {
  /* BEGIN OF ROP_PATCOPY */
     AREABUNDLE abnd;

     DBPRINTF (("Doing ROP_PATTERN \n"));

     /*
     **  Save the current logical Position
     */
     SavedPos = pDDC->DCState.LogPosition;

     /*
     **  (If it is a standard pattern) or (a user pattern and it is a PCL
     **  device then call boxinterior.
     */
     if ( !(pDDC->DCState.abnd.usSet) ||
           (fulOddCaps & OD_PCL) )
     {
       LONG    lColor;
       LONG    lBackColor;
       POINTL  ptlcurCP;

       /*
       ** Save the areabundle colors. We may be modifying these colors if
       ** BLTMODE_ATTRS_PRES. Using SaveDC and RestoreDC for this purpose is
       ** very expencive.
       */
       lColor = pDDC->DCState.abnd.lColor;
       lBackColor = pDDC->DCState.abnd.lBackColor;

       if (Options & BLTMODE_ATTRS_PRES)
       {
         switch (pAttrs->cSize)
         {
         case 12: pDDC->DCState.abnd.lBackColor = pAttrs->lBackColor;
         case  8: pDDC->DCState.abnd.lColor = pAttrs->lColor;
                  break;
         default: break;
         }
       }

       GreGetCurrentPosition(hDC, &ptlOldCP);  /* Save for later            */

       ptlcurCP.x = rclDst.xLeft;
       ptlcurCP.y = rclDst.yBottom;

       GreSetCurrentPosition(hDC, &ptlcurCP);

       aptl[0].x = rclDst.xRight;             /* cornerX, cornerY          */
       aptl[0].y = rclDst.yTop;
       aptl[1].x = aptl[1].y = 0L;            /* diamX, diamY = 0 => square*/
                                              /* corners                   */
       BoxInterior(hDC, aptl, pDDC, MAKEULONG(NGreBoxInterior,
                            HIUSHORT(FunN & ~COM_TRANSFORM)));

       GreSetCurrentPosition(hDC, &ptlOldCP);  /* Where we were            */

       /*
       ** Restore back the colors in areabundle.
       */
       pDDC->DCState.abnd.lColor = lColor;
       pDDC->DCState.abnd.lBackColor = lBackColor;

    }  /*  end of Standard pattern or PCL device  */
    else
    {
       /*
       ** It is a user pattern and the device is not a pcl device.
       */

       ULONG             ullcid;
       BITMAPINFOHEADER  bmi;
       HBITMAP           hbm;
       PBITMAPINFO       pbmi;
       PBYTE             pbScan;
       PBYTE             pBits;
       ULONG             nColors;
       ULONG             ulLinesScanned;
       ULONG             ulBytesPerScan;
       ULONG             ulScan;
       ULONG             GreyBytes;
       PXFORM            pNxform;
       PXFORM            pOxform;
       HBITMAP           hbmDst;
       PULONG            pbltXY;

       /*
       **  The user defined pattern is defined by a bitmap.
       **  The lcid get us the bitmap handle.
       **  Call getbitmapparametes to get the details of bitmap.
       **  We will then call GreGetBitmapBits to get the bits.
       */
       ullcid = pDDC->DCState.abnd.usSet;
       hbm = GreQueryBitmapHandle(hDC,ullcid);

       if(pDDC->lEngineVersion <= 0x220L) // This      is needed to workaround
       {                                  // the defect in GreQueryBitmapHandle
         hbm &= 0x0FFFFFFF;
         if(hbm > 0x04FFFFFF)
         {
           DBPRINTF (("Definitely a font."));
           assert(FALSE);
           return(TRUE);
         }
       }
       if (!hbm)
       {
         /* implement font */
         LeaveDriver( pDDC );
         return(TRUE);
       }

       /*
       **  Get bitmap size and parameters
       */
       if (!(GreGetBitmapParameters(hbm,&bmi)))
       {
         LeaveDriver( pDDC );
         return(FALSE);
       }

       set_transparency_mode(pDDC, 0);

       /*
       ** Check if you can blt the pattern using HPGL2 RF rasterfill command.
       ** if so then blt it and get out.
       ** Note we can use HPGL2 RF only for the following cases.
       ** HP Design Jet 600:
       ** The width and height of the pattern we define with RF should be
       ** powers of 2 and should not be greater than 64.
       ** PaintJet XL 300 using HPGL2:
       ** The width and height should be less than 256 and we can only output a
       ** Black and White Pattern. Index or Pen number > 0 will be mapped to
       ** Black. Ref: HP PCL 5 Reference Manual 20-41
       ** It seems it is better to stick to PCL for this device.
       ** PaintJet XL 300 using PCL: HP PCL 5 Color Printer Language 5-16 to 22
       ** 1. Specify the pattern ID Esc*c#G
       ** 2. Download the pattern Esc*c#W[data]
       ** 3. Define the rectangle to fill with the above pattern Esc*c#A#B
       ** 4. Fill the rectangle area. Esc*c4P
       */
       if ((bmi.cx == 8 || bmi.cx == 16 || bmi.cx == 32 || bmi.cx == 64) &&
           (bmi.cy == 8 || bmi.cy == 16 || bmi.cy == 32 || bmi.cy == 64))
       {
          ulRet = fill_pattern_use_device(hDC,pDDC,&bmi,&rclDst,hbm,pAttrs,Options);
          pDDC->DCState.LogPosition = SavedPos;
          set_transparency_mode(pDDC, 1);
          LeaveDriver( pDDC );
          return(ulRet);
       }

       hbmDst = hbm;
       GreSelectBitmap(pDDC->hdcMemory,hbmDst);

       /*
       ** Calculate the size of the bitmap and allocate memory.
       */
       ulBytesPerScan = ((bmi.cBitCount * bmi.cx + 31) >> 5) << 2;
       ulScan = bmi.cy;
       pbScan = GplMemoryAlloc(NULL,ulBytesPerScan * ulScan);

       if (bmi.cBitCount == 24)
         nColors = 0;
       else
         nColors = 2 << bmi.cBitCount - 1;

       pbmi = (PBITMAPINFO) GplMemoryAlloc(pDDC->pPDevice->hmcbHeap,
                                           (sizeof(BITMAPINFO) + 4 * nColors));

       pbmi->cbFix     = sizeof(BITMAPINFOHEADER);
       pbmi->cx        = bmi.cx;
       pbmi->cy        = bmi.cy;
       pbmi->cBitCount = bmi.cBitCount;
       pbmi->cPlanes   = bmi.cPlanes;

       ulLinesScanned = GreGetBitmapBits(pDDC->hdcMemory,hbmDst,0L,bmi.cy,pbScan,pbmi);
       if ((ulLinesScanned == -1) || (ulLinesScanned != bmi.cy))
       {
         if (GplMemoryFree ((PVOID)pbScan))
            pbScan = NULL;
         if (GplMemoryFree ((PVOID)pbmi))
            pbmi = (PBITMAPINFO)NULL;
         if (fulOddCaps & OD_PCL)
            GreSelectBitmap(pDDC->hdcMemory,NULL);
         LeaveDriver( pDDC );
         return(FALSE);
       }

       if (fulOddCaps & OD_COLOR)
       {
         GreyBytes = ulBytesPerScan;
         pBits = pbScan;
       }
       else
       {
         GreyBytes = ((pbmi->cx + 7) >> 5) << 2;
         pBits = GplMemoryAlloc(NULL,GreyBytes * ulScan);

         greyscalesourcebits(pBits,pbScan,&rclDst,ulBytesPerScan,ulScan,pbmi,pDDC);
       }

       if(bmi.cBitCount == 1)
       {
         ULONG  ulFrgColor;
         ULONG  ulBackColor;

         ulFrgColor = pDDC->DCState.abnd.lColor;
         ulBackColor = pDDC->DCState.abnd.lBackColor;

         if(pAttrs && (Options & BLTMODE_ATTRS_PRES))
         {
           switch (pAttrs->cSize)
           {
             case 12: ulBackColor = pAttrs->lBackColor; //Fall through
             case  8: ulFrgColor  = pAttrs->lColor;
                      break;
             default: break;
           }
         }

         ulFrgColor  = convert_color(pDDC,ulFrgColor);
         ulBackColor = convert_color(pDDC,ulBackColor);

         pbmi->argbColor[0].bBlue  = (BYTE)ulBackColor;
         pbmi->argbColor[0].bGreen = (BYTE)(ulBackColor >> 8);
         pbmi->argbColor[0].bRed   = (BYTE)(ulBackColor >> 16);

         pbmi->argbColor[1].bBlue  = (BYTE)ulFrgColor;
         pbmi->argbColor[1].bGreen = (BYTE)(ulFrgColor >> 8);
         pbmi->argbColor[1].bRed   = (BYTE)(ulFrgColor >> 16);
       }
       /*
       ** set up raster transfer
       */
       enter_PCL_or_HPRTL(pDDC, fulOddCaps);
       set_palette(pDDC, fulOddCaps,
                   pbmi->cBitCount,
                   (PRGB2)pbmi->argbColor,
                   COLOR_FORMAT_RGB);
       set_raster_width_and_height(pDDC,fulOddCaps,&rclSrc,&rclDst,FALSE);
       set_graphics_position(pDDC, fulOddCaps, &rclDst,0L,0L);
       /*
       **  Set Transparency mode. Opaque.
       */
       output_bytes(pDDC,"\033*v1N");
       begin_raster_graphics(pDDC, fulOddCaps, FALSE);

       fill_pattern(pDDC,pBits,pbmi,GreyBytes,ulScan,rclDst);

       /*
       ** end raster transfer
       */
       end_raster_graphics(pDDC, fulOddCaps);
       return_to_HPGL2(pDDC, fulOddCaps);
       set_transparency_mode(pDDC, 1);

       GreSelectBitmap(pDDC->hdcMemory,NULL);
       GreDeleteBitmap(hbmDst);
       if(!(fulOddCaps & OD_COLOR))
         GplMemoryFree ((PVOID)pBits);
       GplMemoryFree ((PVOID)pbmi);
       GplMemoryFree ((PVOID)pbScan);
    }
  } /* END OF ROP_PATCOPY */
  else    // All Others
  {
    if (Mix != ROP_SRCCOPY)
    {
       DBPRINTF (("Mix is : %d\n",Mix));
    }
    set_transparency_mode(pDDC, 0);
    ulRet = drawimage( pDDC, hDC, hdcSrc, Options, &rclDst,
                         &rclSrc, pAttrs, Mix, FunN);
    DBPRINTF (("Return code from DrawImage : %d\n",ulRet));
    set_transparency_mode(pDDC, 1);
    LeaveDriver( pDDC );
    return ulRet;
  }
  if (pPDevice->ulCurrentPrintMode == HPGL2)
    set_transparency_mode(pDDC, 1);
  LeaveDriver( pDDC );
  return  GPI_OK;
}
////////////////////////////////////
#define OPENED_MEMORY_DC  1
#define BITMAP_SELECTED   2

LONG Bitblt2(HDC hDC,HDC hdcSrc,LONG Count,PPOINTL pXY,ULONG Mix,
            ULONG Options,PBITBLTATTRS pAttrs,PDDC pDDC,ULONG FunN)
{
  LONG                 lReturn       = GPI_OK;
  PPDEVICE             pPDevice      = pDDC->pPDevice;
  PDEVICESURFACE       pDS           = pDDC->pDeviceSurface;
  ULONG                Plotter       = pPDevice->Plotter;
  ULONG                fulOddCaps    = PlotterClass[Plotter].fsOdd;
  USHORT               usDCType      = pDDC->usDCType;
  USHORT               usMix         = LOUSHORT(Mix);
  BOOL                 fScale        = FALSE;
  BOOL                 fCompress     = FALSE;
  PBYTE                pbScan        = (PBYTE)NULL;
  PBITMAPINFO2         pbmiColor     = (PBITMAPINFO2)NULL;
  PBITMAPINFOHEADER2   pbmi          = (PBITMAPINFOHEADER2)NULL;
  ULONG                ulModeFlags;
  HBITMAP              hbmSrc;
  ULONG                fulCallEngine;
  RECTL                rectlSrc,rectlDest;
  LONG                 lSrcWidth,lSrcHeight;
  LONG                 lDstWidth,lDstHeight;
  ULONG                ulBytesPerScan;
  BOOL                 fNeedsSource;
  ULONG                ulLinesScanned;
  LONG                 nBitsPerSample;
  LONG                 nColors;
  ULONG                ulUndo = 0L;


  if (EnterDriver(pDDC) == 0)
      return(GPI_ERROR);

  assert(pDDC->lEngineVersion >= RASTER_ENGINE_22);

  if (pDDC->bJournalPlayed)
      return (lReturn);

  /*
  ** return OK if DRAW bit not set or dc is a od_info or
  ** the dc is queued and datatype is standard.
  */
  if ( !(FunN&COM_DRAW) || (usDCType == OD_INFO) ||
       ((usDCType == OD_QUEUED) && (pPDevice->DataType == PM_Q_STD)) )
  {
    LeaveDriver( pDDC );
    return (lReturn);
  }

  fNeedsSource = ((usMix & 0x33) != ((usMix & 0xCC) >> 2));

  if (fNeedsSource)
  {
    /*
    ** Destination coordinates will be converted
    ** from world to device if the BBO_TARGWORLD is set in the usStyle.
    ** Hence, copy them from pXY to rclDst,
    ** so that the driver will sent back the points as it received.
    */
    rectlDest.xLeft   = pXY[0].x;
    rectlDest.yBottom = pXY[0].y;
    rectlDest.xRight  = pXY[1].x;
    rectlDest.yTop    = pXY[1].y;

    /*
    ** Convert the rclDst.
    */
    if (Options & BBO_TARGWORLD)
    {
      GreConvert( hDC, CVTC_WORLD, CVTC_DEVICE, (PPOINTL) &rectlDest, 2L );
      rectlDest.xRight += 1;
      rectlDest.yTop += 1;
    }

    rectlSrc.xLeft   = pXY[2].x;
    rectlSrc.yBottom = pXY[2].y;
    if (Count == 3)
    {
      rectlSrc.xRight = rectlSrc.xLeft + (rectlDest.xRight - rectlDest.xLeft);
      rectlSrc.yTop   = rectlSrc.yBottom + (rectlDest.yTop - rectlDest.yBottom);
    }
    else
    {
      rectlSrc.xRight = pXY[3].x;
      rectlSrc.yTop   = pXY[3].y;
    }
    lSrcWidth  = rectlSrc.xRight - rectlSrc.xLeft;
    lSrcHeight = rectlSrc.yTop - rectlSrc.yBottom;
    lDstWidth  = rectlDest.xRight - rectlDest.xLeft;
    lDstHeight = rectlDest.yTop - rectlDest.yBottom;

    fScale = lDstWidth > lSrcWidth  || lDstHeight > lSrcHeight;
    fCompress = lSrcWidth > lDstWidth || lSrcHeight > lDstHeight;
  }


  fulCallEngine = ( ( (usDCType == OD_MEMORY)               || //if mem dc
                      (pDDC->DCState.ClipComplexity > 1)    || //if complex clipping
                      (!(fulOddCaps & OD_PCL))              || //if !pcl device
                      (!(fulOddCaps & OD_COLOR))            || //if !color device
                      (!fNeedsSource)                       || //if not src copy
                      (Count < 3) )                         || //if rop involves only dest
                      (fCompress)                           || //if needs compression
                      (!fScale)                             ?  //if no stretch
                      TRUE : FALSE );

  if (fulCallEngine)
  {
    lReturn = (*daBitblt)(hDC,hdcSrc,Count,pXY,Mix,Options,pAttrs,pDDC,FunN | COM_DEVICE);
    LeaveDriver( pDDC );
    return (lReturn);
  }

  pbmi = GplMemoryAlloc(pPDevice->hmcbHeap, sizeof(BITMAPINFOHEADER2));
  if (pbmi)
  {
    pbmi->cbFix = sizeof(BITMAPINFOHEADER2);
  }
  else
  {
    GplErrSetError( (ERRORID)PMERR_INSUFFICIENT_MEMORY );
    lReturn = GPI_ERROR;
    goto depart;
  }

  if (hdcSrc)
  {
     if (Options & BLTMODE_SRC_BITMAP)
     {
       if (GreGetBitmapInfoHeader(hdcSrc,pbmi))
       {
         ULONG  ulRet;
         hbmSrc = (HBITMAP)hdcSrc;
         hdcSrc = hDC;

         ulRet = (HBITMAP) GetDriverInfo( (HBITMAP) hdcSrc, 1L, hDC);

         if( ulRet == (ULONG)GPI_ALTERROR )
         //Bitmap is not our DC compatible
         {
           hdcSrc = GreOpenDC(hDC, OD_MEMORY, "*", 0L, (PVOID)NULL);
           ulUndo |= OPENED_MEMORY_DC;
           GreSelectBitmap(hdcSrc, hbmSrc);
           ulUndo |= BITMAP_SELECTED;
         }
       }
       else
       {
         lReturn = GPI_ERROR;
         goto depart;
       }
     }
     else  // Source is a DC. Bump out the bitmap handle.
     {
        hbmSrc = GreSelectBitmap(hdcSrc,NULL);
        if(GreGetBitmapInfoHeader(hbmSrc,pbmi))
        {
          GreSelectBitmap(hdcSrc,hbmSrc);
        }
        else
        {
          lReturn = GPI_ERROR;
          goto depart;
        }
     }
  }

  nBitsPerSample = pbmi->cBitCount;
  if (nBitsPerSample == 24)
    nColors = 0L;
  else
    nColors = 2 << (nBitsPerSample -1);

  pbmiColor = GplMemoryAlloc(pPDevice->hmcbHeap,
                sizeof(BITMAPINFO2) + sizeof(ULONG) * nColors);
  if (!pbmiColor)
  {
     GplErrSetError( (ERRORID)PMERR_INSUFFICIENT_MEMORY );
     lReturn = GPI_ERROR;
     goto depart;
  }
  else
  {
    *(PBITMAPINFOHEADER2)pbmiColor = *pbmi;
  }

  /*
  ** Find the number of bytes per scan line.
  ** The lines are in 32 bit boundary.
  */

  ulBytesPerScan = ((nBitsPerSample * pbmi->cx + 31) >> 5) << 2;

  /*
  ** Allocate memory for the entire bitmap (no of bytes per scanline * no of
  ** scan lines in bitmap).
  */
  if (!(pbScan = GplMemoryAlloc(NULL, ulBytesPerScan * lSrcHeight)))
  {
    GplErrSetError( (ERRORID)PMERR_INSUFFICIENT_MEMORY );
    lReturn = GPI_ERROR;
    goto depart;
  }

  /*
  **  Get all the bits into pbScan.
  */
  ulLinesScanned = (ULONG) GreGetBitmapBits (hdcSrc, hbmSrc,
                                              rectlSrc.yBottom,
                                              lSrcHeight, pbScan,
                                             (PBITMAPINFO2)pbmiColor);
  assert(ulLinesScanned == lSrcHeight);
  if (ulLinesScanned != lSrcHeight)
  {
    DBPRINTF(("Number of scans retruned by getbitmapbits is not right"));
    lReturn = GPI_ERROR;
    goto depart;
  }

  /*
  ** If the bitmap is monochrome
  */
  if(nBitsPerSample == 1)
  {
    ULONG  ulFrgColor;
    ULONG  ulBackColor;

    /*
    ** The pm specification says to use image foreground and back ground
    ** colors if the BLTMODE_ATTRS are not present.
    */
    ulFrgColor  = pDDC->DCState.ibnd.lColor;
    ulBackColor = pDDC->DCState.ibnd.lBackColor;

    /*
    ** If the Attributes are present then use them
    */
    if (Options & BLTMODE_ATTRS_PRES)
    {
      switch (pAttrs->cSize)
      {
      case 12: ulBackColor = pAttrs->lBackColor;
      case 8:  ulFrgColor  = pAttrs->lColor;
               break;
      default: DBPRINTF(("Ooops we did't get the attrs"));
               break;
      }
    }
    ulFrgColor = convert_color(pDDC,ulFrgColor);
    ulBackColor = convert_color(pDDC,ulBackColor);

    /*
    ** Set the background color into pbmi
    */
    pbmiColor->argbColor[0].bBlue  = (BYTE)ulBackColor;
    pbmiColor->argbColor[0].bGreen = (BYTE)(ulBackColor >> 8);
    pbmiColor->argbColor[0].bRed   = (BYTE)(ulBackColor >> 16);

    /*
    ** Set the foreground color into pbmi
    */
    pbmiColor->argbColor[1].bBlue = (BYTE)ulFrgColor;
    pbmiColor->argbColor[1].bGreen = (BYTE)(ulFrgColor >> 8);
    pbmiColor->argbColor[1].bRed   = (BYTE)(ulFrgColor >> 16);

  }

  if (pPDevice->ulCurrentPrintMode == HPGL2)
  {
    /*
    ** Set the Mix Mode or ROP in the device with the MC(Merge Control)
    ** command.
    ** For now we will perserve the current ROP and restore
    ** it. We should remove the restore code when every function
    ** is correctly setting the MC.
    ** Also set the transparency mode off. Reset it to ON when leaving.
    */
    set_transparency_mode(pDDC, 0);
    pPDevice->usPreviousMCROP = pPDevice->usCurrentMCROP;
    set_mix_mode(pDDC, 0, 0, (USHORT)(Mix & 0xFF));
  }

  ulModeFlags = DS_BOTTOMTOP;

  /*
  ** set up the raster transfer
  */
  enter_PCL_or_HPRTL(pDDC, fulOddCaps);
  set_palette(pDDC, fulOddCaps, pbmiColor->cBitCount,
              (PRGB2)pbmiColor->argbColor, COLOR_FORMAT_RGB2);
  set_raster_width_and_height(pDDC,fulOddCaps,&rectlSrc,&rectlDest,fScale);
  set_graphics_position(pDDC, fulOddCaps, &rectlDest,0L,ulModeFlags);
  begin_raster_graphics(pDDC, fulOddCaps, fScale);

  /*
  **  Simply outputs the necessary output commands and then the bits in pBits.
  */
  image_scan (pDDC, pbScan, ulBytesPerScan, lSrcHeight, fulOddCaps,
              nBitsPerSample, pbmi->cx, Mix, 0L, ulModeFlags,0L);
  /*
  **  We are merging the vector and Raster Graphics, Then we have
  **  to end the RasterGraphics and Enter the HPGL-2 mode.
  */
  end_raster_graphics(pDDC, fulOddCaps);
  return_to_HPGL2(pDDC, fulOddCaps);
  lReturn = GPI_OK;
depart:
  if (pbmi)
    GplMemoryFree(pbmi);
  if (pbmiColor)
    GplMemoryFree(pbmiColor);
  if (pbScan)
    GplMemoryFree(pbScan);
  if (ulUndo & BITMAP_SELECTED)
     GreSelectBitmap(hdcSrc,NULL);
  if (ulUndo & OPENED_MEMORY_DC)
     GreCloseDC(hdcSrc);
  return(lReturn);

}
////////////////////////////////////
/***************************************************************************
 *
 * FUNCTION NAME = DeviceCreateBitmap()
 *
 * DESCRIPTION   = Create Plotter Driver Bit map
 *                 This function is called to create a bitmap of the
 *                 specified form and to obtain its handle.
 *
 *
 *
 *
 * INPUT         = HDC hDC;
 *                 PULONG pInfoHdr;
 *                 ULONG Usage;
 *                 PULONG pBits;
 *                 PULONG pInitInfo;
 *                 PDDC pDDC;
 *                 ULONG FunN;
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0L
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

HBITMAP DeviceCreateBitmap(HDC hDC,PULONG pInfoHdr,ULONG Usage,
                                   PULONG pBits,PULONG pInitInfo,PDDC pDDC
                                         ,ULONG FunN)
{
  ULONG ulRet;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);

  /*
  **      Create the bitmap in the Shadow Memory DC in Display
  */
  ulRet = InnerGreCreateBitmap (pDDC->hdcMemory, pInfoHdr, Usage,
                                pBits, pInitInfo, FunN);

  // GplErrSetError(PMERR_DEV_FUNC_NOT_INSTALLED);
  LeaveDriver(pDDC);
  return (ulRet);
}

/***************************************************************************
 *
 * FUNCTION NAME = DeviceDeleteBitmap()
 *
 * DESCRIPTION   = Delete plotter driver bit map
 *                 This function is called to destroy a specified
 *                 bitmap created by DeviceCreateBitmap.
 *
 *
 *
 *
 * INPUT         = HDC hDC;
 *                 HBITMAP hBitmap
 *                 PULONG pReturns
 *                 ULONG Usage;
 *                 PDDC pDDC;
 *                 ULONG FunN;
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0L
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

LONG DeviceDeleteBitmap (ULONG hdc, HBITMAP hbm,
                               PULONG pReturns,
                               ULONG flOptions, PDDC pDDC, ULONG ulFunN)
{
  ULONG ulReturn = FALSE ;

  /*
  ** GRE will not pass a VALID HDC and PDDC.
  ** EnterDriver(pddc);
  */

  if (flOptions & CBM_INIT)
  {
     BITMAPINFOHEADER bmi;
     PBITMAPINFOHEADER2 pInfo ;
     ULONG ulSize ;
     ULONG pBits ;
     HDC hdcMemory ;

     /*
     ** Determine the bitmap format
     */
     bmi.cbFix = sizeof(BITMAPINFOHEADER) ;
     if (!GreGetBitmapParameters (hbm, &bmi))
     {
        return (0L) ;
     }

      if (bmi.cBitCount == 24)
     {
         ulSize = 0;
     }
     else
     {
         ulSize = sizeof(RGB2) * (1 << bmi.cBitCount) ;
     }
     /**************************************************************/
     /* Allocate memory for bitmap info table. return error if     */
     /* allocation fails.                                          */
     /**************************************************************/
     /**************************************************************/
     /* we don't want to setup a full BITMAPINFO2 structure        */
     /* all we want is the first 5 fields                          */
     /*      ULONG    cbFix                                        */
     /*      ULONG    cx,cy                                        */
     /*      USHORT   cPlanes,cBitCount                            */
     /* This comes to a total of 16 bytes                          */
     /**************************************************************/
     #define BITMAPINFOUSEDPART 16
     if (SSAllocMem (&pInfo, BITMAPINFOUSEDPART + ulSize, 0L))
        return (0L) ;

     /**************************************************************/
     /* Fill in the parameters in BITMAPINFO structure             */
     /**************************************************************/
     pInfo->cbFix     = BITMAPINFOUSEDPART ;
     pInfo->cx        = bmi.cx ;
     pInfo->cy        = bmi.cy ;
     pInfo->cPlanes   = bmi.cPlanes ;
     pInfo->cBitCount = bmi.cBitCount ;

     /**************************************************************/
     /* Calculate memory required for the bits and allocate it.    */
     /**************************************************************/
     ulSize = (((bmi.cx * bmi.cBitCount + 31) >> 5) << 2) * bmi.cy ;
     if (SSAllocMem (&pBits, ulSize, 0L))
     {
        SSFreeMem (pInfo) ;
        return (FALSE) ;
     }


     // Open a memory DC in the display and select the bitmap into it
     // if we are on the old GRE.
     // Open a memory DC to ourselves if we are on the new gre.
     // no pDDC ??????
     if ((hdcMemory =
     //     GreOpenDC((HDC)(pDDC->lEngineVersion >= RASTER_ENGINE_22)?hdc:NULL),
            GreOpenDC((HDC)NULL, OD_MEMORY,"*", 0L, (PDEVOPENDATA) NULL)))
     {

       // Select the bitmap.
       if (GreSelectBitmap (hdcMemory, hbm) != HBM_ERROR)
       {

         // Get the bits from the bitmap.
         if (GreGetBitmapBits (hdcMemory, hbm, 0, bmi.cy, pBits, pInfo) ==
                                                                    bmi.cy)

         {
            ulReturn = TRUE ;

         }

         GreSelectBitmap (hdcMemory, (HBITMAP) NULL) ;
       }


       GreCloseDC (hdcMemory) ;
     }


     if (ulReturn && !InnerGreDeleteBitmap(hbm, ulFunN))
     {
        SSFreeMem ((PVOID)pInfo) ;
        SSFreeMem ((PVOID)pBits) ;
        return (FALSE) ;
     }

     /**************************************************************/
     /* Set the returned BITMAPINFO structure pointer              */
     /**************************************************************/
     ((PDELETERETURN)pReturns)->pInfo = (ULONG)pInfo ;
     ((PDELETERETURN)pReturns)->pBits = (ULONG)pBits ;

     // GRE will free the pInfo and pBits !!!

     return (TRUE) ;

  }
  else
     ulReturn = InnerGreDeleteBitmap(hbm, ulFunN);

  return (ulReturn);
}

/***************************************************************************
 *
 * FUNCTION NAME = DeviceSelectBitmap()
 *
 * DESCRIPTION   = Select plotter driver bit map
 *                 This function tells the device driver that a new
 *                 bitmap is being selected into the given DC.
 *
 *
 *
 *
 * INPUT         = HDC hDC;
 *                 HBITMAP hBitmap;
 *                 PDDC pDDC;
 *                 ULONG FunN;
 *
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0L
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

LONG DeviceSelectBitmap (HDC hdc, ULONG hbm, PDDC pDDC, ULONG ulFunN)
{
  ULONG ulRet;

  if(!EnterDriver(pDDC))
      return(GPI_ERROR);

  ulRet = InnerGreSelectBitmap (pDDC->hdcMemory, hbm, ulFunN);

  if (ulRet == HBM_ERROR)
  {
    ulRet = FALSE;
  }
  else
  {
    ulRet = TRUE;
  }
  LeaveDriver (pDDC);
  return (ulRet);
}

/***************************************************************************
 *
 * FUNCTION NAME = DeviceSetCursor()
 *
 * DESCRIPTION   = Set cursor bitmap
 *                 This function sets the cursor bitmap that defines
 *                 the cursor shape.  It This function sets the cursor
 *                 bitmap that defines the cursor shape.  It goes
 *                 without saying that I will fire back an error real
 *                 quick on this goes without saying that I will fire
 *                 back an error real quick on this one!  one!
 *
 *
 *
 *
 * INPUT         =  HDC hDC;
 *                  PPOINTL pPts;
 *                  HBITMAP hBitmap;
 *                  PDDC pDDC;
 *                  ULONG FunN;
 *
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BOOL DeviceSetCursor(HDC hDC,PPOINTL pPts,HBITMAP hBitmap,PDDC pDDC
                                 ,ULONG FunN)
{
  GplErrSetError(PMERR_DEV_FUNC_NOT_INSTALLED);
  return (0);
}

/***************************************************************************
 *
 * FUNCTION NAME =  DrawBorder()
 *
 * DESCRIPTION   =  Draw border inside a rectangle
 *                  This function draws a border inside a rectangle
 *                  and optionally fills the interior.  This is a
 *                  Bitblt accelerator, and as such, I will return an
 *                  error.
 *
 *
 *
 * INPUT         =  HDC hDC;
 *                  PRECTL pRect;
 *                  ULONG xWidth;
 *                  ULONG yWidth;
 *                  LONG BordCol;
 *                  LONG IntCol;
 *                  ULONG Options;
 *                  PDDC pDDC;
 *                  ULONG FunN;
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BOOL DrawBorder(HDC hDC,PRECTL pRect,ULONG xWidth,ULONG yWidth,LONG
                            BordCol,LONG IntCol,ULONG Options,PDDC pDDC,ULONG
                            FunN)
{
  ULONG ulRet;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    ulRet = InnerGreDrawBorder (pDDC->hdcMemory, pRect, xWidth, yWidth,
                                BordCol, IntCol, Options, FunN);
    LeaveDriver( pDDC );
    return( ulRet );
  }
  GplErrSetError(PMERR_DEV_FUNC_NOT_INSTALLED);
  return (0);
}

/***************************************************************************
 *
 * FUNCTION NAME =   GetBitmapBits()
 *
 * DESCRIPTION   =  Get bit map data
 *                  This transfers bitmap data from the specified DC to
 *                  application storage.  The DC must be a memory hDC,
 *                  with a bitmap currently selected.
 *
 *
 *
 *
 *
 *
 *
 *
 *
 * INPUT         = HDC hDC;
 *                 HBITMAP hBM;
 *                 LONG ScanStart;
 *                 LONG ScanCount;
 *                 PBYTE pBits;
 *                 PBYTE pInfo;
 *                 PDDC pDDC;
 *                 ULONG FunN;
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = -1L
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

LONG GetBitmapBits (HDC hdc,HBITMAP hbm, LONG iyOrg, LONG nyExt,
                         PBYTE pbBits, PBYTE pbInfo, PDDC pddc, ULONG ulFunN)
{
  ULONG ulRet;

  if (!EnterDriver(pddc))
      return(GPI_ERROR);

  if (hbm)
  {
     HBITMAP hbmDisplay ;

     // Get the bitmap handle of our shadow memory DC.
     hbmDisplay = GetDriverInfo (hbm, 1, hdc) ;

     if (hbmDisplay != GPI_ALTERROR)
     {
        ulRet = InnerGreGetBitmapBits (pddc->hdcMemory, hbmDisplay,
                                       iyOrg, nyExt,
                                       pbBits, pbInfo, ulFunN);
     }
     else
     {
        ulRet = GPI_ALTERROR ;
     }
  }
  else
  {
     ulRet = InnerGreGetBitmapBits (pddc->hdcMemory, hbm, iyOrg, nyExt,
                                    pbBits, pbInfo, ulFunN);
  }

  LeaveDriver (pddc);

  return (ulRet);
}

/***************************************************************************
 *
 * FUNCTION NAME = GetPel()
 *
 * DESCRIPTION   =  Get Pel from coordinates specified
 *                  This function gets a pel from a position specified in
 *                  world coordinates.  This function returns -1 for error,
 *                  otherwise it returns the color table index value for
 *                  the pel.
 *
 *
 *
 *
 *
 * INPUT         = HDC hDC;
 *                 PPOINTL pXY;
 *                 PDDC pDDC;
 *                 ULONG FunN;
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = -1L
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

LONG GetPel(HDC hDC,PPOINTL pXY,PDDC pDDC,ULONG FunN)
{
  ULONG ulRet;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    ulRet = InnerGreGetPel (pDDC->hdcMemory, pXY, FunN);
    LeaveDriver( pDDC );
    return( ulRet );
  }
  GplErrSetError(PMERR_DEV_FUNC_NOT_INSTALLED);
  LeaveDriver(pDDC);
  return (-1L);
}

/***************************************************************************
 *
 * FUNCTION NAME =  ImageData()
 *
 * DESCRIPTION   =  This function draws a row of image data.
 *
 *
 *
 *
 *
 *
 * INPUT         =  HDC hDC;
 *                  PBYTE pData;
 *                  LONG Count;
 *                  LONG Row;
 *                  PDDC pDDC;
 *                  ULONG FunN;
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0L
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

LONG ImageData(HDC hDC,PBYTE pData,LONG Count,LONG Row,PDDC pDDC,
                           ULONG FunN)
{
  ULONG ulRet;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    ulRet = InnerGreImageData (pDDC->hdcMemory , pData, Count, Row, FunN );
    LeaveDriver( pDDC );
    return( ulRet );
  }

  GplErrSetError(PMERR_DEV_FUNC_NOT_INSTALLED);
  LeaveDriver(pDDC);
  return (0L);
}



/***************************************************************************
 *
 * FUNCTION NAME = RestoreScreenBits()
 *
 * DESCRIPTION   = Restore screen bits
 *                 This function restores a rectangle of bits saved by
 *                 SaveScreenBits.  Since I am not in the habit of having
 *                 a screen, this too is an error.
 *
 *
 *
 *
 * INPUT         =  HDC hDC;
 *                  ULONG hBits;
 *                  PRECTL pRect;
 *                  ULONG Flags;
 *                  PDDC pDDC;
 *                  ULONG FunN;
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

BOOL RestoreScreenBits(HDC hDC,ULONG hBits,PRECTL pRect,ULONG Flags
                                   ,PDDC pDDC,ULONG FunN)
{
  GplErrSetError(PMERR_DEV_FUNC_NOT_INSTALLED);
  return (0);
}

/***************************************************************************
 *
 * FUNCTION NAME =  SaveScreenBits()
 *
 * DESCRIPTION   =  Save plotter driver screen bits
 *                  This function saves a rectangle of bits from the
 *                  screen.  The plotter driver returns error.
 *
 *
 *
 *
 *
 * INPUT         =  HDC hDC;
 *                  PRECTL pRect;
 *                  PDDC pDDC;
 *                  ULONG FunN;
 *
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0L
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

LONG SaveScreenBits(HDC hDC,PRECTL pRect,PDDC pDDC,ULONG FunN)
{
  GplErrSetError(PMERR_DEV_FUNC_NOT_INSTALLED);
  return (0L);
}

/***************************************************************************
 *
 * FUNCTION NAME =   SetBitmapBits
 *
 * DESCRIPTION   =   Set plotter driver bit map
 *               =   This transfers bitmap data from application
 *                   storage to the specfied DC.  The DC must be a
 *                   memory hDC, with a bitmap currently selected.
 *
 *
 *
 *
 * INPUT         =   HDC hDC;
 *                   HBITMAP hBM;
 *                   LONG ScanStart;
 *                   LONG ScanCount;
 *                   PBYTE pBits;
 *                   PBYTE pInfo;
 *                   PDDC pDDC;
 *                   ULONG FunN;
 *
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = -1L
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

LONG SetBitmapBits (HDC hdc, HBITMAP hbm, LONG iyOrg, LONG nyExt,
                          PBYTE pbBits, PBYTE pbInfo, PDDC pddc, ULONG ulFunN)
{
  ULONG ulRet;

  if (!EnterDriver(pddc))
      return(GPI_ERROR);

  if (hbm)
  {
    HBITMAP hbmDisplay ;

    /*
    ** Get the bitmap handle of our shadow memory DC.
    */
    hbmDisplay = GetDriverInfo (hbm, 1, hdc);

    if (hbmDisplay != GPI_ALTERROR)
    {
      ulRet = InnerGreSetBitmapBits (pddc->hdcMemory, hbmDisplay, iyOrg, nyExt,
                                     pbBits, pbInfo, ulFunN);
    }
    else
    {
      ulRet = GPI_ALTERROR;
    }
  }
  else
  {
    ulRet = GreSetBitmapBits (pddc->hdcMemory, hbm, iyOrg, nyExt,
                              pbBits, pbInfo);
  }

  LeaveDriver (pddc);
  return (ulRet);
}

/***************************************************************************
 *
 * FUNCTION NAME = SetPel
 *
 * DESCRIPTION   = Set pel from coordinates
 *               = This function sets a pel from a position specified in
 *                 world coordinates.  The plotters driver simply
 *                 returns ok for this function
 *
 *
 * INPUT         = HDC hDC;
 *                 PPOINTL pXY;
 *                 PDDC pDDC;
 *                 ULONG FunN;
 *
 *
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = 0L
 * RETURN-ERROR  = NONE
 *
 ****************************************************************************/

LONG SetPel(HDC hDC,PPOINTL pXY,PDDC pDDC,ULONG FunN)
{
  ULONG ulRet;

  if (!EnterDriver(pDDC))
      return(GPI_ERROR);

  /*
  **          In case of MEMORYDC Dispatch to Graphics Engine
  */
  if (pDDC->usDCType == OD_MEMORY)
  {
    ulRet = GreSetPel( pDDC->hdcMemory, pXY );
    LeaveDriver( pDDC );
    return( ulRet );
  }
  GplErrSetError(PMERR_DEV_FUNC_NOT_INSTALLED);
  LeaveDriver(pDDC);
  return (0L);
}

/***************************************************************************
 *
 * FUNCTION NAME = enter_PCL_or_HPRTL
 *
 * DESCRIPTION   = Function sends the necessary commands to get the plotter
 *                 into PCL or HPRTL mode. This is necessary to setup
 *                 the device for a raster transfer.
 *
 * INPUT         = PDDC  pDDC       - pointer to device driver context
 *                 ULONG fulOddCaps - odd capabilities flag the bits
 *                                    tell us if this is a PCL for HPRTL
 *                                    device.
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 **************************************************************************/

LOCAL BOOL  enter_PCL_or_HPRTL(PDDC pDDC, ULONG fulOddCaps)
{
  PPDEVICE pPDevice = pDDC->pPDevice;

  if (fulOddCaps & (OD_PCL | OD_HPRTL))
  {
    /*
    **  We are merging the vector and Raster Graphics, we must
    **  enter the appropriate mode before sending any raster commands
    */
    if (pPDevice->ulCurrentPrintMode == HPGL2)
    {
      check_line_construction(pDDC);
      if (fulOddCaps & OD_PCL)
      {
        output_bytes(pDDC,"\033%0A");// see HPRTL use previous PCL pos
        //output_bytes(pDDC,"\033%1A");  // enter HPRTL mode,use HPGL-2 Pen Pos
        //Set the resolution
        output_bytes(pDDC,"\033*t"); // pclBTTB
        output_number(pDDC,MAX(pPDevice->lRes_XPelsPerInch,
                               pPDevice->lRes_YPelsPerInch));
        output_bytes(pDDC,"R"); // pclBTTB
        pPDevice->ulCurrentPrintMode = PCL;
      }
      else /* HPGL */
      {
        output_bytes(pDDC,"\033%1A");  // enter HPRTL mode,use HPGL-2 Pen Pos
        pPDevice->ulCurrentPrintMode = HPRTL;
      }
    }
  }
  return (TRUE);
}

/***************************************************************************
 *
 * FUNCTION NAME = return_to_HPGL2
 *
 * DESCRIPTION   = Function sends the necessary commands to get the plotter
 *                 back into HPGL mode from raster mode. Note: Raster Mode
 *                 may either be PCL or RTL
 *
 * INPUT         = PDDC  pDDC      - pointer to device driver context
 *                 ULONG ulOddCaps - odd capabilities flag the bits
 *                                   tell us if this is a PCL for HPRTL
 *                                   device.
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 **************************************************************************/

LOCAL BOOL  return_to_HPGL2(PDDC pDDC, ULONG fulOddCaps)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  if (fulOddCaps & (OD_PCL | OD_HPRTL))
  {
    /*
    **  Say we are merging the vector and Raster Graphics, Then we have
    **  to end the RasterGraphics mode  and Enter the HPGL-2 mode.
    **  "\033%0B" gets us the previous HPGL-2 current pen position and palette.
    */
    if (fulOddCaps & OD_PCL)                // PCL
    {
      if (pPDevice->bHPGL2_PalettePushed)
      {
        output_bytes (pDDC,"\033*p1P");     // POP HPGL2 Palette
        pPDevice->bHPGL2_PalettePushed = FALSE;
      }
      output_bytes(pDDC,"\033%0B");         // go to HPGL2 use HPGL palette and
                                            // position
    }
    else                                    // HPGL
    {
      if (pPDevice->bHPGL2_PalettePushed)
      {
        output_bytes (pDDC,"\033*p1P");     // POP HPGL2 Palette
        pPDevice->bHPGL2_PalettePushed = FALSE;
      }
      output_bytes(pDDC,"\033%0B");         // go to HPGL2 use HPGL palette and
                                            // position
    }

    pPDevice->ulCurrentPrintMode = HPGL2;
  }
  return (TRUE);
}

/***************************************************************************
 *
 * FUNCTION NAME = set_graphics_position
 *
 * DESCRIPTION   = Function sends the necessary commands to set the position
 *                 while in PCL or HPRTL mode
 *
 * INPUT         = PDDC  pDDC      - pointer to device driver context
 *                 ULONG ulOddCaps - odd capabilities flag the bits
 *                                   tell us if this is a PCL for HPRTL
 *                                   device.
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 **************************************************************************/

LOCAL BOOL  set_graphics_position(PDDC pDDC, ULONG fulOddCaps, PRECTL prclDst,ULONG ulROPType,ULONG ulModeFlags)
{
  PPDEVICE pPDevice = pDDC->pPDevice;
  POINTL   pPtl;
  #define ROP_INCL_SRC 0x01

  if (fulOddCaps & (OD_PCL | OD_HPRTL))
  {
    if (fulOddCaps & OD_PCL)                // PCL
    {
      pPtl.x = prclDst->xLeft;
      if (pDDC->lEngineVersion < RASTER_ENGINE_22 || ulModeFlags & DS_BOTTOMTOP)
        pPtl.y = pPDevice->lCapsHeight - prclDst->yTop;
      else
        pPtl.y = prclDst->yTop;
    }
    else                                    // RTL
    {
      if (pPDevice->fsTransform & DXF_PORTRAIT)
      {
         if (pDDC->lEngineVersion < RASTER_ENGINE_22)
         {
           pPtl.x = pPDevice->lCapsWidth - prclDst->xRight;
           pPtl.y = prclDst->yBottom;
         }
         else
         {
           pPtl.x = pPDevice->lCapsWidth - prclDst->xRight;
           pPtl.y = pPDevice->lCapsHeight - prclDst->yTop;
         }
      }
      else
      {
         if (pDDC->lEngineVersion < RASTER_ENGINE_22)
         {
             pPtl.x = prclDst->yBottom;
             pPtl.y = prclDst->xLeft;
         }
         else
         {
           if (ulROPType  & ROP_INCL_SRC)
           {
             pPtl.x = pPDevice->lCapsHeight - prclDst->xRight;;
             pPtl.y = prclDst->yBottom;
           }
           /*
           ** This is the correct position for patterns.
           */
           else
           {
             pPtl.x = pPDevice->lCapsHeight - prclDst->yTop;
             pPtl.y = prclDst->xLeft;
           }
         }
      }
    }
    /*
    **  Set current position.  ESC*PiXjY (absolute pos)
    */
    output_bytes(pDDC,"\033*p");
    output_number(pDDC,pPtl.x);
    output_bytes(pDDC,"x");
    output_number(pDDC,pPtl.y);
    output_bytes(pDDC,"Y");
  }
  return (TRUE);
}
/***************************************************************************
 *
 * FUNCTION NAME = set_raster_width_and_height
 *
 * DESCRIPTION   = Function sends the necessary commands to set the source
 *                 width.
 *                 The destination width and height will olly be set
 *                 if we are scaling the bitmap.
 *
 * INPUT         = PDDC  pDDC      - pointer to device driver context
 *                 ULONG ulOddCaps - odd capabilities flag the bits
 *                                   tell us if this is a PCL for HPRTL
 *                                   device.
 *                 PRECTL prclSrc  - Source bitmap rectangle
 *                 PRECTL prclDest - Target bitmap rectangle
 *                 BOOL   bScale   - TRUE if we should scale the bitmap
 *
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 **************************************************************************/

LOCAL BOOL  set_raster_width_and_height(PDDC pDDC, ULONG fulOddCaps,
                                  PRECTL prclSrc, PRECTL prclDst, BOOL bScale)
{
  if (fulOddCaps & (OD_PCL | OD_HPRTL))
  {
    /*
    ** if we have to do some scaling then tell the device to do it.
    */
    if (bScale)
    {
      if (fulOddCaps & OD_BITMAP_SCALING) // device can do bitmap scaling
      {
        output_bytes(pDDC,"\033*r");                         /* source width */
        output_number(pDDC,prclSrc->xRight - prclSrc->xLeft);
        output_bytes(pDDC,"s");
        /*
        **  Set source raster height
        */
        //output_bytes(pDDC,"\033*r");                     /* source height */
        output_number(pDDC,prclSrc->yTop - prclSrc->yBottom);
        output_bytes(pDDC,"T");

        /*
        **  Set Destination width and height
        */
        output_bytes(pDDC,"\033*t");                     /* Dest Width  */
        output_number(pDDC, (prclDst->xRight - prclDst->xLeft) * 12 / 5);
        output_bytes(pDDC,"h");

        //output_bytes(pDDC,"\033*t");                     /* Dest height */
        output_number(pDDC, (prclDst->yTop - prclDst->yBottom) * 12 / 5);
        output_bytes(pDDC,"V");
      }
      else
      {
        /*
        ** Set raster width
        ** Setting the Source Width is very important.
        ** If you don't,it will default to logical page width and fills the rest
        ** of the row with zeros overwriting previous data if any.
        */
        output_bytes(pDDC,"\033*r");                         /* source width */
        output_number(pDDC,prclDst->xRight - prclDst->xLeft);
        output_bytes(pDDC,"S");
      }
    }
    else
    {
       /*
       ** Set raster width
       ** Setting the Source Width is very important.
       ** If you don't,it will default to logical page width and fills the rest
       ** of the row with zeros overwriting previous data if any.
       */
       output_bytes(pDDC,"\033*r");                         /* source width */
       output_number(pDDC,prclDst->xRight - prclDst->xLeft);
       output_bytes(pDDC,"S");
    }
  }
  return (TRUE);
}

/***************************************************************************
 *
 * FUNCTION NAME = begin_raster_graphics
 *
 * DESCRIPTION   = send the necessary commands to get into
 *                 raster graphics transfer mode. Note: Raster Mode
 *                 may either be PCL or RTL
 *
 * INPUT         = PDDC  pDDC      - pointer to device driver context
 *                 ULONG ulOddCaps - odd capabilities flag the bits
 *                                   tell us if this is a PCL for HPRTL
 *                                   device.
 *                 BOOL  bScale     -True if scalling.
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 **************************************************************************/

LOCAL BOOL  begin_raster_graphics(PDDC pDDC, ULONG fulOddCaps, BOOL bScale)
{
  PPDEVICE pPDevice = pDDC->pPDevice;

  if (fulOddCaps & (OD_PCL | OD_HPRTL))
  {
    /*
    **  We must get out of raster graphics transfer mode before
    **  moving the current position
    */
    if (fulOddCaps & OD_PCL)                // PCL
    {
      if (bScale)
        output_bytes(pDDC,"\033*r3A");  // Start raster graphics with scale
      else
        output_bytes(pDDC,"\033*r1A");  // Start raster graphics-no scale
    }
    else                                    // HPGL2 RTL
    {
      if (bScale)
        output_bytes(pDDC,"\033*r3A");      // start raster graphics with scalling
      else
        output_bytes(pDDC,"\033*r1A");      // start raster graphics- no scalling
    }
    pDDC->pPDevice->bInRasterMode = TRUE;
  }
  return (TRUE);
}

/***************************************************************************
 *
 * FUNCTION NAME = end_raster_graphics
 *
 * DESCRIPTION   = send the necessary commands to get out of
 *                 raster graphics transfer mode. Note: Raster Mode
 *                 may either be PCL or RTL
 *
 * INPUT         = PDDC  pDDC      - pointer to device driver context
 *                 ULONG ulOddCaps - odd capabilities flag the bits
 *                                   tell us if this is a PCL for HPRTL
 *                                   device.
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 **************************************************************************/

LOCAL BOOL  end_raster_graphics(PDDC pDDC, ULONG fulOddCaps)
{
  PPDEVICE pPDevice = pDDC->pPDevice;

  if (fulOddCaps & (OD_PCL | OD_HPRTL))
  {
    /*
    **  We must get out of raster graphics transfer mode before
    **  moving the current position
    */
    if (fulOddCaps & OD_PCL)          // PCL
    {
      output_bytes(pDDC,"\033*rB");   // end raster graphics transfer for PCL
    }
    else                              // HPGL2 RTL
    {
      output_bytes(pDDC,"\033*rC");   // end raster graphics transfer for RTL
    }
    pDDC->pPDevice->bInRasterMode = FALSE;
  }
  return (TRUE);
}

/***************************************************************************
 *
 * FUNCTION NAME = vector_bitmap
 *
 * DESCRIPTION   = turn the bitmap into line commands for non
 *                 raster devices (pen plotters)
 *
 * INPUT         = PDDC    pDDC      - pointer to device driver context
 *                 PBYTE   pbScan    - Pointer to the source bits.
 *                 ULONG   ulBytesPerScan - Number of bytes per row
 *                 LONG    lScan          - Number of lines in bitmap
 *                 ULONG   fulOddCaps     - Odd capabilities
 *                 ULONG   bBpp           - Bits per Pel
 *                 PRGB2   paRGB2         - ptr  to an array of rgb values
 *                 LONG    flColorType    - flag for color array type
 *
 * OUTPUT        = NONE
 *
 * RETURN-NORMAL = TRUE
 * RETURN-ERROR  = FALSE
 *
 **************************************************************************/

LOCAL BOOL  vector_bitmap(PDDC pDDC,
                          PBYTE  pbScan,
                          ULONG  ulBytesPerScan,
                          LONG   lScan,
                          ULONG  ulBpp,
                          ULONG  ulBltFlags,
                          PRECTL prclDest,
                          PRGB2  paRGB2,
                          LONG   flColorType)
{
  PPDEVICE pPDevice  = pDDC->pPDevice;
  LONG     lNBytes   = ulBytesPerScan;
  LONG     lWidthInPels = prclDest->xRight - prclDest->xLeft;
  RGB      rgbColor;
  LONG     lColor;
  LONG     lPelsWritten;
  LONG     lPels;
  PBYTE    pbCurrentScan;
  PBYTE    pbTemp;
  POINTL   ptlStart;
  POINTL   ptlEnd;
  USHORT   usLogColorTableFormat;
  BOOL     bFillOpt = FALSE;

  /*
  ** vector device - do the best we can do - vector the bitmap
  */
#ifdef DEBUG
//     ptlStart.x = prclDest->xRight + 20;
//     ptlStart.y =  pPDevice->lCapsHeight - prclDest->yTop;
//     check_line_construction(pDDC);
//     move_pen( pDDC, &ptlStart, FALSE );
//     output_bytes(pDDC, "LBxx\3");
#endif
  /*
  ** Save the current color table format and
  ** put us in RGB mode since we are use the rgb values from
  ** the bitmap color table.
  ** This will cause the color functions to just use the RGB
  ** we pass in.
  */
  usLogColorTableFormat = pDDC->DCState.usColorFormat;
  pDDC->DCState.usColorFormat = LCOLF_RGB;

  if (ulBltFlags != BF_DIR_BOTTOM_TOP)
  {
    pbCurrentScan = pbScan + (ulBytesPerScan * (lScan -1));
    lNBytes = -lNBytes;
  }
  else
  {
    pbCurrentScan = pbScan;
  } /* endif */

  set_line_type( pDDC, LINETYPE_SOLID);
  //ptlStart.y = prclDest->yTop;
  ptlStart.y =  pPDevice->lCapsHeight - prclDest->yTop;

  /*
  **  If we are color sorting we can use the fill_opt code
  **  to plot the lines more efficiently
  */
  if (pPDevice->bColorSorting)
  {
    bFillOpt = TRUE;
    fill_opt_init(pDDC);
  }

  while (--lScan >= 0)
  {
    ptlStart.x   = prclDest->xLeft;
    ptlEnd.y     = ptlStart.y;
    pbTemp       = pbCurrentScan;
    lPelsWritten = 0;

    /*
    ** check for an abort since this takes a long time
    */
    if (!pPDevice->bEnableOutput)
      break;
    /*
    **  Loop through all of the bytes in each scan line on a per RGB
    **  basis...
    */
    while (lPelsWritten != lWidthInPels)
    {
      /*
      **  Find out what the next RGB color is in the source bitmap
      **  and how many consecutive pels are set to that color.
      */
      getnextcolor(pbTemp, (PBYTE) &rgbColor,
                   (USHORT)(lWidthInPels - lPelsWritten),
                    &lPels, lPelsWritten, ulBpp, pDDC);
      /*
      ** Get the RGB value from the color table or the RGB returned
      ** if this is a 24 bit per pel bitmap
      */
      if (ulBpp <= 8)
      { // its an index
        if (flColorType == COLOR_FORMAT_RGB2)
        { // RGB2 color table
          PRGB2 pRGB2 = &paRGB2[rgbColor.bBlue];
          lColor = (ULONG) (pRGB2->bRed);
          lColor = (ULONG) ((lColor << 8) | pRGB2->bGreen);
          lColor = (ULONG) ((lColor << 8) | pRGB2->bBlue);
        }
        else
        { // RGB color table
          RGB *pRGB = (RGB*)paRGB2;
          pRGB = &pRGB[rgbColor.bBlue];
          lColor = (ULONG) (pRGB->bRed);
          lColor = (ULONG) ((lColor << 8) | pRGB->bGreen);
          lColor = (ULONG) ((lColor << 8) | pRGB->bBlue);
        }
      }
      else
      { /* its an RGB color  */
        lColor = (ULONG) rgbColor.bRed;
        lColor = (lColor << 8) | rgbColor.bGreen;
        lColor = (lColor << 8) | rgbColor.bBlue;
      } /* endif */

      /*
      ** Draw the line
      */
      ptlEnd.x = ptlStart.x + lPels -1;
      if (check_color_sorting(pDDC, lColor, USAGE_LINES))
      {
         select_line_pen( pDDC, lColor );
         move_pen( pDDC, &ptlStart, FALSE );
         plot_line( pDDC, &ptlEnd );
      }
      ptlStart.x = ptlEnd.x + 1;

      lPelsWritten += lPels;
    }
    pbCurrentScan += lNBytes;
    ptlStart.y++;
  }

  /*
  ** flush any buffered lines
  */
  if (bFillOpt)
    fill_opt_end(pDDC);

  /*
  ** Put color table format back to what is was
  */
  pDDC->DCState.usColorFormat =usLogColorTableFormat ;

  return (TRUE);
}

/***************************************************************************
 *
 * FUNCTION NAME = sdBitBlt
 *
 * DESCRIPTION   = Function is called from the new raster GRE if we
 *                 we hooked the function is QueryDeviceSurface.
 *                 Function prints an array of pre clipped and stretched
 *                 bitmaps.
 *
 *
 * INPUT         = PBITMAPINFO
 *                 PDDC
 *
 *
 * RETURN-NORMAL =  1 GPI_OK
 * RETURN-ERROR  = -1 GPI_ERROR
 *
 ****************************************************************************/
//remove this when ddi.h has new flag
#ifndef BF_SRC_BITS_EXTERNAL
#define BF_SRC_BITS_EXTERNAL      0x00001000
#endif
#ifndef BF_LAST_BLT
  #define BF_LAST_BLT               0x00002000
#endif
/*
** Local Defines for the sdBitBlt Function
*/
#define    ROP_INCL_SRC   0x01    /* Source bitblt */
#define    ROP_INCL_PAT   0x02    /* Pattern copy  */
#define    ROP_3WAY       0x03    /* 3Way bitblt   */
#define    SD_ROP_ZERO    0x04    /* ROP_ZERO      */
#define    SD_ROP_ONE     0x08    /* ROP_ONE       */

LONG  sdBitBlt ( PBITBLTINFO pBitBltInfo)
{
  LONG   lReturn    = RC_SUCCESS;
  /*
  **  *** Possible returns ***
  **  RC_SUCCESS              0
  **  RC_SIMULATE             1
  **  RC_UNSUPPORTED          2
  **  RC_ERROR                3
  */

  ///*
  //** Get the pddc from the pbits of the destination bitmap
  //** until Mike changes sdBitBlt to pass the pddc.
  //*/
  PDDC   pDDC        = (PDDC)pBitBltInfo->pDstBmapInfo->pBits;
  ULONG  ulOrgMask = 0L;

  PPDEVICE pPDevice  = pDDC->pPDevice;
  PDEVICESURFACE pDS = pDDC->pDeviceSurface;
  ULONG  ulDSFlgs    = pDS->ulDSFlgs; //@pclTB
  ULONG  Plotter     = pPDevice->Plotter;
  ULONG  fulOddCaps  = PlotterClass[Plotter].fsOdd; /* odd caps      */
  ULONG  ulROPType   = 0L;
  // bitmap vars
  ULONG  ulSrcFormat = 0L;
  ULONG  ulSrcWrap   = 0L;
  ULONG  ulPatFormat = 0L;
  ULONG  ulPatWrap   = 0L;
  ULONG  ulcBlits;
  RECTL  rectlSrc;
  RECTL  rectlDest;
  RECTL  rectlPatDest;
  PBLTRECT pbrDest;
  PBYTE  pSrc        = (PBYTE)NULL;
  PBYTE  pPat        = (PBYTE)NULL;
  RGB2   argb2SrcMonoColors[2];
  PRGB2  prgb2SrcColors;
  RGB2   argb2PatMonoColors[2];
  PRGB2  prgb2PatColors;
  ULONG  ulModeFlags = (pDS->ulDSFlgs & DS_TOPBOTTOM ?
                                DS_TOPBOTTOM : DS_BOTTOMTOP);
  ULONG  ulBltFlags = pBitBltInfo->ulBltFlags ;
  ULONG  ulWidth;
  ULONG  ulHeight;
  ULONG  fulUseRF = FALSE;
  BITMAPINFO bmi;
  ULONG  ulColor;


  if (!EnterDriver(pDDC))
      return(RC_ERROR);

  /*
  ** See if the engine is just telling us to
  ** get out of bitblt mode.  ie. sdBitBlt with 0 blts
  */
  if (!pBitBltInfo->cBlits)
  {
    goto sdBitBltExit;
  }


  /*
  ** See if we are doing ROP_ONE or ROP_ZERO
  */
  if ( (BYTE)pBitBltInfo->ulROP == (BYTE)ROP_ZERO)
  {
     ulColor = COLOR_BLACK;
     ulROPType = SD_ROP_ZERO;

  }
  if ( (BYTE)pBitBltInfo->ulROP == (BYTE)ROP_ONE)
  {
     ulColor = COLOR_WHITE;
     ulROPType = SD_ROP_ONE;
  }
  /*
  ** See if we have a source or pattern or both
  */
  if ( (((BYTE)pBitBltInfo->ulROP & 0x33) << 2) != ((BYTE)pBitBltInfo->ulROP & 0xCC) )
  {
     // we have a source involved ROP
     ulROPType  |= ROP_INCL_SRC;
     DBPRINTF (("sdBitBlt SRC bitblt"));
     ulSrcFormat = pBitBltInfo->pSrcBmapInfo->ulBpp;
     ulSrcWrap   = pBitBltInfo->pSrcBmapInfo->ulBytesPerLine;
  }
  if ( (((BYTE)pBitBltInfo->ulROP >> 4) ^ (BYTE)pBitBltInfo->ulROP) & 0x0F)
  {
     // we have a pattern;
     ulROPType  |= ROP_INCL_PAT;
     DBPRINTF (("sdBitBlt PAT bitblt"));
     /*
     ** If the BF_PAT_SOLID is set we will not have
     ** a pattern bitmap.
     */
     if (!(pBitBltInfo->ulBltFlags & BF_PAT_SOLID))
     {
       ulPatFormat = pBitBltInfo->pPatBmapInfo->ulBpp;
       ulPatWrap   = pBitBltInfo->pPatBmapInfo->ulBytesPerLine;
       ulWidth     = pBitBltInfo->pPatBmapInfo->ulWidth;
       ulHeight    = pBitBltInfo->pPatBmapInfo->ulHeight;
       bmi.cx = ulWidth;
       bmi.cy = ulHeight;
       bmi.cBitCount = ulPatFormat;
     } /* endif */
  }

  /*
  ** if we have a source bitmap
  */
  if (ulROPType  & ROP_INCL_SRC)
  {
    /*
    ** Find the color table for the source bitmap
    ** If the color table was passed in with the bitmap use it.
    ** else use the hardware palette in the device surface
    */
    prgb2SrcColors = (pBitBltInfo->abColors &&
                      (pBitBltInfo->ulBltFlags & BF_SRC_BITS_EXTERNAL)) ?
                                          pBitBltInfo->abColors :
                                          pDDC->pDeviceSurface->pHWPalette;
    /*
    ** if Mono use src forground and background colors
    */
    if (ulSrcFormat == 1)
    {
      switch (pDS->SurfaceBmapInfo.ulBpp)
      {
        case  CAPS_COLOR_BITCOUNT_24:
          /*
          ** if we are in RGB mode the mono foreground and background colors
          ** are RGB values
          */
          argb2SrcMonoColors[0] = *(PRGB2)(&pBitBltInfo->ulSrcBGColor);
          argb2SrcMonoColors[1] = *(PRGB2)(&pBitBltInfo->ulSrcFGColor);
          break;
        case  CAPS_COLOR_BITCOUNT_1:
          /*
          ** Else the mono foreground and background colors
          ** are 0 for black and 1 for white
          */
          argb2SrcMonoColors[0] = (pBitBltInfo->ulSrcBGColor == 1L ?
                                          vrgb2ColorWhite : vrgb2ColorBlack);
          argb2SrcMonoColors[1] = (pBitBltInfo->ulSrcFGColor == 1L ?
                                          vrgb2ColorWhite : vrgb2ColorBlack);
          break;
        case  CAPS_COLOR_BITCOUNT_8:
        case  CAPS_COLOR_BITCOUNT_4:
        default:
          /*
          ** Else the mono foreground and background colors
          ** are index values into the current hardware color table
          */
          // we should check for BF_APPLY_BACK_ROP in ulMonoBackROP flag.
          argb2SrcMonoColors[0] = prgb2SrcColors[pBitBltInfo->ulSrcBGColor];
          argb2SrcMonoColors[1] = prgb2SrcColors[pBitBltInfo->ulSrcFGColor];
          break;
      }
      prgb2SrcColors = argb2SrcMonoColors;
    }
    DBPRINTF (("sdBitBlt Src BPP:%d ByPerLine:%d Height:%d Width:%d",
                pBitBltInfo->pSrcBmapInfo->ulBpp,
                pBitBltInfo->pSrcBmapInfo->ulBytesPerLine,
                pBitBltInfo->pSrcBmapInfo->ulHeight,
                pBitBltInfo->pSrcBmapInfo->ulWidth));
  }

  /*
  ** if we have a Pattern bitmap
  */
  if (ulROPType & ROP_INCL_PAT)
  {
    /*
    ** Use our hardware color table for the pattern
    */
    prgb2PatColors = pDDC->pDeviceSurface->pHWPalette;
    /*
    ** if Mono use Pattern forground and background colors
    */
    if (ulPatFormat == 1 || pBitBltInfo->ulBltFlags & BF_PAT_SOLID)
    {
      if (pDS->DevCaps[CAPS_COLOR_BITCOUNT] == CAPS_COLOR_BITCOUNT_24)
      {
        /*
        ** if we are in RGB mode the mono foreground and background colors
        ** are RGB values
        */
        argb2PatMonoColors[0] = *(PRGB2)(&pBitBltInfo->ulPatBGColor);
        argb2PatMonoColors[1] = *(PRGB2)(&pBitBltInfo->ulPatFGColor);
      }
      else
      {
        ULONG ulTemp;
        /*
        ** Else the Pattern mono foreground and background colors
        ** are index values into the current hardware color table
        */
        //The pattern colors have been maped to the hardware palette
        //Lets use the original colors in the area bundle
        //argb2PatMonoColors[0] = prgb2PatColors[pBitBltInfo->ulPatBGColor];
        //argb2PatMonoColors[0].fcOptions = (BYTE)NULL;
        //argb2PatMonoColors[1] = prgb2PatColors[pBitBltInfo->ulPatFGColor];
        //argb2PatMonoColors[1].fcOptions = (BYTE)NULL;
        //
        ulTemp = convert_color(pDDC,pDDC->DCState.abnd.lBackColor);
        argb2PatMonoColors[0].bBlue     = (BYTE)ulTemp;
        argb2PatMonoColors[0].bGreen    = (BYTE)(ulTemp >> 8);
        argb2PatMonoColors[0].bRed      = (BYTE)(ulTemp >> 16);
        argb2PatMonoColors[0].fcOptions = (BYTE)0;
        ulTemp = convert_color(pDDC,pDDC->DCState.abnd.lColor);
        argb2PatMonoColors[1].bBlue     = (BYTE)ulTemp;
        argb2PatMonoColors[1].bGreen    = (BYTE)(ulTemp >> 8);
        argb2PatMonoColors[1].bRed      = (BYTE)(ulTemp >> 16);
        argb2PatMonoColors[1].fcOptions = (BYTE)0;
      }
      /*
      ** We need to check for BF_APPLY_BACK_ROP here. If this bit in
      ** ulMonoBackRop is not set then we should make our background color
      ** transparent. Which meens in plotters we have to set this to White
      ** and set transparency mode on.
      */
      if (!(pBitBltInfo->ulMonoBackROP & BF_APPLY_BACK_ROP))
      {
         ULONG ulTemp = COLOR_WHITE;
         argb2PatMonoColors[0].bBlue     = (BYTE)ulTemp;
         argb2PatMonoColors[0].bGreen    = (BYTE)(ulTemp >> 8);
         argb2PatMonoColors[0].bRed      = (BYTE)(ulTemp >> 16);
         argb2PatMonoColors[0].fcOptions = (BYTE)0;
      }

      prgb2PatColors = argb2PatMonoColors;
    }
#ifdef DEBUG
    if (pBitBltInfo->pPatBmapInfo)
    {
      DBPRINTF (("sdBitBlt Pat Bpp:%d ByPerLine:%d Height:%d Width:%d",
                 pBitBltInfo->pPatBmapInfo->ulBpp,
                 pBitBltInfo->pPatBmapInfo->ulBytesPerLine,
                 pBitBltInfo->pPatBmapInfo->ulHeight,
                 pBitBltInfo->pPatBmapInfo->ulWidth));
    }
#endif
  }

  /*
  ** if we are in HPGL2 MODE set up and start raster mode
  */
  if (pPDevice->ulCurrentPrintMode == HPGL2)
  {
    /*
    ** Set the Mix Mode or ROP in the device with the MC(Merge Control)
    ** command.
    ** For now we will perserve the current ROP and restore
    ** it. We should remove the restore code when every function
    ** is correctly setting the MC.
    ** Also set the transparency mode off. Reset it to ON when leaving.
    */
    set_transparency_mode(pDDC, 0);
    pPDevice->usPreviousMCROP = pPDevice->usCurrentMCROP;
    set_mix_mode(pDDC, 0, 0, (USHORT)(pBitBltInfo->ulROP & 0xFF));

    if (ulROPType  & ROP_INCL_PAT)
    {
      /*
      ** We need to send in the pBitBltInfo to setup_raster as for Gre22
      ** the bits come from pbits of pPatBmapInfo in pBitBltInfo.
      ** Also we should pass in the prgb2PatColors.
      */
      if (pDDC->DCState.abnd.usSet)
      {
         /*
         ** See if we can use RF command.
         */
         if ((ulWidth == 8 || ulWidth == 16 || ulWidth == 32 || ulWidth == 64) &&
             (ulHeight == 8 || ulHeight == 16 || ulHeight == 32 || ulHeight == 64))
         {
            fulUseRF = TRUE;
            setup_raster_fill_index(pDDC->hdc, pDDC, prgb2PatColors,pBitBltInfo->pPatBmapInfo);
         }
         else
         {
            /*
            ** set up raster transfer
            */

            enter_PCL_or_HPRTL(pDDC, fulOddCaps);
            set_palette(pDDC, fulOddCaps,
                        ulPatFormat,
                        (PRGB2)prgb2PatColors,
                        COLOR_FORMAT_RGB2);

         }
      }
    }

    if (ulROPType  & ROP_INCL_SRC)
    {
      enter_PCL_or_HPRTL(pDDC, fulOddCaps);
      set_palette(pDDC, fulOddCaps, pBitBltInfo->pSrcBmapInfo->ulBpp,
                  prgb2SrcColors, COLOR_FORMAT_RGB2);
    }
  }

  /*
  ** Loop through the bitblts
  */
  DBPRINTF (("sdBitBlt # of Blits : %d",pBitBltInfo->cBlits));
  for (ulcBlits = 0;ulcBlits < pBitBltInfo->cBlits ;ulcBlits++)
  {
    /*
    ** Determine the source and destination rectangles
    */
    pbrDest             = &pBitBltInfo->abrDst[ulcBlits];

    if ( (ulROPType  & ROP_INCL_PAT) ||
         (ulROPType & (SD_ROP_ONE | SD_ROP_ZERO)) ||
         !(fulOddCaps & (OD_PCL | OD_HPRTL)) )   // Vector case
    {
      /*
      ** Determine the source and destination rectangles
      */
      rectlPatDest.xLeft     = pbrDest->ulXOrg;
      rectlPatDest.xRight    = rectlPatDest.xLeft + pbrDest->ulXExt;

      rectlPatDest.yBottom   = pbrDest->ulYOrg;
      rectlPatDest.yTop      = rectlPatDest.yBottom + pbrDest->ulYExt;
      DBPRINTF (("sdBitBlt Dest blt Pattern rectl : xLeft=%d,yBottom=%d,xRight=%d,yTop=%d\n",
                rectlPatDest.xLeft, rectlPatDest.yBottom,
                rectlPatDest.xRight, rectlPatDest.yTop));
    }
    else if (ulROPType  & ROP_INCL_SRC) // We dont want to come here for vectors.
    {
      /*
      ** Seperate the pcl devices. We donot use engine rotation algorithms
      ** for these devices. We use device raster direction capabilities. Kran
      */
      if (fulOddCaps & OD_PCL)
      {
         rectlDest.xLeft     = pbrDest->ulXOrg;
         rectlDest.xRight    = rectlDest.xLeft + pbrDest->ulXExt - 1;
         if (pDS->ulDSFlgs & DS_BOTTOMTOP)
         {
            rectlDest.yBottom   = pbrDest->ulYOrg;
            rectlDest.yTop      = rectlDest.yBottom + pbrDest->ulYExt - 1;
         }
         else
         {
            rectlDest.yTop    = pbrDest->ulYOrg - 1;
            rectlDest.yBottom = rectlDest.yTop + pbrDest->ulYExt;
         }
      }
      else // hprtl case. We use engine rotation functions.
      {
         if (pPDevice->fsTransform & DXF_PORTRAIT)  // portrait case
         {
           /*
           ** Set the xleft and xRight of Destination Rectangle
           */
           if (ulBltFlags & BF_DIR_RIGHT_LEFT)
           {
             rectlDest.xRight    = pbrDest->ulXOrg + 1 ;
             rectlDest.xLeft     = rectlDest.xRight - pbrDest->ulXExt ;
           }
           else
           {
              rectlDest.xLeft     = pbrDest->ulXOrg;
              rectlDest.xRight    = rectlDest.xLeft + pbrDest->ulXExt;
           }

           /*
           ** Set the yBottom and yTop of Destination Rectangle
           */
           if (ulBltFlags & BF_DIR_BOTTOM_TOP)
           {
              rectlDest.yTop    = pbrDest->ulYOrg + 1;
              rectlDest.yBottom = rectlDest.yTop - pbrDest->ulYExt;
           }
           else
           {
               rectlDest.yBottom   = pbrDest->ulYOrg;
               rectlDest.yTop      = rectlDest.yBottom + pbrDest->ulYExt;
           }
         }
         else // hprtl landscape case
         {
           /*
           ** Set the xleft and xRight of Destination Rectangle
           */
           if (ulBltFlags & BF_DIR_BOTTOM_TOP)
           {
             rectlDest.xRight     = pbrDest->ulYOrg + 1 ;
             rectlDest.xLeft      = rectlDest.xRight - pbrDest->ulYExt ;
           }
           else
           {
             rectlDest.xLeft     = pbrDest->ulYOrg;
             rectlDest.xRight    = rectlDest.xLeft + pbrDest->ulYExt;
           }

           /*
           ** Set the yBottom and yTop of Destination Rectangle
           */
           if (ulBltFlags & BF_DIR_RIGHT_LEFT)
           {
              rectlDest.yTop    = pbrDest->ulXOrg + 1;
              rectlDest.yBottom = rectlDest.yTop - pbrDest->ulXExt;
           }
           else
           {
              rectlDest.yBottom  = pbrDest->ulXOrg ;
              rectlDest.yTop     = rectlDest.yBottom + pbrDest->ulXExt;
           }
         }
      }
      DBPRINTF (("sdBitBlt Dest blt rectl : xLeft=%d,yBottom=%d,xRight=%d,yTop=%d\n",
                rectlDest.xLeft, rectlDest.yBottom,
                rectlDest.xRight, rectlDest.yTop));
    }

    /*
    ** if we have a source bitmap
    */
    if (ulROPType  & ROP_INCL_SRC)
    {
       rectlSrc.xLeft      = pBitBltInfo->aptlSrcOrg[ulcBlits].x;
       rectlSrc.yBottom    = pBitBltInfo->aptlSrcOrg[ulcBlits].y;

       if (pPDevice->fsTransform & DXF_PORTRAIT  ||
           !(fulOddCaps & OD_HPRTL))    // vector case and PCL
       {
          rectlSrc.xRight     = rectlSrc.xLeft + pbrDest->ulXExt;
          rectlSrc.yTop       = rectlSrc.yBottom + pbrDest->ulYExt;
       }
       else
       {
          if (pDDC->lEngineVersion > RASTER_ENGINE_22)
          {
             rectlSrc.xLeft      = pBitBltInfo->aptlSrcOrg[ulcBlits].y;
             rectlSrc.yBottom    = pBitBltInfo->aptlSrcOrg[ulcBlits].x;
          }
          rectlSrc.xRight     = rectlSrc.xLeft + pbrDest->ulYExt;
          rectlSrc.yTop       = rectlSrc.yBottom + pbrDest->ulXExt;
       }

      /*
      ** Calculate source pointer position.
      */
      if (pPDevice->fsTransform & DXF_PORTRAIT  ||
          !(fulOddCaps & OD_HPRTL))    // vector or pcl or (hprtl portrait)
      {
         pSrc = pBitBltInfo->pSrcBmapInfo->pBits +
                (ulSrcWrap * pBitBltInfo->aptlSrcOrg[ulcBlits].y) +
                (pBitBltInfo->aptlSrcOrg[ulcBlits].x * ulSrcFormat / 8);

         /*
         ** It is byte aligned for color bmaps. We should handle src origin
         ** only for mono bmaps.
         */
         ulOrgMask = rectlSrc.xLeft %8;
         if ((ulSrcFormat == 1) && ulOrgMask)
           ulOrgMask = 0xFF >> ulOrgMask;
         else
           ulOrgMask = 0L;

      }
      else //HpRTL LandScape.
      {
         if (pDDC->lEngineVersion > RASTER_ENGINE_22)
         {
            pSrc = pBitBltInfo->pSrcBmapInfo->pBits +
                   (ulSrcWrap * pBitBltInfo->aptlSrcOrg[ulcBlits].x) +
                   (pBitBltInfo->aptlSrcOrg[ulcBlits].y * ulSrcFormat) / 8;
         }
         else
         {
              pSrc = pBitBltInfo->pSrcBmapInfo->pBits +
                   (ulSrcWrap * pBitBltInfo->aptlSrcOrg[ulcBlits].y) +
                   ((pBitBltInfo->pSrcBmapInfo->ulWidth - rectlSrc.xRight) *
                   ulSrcFormat / 8);
         }
      }


      if (fulOddCaps & (OD_PCL | OD_HPRTL))
      {
        /*
        ** set up the raster transfer
        */
        set_raster_width_and_height(pDDC,fulOddCaps,&rectlSrc,&rectlDest,FALSE);
        set_graphics_position(pDDC, fulOddCaps, &rectlDest,ulROPType,ulModeFlags);
        begin_raster_graphics(pDDC, fulOddCaps, FALSE);
        /*
        **  Simply outputs the necessary output commands
        **  and then the bits in pBits.
        */
        image_scan(pDDC, pSrc,
                   pBitBltInfo->pSrcBmapInfo->ulBytesPerLine,
                   rectlSrc.yTop - rectlSrc.yBottom,
                   fulOddCaps,
                   pBitBltInfo->pSrcBmapInfo->ulBpp,
                   rectlSrc.xRight - rectlSrc.xLeft, // RightpBitBltInfo->pSrcBmapInfo->ulWidth,
                   pBitBltInfo->ulROP,
                   pBitBltInfo->ulBltFlags,
                   ulModeFlags,ulOrgMask );

        end_raster_graphics(pDDC, fulOddCaps);
      }
      /*
      ** else vector device
      */
      else
      {
         vector_bitmap(pDDC, pSrc,
                       pBitBltInfo->pSrcBmapInfo->ulBytesPerLine,
                       rectlSrc.yTop - rectlSrc.yBottom,
                      // pBitBltInfo->abrDst[ulcBlits].ulYExt,
                       pBitBltInfo->pSrcBmapInfo->ulBpp,
                       pBitBltInfo->ulBltFlags,
                       &rectlPatDest,
                       prgb2SrcColors,
                       COLOR_FORMAT_RGB2);
      }
    }
    /*
    ** if we are doing a pattern copy ROP_PATCOPY
    */
    if (ulROPType  & ROP_INCL_PAT)
    {
      /* BEGIN OF ROP_PATCOPY */
      /*
      **  (If it is a standard pattern) or (a user pattern and it is a PCL
      **  device then call boxinterior.
      */

      LONG    lColor;
      LONG    lBackColor;
      USHORT  usColorFormat;
      POINTL  ptlStartPos;
      POINTL  ptlSaveLogPos;
      POINTL  aptl[2];

      /*
      ** Save the areabundle colors. We may be modifying these colors if
      ** BLTMODE_ATTRS_PRES. Using SaveDC and RestoreDC for this purpose is
      ** very expencive.
      */
      lColor        = pDDC->DCState.abnd.lColor;
      lBackColor    = pDDC->DCState.abnd.lBackColor;
      usColorFormat = pDDC->DCState.usColorFormat;

      pDDC->DCState.usColorFormat   = LCOLF_RGB;
      pDDC->DCState.abnd.lBackColor = (ULONG) prgb2PatColors[0].bRed;
      pDDC->DCState.abnd.lBackColor = (pDDC->DCState.abnd.lBackColor << 8) | prgb2PatColors[0].bGreen;
      pDDC->DCState.abnd.lBackColor = (pDDC->DCState.abnd.lBackColor << 8) | prgb2PatColors[0].bBlue;

      pDDC->DCState.abnd.lColor = (ULONG) prgb2PatColors[1].bRed;
      pDDC->DCState.abnd.lColor = (pDDC->DCState.abnd.lColor << 8) | prgb2PatColors[1].bGreen;
      pDDC->DCState.abnd.lColor = (pDDC->DCState.abnd.lColor << 8) | prgb2PatColors[1].bBlue;

      ptlStartPos.x  = rectlPatDest.xRight;     /* cornerX, cornerY          */
      if (pDS->ulDSFlgs & DS_TOPBOTTOM)
        ptlStartPos.y  = pPDevice->lCapsHeight - rectlPatDest.yTop; //@pclTB
      else
        ptlStartPos.y  = rectlPatDest.yTop; //@pclBT

      ptlSaveLogPos  = pDDC->DCState.LogPosition;
      pDDC->DCState.LogPosition = ptlStartPos;

      aptl[0].x = rectlPatDest.xLeft;

      if (pDS->ulDSFlgs & DS_TOPBOTTOM)
        aptl[0].y = pPDevice->lCapsHeight - rectlPatDest.yBottom; //@pclTB
      else
        aptl[0].y = rectlPatDest.yBottom; //@pclTB
      aptl[1].x = aptl[1].y = 0L;            /* diamX, diamY = 0 => square*/
                                             /* corners                   */
      if (pDDC->DCState.abnd.usSet)  // user defined pattern
      {
         if (fulUseRF)
         {
           if(pDDC->DCState.abnd.usMixMode == FM_LEAVEALONE)
              draw_box( pDDC, &aptl[0], pDDC->DCState.abnd.lBackColor, TRUE,
                        PATSYM_SOLID);
           else
              draw_box( pDDC, &aptl[0], pDDC->DCState.abnd.lColor, TRUE,
                        PATSYM_USERDEFINED);
         }
         else
         {
           set_raster_width_and_height(pDDC,fulOddCaps,NULL,&rectlPatDest,FALSE);
           set_graphics_position(pDDC, fulOddCaps, &rectlPatDest,ulROPType,ulModeFlags);
           /*
           **  Set Transparency mode. Opaque.
           */
           output_bytes(pDDC,"\033*v1N");
           begin_raster_graphics(pDDC, fulOddCaps, FALSE);

           fill_pattern(pDDC,pBitBltInfo->pPatBmapInfo->pBits,&bmi,ulPatWrap,ulHeight,rectlPatDest);
           /*
           ** end raster transfer
           */
           end_raster_graphics(pDDC, fulOddCaps);

         }
      }
      else    // standard pattern
      {
        /*
        ** if the pattern is not solid and we pass the color sorting
        ** test draw the background of the pattern
        */
        if (!(pBitBltInfo->ulBltFlags & BF_PAT_SOLID) &&
            (check_color_sorting(pDDC, pDDC->DCState.abnd.lBackColor,
                                 USAGE_FILLS)))
        {
          draw_box(pDDC, &aptl[0], pDDC->DCState.abnd.lBackColor, TRUE,
                   PATSYM_SOLID);
        }
        if (pDDC->DCState.abnd.usSymbol != PATSYM_NOSHADE &&
            pDDC->DCState.abnd.usSymbol != PATSYM_BLANK   &&
            check_color_sorting(pDDC, pDDC->DCState.abnd.lColor, USAGE_FILLS))
        {
          draw_box(pDDC, &aptl[0], pDDC->DCState.abnd.lColor, TRUE,
                   pDDC->DCState.abnd.usSymbol);
        }
      }
      /*
      ** Restore back the colors in areabundle.
      */
      pDDC->DCState.abnd.lColor     = lColor;
      pDDC->DCState.abnd.lBackColor = lBackColor;
      pDDC->DCState.usColorFormat   = usColorFormat;
      /*
      ** Restore Device coord logical position
      */
      ptlSaveLogPos = pDDC->DCState.LogPosition  = ptlSaveLogPos;

    } /* end PATCOPY */
    /*
    ** If we have SD_ROP_ONE or SD_ROP_ZERO
    */
    if (ulROPType & (SD_ROP_ONE | SD_ROP_ZERO))
    {
      USHORT  usColorFormat = pDDC->DCState.usColorFormat;
      POINTL  ptlStartPos;
      POINTL  ptlSaveLogPos;
      POINTL  aptl[2];

      pDDC->DCState.usColorFormat   = LCOLF_RGB;
      ptlStartPos.x  = rectlPatDest.xRight;     /* cornerX, cornerY          */
      if (pDS->ulDSFlgs & DS_TOPBOTTOM)
        ptlStartPos.y  = pPDevice->lCapsHeight - rectlPatDest.yTop; //@pclTB
      else
        ptlStartPos.y  = rectlPatDest.yTop; //@pclBT

      ptlSaveLogPos  = pDDC->DCState.LogPosition;
      pDDC->DCState.LogPosition = ptlStartPos;

      aptl[0].x = rectlPatDest.xLeft;
      if (ulDSFlgs & DS_TOPBOTTOM)
        aptl[0].y = pPDevice->lCapsHeight - rectlPatDest.yBottom; //@pclTB
      else
        aptl[0].y = rectlPatDest.yBottom; //@pclBT
      aptl[1].x = aptl[1].y = 0L;            /* diamX, diamY = 0 => square*/
                                             /* corners                   */

      draw_box(pDDC, &aptl[0], ulColor, TRUE, PATSYM_SOLID);

      /*
      ** Restore Device coord logical position
      */
      ptlSaveLogPos = pDDC->DCState.LogPosition  = ptlSaveLogPos;
      pDDC->DCState.usColorFormat = usColorFormat;
    }

  } /* endfor number of bitblts */

sdBitBltExit:
  /*
  ** if This is the last sdBitBlt we must put the device back in
  ** HPGL MODE.
  */
  if (pBitBltInfo->ulBltFlags & BF_LAST_BLT)
  {
    /*
    **  We are merging the vector and Raster Graphics, Then we have
    **  to end the RasterGraphics and Enter the HPGL-2 mode.
    */
    if (pPDevice->ulCurrentPrintMode != HPGL2)
    {
      return_to_HPGL2(pDDC, fulOddCaps);
    }
    // /*
    // ** Restore Rotation
    // */
    // if (fulOddCaps & (OD_PCL | OD_HPRTL))
    // {
    //    set_rotation(pDDC,pPDevice->lPreviousRotate,TRUE);
    // }
    // /*
    // ** restore HPGL ROP
    // */
    set_transparency_mode(pDDC, 1);
    set_mix_mode(pDDC, 0, 0, pPDevice->usPreviousMCROP);

  } /* endif last sdBitBlt */

  LeaveDriver(pDDC);
  return(lReturn);
}
