home *** CD-ROM | disk | FTP | other *** search
/ Inside Multimedia 1995 July / IMM0795.ISO / share / os2 / pmfract / src / pmfrload.c < prev    next >
Text File  |  1994-01-24  |  20KB  |  628 lines

  1. /*--------------------------------------------------
  2.    PMFRLOAD.C -- FRACTINT for PM
  3.  
  4.       Load Processor
  5.  
  6.       This module contains both the code to read
  7.       GIF, BMP, MET, and PCX files, it also contains
  8.       the code used to fetch objects from the clipboard.
  9.  
  10.    05/25/91      Code by Donald P. Egen (with help)
  11.  
  12.    This module's first function (LoadDriver) is the
  13.    main load action function.
  14.  
  15.    **** WARNING **** WARNING **** WARNING ****
  16.    The functions in this module dealing with file I/O
  17.    are called as part of the background subthread.
  18.  
  19.    The functions dealing with Clipboard fetching
  20.    are called as part of the main foreground PM thread.
  21.  
  22.    Serialization is something we all hope for.
  23.  
  24.  ---------------------------------------------------*/
  25.  
  26. #define INCL_WIN
  27. #define INCL_GPI
  28. #define INCL_DOS
  29. #define INCL_PM
  30. #include <os2.h>
  31. #include <process.h>
  32. #include <stdlib.h>
  33. #include <stdio.h>
  34. #include <setjmp.h>
  35. #include <float.h>
  36. #include <malloc.h>
  37. #include <string.h>
  38. #include <smplhelp.h>
  39.  
  40. #include "pmfract.h"
  41. #include "fractint.h"
  42. #include "fractype.h"
  43.  
  44. /* routines in this module */
  45.  
  46. static int LoadDriverGIF(VOID);
  47. static int LoadDriverBMP(VOID);
  48. static int LoadDriverMET(VOID);
  49. static int LoadDriverPCX(VOID);
  50.  
  51.  
  52. extern HAB    habThread;
  53.  
  54. /* engine interface routines and variables */
  55.  
  56. extern int out_line();
  57. extern int (*outln)();
  58. extern char readname[];
  59.  
  60. extern int xdots, ydots, colors, maxiter;
  61. extern int ytop, ybottom, xleft, xright;
  62.  
  63. extern int fractype;
  64. extern int invert;
  65.  
  66. extern double ftemp, xxmin, xxmax, yymin, yymax;
  67.  
  68. extern long lm, linitx, linity;
  69. extern int maxit, bitshift, color, row, col;
  70.  
  71. extern int read_overlay(void);
  72. extern int gifview(void);
  73.  
  74. extern char usr_stdcalcmode, stdcalcmode;
  75. extern int  usr_distest, usr_floatflag, usr_periodicitycheck;
  76. extern double param[4];
  77. extern unsigned char trigndx[4];
  78. extern void set_trig_pointers(int which);
  79.  
  80. extern unsigned char dacbox[257][3];
  81. extern int decomp[2];
  82. extern int biomorph, inside, outside;
  83. extern int filexdots, fileydots, filecolors;
  84.  
  85. extern int reallyega;
  86.  
  87. /* our driver routine */
  88.  
  89. int  FAR LoadDriver (VOID)
  90.      {
  91.  
  92.      int rc;
  93.  
  94.      /* dispatch based on sub-function - What format? */
  95.  
  96.      switch (cp.sSubFunction)
  97.             {
  98.             case SUB_LOADSAVE_GIF:
  99.                  rc = LoadDriverGIF();
  100.                  break;
  101.  
  102.             case SUB_LOADSAVE_WIN3BMP:
  103.             case SUB_LOADSAVE_BMP:
  104.                  rc = LoadDriverBMP();
  105.                  break;
  106.  
  107.             case SUB_LOADSAVE_MET:
  108.                  rc = LoadDriverMET();
  109.                  break;
  110.  
  111.             case SUB_LOADSAVE_PCX:
  112.                  rc = LoadDriverPCX();
  113.                  break;
  114.  
  115.             default:
  116.                  rc = 999;   /* let the caller figure it out */
  117.                  break;
  118.  
  119.             }
  120.  
  121.      /* and go back */
  122.  
  123.      return rc;
  124.  
  125.      }
  126.  
  127. /*--------------------------------------------------
  128.  
  129.  Load a GIF file using the FRACTINT for DOS code.
  130.  
  131.  ---------------------------------------------------*/
  132. static int LoadDriverGIF (VOID)
  133.      {
  134.  
  135.      unsigned char _far *pcSrc;
  136.      unsigned char _far *pcDest;
  137.      unsigned char _far *fp1;
  138.      unsigned char _far *fp2;
  139.      USHORT sOffset, sReps;
  140.      int i;
  141.  
  142.      _fstrcpy(readname, cp.szFileName);
  143.  
  144.      outln = out_line;
  145.  
  146.      /* read_overlay reads the header and (if present) the FRACTINT-
  147.         specific information in the file.  All appropriate engine
  148.         variables are set on return */
  149.      if (read_overlay())
  150.         { /* problem */
  151.         return SUB_STAT_ABORT;
  152.         }
  153.  
  154.    cp.cx = xdots = filexdots;
  155.    cp.cy = ydots = fileydots;
  156.    cp.colors = colors = filecolors;
  157.    cp.iFractType = fractype;
  158.    cp.cFloatflag = usr_floatflag;
  159.    cp.XL = xxmin;
  160.    cp.XR = xxmax;
  161.    cp.YT = yymax;
  162.    cp.YB = yymin;
  163.    cp.param[0] = param[0];
  164.    cp.param[1] = param[1];
  165.    cp.param[2] = param[2];
  166.    cp.param[3] = param[3];
  167.    cp.trigndx[0] = trigndx[0];
  168.    cp.trigndx[1] = trigndx[1];
  169.    cp.trigndx[2] = trigndx[2];
  170.    cp.trigndx[3] = trigndx[3];
  171.    cp.stdCalcMode = usr_stdcalcmode;
  172.    cp.distest = usr_distest;
  173.    cp.periodicitycheck = usr_periodicitycheck;
  174.    cp.biomorph = biomorph;
  175.    cp.decomp[0] = decomp[0]; cp.decomp[1] = decomp[1];
  176.    cp.inside = inside;
  177.    cp.outside = outside;
  178.  
  179.     ytop    = 0;
  180.     ybottom = ydots-1;
  181.     xleft   = 0;
  182.     xright  = xdots-1;
  183.  
  184.      /* resize the memory bitmap for the load */
  185.      /* fall on sword if can't get memory */
  186.      if (GetMemoryBitmap(habThread))
  187.         return(SUB_STAT_FATAL);
  188.  
  189.      /* the following turns off the expected palette translation
  190.         in the read code if it thinks it has a physical VGA
  191.         running in 16 color mode.  The flag "reallyega" turns
  192.         of this translation.
  193.      */
  194.      reallyega = (cp.colors == 16) ? 1 : 0;
  195.  
  196.      /* now read in the bits */
  197.      gifview();
  198.  
  199.      /* map the colors from the file, now in "dacbox",
  200.         into our "user palette" structure for use.
  201.  
  202.         Unfortunately, PM uses "BGR", and dacbox uses "RGB"
  203.      */
  204.  
  205.      cp.pbmiMemory = &bmiColorTableUser;
  206.      cp.sCurrentPalette = IDD_PAL_USER;
  207.      pcDest = (unsigned char _far *) &(cp.pbmiMemory->argbColor[0]);
  208.      pcSrc = (unsigned char _far *) &dacbox[0][0];
  209.  
  210.      for (i = 0; i < cp.colors; i++)
  211.          {
  212.          pcDest[0] = pcSrc[2] << 2U;
  213.          pcDest[1] = pcSrc[1] << 2U;
  214.          pcDest[2] = pcSrc[0] << 2U;
  215.  
  216.          pcSrc += 3;
  217.          pcDest += 3;
  218.          }
  219.  
  220.    /* now replicate the color table to 256 entries, if necessary */
  221.    if (cp.colors < 256)
  222.       {
  223.       fp1 = (unsigned char _far *) &bmiColorTableUser.argbColor[0]; /* source */
  224.       fp2 = pcDest;                                          /* dest */
  225.       sOffset = fp2 - fp1;             /* distance we have come so far */
  226.       sReps = 256 / cp.colors;         /* if it ain't even, forget excess! */
  227.       for (i = 1; i < sReps; i++)
  228.           {
  229.           _fmemcpy(fp2, fp1, sOffset); /* copy a thwak */
  230.           fp2 += sOffset;              /*  then bump dest */
  231.           }
  232.       }
  233.  
  234.      cp.fHaveUserPalette = TRUE;
  235.  
  236.      /* and go home */
  237.  
  238.      return (SUB_STAT_OK);
  239.      }
  240.  
  241.   /* ------------------------------------------------------------------ */
  242.  
  243.   /* The following structures map the Windows 3.0 bitmap file format. */
  244.  
  245. typedef struct tagRGBQUAD {
  246.         CHAR    rgbBlue;
  247.         CHAR    rgbGreen;
  248.         CHAR    rgbRed;
  249.         CHAR    rgbReserved;
  250. } RGBQUAD;
  251.  
  252. typedef struct tagBITMAPINFOHEADER{
  253.         ULONG      biSize;
  254.         ULONG      biWidth;
  255.         ULONG      biHeight;
  256.         USHORT     biPlanes;
  257.         USHORT     biBitCount;
  258.  
  259.         ULONG      biCompression;
  260.         ULONG      biSizeImage;
  261.         ULONG      biXPelsPerMeter;
  262.         ULONG      biYPelsPerMeter;
  263.         ULONG      biClrUsed;
  264.         ULONG      biClrImportant;
  265. } W3BITMAPINFOHEADER;
  266.  
  267. static int LoadDriverBMP(VOID)
  268.      {
  269.  
  270.      /* NOTE: This function attempts to read both OS/2 1.1/1.2 PM
  271.         Bitmaps as well as Windows 3.0 Bitmaps.
  272.         The reason is that a user can't, from the outside, tell
  273.         one from the other ( at least I can't).                    */
  274.  
  275.      BITMAPFILEHEADER bfhIt;
  276.      HFILE hfileIt;
  277.      W3BITMAPINFOHEADER bmpIt3;
  278.  
  279.      /* note: we will be using direct DOS reads rather than C file I/O
  280.         because we need to deal with far (and huge) addresses */
  281.      LONG cbColorTable, cbBitSize;
  282.      unsigned char _far *fp1;
  283.      unsigned char _far *fp2;
  284.      unsigned char _huge *hp;
  285.      RGB _far *prgb1;
  286.      USHORT sOffset, sReps;
  287.      ULONG  ulNewPtr;
  288.      USHORT usIOAction;
  289.      int i;
  290.      FILESTATUS fstsIt;
  291.      char achMsg[65];
  292.      USHORT cxReal, cyReal, bitsReal, planesReal, cbColors;
  293.      BOOL OS2fmt = TRUE;
  294.  
  295.    _fstrcpy(readname, cp.szFileName);
  296.  
  297.    /* begin by opening the file */
  298.    if ( 0 != DosOpen(cp.szFileName, &hfileIt, &usIOAction, 0L, 0,
  299.              FILE_OPEN, OPEN_ACCESS_READONLY | OPEN_SHARE_DENYNONE, 0L) )
  300.       {
  301.       return SUB_STAT_ABORT;
  302.       }
  303.  
  304.    /* read in the file header.  This will give us format and color table size */
  305.    if (0 != DosRead(hfileIt, &bfhIt, sizeof(BITMAPFILEHEADER),
  306.                     &usIOAction) )
  307.       {
  308.       DosClose(hfileIt);
  309.       return SUB_STAT_ABORT;
  310.       }
  311.  
  312.    /* check that this is a "BM" file.  We could get into trouble
  313.       if we arbitrarily try to read something else.                 */
  314.    if (bfhIt.usType != BFT_BMAP)
  315.       {
  316.       DosClose(hfileIt);
  317.       sprintf(achMsg, "%s is not a Bitmap File!", readname);
  318.       PMfrSyncMsg(0, achMsg);    /* flag the new information */
  319.       return SUB_STAT_OK;
  320.       }
  321.  
  322.    /* *** WARNING *** DON'T DEPEND ON THE cbSize figure from
  323.       the Bitmap header.  It may be wrong.  Get the file size from
  324.       the file system.                                              */
  325.    DosQFileInfo(hfileIt, FIL_STANDARD, &fstsIt, sizeof(fstsIt));
  326.  
  327.    /* determine if this is OS/2 1.1/1.2/1.3 format or Windows 3.0 format.
  328.       If it is a Windows bitmap, reposition and reread the BITMAPINFOHEADER
  329.       part of the file.  Copy width, heigth, planes, and bits-per-pixel
  330.       to common variables for use later.  Let the file positioned
  331.       at the beginning of the color table.                          */
  332.    if (bfhIt.bmp.cbFix == sizeof(BITMAPINFOHEADER) )
  333.       {   /* its OS/2 */
  334.  
  335.       cxReal = bfhIt.bmp.cx;
  336.       cyReal = bfhIt.bmp.cy;
  337.       bitsReal = bfhIt.bmp.cBitCount;
  338.       planesReal = bfhIt.bmp.cPlanes;
  339.       OS2fmt = TRUE;
  340.       /* calculate the color table size */
  341.       cbColorTable = bfhIt.offBits - (ULONG) sizeof(BITMAPFILEHEADER);
  342.       }
  343.    else
  344.       {   /* it's Windows 3.0 */
  345.       /* rewind the file to the beginning of the BitmapInfoHeader area */
  346.       if (0 != DosChgFilePtr(hfileIt,
  347.                     sizeof(BITMAPFILEHEADER) - sizeof(BITMAPINFOHEADER),
  348.                     FILE_BEGIN, &ulNewPtr) )
  349.          {
  350.          DosClose(hfileIt);
  351.          return SUB_STAT_ABORT;
  352.          }
  353.       /* now read it */
  354.       if ( 0 != DosRead(hfileIt, &bmpIt3,
  355.                   sizeof(W3BITMAPINFOHEADER), &usIOAction) )
  356.          {
  357.          DosClose(hfileIt);
  358.          return SUB_STAT_ABORT;
  359.          }
  360.  
  361.       OS2fmt = FALSE;
  362.       cxReal = bmpIt3.biWidth;
  363.       cyReal = bmpIt3.biHeight;
  364.       bitsReal = bmpIt3.biBitCount;
  365.       planesReal = bmpIt3.biPlanes;
  366.  
  367.       cbColorTable = bfhIt.offBits - (ULONG) (sizeof(BITMAPFILEHEADER)
  368.                            - sizeof(BITMAPINFOHEADER) )
  369.                            - (ULONG) sizeof(W3BITMAPINFOHEADER);
  370.       }
  371.  
  372.    /* calculate the actual bit values size */
  373.    cbBitSize = fstsIt.cbFile - bfhIt.offBits;
  374.  
  375.    /* ensure cp and engine variables have reasonable values */
  376.  
  377.    cp.cx = xdots = filexdots = cxReal;
  378.    cp.cy = ydots = fileydots = cyReal;
  379.             /* note: standard bitmap assumed : cPlanes = 1 */
  380.    cp.colors = colors = filecolors = cbColors = 1 << bitsReal;
  381.    cp.iFractType = fractype = PLASMA;
  382.    cp.cFloatflag = usr_floatflag = 0;
  383.    cp.XL = xxmin = fractalspecific[PLASMA].xmin;
  384.    cp.XR = xxmax = fractalspecific[PLASMA].xmax;
  385.    cp.YT = yymax = fractalspecific[PLASMA].ymax;
  386.    cp.YB = yymin = fractalspecific[PLASMA].ymin;
  387.    cp.param[0] = param[0] = fractalspecific[PLASMA].paramvalue[0];
  388.    cp.param[1] = param[1] = fractalspecific[PLASMA].paramvalue[1];
  389.    cp.param[2] = param[2] = fractalspecific[PLASMA].paramvalue[2];
  390.    cp.param[3] = param[3] = fractalspecific[PLASMA].paramvalue[3];;
  391.    cp.trigndx[0] = trigndx[0] = SIN;
  392.    cp.trigndx[1] = trigndx[1] = SQR;
  393.    cp.trigndx[2] = trigndx[2] = SINH;
  394.    cp.trigndx[3] = trigndx[3] = COSH;
  395.    cp.stdCalcMode = usr_stdcalcmode = 'g';
  396.    cp.distest = usr_distest = 0;
  397.    cp.periodicitycheck = usr_periodicitycheck = 1;
  398.    cp.biomorph = biomorph = -1;
  399.    cp.decomp[0] = decomp[0] = 0; cp.decomp[1] = decomp[1] = 0;
  400.    cp.inside = inside = 1;
  401.    cp.outside = outside = -1;
  402.  
  403.     ytop    = 0;
  404.     ybottom = ydots-1;
  405.     xleft   = 0;
  406.     xright  = xdots-1;
  407.  
  408.      /* resize the memory bitmap for the load */
  409.      /* fall on sword if can't get memory */
  410.      if (GetMemoryBitmap(habThread))
  411.         return(SUB_STAT_FATAL);
  412.  
  413.      /* switch to the User (loaded) Palette */
  414.      cp.pbmiMemory = &bmiColorTableUser;
  415.      cp.sCurrentPalette = IDD_PAL_USER;
  416.  
  417.      bmiColorTableUser.cx = cxReal;
  418.      bmiColorTableUser.cy = cyReal;
  419.      bmiColorTableUser.cPlanes = planesReal;
  420.      bmiColorTableUser.cBitCount = bitsReal;
  421.  
  422.      /* suck the color table out of the file */
  423.      if (OS2fmt)
  424.         {
  425.         if (0 != DosRead(hfileIt,
  426.                    (PVOID) &bmiColorTableUser.argbColor[0],
  427.                     cbColorTable,
  428.                     &usIOAction) )
  429.            {
  430.            DosClose(hfileIt);
  431.            return SUB_STAT_ABORT;
  432.            }
  433.         }
  434.      else
  435.         {
  436.         /* need to go from 4 bytes/entry to 3 bytes/entry */
  437.         cbColors = cbColorTable / sizeof(RGBQUAD);
  438.         prgb1 = &bmiColorTableUser.argbColor[0];
  439.         for (i = 0; i < cbColors; i++)
  440.             {
  441.                      /* get R G B */
  442.             if (0 != DosRead(hfileIt, &prgb1[i], sizeof(RGB), &usIOAction) )
  443.                {
  444.                DosClose(hfileIt);
  445.                return SUB_STAT_ABORT;
  446.                }
  447.             /* skip over the next byte */
  448.             DosChgFilePtr(hfileIt, 1L, FILE_CURRENT, &ulNewPtr);
  449.             }
  450.         /* recompute the amount of the palette table that we have
  451.            now actually filled, for the replication routine next */
  452.         cbColorTable = cbColors * sizeof(RGB);
  453.         }
  454.  
  455.    /* now replicate the color table to 256 entries, if necessary */
  456.    if (cp.colors < 256)
  457.       {
  458.       fp1 = (unsigned char _far *) &bmiColorTableUser.argbColor[0]; /* source */
  459.       fp2 = fp1 + cbColorTable;        /* dest */
  460.       sOffset = fp2 - fp1;             /* distance we have come so far */
  461.       sReps = 256 / cp.colors;         /* if it ain't even, forget excess! */
  462.       for (i = 1; i < sReps; i++)
  463.           {
  464.           _fmemcpy(fp2, fp1, sOffset); /* copy a thwak */
  465.           fp2 += sOffset;              /*  then bump dest */
  466.           }
  467.       }
  468.  
  469.      cp.fHaveUserPalette = TRUE;
  470.  
  471.      /* now suck in the actual bits */
  472.      /* read in (up to) 32K at a time */
  473.      hp = cp.pixels;
  474.      while(cbBitSize > 0)
  475.         {
  476.         if (0 != DosRead(hfileIt,
  477.                     (PVOID) hp,
  478.                     (cbBitSize > 0x8000L) ? 0x8000 : (USHORT) cbBitSize,
  479.                     &usIOAction) )
  480.            {
  481.            DosClose(hfileIt);
  482.            return SUB_STAT_ABORT;
  483.            }
  484.            hp += 0x8000L;
  485.            cbBitSize -= 0x8000L;
  486.         }
  487.  
  488.      DosClose(hfileIt);
  489.      /* that's all, folks */
  490.      return (SUB_STAT_OK);
  491.      }
  492.  
  493. static int LoadDriverMET(VOID)
  494.      {
  495.  
  496.      /* and go home */
  497.      return (SUB_STAT_FATAL);
  498.      }
  499.  
  500. static int LoadDriverPCX(VOID)
  501.      {
  502.  
  503.      /* and go home */
  504.      return (SUB_STAT_FATAL);
  505.      }
  506.  
  507. /* --------------------------------------------------------------------- */
  508.  
  509. /* --------------------------------------------------------
  510.    This routine fetches a bitmap from the PM Clipboard
  511.    and puts it into our pixel array.  From there we will
  512.    display it as a PLASMA.
  513.    -------------------------------------------------------- */
  514.  
  515. VOID PMfrFetchClipbrdBmp(HAB hab)
  516.    {
  517.  
  518.    HDC hdcClip;         /* memory DC and PS to extract from the clipboard */
  519.    HPS hpsClip;
  520.    HBITMAP hbmClip;
  521.    BITMAPINFOHEADER bmiClip;
  522.    SIZEL sizl;
  523.    unsigned char _far *fp1;
  524.    unsigned char _far *fp2;
  525.    USHORT sOffset, sReps;
  526.    int i;
  527.  
  528.    if (WinOpenClipbrd(hab))
  529.       {
  530.       if (hbmClip = (HBITMAP) WinQueryClipbrdData(hab, CF_BITMAP))
  531.          {
  532.          /* find the size of the bitmap */
  533.          bmiClip.cbFix = sizeof(BITMAPINFOHEADER);
  534.  
  535.          GpiQueryBitmapParameters (hbmClip, &bmiClip);
  536.  
  537.          /* get the memory DC and PS to extract the bits */
  538.          hdcClip = DevOpenDC (hab, OD_MEMORY, "*", 0L, NULL, NULL) ;
  539.  
  540.          sizl.cx = bmiClip.cx; sizl.cy = bmiClip.cy;
  541.  
  542.          hpsClip = GpiCreatePS (hab, hdcClip, &sizl,
  543.                        PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
  544.  
  545.          /* set the bitmap in our PS */
  546.          GpiSetBitmap(hpsClip, hbmClip);
  547.  
  548.          /* ensure cp and engine variables have reasonable values */
  549.  
  550.          cp.cx = xdots = filexdots = bmiClip.cx;
  551.          cp.cy = ydots = fileydots = bmiClip.cy;
  552.             /* note: standard bitmap assumed : cPlanes = 1 */
  553.          cp.colors = colors = filecolors = 1 << bmiClip.cBitCount;
  554.          cp.iFractType = fractype = PLASMA;
  555.          cp.cFloatflag = usr_floatflag = 0;
  556.          cp.XL = xxmin = fractalspecific[PLASMA].xmin;
  557.          cp.XR = xxmax = fractalspecific[PLASMA].xmax;
  558.          cp.YT = yymax = fractalspecific[PLASMA].ymax;
  559.          cp.YB = yymin = fractalspecific[PLASMA].ymin;
  560.          cp.param[0] = param[0] = fractalspecific[PLASMA].paramvalue[0];
  561.          cp.param[1] = param[1] = fractalspecific[PLASMA].paramvalue[1];
  562.          cp.param[2] = param[2] = fractalspecific[PLASMA].paramvalue[2];
  563.          cp.param[3] = param[3] = fractalspecific[PLASMA].paramvalue[3];;
  564.          cp.trigndx[0] = trigndx[0] = SIN;
  565.          cp.trigndx[1] = trigndx[1] = SQR;
  566.          cp.trigndx[2] = trigndx[2] = SINH;
  567.          cp.trigndx[3] = trigndx[3] = COSH;
  568.          cp.stdCalcMode = usr_stdcalcmode = 'g';
  569.          cp.distest = usr_distest = 0;
  570.          cp.periodicitycheck = usr_periodicitycheck = 1;
  571.          cp.biomorph = biomorph = -1;
  572.          cp.decomp[0] = decomp[0] = 0; cp.decomp[1] = decomp[1] = 0;
  573.          cp.inside = inside = 1;
  574.          cp.outside = outside = -1;
  575.  
  576.          ytop    = 0;
  577.          ybottom = ydots-1;
  578.          xleft   = 0;
  579.          xright  = xdots-1;
  580.  
  581.          /* resize the memory bitmap for the load */
  582.          /* fall on sword if can't get memory */
  583.          if (GetMemoryBitmap(hab))
  584.              goto stopit;
  585.  
  586.          /* switch to the User (loaded) Palette */
  587.          cp.pbmiMemory = &bmiColorTableUser;
  588.          cp.sCurrentPalette = IDD_PAL_USER;
  589.  
  590.          bmiColorTableUser.cx = bmiClip.cx;
  591.          bmiColorTableUser.cy = bmiClip.cy;
  592.          bmiColorTableUser.cPlanes = bmiClip.cPlanes;
  593.          bmiColorTableUser.cBitCount = bmiClip.cBitCount;
  594.  
  595.          /* now grab the actual bits */
  596.          GpiQueryBitmapBits(hpsClip, 0L, (LONG) bmiClip.cy,
  597.                     cp.pixels, &bmiColorTableUser);
  598.  
  599.          /* now replicate the color table to 256 entries, if necessary */
  600.          if (cp.colors < 256)
  601.             {
  602.             fp1 = (unsigned char _far *) &bmiColorTableUser.argbColor[0]; /* source */
  603.             fp2 = fp1 + (cp.colors * sizeof(RGB) );        /* dest */
  604.             sOffset = fp2 - fp1;             /* distance we have come so far */
  605.             sReps = 256 / cp.colors;         /* if it ain't even, forget excess! */
  606.             for (i = 1; i < sReps; i++)
  607.                 {
  608.                 _fmemcpy(fp2, fp1, sOffset); /* copy a thwak */
  609.                 fp2 += sOffset;              /*  then bump dest */
  610.                 }
  611.             }
  612.  
  613.          cp.fHaveUserPalette = TRUE;
  614.          cp.fNewBits = TRUE;
  615.  
  616.          /* now clean up */
  617.  
  618.  stopit:
  619.          GpiSetBitmap(hpsClip, (HBITMAP) NULL);
  620.          GpiDestroyPS(hpsClip);
  621.          DevCloseDC(hdcClip);
  622.          }
  623.  
  624.       WinCloseClipbrd(hab);
  625.       }
  626.  
  627.    }
  628.