home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / gbmos2pm.zip / gbmv2 / model.c < prev    next >
C/C++ Source or Header  |  1996-12-04  |  23KB  |  1,006 lines

  1.  
  2. /*
  3.  
  4. model.c - Work on the model used in GbmV2
  5.  
  6. */
  7.  
  8. /*...sincludes:0:*/
  9. #define    INCL_DOS
  10. #define    INCL_WIN
  11. #define    INCL_GPI
  12. #define    INCL_DEV
  13. #define    INCL_BITMAPFILEFORMAT
  14. #include <os2.h>
  15. #include <stdio.h>
  16. #include <ctype.h>
  17. #include <stdlib.h>
  18. #include <string.h>
  19. #include <malloc.h>
  20. #include <memory.h>
  21. #include <sys/types.h>
  22. #include <sys/stat.h>
  23. #include <io.h>
  24. #include <fcntl.h>
  25. #include <math.h>
  26. #include "gbm.h"
  27. #include "gbmtrunc.h"
  28. #include "gbmerr.h"
  29. #include "gbmht.h"
  30. #include "gbmhist.h"
  31. #include "gbmmcut.h"
  32. #include "gbmmir.h"
  33. #include "gbmrect.h"
  34. #include "gbmscale.h"
  35. #include "model.h"
  36.  
  37. /*...vgbm\46\h:0:*/
  38. /*...vgbmtrunc\46\h:0:*/
  39. /*...vgbmerr\46\h:0:*/
  40. /*...vgbmht\46\h:0:*/
  41. /*...vgbmhist\46\h:0:*/
  42. /*...vgbmmcut\46\h:0:*/
  43. /*...vgbmmir\46\h:0:*/
  44. /*...vgbmrect\46\h:0:*/
  45. /*...vgbmscale\46\h:0:*/
  46. /*...vmodel\46\h:0:*/
  47. /*...e*/
  48.  
  49. /*...sStrideOf:0:*/
  50. static int StrideOf(const MOD *mod)
  51.     {
  52.     return ( ( mod->gbm.w * mod->gbm.bpp + 31 ) / 32 ) * 4;
  53.     }
  54. /*...e*/
  55. /*...sAllocateData:0:*/
  56. static BOOL AllocateData(MOD *mod)
  57.     {
  58.     int stride = StrideOf(mod);
  59.     if ( (mod->pbData = malloc(stride * mod->gbm.h)) == NULL )
  60.         return FALSE;
  61.     return TRUE;
  62.     }
  63. /*...e*/
  64.  
  65. /*...sModCreate:0:*/
  66. MOD_ERR ModCreate(
  67.     int w, int h, int bpp, const GBMRGB gbmrgb[],
  68.     MOD *modNew
  69.     )
  70.     {
  71.     modNew->gbm.w   = w;
  72.     modNew->gbm.h   = h;
  73.     modNew->gbm.bpp = bpp;
  74.     if ( gbmrgb != NULL && bpp != 24 )
  75.         memcpy(&(modNew->gbmrgb), gbmrgb, sizeof(GBMRGB) << bpp);
  76.     if ( !AllocateData(modNew) )
  77.         return MOD_ERR_MEM;
  78.     return MOD_ERR_OK;
  79.     }
  80. /*...e*/
  81. /*...sModDelete:0:*/
  82. MOD_ERR ModDelete(MOD *mod)
  83.     {
  84.     free(mod->pbData);
  85.     return MOD_ERR_OK;
  86.     }
  87. /*...e*/
  88. /*...sModCopy:0:*/
  89. MOD_ERR ModCopy(const MOD *mod, MOD *modNew)
  90.     {
  91.     modNew->gbm.w   = mod->gbm.w;
  92.     modNew->gbm.h   = mod->gbm.h;
  93.     modNew->gbm.bpp = mod->gbm.bpp;
  94.     if ( mod->gbm.bpp != 24 )
  95.         memcpy(modNew->gbmrgb, mod->gbmrgb, sizeof(GBMRGB) << mod->gbm.bpp);
  96.  
  97.     if ( !AllocateData(modNew) )
  98.         return MOD_ERR_MEM;
  99.     memcpy(modNew->pbData, mod->pbData, StrideOf(mod) * mod->gbm.h);
  100.     return MOD_ERR_OK;
  101.     }
  102. /*...e*/
  103. /*...sModMove:0:*/
  104. MOD_ERR ModMove(MOD *mod, MOD *modNew)
  105.     {
  106.     memcpy(modNew, mod, sizeof(MOD));
  107.     return MOD_ERR_OK;
  108.     }
  109. /*...e*/
  110. /*...sModCreateFromFile:0:*/
  111. MOD_ERR ModCreateFromFile(
  112.     const CHAR *szFn, const CHAR *szOpt,
  113.     MOD *modNew
  114.     )
  115.     {
  116.     GBM_ERR grc;
  117.     int fd, ft;
  118.  
  119.     if ( (grc = gbm_guess_filetype(szFn, &ft)) != GBM_ERR_OK )
  120.         return MOD_ERR_GBM(grc);
  121.  
  122.     if ( (fd = gbm_io_open(szFn, O_RDONLY|O_BINARY)) == -1 )
  123.         return MOD_ERR_OPEN;
  124.  
  125.     if ( (grc = gbm_read_header(szFn, fd, ft, &(modNew->gbm), szOpt)) != GBM_ERR_OK )
  126.         {
  127.         gbm_io_close(fd);
  128.         return MOD_ERR_GBM(grc);
  129.         }
  130.  
  131.     if ( (grc = gbm_read_palette(fd, ft, &(modNew->gbm), modNew->gbmrgb)) != GBM_ERR_OK )
  132.         {
  133.         gbm_io_close(fd);
  134.         return MOD_ERR_GBM(grc);
  135.         }
  136.  
  137.     if ( !AllocateData(modNew) )
  138.         {
  139.         gbm_io_close(fd);
  140.         return MOD_ERR_MEM;
  141.         }
  142.  
  143.     if ( (grc = gbm_read_data(fd, ft, &(modNew->gbm), modNew->pbData)) != GBM_ERR_OK )
  144.         {
  145.         free(modNew->pbData);
  146.         gbm_io_close(fd);
  147.         return MOD_ERR_GBM(grc);
  148.         }
  149.  
  150.     gbm_io_close(fd);
  151.  
  152.     return MOD_ERR_OK;
  153.     }
  154. /*...e*/
  155. /*...sModWriteToFile:0:*/
  156. MOD_ERR ModWriteToFile(
  157.     const MOD *mod,
  158.     const CHAR *szFn, const CHAR *szOpt
  159.     )
  160.     {
  161.     GBM_ERR grc;
  162.     int fd, ft, flag;
  163.     GBMFT gbmft;
  164.  
  165.     if ( (grc = gbm_guess_filetype(szFn, &ft)) != GBM_ERR_OK )
  166.         return grc;
  167.  
  168.     gbm_query_filetype(ft, &gbmft);
  169.     switch ( mod->gbm.bpp )
  170.         {
  171.         case 1:        flag = GBM_FT_W1;    break;
  172.         case 4:        flag = GBM_FT_W4;    break;
  173.         case 8:        flag = GBM_FT_W8;    break;
  174.         case 24:    flag = GBM_FT_W24;    break;
  175.         }
  176.  
  177.     if ( (gbmft.flags & flag) == 0 )
  178.         return MOD_ERR_SUPPORT;
  179.  
  180.     if ( (fd = gbm_io_create(szFn, O_WRONLY|O_BINARY)) == -1 )
  181.         return MOD_ERR_CREATE;
  182.  
  183.     if ( (grc = gbm_write(szFn, fd, ft, &(mod->gbm), mod->gbmrgb, mod->pbData, szOpt)) != GBM_ERR_OK )
  184.         {
  185.         gbm_io_close(fd);
  186.         unlink(szFn);
  187.         return MOD_ERR_GBM(grc);
  188.         }
  189.  
  190.     gbm_io_close(fd);
  191.  
  192.     return MOD_ERR_OK;
  193.     }
  194. /*...e*/
  195. /*...sModExpandTo24Bpp:0:*/
  196. MOD_ERR ModExpandTo24Bpp(const MOD *mod, MOD *mod24)
  197.     {
  198.     MOD_ERR mrc;
  199.     int stride, stride24, y;
  200.  
  201.     if ( (mrc = ModCreate(mod->gbm.w, mod->gbm.h,
  202.          24, mod->gbmrgb, mod24)) != MOD_ERR_OK )
  203.         return mrc;
  204.  
  205.     stride   = StrideOf(mod  );
  206.     stride24 = StrideOf(mod24);
  207.  
  208.     for ( y = 0; y < mod->gbm.h; y++ )
  209.         {
  210.         BYTE *pbSrc  = mod  ->pbData + y * stride  ;
  211.         BYTE *pbDest = mod24->pbData + y * stride24;
  212.         int x;
  213.  
  214.         switch ( mod->gbm.bpp )
  215.             {
  216. /*...s1:24:*/
  217. case 1:
  218.     {
  219.     BYTE c;
  220.  
  221.     for ( x = 0; x < mod->gbm.w; x++ )
  222.         {
  223.         if ( (x & 7) == 0 )
  224.             c = *pbSrc++;
  225.         else
  226.             c <<= 1;
  227.  
  228.         *pbDest++ = mod->gbmrgb[c >> 7].b;
  229.         *pbDest++ = mod->gbmrgb[c >> 7].g;
  230.         *pbDest++ = mod->gbmrgb[c >> 7].r;
  231.         }
  232.     }
  233.     break;
  234. /*...e*/
  235. /*...s4:24:*/
  236. case 4:
  237.     for ( x = 0; x + 1 < mod->gbm.w; x += 2 )
  238.         {
  239.         BYTE c = *pbSrc++;
  240.  
  241.         *pbDest++ = mod->gbmrgb[c >> 4].b;
  242.         *pbDest++ = mod->gbmrgb[c >> 4].g;
  243.         *pbDest++ = mod->gbmrgb[c >> 4].r;
  244.         *pbDest++ = mod->gbmrgb[c & 15].b;
  245.         *pbDest++ = mod->gbmrgb[c & 15].g;
  246.         *pbDest++ = mod->gbmrgb[c & 15].r;
  247.         }
  248.  
  249.     if ( x < mod->gbm.w )
  250.         {
  251.         BYTE c = *pbSrc;
  252.  
  253.         *pbDest++ = mod->gbmrgb[c >> 4].b;
  254.         *pbDest++ = mod->gbmrgb[c >> 4].g;
  255.         *pbDest++ = mod->gbmrgb[c >> 4].r;
  256.         }
  257.     break;
  258. /*...e*/
  259. /*...s8:24:*/
  260. case 8:
  261.     for ( x = 0; x < mod->gbm.w; x++ )
  262.         {
  263.         BYTE c = *pbSrc++;
  264.  
  265.         *pbDest++ = mod->gbmrgb[c].b;
  266.         *pbDest++ = mod->gbmrgb[c].g;
  267.         *pbDest++ = mod->gbmrgb[c].r;
  268.         }
  269.     break;
  270. /*...e*/
  271. /*...s24:24:*/
  272. case 24:
  273.     memcpy(pbDest, pbSrc, stride);
  274.     break;
  275. /*...e*/
  276.             }
  277.         }
  278.  
  279.     return MOD_ERR_OK;
  280.     }
  281. /*...e*/
  282. /*...sModReflectHorz:0:*/
  283. MOD_ERR ModReflectHorz(const MOD *mod, MOD *modNew)
  284.     {
  285.     MOD_ERR mrc;
  286.     if ( (mrc = ModCopy(mod, modNew)) != MOD_ERR_OK )
  287.         return mrc;
  288.     if ( !gbm_ref_horz(&(modNew->gbm), modNew->pbData) )
  289.         {
  290.         free(modNew->pbData);
  291.         return MOD_ERR_MEM;
  292.         }
  293.     return MOD_ERR_OK;
  294.     }
  295. /*...e*/
  296. /*...sModReflectVert:0:*/
  297. MOD_ERR ModReflectVert(const MOD *mod, MOD *modNew)
  298.     {
  299.     MOD_ERR mrc;
  300.     if ( (mrc = ModCopy(mod, modNew)) != MOD_ERR_OK )
  301.         return mrc;
  302.     if ( !gbm_ref_vert(&(modNew->gbm), modNew->pbData) )
  303.         {
  304.         free(modNew->pbData);
  305.         return MOD_ERR_MEM;
  306.         }
  307.     return MOD_ERR_OK;
  308.     }
  309. /*...e*/
  310. /*...sModTranspose:0:*/
  311. MOD_ERR ModTranspose(const MOD *mod, MOD *modNew)
  312.     {
  313.     modNew->gbm.w   = mod->gbm.h;
  314.     modNew->gbm.h   = mod->gbm.w;
  315.     modNew->gbm.bpp = mod->gbm.bpp;
  316.     if ( mod->gbm.bpp != 24 )
  317.         memcpy(modNew->gbmrgb, mod->gbmrgb, sizeof(GBMRGB) << mod->gbm.bpp);
  318.     if ( !AllocateData(modNew) )
  319.         return MOD_ERR_MEM;
  320.     gbm_transpose(&(mod->gbm), mod->pbData, modNew->pbData);
  321.     return MOD_ERR_OK;
  322.     }
  323. /*...e*/
  324. /*...sModRotate90:0:*/
  325. MOD_ERR ModRotate90(const MOD *mod, MOD *modNew)
  326.     {
  327.     MOD_ERR mrc;
  328.     MOD modTmp;
  329.  
  330.     if ( (mrc = ModReflectVert(mod, &modTmp)) != MOD_ERR_OK )
  331.         return mrc;
  332.     mrc = ModTranspose(&modTmp, modNew);
  333.     ModDelete(&modTmp);
  334.     return mrc;
  335.     }
  336. /*...e*/
  337. /*...sModRotate180:0:*/
  338. MOD_ERR ModRotate180(const MOD *mod, MOD *modNew)
  339.     {
  340.     MOD_ERR mrc;
  341.     if ( (mrc = ModCopy(mod, modNew)) != MOD_ERR_OK )
  342.         return mrc;
  343.     if ( !gbm_ref_horz(&(modNew->gbm), modNew->pbData) )
  344.         {
  345.         free(modNew->pbData);
  346.         return MOD_ERR_MEM;
  347.         }
  348.     if ( !gbm_ref_vert(&(modNew->gbm), modNew->pbData) )
  349.         {
  350.         free(modNew->pbData);
  351.         return MOD_ERR_MEM;
  352.         }
  353.     return MOD_ERR_OK;
  354.     }
  355. /*...e*/
  356. /*...sModRotate270:0:*/
  357. MOD_ERR ModRotate270(const MOD *mod, MOD *modNew)
  358.     {
  359.     MOD_ERR mrc;
  360.     MOD modTmp;
  361.  
  362.     if ( (mrc = ModReflectHorz(mod, &modTmp)) != MOD_ERR_OK )
  363.         return mrc;
  364.     mrc = ModTranspose(&modTmp, modNew);
  365.     ModDelete(&modTmp);
  366.     return mrc;
  367.     }
  368. /*...e*/
  369. /*...sModExtractSubrectangle:0:*/
  370. MOD_ERR ModExtractSubrectangle(
  371.     const MOD *mod,
  372.     int x, int y, int w, int h,
  373.     MOD *modNew
  374.     )
  375.     {
  376.     modNew->gbm.w   = w;
  377.     modNew->gbm.h   = h;
  378.     modNew->gbm.bpp = mod->gbm.bpp;
  379.     if ( mod->gbm.bpp != 24 )
  380.         memcpy(modNew->gbmrgb, mod->gbmrgb, sizeof(GBMRGB) << mod->gbm.bpp);
  381.  
  382.     if ( !AllocateData(modNew) )
  383.         return MOD_ERR_MEM;
  384.  
  385.     gbm_subrectangle(&(mod->gbm), x, y, w, h, mod->pbData, modNew->pbData);
  386.  
  387.     return MOD_ERR_OK;
  388.     }
  389. /*...e*/
  390. /*...sModBlit:0:*/
  391. MOD_ERR ModBlit(
  392.           MOD *modDst, int dx, int dy,
  393.     const MOD *modSrc, int sx, int sy,
  394.     int w, int h
  395.     )
  396.     {
  397.     if ( sx < 0 || sx+w > modSrc->gbm.w ||
  398.          sy < 0 || sy+h > modSrc->gbm.h ||
  399.          dx < 0 || dx+w > modDst->gbm.w ||
  400.          dy < 0 || dy+h > modDst->gbm.h )
  401.         return MOD_ERR_CLIP;
  402.     gbm_blit(
  403.         modSrc->pbData, modSrc->gbm.w, sx, sy,
  404.         modDst->pbData, modDst->gbm.w, dx, dy,
  405.         w, h,
  406.         modSrc->gbm.bpp);
  407.     return MOD_ERR_OK;
  408.     }
  409. /*...e*/
  410. /*...sModColourAdjust:0:*/
  411. /*...smap_compute:0:*/
  412. /*...slstar_from_i:0:*/
  413. static double lstar_from_i(double y)
  414.     {
  415.     y = pow(1.16 * y, 1.0/3.0) - 0.16;
  416.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  417.     return y;
  418.     }
  419. /*...e*/
  420. /*...si_from_lstar:0:*/
  421. static double i_from_lstar(double y)
  422.     {
  423.     y = pow(y + 0.16, 3.0) / 1.16;
  424.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  425.     return y;
  426.     }
  427. /*...e*/
  428. /*...spal_from_i:0:*/
  429. static double pal_from_i(double y, double gam, double shelf)
  430.     {
  431.     y = pow(y,1.0 / gam) * (1.0 - shelf) + shelf;
  432.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  433.     return y;
  434.     }
  435. /*...e*/
  436. /*...si_from_pal:0:*/
  437. static double i_from_pal(double y, double gam, double shelf)
  438.     {
  439.     if ( y >= shelf )
  440.         y = pow((y - shelf) / (1.0 - shelf), gam);
  441.     else
  442.         y = 0.0;
  443.     if ( y < 0.0 ) y = 0.0; else if ( y > 1.0 ) y = 1.0;
  444.     return y;
  445.     }
  446. /*...e*/
  447.  
  448. static void map_compute(int m, byte remap[], double gam, double shelf)
  449.     {
  450.     int    i;
  451.  
  452.     for ( i = 0; i < 0x100; i++ )
  453.         {
  454.         double y = (double) i / 255.0;
  455.  
  456.         switch ( m )
  457.             {
  458.             case CVT_I_TO_P: y = pal_from_i(y, gam, shelf); break;
  459.             case CVT_P_TO_I: y = i_from_pal(y, gam, shelf); break;
  460.             case CVT_I_TO_L: y = lstar_from_i(y); break;
  461.             case CVT_L_TO_I: y = i_from_lstar(y); break;
  462.             case CVT_P_TO_L: y = lstar_from_i(i_from_pal(y, gam, shelf)); break;
  463.             case CVT_L_TO_P: y = pal_from_i(i_from_lstar(y), gam, shelf); break;
  464.             }
  465.  
  466.         remap[i] = (byte) (y * 255.0);
  467.         }
  468.     }
  469. /*...e*/
  470. /*...smap_data:0:*/
  471. static void map_data(byte *data, int w, int h, const byte remap[])
  472.     {
  473.     int stride = ((w * 3 + 3) & ~3);
  474.     int x, y;
  475.  
  476.     for ( y = 0; y < h; y++, data += stride )
  477.         for ( x = 0; x < w * 3; x++ )
  478.             data[x] = remap[data[x]];
  479.     }
  480. /*...e*/
  481. /*...smap_palette:0:*/
  482. static void map_palette(GBMRGB *gbmrgb, int npals, const byte remap[])
  483.     {
  484.     for ( ; npals--; gbmrgb++ )
  485.         {
  486.         gbmrgb->b = remap[gbmrgb->b];
  487.         gbmrgb->g = remap[gbmrgb->g];
  488.         gbmrgb->r = remap[gbmrgb->r];
  489.         }
  490.     }
  491. /*...e*/
  492.  
  493. MOD_ERR ModColourAdjust(
  494.     const MOD *mod,
  495.     int map, double gama, double shelf,
  496.     MOD *modNew
  497.     )
  498.     {
  499.     MOD_ERR mrc;
  500.     BYTE abRemap[0x100];
  501.  
  502.     if ( (mrc = ModCopy(mod, modNew)) != MOD_ERR_OK )
  503.         return mrc;
  504.  
  505.     map_compute(map, abRemap, gama, shelf);
  506.  
  507.     if ( mod->gbm.bpp == 24 )
  508.         map_data(modNew->pbData, modNew->gbm.w, modNew->gbm.h, abRemap);
  509.     else
  510.         map_palette(modNew->gbmrgb, 1 << modNew->gbm.bpp, abRemap);
  511.  
  512.     return MOD_ERR_OK;
  513.     }
  514. /*...e*/
  515. /*...sModBppMap:0:*/
  516. /*...sBppMap:0:*/
  517. /*...sToGreyPal:0:*/
  518. static VOID ToGreyPal(GBMRGB *gbmrgb)
  519.     {
  520.     int i;
  521.  
  522.     for ( i = 0; i < 0x100; i++ )
  523.         gbmrgb[i].r =
  524.         gbmrgb[i].g =
  525.         gbmrgb[i].b = (byte) i;
  526.     }
  527. /*...e*/
  528. /*...sToGrey:0:*/
  529. static VOID ToGrey(GBM *gbm, const byte *src_data, byte *dest_data)
  530.     {
  531.     int src_stride  = ((gbm -> w * 3 + 3) & ~3);
  532.     int dest_stride = ((gbm -> w     + 3) & ~3);
  533.     int y;
  534.  
  535.     for ( y = 0; y < gbm -> h; y++ )
  536.         {
  537.         const byte *src  = src_data;
  538.               byte *dest = dest_data;
  539.         int x;
  540.  
  541.         for ( x = 0; x < gbm -> w; x++ )
  542.             {
  543.             byte b = *src++;
  544.             byte g = *src++;
  545.             byte r = *src++;
  546.  
  547.             *dest++ = (byte) (((word) r * 77 + (word) g * 151 + (word) b * 28) >> 8);
  548.             }
  549.  
  550.         src_data  += src_stride;
  551.         dest_data += dest_stride;
  552.         }
  553.     gbm -> bpp = 8;
  554.     }
  555. /*...e*/
  556. /*...sTripelPal:0:*/
  557. static VOID TripelPal(GBMRGB *gbmrgb)
  558.     {
  559.     int i;
  560.  
  561.     memset(gbmrgb, 0, 0x100 * sizeof(GBMRGB));
  562.  
  563.     for ( i = 0; i < 0x40; i++ )
  564.         {
  565.         gbmrgb[i       ].r = (byte) (i << 2);
  566.         gbmrgb[i + 0x40].g = (byte) (i << 2);
  567.         gbmrgb[i + 0x80].b = (byte) (i << 2);
  568.         }
  569.     }
  570. /*...e*/
  571. /*...sTripel:0:*/
  572. static VOID Tripel(GBM *gbm, const byte *src_data, byte *dest_data)
  573.     {
  574.     int src_stride  = ((gbm -> w * 3 + 3) & ~3);
  575.     int dest_stride = ((gbm -> w     + 3) & ~3);
  576.     int y;
  577.  
  578.     for ( y = 0; y < gbm -> h; y++ )
  579.         {
  580.         const byte *src  = src_data;
  581.               byte *dest = dest_data;
  582.         int x;
  583.  
  584.         for ( x = 0; x < gbm -> w; x++ )
  585.             {
  586.             byte b = *src++;
  587.             byte g = *src++;
  588.             byte r = *src++;
  589.  
  590.             switch ( (x+y)%3 )
  591.                 {
  592.                 case 0:    *dest++ = (byte)         (r >> 2) ;    break;
  593.                 case 1:    *dest++ = (byte) (0x40 + (g >> 2));    break;
  594.                 case 2:    *dest++ = (byte) (0x80 + (b >> 2));    break;
  595.                 }
  596.             }
  597.  
  598.         src_data  += src_stride;
  599.         dest_data += dest_stride;
  600.         }
  601.     gbm -> bpp = 8;
  602.     }
  603. /*...e*/
  604.  
  605. static BOOL BppMap(
  606.     const MOD *mod24,
  607.     int iPal, int iAlg,
  608.     int iKeepRed, int iKeepGreen, int iKeepBlue, int nCols,
  609.     MOD *modNew
  610.     )
  611.     {
  612.     BYTE rm = (BYTE) (0xff00 >> iKeepRed  );
  613.     BYTE gm = (BYTE) (0xff00 >> iKeepGreen);
  614.     BYTE bm = (BYTE) (0xff00 >> iKeepBlue );
  615.     BOOL ok = TRUE;
  616.  
  617. #define    SW2(a,b) (((a)<<8)|(b))
  618.     switch ( SW2(iPal,iAlg) )
  619.         {
  620.         case SW2(CVT_BW,CVT_NEAREST):
  621.             gbm_trunc_pal_BW(modNew->gbmrgb);
  622.             gbm_trunc_BW(&(modNew->gbm), mod24->pbData, modNew->pbData);
  623.             break;
  624.         case SW2(CVT_4G,CVT_NEAREST):
  625.             gbm_trunc_pal_4G(modNew->gbmrgb);
  626.             gbm_trunc_4G(&(modNew->gbm), mod24->pbData, modNew->pbData);
  627.             break;
  628.         case SW2(CVT_8,CVT_NEAREST):
  629.             gbm_trunc_pal_8(modNew->gbmrgb);
  630.             gbm_trunc_8(&(modNew->gbm), mod24->pbData, modNew->pbData);
  631.             break;
  632.         case SW2(CVT_VGA,CVT_NEAREST):
  633.             gbm_trunc_pal_VGA(modNew->gbmrgb);
  634.             gbm_trunc_VGA(&(modNew->gbm), mod24->pbData, modNew->pbData);
  635.             break;
  636.         case SW2(CVT_784,CVT_NEAREST):
  637.             gbm_trunc_pal_7R8G4B(modNew->gbmrgb);
  638.             gbm_trunc_7R8G4B(&(modNew->gbm), mod24->pbData, modNew->pbData);
  639.             break;
  640.         case SW2(CVT_666,CVT_NEAREST):
  641.             gbm_trunc_pal_6R6G6B(modNew->gbmrgb);
  642.             gbm_trunc_6R6G6B(&(modNew->gbm), mod24->pbData, modNew->pbData);
  643.             break;
  644.         case SW2(CVT_8G,CVT_NEAREST):
  645.             ToGreyPal(modNew->gbmrgb);
  646.             ToGrey(&(modNew->gbm), mod24->pbData, modNew->pbData);
  647.             break;
  648.         case SW2(CVT_TRIPEL,CVT_NEAREST):
  649.             TripelPal(modNew->gbmrgb);
  650.             Tripel(&(modNew->gbm), mod24->pbData, modNew->pbData);
  651.             break;
  652.         case SW2(CVT_FREQ,CVT_NEAREST):
  653.             memset(modNew->gbmrgb, 0, sizeof(modNew->gbmrgb));
  654.             gbm_hist(&(modNew->gbm), mod24->pbData, modNew->gbmrgb, modNew->pbData, nCols, rm, gm, bm);
  655.             break;
  656.         case SW2(CVT_MCUT,CVT_NEAREST):
  657.             memset(modNew->gbmrgb, 0, sizeof(modNew->gbmrgb));
  658.             gbm_mcut(&(modNew->gbm), mod24->pbData, modNew->gbmrgb, modNew->pbData, nCols);
  659.             break;
  660.         case SW2(CVT_RGB,CVT_NEAREST):
  661.             gbm_trunc_24(&(modNew->gbm), mod24->pbData, modNew->pbData, rm, gm, bm);
  662.             break;
  663.         case SW2(CVT_BW,CVT_ERRDIFF):
  664.             gbm_errdiff_pal_BW(modNew->gbmrgb);
  665.             ok = gbm_errdiff_BW(&(modNew->gbm), mod24->pbData, modNew->pbData);
  666.             break;
  667.         case SW2(CVT_4G,CVT_ERRDIFF):
  668.             gbm_errdiff_pal_4G(modNew->gbmrgb);
  669.             ok = gbm_errdiff_4G(&(modNew->gbm), mod24->pbData, modNew->pbData);
  670.             break;
  671.         case SW2(CVT_8,CVT_ERRDIFF):
  672.             gbm_errdiff_pal_8(modNew->gbmrgb);
  673.             ok = gbm_errdiff_8(&(modNew->gbm), mod24->pbData, modNew->pbData);
  674.             break;
  675.         case SW2(CVT_VGA,CVT_ERRDIFF):
  676.             gbm_errdiff_pal_VGA(modNew->gbmrgb);
  677.             ok = gbm_errdiff_VGA(&(modNew->gbm), mod24->pbData, modNew->pbData);
  678.             break;
  679.         case SW2(CVT_784,CVT_ERRDIFF):
  680.             gbm_errdiff_pal_7R8G4B(modNew->gbmrgb);
  681.             ok = gbm_errdiff_7R8G4B(&(modNew->gbm), mod24->pbData, modNew->pbData);
  682.             break;
  683.         case SW2(CVT_666,CVT_ERRDIFF):
  684.             gbm_errdiff_pal_6R6G6B(modNew->gbmrgb);
  685.             ok = gbm_errdiff_6R6G6B(&(modNew->gbm), mod24->pbData, modNew->pbData);
  686.             break;
  687.         case SW2(CVT_RGB,CVT_ERRDIFF):
  688.             ok = gbm_errdiff_24(&(modNew->gbm), mod24->pbData, modNew->pbData, rm, gm, bm);
  689.             break;
  690.         case SW2(CVT_784,CVT_HALFTONE):
  691.             gbm_ht_pal_7R8G4B(modNew->gbmrgb);
  692.             gbm_ht_7R8G4B_2x2(&(modNew->gbm), mod24->pbData, modNew->pbData);
  693.             break;
  694.         case SW2(CVT_666,CVT_HALFTONE):
  695.             gbm_ht_pal_6R6G6B(modNew->gbmrgb);
  696.             gbm_ht_6R6G6B_2x2(&(modNew->gbm), mod24->pbData, modNew->pbData);
  697.             break;
  698.         case SW2(CVT_8,CVT_HALFTONE):
  699.             gbm_ht_pal_8(modNew->gbmrgb);
  700.             gbm_ht_8_3x3(&(modNew->gbm), mod24->pbData, modNew->pbData);
  701.             break;
  702.         case SW2(CVT_VGA,CVT_HALFTONE):
  703.             gbm_ht_pal_VGA(modNew->gbmrgb);
  704.             gbm_ht_VGA_3x3(&(modNew->gbm), mod24->pbData, modNew->pbData);
  705.             break;
  706.         case SW2(CVT_RGB,CVT_HALFTONE):
  707.             gbm_ht_24_2x2(&(modNew->gbm), mod24->pbData, modNew->pbData, rm, gm, bm);
  708.             break;
  709.         }
  710.     return ok;
  711.     }
  712. /*...e*/
  713.  
  714. MOD_ERR ModBppMap(
  715.     const MOD *mod,
  716.     int iPal, int iAlg,
  717.     int iKeepRed, int iKeepGreen, int iKeepBlue, int nCols,
  718.     MOD *modNew
  719.     )
  720.     {
  721.     MOD_ERR mrc;
  722.     int newbpp;
  723.     BOOL fOk;
  724.  
  725.     switch ( iPal )
  726.         {
  727.         case CVT_BW:
  728.             newbpp = 1;
  729.             break;
  730.         case CVT_4G:
  731.         case CVT_8:
  732.         case CVT_VGA:
  733.             newbpp = 4;
  734.             break;
  735.         case CVT_784:
  736.         case CVT_666:
  737.         case CVT_8G:
  738.         case CVT_TRIPEL:
  739.         case CVT_FREQ:
  740.         case CVT_MCUT:
  741.             newbpp = 8;
  742.             break;
  743.         case CVT_RGB:
  744.             newbpp = 24;
  745.             break;
  746.         }
  747.  
  748.     /* The following breakdown into cases can result in significant
  749.        savings in memory by eliminating costly intermediate bitmaps. */
  750.  
  751.     if ( mod->gbm.bpp == 24 )
  752.         /* 24bpp -> anything, map direct from mod */
  753.         {
  754.         if ( (mrc = ModCreate(mod->gbm.w, mod->gbm.h, newbpp, NULL, modNew)) != MOD_ERR_OK )
  755.             return mrc;
  756.         fOk = BppMap(mod, iPal, iAlg, iKeepRed, iKeepGreen, iKeepBlue, nCols, modNew);
  757.         }
  758.     else if ( newbpp == 24 )
  759.         /* !24 -> 24bpp, expand mod to modNew, map modNew inline */
  760.         {
  761.         if ( (mrc = ModExpandTo24Bpp(mod, modNew)) != MOD_ERR_OK )
  762.             return mrc;
  763.         fOk = BppMap(modNew, iPal, iAlg, iKeepRed, iKeepGreen, iKeepBlue, nCols, modNew);
  764.         }
  765.     else
  766.         /* !24bpp -> 24bpp, expand mod to mod24, and map mod24 to modNew */
  767.         {
  768.         MOD mod24;
  769.         if ( (mrc = ModCreate(mod->gbm.w, mod->gbm.h, newbpp, NULL, modNew)) != MOD_ERR_OK )
  770.             return mrc;
  771.         if ( (mrc = ModExpandTo24Bpp(mod, &mod24)) != MOD_ERR_OK )
  772.             {
  773.             ModDelete(modNew);
  774.             return mrc;
  775.             }
  776.         fOk = BppMap(&mod24, iPal, iAlg, iKeepRed, iKeepGreen, iKeepBlue, nCols, modNew);
  777.         ModDelete(&mod24);
  778.         }
  779.  
  780.     return fOk ? MOD_ERR_OK : MOD_ERR_MEM;
  781.     }
  782. /*...e*/
  783. /*...sModResize:0:*/
  784. MOD_ERR ModResize(
  785.     const MOD *mod,
  786.     int nw, int nh,
  787.     MOD *modNew
  788.     )
  789.     {
  790.     MOD_ERR mrc;
  791.     GBM_ERR grc;
  792.  
  793.     if ( (mrc = ModCreate(nw, nh, mod->gbm.bpp, mod->gbmrgb, modNew)) != MOD_ERR_OK )
  794.         return mrc;
  795.  
  796.     if ( (grc = gbm_simple_scale(mod   ->pbData, mod   ->gbm.w, mod   ->gbm.h,
  797.                      modNew->pbData, modNew->gbm.w, modNew->gbm.h,
  798.                      mod->gbm.bpp)) != GBM_ERR_OK )
  799.         {
  800.         ModDelete(modNew);
  801.         return MOD_ERR_GBM(grc);
  802.         }
  803.  
  804.     return MOD_ERR_OK;
  805.     }
  806. /*...e*/
  807. /*...sModCreateFromHPS:0:*/
  808. MOD_ERR ModCreateFromHPS(
  809.     HPS hps, int w, int h, int bpp,
  810.     MOD *modNew
  811.     )
  812.     {
  813.     MOD_ERR mrc;
  814.     struct
  815.         {
  816.         BITMAPINFOHEADER2 bmp2;
  817.         RGB2 argb2Color[0x100];
  818.         } bm;
  819.  
  820.     if ( (mrc = ModCreate(w, h, bpp, NULL, modNew)) != MOD_ERR_OK )
  821.         return mrc;
  822.  
  823.     memset(&(bm.bmp2), 0, sizeof(bm.bmp2));
  824.     bm.bmp2.cbFix     = sizeof(BITMAPINFOHEADER2);
  825.     bm.bmp2.cx        = w;
  826.     bm.bmp2.cy        = h;
  827.     bm.bmp2.cBitCount = bpp;
  828.     bm.bmp2.cPlanes   = 1;
  829.     GpiQueryBitmapBits(hps, 0L, h, modNew->pbData, (BITMAPINFO2 *) &bm);
  830.  
  831.     if ( bpp != 24 )
  832.         {
  833.         int i;
  834.         for ( i = 0; i < (1<<bpp); i++ )
  835.             {
  836.             modNew->gbmrgb[i].r = bm.argb2Color[i].bRed  ;
  837.             modNew->gbmrgb[i].g = bm.argb2Color[i].bGreen;
  838.             modNew->gbmrgb[i].b = bm.argb2Color[i].bBlue ;
  839.             }
  840.         }
  841.  
  842.     return MOD_ERR_OK;
  843.     }
  844. /*...e*/
  845. /*...sModMakeHBITMAP:0:*/
  846. MOD_ERR ModMakeHBITMAP(
  847.     const MOD *mod,
  848.     HAB hab,
  849.     HBITMAP *phbm
  850.     )
  851.     {
  852.     SIZEL sizl;
  853.     HDC hdc;
  854.     HPS hps;
  855.     struct
  856.         {
  857.         BITMAPINFOHEADER2 bmp2;
  858.         RGB2 argb2Color[0x100];
  859.         } bm;
  860.  
  861.     /* Got the data in memory, now make bitmap */
  862.  
  863.     memset(&(bm.bmp2), 0, sizeof(bm.bmp2));
  864.     bm.bmp2.cbFix     = sizeof(BITMAPINFOHEADER2);
  865.     bm.bmp2.cx        = mod->gbm.w;
  866.     bm.bmp2.cy        = mod->gbm.h;
  867.     bm.bmp2.cBitCount = mod->gbm.bpp;
  868.     bm.bmp2.cPlanes   = 1;
  869.  
  870.     if ( mod->gbm.bpp != 24 )
  871.         {
  872.         int i;
  873.         for ( i = 0; i < (1<<mod->gbm.bpp); i++ )
  874.             {
  875.             bm.argb2Color[i].bRed      = mod->gbmrgb[i].r;
  876.             bm.argb2Color[i].bGreen    = mod->gbmrgb[i].g;
  877.             bm.argb2Color[i].bBlue     = mod->gbmrgb[i].b;
  878.             bm.argb2Color[i].fcOptions = 0;
  879.             }
  880.         }
  881.  
  882.     if ( (hdc = DevOpenDC(hab, OD_MEMORY, "*", 0L, (PDEVOPENDATA) NULL, (HDC) NULL)) == (HDC) NULL )
  883.         return MOD_ERR_HDC;
  884.  
  885.     sizl.cx = mod->gbm.w;
  886.     sizl.cy = mod->gbm.h;
  887.     if ( (hps = GpiCreatePS(hab, hdc, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC)) == (HPS) NULL )
  888.         {
  889.         DevCloseDC(hdc);
  890.         return MOD_ERR_HPS;
  891.         }
  892.  
  893.     if ( mod->gbm.bpp == 1 )
  894. /*...shandle 1bpp case:16:*/
  895. /*
  896. 1bpp presentation spaces have a reset or background colour.
  897. They also have a contrast or foreground colour.
  898. When data is mapped into a 1bpp presentation space :-
  899. Data which is the reset colour, remains reset, and is stored as 0's.
  900. All other data becomes contrast, and is stored as 1's.
  901. The reset colour for 1bpp screen HPSs is white.
  902. I want 1's in the source data to become 1's in the HPS.
  903. We seem to have to reverse the ordering here to get the desired effect.
  904. */
  905.  
  906. {
  907. static RGB2 argb2Black = { 0x00, 0x00, 0x00 };
  908. static RGB2 argb2White = { 0xff, 0xff, 0xff };
  909. bm.argb2Color[0] = argb2Black; /* Contrast */
  910. bm.argb2Color[1] = argb2White; /* Reset */
  911. }
  912. /*...e*/
  913.  
  914.     if ( (*phbm = GpiCreateBitmap(hps, &(bm.bmp2), CBM_INIT, mod->pbData, (BITMAPINFO2 *) &(bm.bmp2))) == (HBITMAP) NULL )
  915.         {
  916.         GpiDestroyPS(hps);
  917.         DevCloseDC(hdc);
  918.         return MOD_ERR_HBITMAP;
  919.         }
  920.  
  921.     GpiSetBitmap(hps, (HBITMAP) NULL);
  922.     GpiDestroyPS(hps);
  923.     DevCloseDC(hdc);
  924.  
  925.     return MOD_ERR_OK;
  926.     }
  927.  
  928. /*...e*/
  929. /*...sModMakeHMF:0:*/
  930. /*
  931. I have observed that if I use GpiBitBlt() instead of the GpiWCBitBlt() below,
  932. when the MetaFile is pasted into CUADraw, although CUADraws sizing frame
  933. appears in the middle of the window, the bitmap bits are always drawn at (0,0)
  934. on CUADraws client window. This is why I use GpiWCBitBlt(). Also, in the
  935. PM Programming Reference, under DevOpenDC is a comment suggesting that
  936. GpiBitBlt() should not be used in order to be SAA conforming, presumably there
  937. is a connection here...
  938. */
  939.  
  940. MOD_ERR ModMakeHMF(
  941.     HBITMAP hbm,
  942.     HAB hab,
  943.     HMF *phmf
  944.     )
  945.     {
  946.     DEVOPENSTRUC dop = { NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL };
  947.     SIZEL sizl;
  948.     HPS hpsHmf;
  949.     HDC hdcHmf;
  950.     BITMAPINFOHEADER bmp;
  951.     POINTL aptl[4];
  952.  
  953.     if ( (hdcHmf = DevOpenDC(hab, OD_METAFILE, "*", 5L, (PDEVOPENDATA)&dop, (HDC) NULL)) == (HDC) NULL )
  954.         return MOD_ERR_HDC;
  955.  
  956.     GpiQueryBitmapParameters(hbm, &bmp);
  957.  
  958.     sizl.cx = bmp.cx;
  959.     sizl.cy = bmp.cy;
  960.     if ( (hpsHmf = GpiCreatePS(hab, hdcHmf, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC)) == (HPS) NULL )
  961.         {
  962.         DevCloseDC(hdcHmf);
  963.         return MOD_ERR_HPS;
  964.         }
  965.  
  966.     aptl[0].x = 0;
  967.     aptl[0].y = 0;
  968.     aptl[1].x = bmp.cx;
  969.     aptl[1].y = bmp.cy;
  970.     aptl[2].x = 0;
  971.     aptl[2].y = 0;
  972.     aptl[3].x = bmp.cx;
  973.     aptl[3].y = bmp.cy;
  974.     GpiWCBitBlt(hpsHmf, hbm, 4L, aptl, ROP_SRCCOPY, BBO_IGNORE);
  975.  
  976.     GpiDestroyPS(hpsHmf);
  977.     (*phmf) = DevCloseDC(hdcHmf);
  978.  
  979.     if ( (*phmf) == DEV_ERROR )
  980.         return MOD_ERR_HMF;
  981.  
  982.     return MOD_ERR_OK;
  983.     }
  984. /*...e*/
  985. /*...sModErrorString:0:*/
  986. const CHAR * ModErrorString(MOD_ERR rc)
  987.     {
  988.     if ( rc >= MOD_ERR_GBM(0) )
  989.         return gbm_err(rc-MOD_ERR_GBM(0));
  990.     switch ( (int) rc )
  991.         {
  992.         case MOD_ERR_OK:    return "no error";
  993.         case MOD_ERR_MEM:    return "out of memory";
  994.         case MOD_ERR_OPEN:    return "can't open file";
  995.         case MOD_ERR_CREATE:    return "can't create file";
  996.         case MOD_ERR_SUPPORT:    return "file format doesn't support this bits per pixel";
  997.         case MOD_ERR_HDC:    return "can't create PM device context resource";
  998.         case MOD_ERR_HPS:    return "can't create PM presentation space resource";
  999.         case MOD_ERR_HMF:    return "can't create PM metafile resource";
  1000.         case MOD_ERR_HBITMAP:    return "can't create PM bitmap resource";
  1001.         case MOD_ERR_CLIP:    return "coords need to be clipped";
  1002.         }
  1003.     return "unknown error code";
  1004.     }
  1005. /*...e*/
  1006.