home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / gbmos2pm.zip / gbmv / gbmv.c next >
C/C++ Source or Header  |  1998-12-31  |  13KB  |  573 lines

  1. /*
  2.  
  3. gbmv.c - General Bitmap Viewer
  4.  
  5. */
  6.  
  7. /*...sincludes:0:*/
  8. #define    INCL_DOS
  9. #define    INCL_WIN
  10. #define    INCL_GPI
  11. #define    INCL_DEV
  12. #define    INCL_BITMAPFILEFORMAT
  13. #include <os2.h>
  14. #include <stdio.h>
  15. #include <stdlib.h>
  16. #include <stdarg.h>
  17. #include <string.h>
  18. #include <malloc.h>
  19. #include <memory.h>
  20. #include <io.h>
  21. #include <fcntl.h>
  22. #include <sys/types.h>
  23. #include <sys/stat.h>
  24. #include "gbm.h"
  25. #include "gbmerr.h"
  26. #include "gbmht.h"
  27. #include "gbmv.h"
  28.  
  29. /*...vgbmv\46\h:0:*/
  30. /*...e*/
  31. /*...spm gaps:0:*/
  32. /*
  33. Things you would expect PM to have, but find that it doesn't.
  34. */
  35.  
  36. /*...sError:0:*/
  37. static VOID Error(HWND hwnd, const CHAR *szFmt, ...)
  38.     {
  39.     va_list vars;
  40.     CHAR sz [256+1];
  41.  
  42.     va_start(vars, szFmt);
  43.     vsprintf(sz, szFmt, vars);
  44.     va_end(vars);
  45.     WinMessageBox(HWND_DESKTOP, hwnd, sz, NULL, 0, MB_OK | MB_ERROR | MB_MOVEABLE);
  46.     }
  47. /*...e*/
  48. /*...sFatal:0:*/
  49. static VOID Fatal(HWND hwnd, const CHAR *sz)
  50.     {
  51.     Error(hwnd, sz);
  52.     exit(1);
  53.     }
  54. /*...e*/
  55. /*...sUsage:0:*/
  56. static VOID Usage(HWND hwnd)
  57.     {
  58.     Fatal(hwnd, "Usage: gbmv [-e] [-h] [--] filename.ext{,opt}");
  59.     }
  60. /*...e*/
  61. /*...sWarning:0:*/
  62. static VOID Warning(HWND hwnd, const CHAR *szFmt, ...)
  63.     {
  64.     va_list vars;
  65.     CHAR sz [256+1];
  66.  
  67.     va_start(vars, szFmt);
  68.     vsprintf(sz, szFmt, vars);
  69.     va_end(vars);
  70.     WinMessageBox(HWND_DESKTOP, hwnd, sz, NULL, 0, MB_OK | MB_WARNING | MB_MOVEABLE);
  71.     }
  72. /*...e*/
  73. /*...e*/
  74. /*...smain:0:*/
  75. #define    WC_GBMV "GbmViewerClass"
  76.  
  77. static HWND hwndFrame, hwndClient;
  78.  
  79. static HBITMAP hbmBmp;
  80. static LONG lColorBg, lColorFg;
  81.  
  82. /*...sLoadBitmap:0:*/
  83. static BOOL LoadBitmap(
  84.     HWND hwnd,
  85.     const CHAR *szFn, const CHAR *szOpt,
  86.     GBM *gbm, GBMRGB *gbmrgb, BYTE **ppbData
  87.     )
  88.     {
  89.     GBM_ERR rc;
  90.     int fd, ft;
  91.     ULONG cb;
  92.     USHORT usStride;
  93.  
  94.     if ( gbm_guess_filetype(szFn, &ft) != GBM_ERR_OK )
  95.         {
  96.         Warning(hwnd, "Can't deduce bitmap format from file extension: %s", szFn);
  97.         return ( FALSE );
  98.         }
  99.  
  100.     if ( (fd = gbm_io_open(szFn, O_RDONLY | O_BINARY)) == -1 )
  101.         {
  102.         Warning(hwnd, "Can't open file: %s", szFn);
  103.         return ( FALSE );
  104.         }
  105.  
  106.     if ( (rc = gbm_read_header(szFn, fd, ft, gbm, szOpt)) != GBM_ERR_OK )
  107.         {
  108.         gbm_io_close(fd);
  109.         Warning(hwnd, "Can't read file header of %s: %s", szFn, gbm_err(rc));
  110.         return ( FALSE );
  111.         }
  112.  
  113.     if ( (rc = gbm_read_palette(fd, ft, gbm, gbmrgb)) != GBM_ERR_OK )
  114.         {
  115.         gbm_io_close(fd);
  116.         Warning(hwnd, "Can't read file palette of %s: %s", szFn, gbm_err(rc));
  117.         return ( FALSE );
  118.         }
  119.  
  120.     usStride = ((gbm -> w * gbm -> bpp + 31)/32) * 4;
  121.     cb = gbm -> h * usStride;
  122.     if ( (*ppbData = malloc((int) cb)) == NULL )
  123.         {
  124.         gbm_io_close(fd);
  125.         Warning(hwnd, "Out of memory requesting %ld bytes", cb);
  126.         return ( FALSE );
  127.         }
  128.  
  129.     if ( (rc = gbm_read_data(fd, ft, gbm, *ppbData)) != GBM_ERR_OK )
  130.         {
  131.         free(*ppbData);
  132.         gbm_io_close(fd);
  133.         Warning(hwnd, "Can't read file data of %s: %s", szFn, gbm_err(rc));
  134.         return ( FALSE );
  135.         }
  136.  
  137.     gbm_io_close(fd);
  138.  
  139.     return ( TRUE );
  140.     }
  141. /*...e*/
  142. /*...sTo24Bit:0:*/
  143. static BOOL To24Bit(GBM *gbm, GBMRGB *gbmrgb, BYTE **ppbData)
  144.     {
  145.     int    stride = ((gbm -> w * gbm -> bpp + 31)/32) * 4;
  146.     int    new_stride = ((gbm -> w * 3 + 3) & ~3);
  147.     int    bytes, y;
  148.     byte    *pbDataNew;
  149.  
  150.     if ( gbm -> bpp == 24 )
  151.         return ( TRUE );
  152.  
  153.     bytes = new_stride * gbm -> h;
  154.     if ( (pbDataNew = malloc(bytes)) == NULL )
  155.         return ( FALSE );
  156.  
  157.     for ( y = 0; y < gbm -> h; y++ )
  158.         {
  159.         byte    *src = *ppbData + y * stride;
  160.         byte    *dest = pbDataNew + y * new_stride;
  161.         int    x;
  162.  
  163.         switch ( gbm -> bpp )
  164.             {
  165. /*...s1:24:*/
  166. case 1:
  167.     {
  168.     byte    c;
  169.  
  170.     for ( x = 0; x < gbm -> w; x++ )
  171.         {
  172.         if ( (x & 7) == 0 )
  173.             c = *src++;
  174.         else
  175.             c <<= 1;
  176.  
  177.         *dest++ = gbmrgb [(c & 0x80) != 0].b;
  178.         *dest++ = gbmrgb [(c & 0x80) != 0].g;
  179.         *dest++ = gbmrgb [(c & 0x80) != 0].r;
  180.         }
  181.     }
  182.     break;
  183. /*...e*/
  184. /*...s4:24:*/
  185. case 4:
  186.     for ( x = 0; x + 1 < gbm -> w; x += 2 )
  187.         {
  188.         byte    c = *src++;
  189.  
  190.         *dest++ = gbmrgb [c >> 4].b;
  191.         *dest++ = gbmrgb [c >> 4].g;
  192.         *dest++ = gbmrgb [c >> 4].r;
  193.         *dest++ = gbmrgb [c & 15].b;
  194.         *dest++ = gbmrgb [c & 15].g;
  195.         *dest++ = gbmrgb [c & 15].r;
  196.         }
  197.  
  198.     if ( x < gbm -> w )
  199.         {
  200.         byte    c = *src;
  201.  
  202.         *dest++ = gbmrgb [c >> 4].b;
  203.         *dest++ = gbmrgb [c >> 4].g;
  204.         *dest++ = gbmrgb [c >> 4].r;
  205.         }
  206.     break;
  207. /*...e*/
  208. /*...s8:24:*/
  209. case 8:
  210.     for ( x = 0; x < gbm -> w; x++ )
  211.         {
  212.         byte    c = *src++;
  213.  
  214.         *dest++ = gbmrgb [c].b;
  215.         *dest++ = gbmrgb [c].g;
  216.         *dest++ = gbmrgb [c].r;
  217.         }
  218.     break;
  219. /*...e*/
  220.             }
  221.         }
  222.     free(*ppbData);
  223.     *ppbData = pbDataNew;
  224.     gbm -> bpp = 24;
  225.  
  226.     return ( TRUE );
  227.     }
  228. /*...e*/
  229. /*...sMakeBitmap:0:*/
  230. static BOOL MakeBitmap(
  231.     HWND hwnd,
  232.     const GBM *gbm, const GBMRGB *gbmrgb, const BYTE *pbData,
  233.     HBITMAP *phbm
  234.     )
  235.     {
  236.     HAB hab = WinQueryAnchorBlock(hwnd);
  237.     USHORT cRGB, usCol;
  238.     SIZEL sizl;
  239.     HDC hdc;
  240.     HPS hps;
  241.     struct
  242.         {
  243.         BITMAPINFOHEADER2 bmp2;
  244.         RGB2 argb2Color [0x100];
  245.         } bm;
  246.  
  247.     /* Got the data in memory, now make bitmap */
  248.  
  249.     memset(&bm, 0, sizeof(bm));
  250.  
  251.     bm.bmp2.cbFix     = sizeof(BITMAPINFOHEADER2);
  252.     bm.bmp2.cx        = gbm -> w;
  253.     bm.bmp2.cy        = gbm -> h;
  254.     bm.bmp2.cBitCount = gbm -> bpp;
  255.     bm.bmp2.cPlanes   = 1;
  256.  
  257.     cRGB = ( (1 << gbm -> bpp) & 0x1ff );
  258.         /* 1 -> 2, 4 -> 16, 8 -> 256, 24 -> 0 */
  259.  
  260.     for ( usCol = 0; usCol < cRGB; usCol++ )
  261.         {
  262.         bm.argb2Color [usCol].bRed   = gbmrgb [usCol].r;
  263.         bm.argb2Color [usCol].bGreen = gbmrgb [usCol].g;
  264.         bm.argb2Color [usCol].bBlue  = gbmrgb [usCol].b;
  265.         }
  266.  
  267.     if ( (hdc = DevOpenDC(hab, OD_MEMORY, "*", 0L, (PDEVOPENDATA) NULL, (HDC) NULL)) == (HDC) NULL )
  268.         {
  269.         Warning(hwnd, "DevOpenDC failure");
  270.         return ( FALSE );
  271.         }
  272.  
  273.     sizl.cx = bm.bmp2.cx;
  274.     sizl.cy = bm.bmp2.cy;
  275.     if ( (hps = GpiCreatePS(hab, hdc, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC)) == (HPS) NULL )
  276.         {
  277.         Warning(hwnd, "GpiCreatePS failure");
  278.         DevCloseDC(hdc);
  279.         return ( FALSE );
  280.         }
  281.  
  282.  
  283.     if ( cRGB == 2 )
  284. /*...shandle 1bpp case:16:*/
  285. /*
  286. 1bpp presentation spaces have a reset or background colour.
  287. They also have a contrast or foreground colour.
  288. When data is mapped into a 1bpp presentation space :-
  289. Data which is the reset colour, remains reset, and is stored as 0's.
  290. All other data becomes contrast, and is stored as 1's.
  291. The reset colour for 1bpp screen HPSs is white.
  292. I want 1's in the source data to become 1's in the HPS.
  293. We seem to have to reverse the ordering here to get the desired effect.
  294. */
  295.  
  296. {
  297. static RGB2 argb2Black = { 0x00, 0x00, 0x00 };
  298. static RGB2 argb2White = { 0xff, 0xff, 0xff };
  299. bm.argb2Color [0] = argb2Black; /* Contrast */
  300. bm.argb2Color [1] = argb2White; /* Reset */
  301. }
  302. /*...e*/
  303.  
  304.     if ( (*phbm = GpiCreateBitmap(hps, &(bm.bmp2), CBM_INIT, (BYTE *) pbData, (BITMAPINFO2 *) &(bm.bmp2))) == (HBITMAP) NULL )
  305.         {
  306.         Warning(hwnd, "GpiCreateBitmap failure");
  307.         GpiDestroyPS(hps);
  308.         DevCloseDC(hdc);
  309.         return ( FALSE );
  310.         }
  311.  
  312.     GpiSetBitmap(hps, (HBITMAP) NULL);
  313.     GpiDestroyPS(hps);
  314.     DevCloseDC(hdc);
  315.  
  316.     return ( TRUE );
  317.     }
  318. /*...e*/
  319.  
  320. /*...sGbmVWndProc:0:*/
  321. MRESULT _System GbmVWndProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  322.     {
  323.     switch ( (int) msg )
  324.         {
  325. /*...sWM_COMMAND \45\ menu command:16:*/
  326. case WM_COMMAND:
  327.     switch ( COMMANDMSG(&msg) -> cmd )
  328.         {
  329. /*...sMID_EXIT \45\ initiate shutdown of this app:32:*/
  330. case MID_EXIT:
  331.     WinPostMsg(hwnd, WM_QUIT, 0L, 0L);
  332.     break;
  333. /*...e*/
  334.         }
  335.     return ( (MRESULT) 0 );
  336. /*...e*/
  337. /*...sWM_PAINT   \45\ repaint client area:16:*/
  338. case WM_PAINT:
  339.     {
  340.     static SIZEL sizl = { 0, 0 };
  341.     HPS hps = WinBeginPaint(hwnd, (HPS) NULL, NULL);
  342.     HAB hab = WinQueryAnchorBlock(hwnd);
  343.     HDC hdcBmp = DevOpenDC(hab, OD_MEMORY, "*", 0L, (PDEVOPENDATA) NULL, (HDC) NULL);
  344.     HPS hpsBmp = GpiCreatePS(hab, hdcBmp, &sizl, PU_PELS | GPIF_DEFAULT | GPIT_MICRO | GPIA_ASSOC);
  345.     POINTL aptl [4];
  346.     RECTL rcl;
  347.     BITMAPINFOHEADER bmp;
  348.  
  349.     GpiQueryBitmapParameters(hbmBmp, &bmp);
  350.  
  351.     GpiSetBitmap(hpsBmp, hbmBmp);
  352.  
  353.     GpiSetBackColor(hps, GpiQueryColorIndex(hps, 0, lColorBg));
  354.     GpiSetColor    (hps, GpiQueryColorIndex(hps, 0, lColorFg));
  355.  
  356.     WinQueryWindowRect(hwnd, &rcl);
  357.     aptl [0].x = rcl.xLeft;
  358.     aptl [0].y = rcl.yBottom;
  359.     aptl [1].x = rcl.xRight;
  360.     aptl [1].y = rcl.yTop;
  361.     aptl [2].x = 0;
  362.     aptl [2].y = 0;
  363.     aptl [3].x = bmp.cx;
  364.     aptl [3].y = bmp.cy;
  365.     GpiBitBlt(hps, hpsBmp, 4L, aptl, ROP_SRCCOPY, BBO_IGNORE);
  366.  
  367.     GpiSetBitmap(hpsBmp, (HBITMAP) NULL);
  368.     GpiDestroyPS(hpsBmp);
  369.     DevCloseDC(hdcBmp);
  370.  
  371.     WinEndPaint(hps);
  372.     }
  373.     return ( (MRESULT) 0 );
  374. /*...e*/
  375.         }
  376.     return ( WinDefWindowProc(hwnd, msg, mp1, mp2) );
  377.     }
  378. /*...e*/
  379.  
  380. int main(int argc, CHAR *argv [])
  381.     {
  382.     HAB hab = WinInitialize(0);
  383.     HMQ hmq = WinCreateMsgQueue(hab, 0);/* 0 => default size for message Q   */
  384.     static ULONG flFrameFlags = FCF_TITLEBAR  | FCF_SYSMENU    |
  385.                     FCF_MINBUTTON | FCF_TASKLIST   |
  386.                     FCF_BORDER    | FCF_ACCELTABLE ;
  387.     QMSG qMsg;
  388.     CHAR sz [255+1], *szOpt;
  389.     GBM gbm;
  390.     GBMRGB gbmrgb [0x100];
  391.     BYTE *pbData;
  392.     BOOL fHalftone = FALSE, fErrdiff = FALSE, fOk;
  393.     int i;
  394.  
  395. /*...sprocess command line options:8:*/
  396. for ( i = 1; i < argc; i++ )
  397.     {
  398.     if ( argv [i][0] != '-' )
  399.         break;
  400.     else if ( argv[i][1] == '-' )
  401.         { ++i; break; }
  402.     switch ( argv [i][1] )
  403.         {
  404.         case 'e':    fErrdiff = TRUE;
  405.                 break;
  406.         case 'h':    fHalftone = TRUE;
  407.                 break;
  408.         default:    Usage(HWND_DESKTOP);
  409.                 break;
  410.         }
  411.     }
  412.  
  413. if ( fErrdiff && fHalftone )
  414.     Fatal(HWND_DESKTOP, "error-diffusion and halftoning can't both be done at once");
  415.  
  416. if ( i == argc )
  417.     Usage(HWND_DESKTOP);
  418. /*...e*/
  419.  
  420.     gbm_init();
  421.  
  422.     if ( (szOpt = strchr(argv [i], ',')) != NULL )
  423.         *szOpt++ = '\0';
  424.     else
  425.         szOpt = "";
  426.  
  427.     if ( LoadBitmap(HWND_DESKTOP, argv [i], szOpt, &gbm, gbmrgb, &pbData) )
  428.         {
  429.         HPS hps = WinGetPS(HWND_DESKTOP);
  430.         HDC hdc = GpiQueryDevice(hps);
  431.         LONG lPlanes, lBitCount;
  432.  
  433.         DevQueryCaps(hdc, CAPS_COLOR_PLANES  , 1L, &lPlanes  );
  434.         DevQueryCaps(hdc, CAPS_COLOR_BITCOUNT, 1L, &lBitCount);
  435.         WinReleasePS(hps);
  436.  
  437.         if ( fHalftone || fErrdiff )
  438.             fOk = To24Bit(&gbm, gbmrgb, &pbData);
  439.         else
  440.             fOk = TRUE;
  441.  
  442.         if ( fOk )
  443. /*...scan now go on to errordiffuse\47\halftone and display:24:*/
  444. {
  445. if ( fHalftone )
  446.     switch ( (int) lBitCount )
  447.         {
  448.         case 4:
  449.             gbm_ht_pal_VGA(gbmrgb);
  450.             gbm_ht_VGA_3x3(&gbm, pbData, pbData);
  451.             gbm.bpp = 4;
  452.             break;
  453.         case 8:
  454.             gbm_ht_pal_7R8G4B(gbmrgb);
  455.             gbm_ht_7R8G4B_2x2(&gbm, pbData, pbData);
  456.             gbm.bpp = 8;
  457.             break;
  458.         case 16:
  459.             gbm_ht_24_2x2(&gbm, pbData, pbData, 0xf8, 0xfc, 0xf8);
  460.             gbm.bpp = 24;
  461.             break;
  462.         }
  463. else if ( fErrdiff )
  464.     switch ( (int) lBitCount )
  465.         {
  466.         case 4:
  467.             gbm_errdiff_pal_VGA(gbmrgb);
  468.             gbm_errdiff_VGA(&gbm, pbData, pbData);
  469.             gbm.bpp = 4;
  470.             break;
  471.         case 8:
  472.             gbm_errdiff_pal_7R8G4B(gbmrgb);
  473.             gbm_errdiff_7R8G4B(&gbm, pbData, pbData);
  474.             gbm.bpp = 8;
  475.             break;
  476.         case 16:
  477.             if ( !gbm_errdiff_24(&gbm, pbData, pbData, 0xf8, 0xfc, 0xf8) )
  478.                 break;
  479.             gbm.bpp = 24;
  480.             break;
  481.         }
  482. fOk = MakeBitmap(HWND_DESKTOP, &gbm, gbmrgb, pbData, &hbmBmp);
  483. if ( gbm.bpp == 1 )
  484. /*...sremember Bg and Fg colours:32:*/
  485. {
  486. lColorBg = (gbmrgb [0].r << 16) + (gbmrgb [0].g << 8) + gbmrgb [0].b;
  487. lColorFg = (gbmrgb [1].r << 16) + (gbmrgb [1].g << 8) + gbmrgb [1].b;
  488. }
  489. /*...e*/
  490.  
  491. free(pbData);
  492. if ( fOk )
  493. /*...sall ok\44\ do PM windows etc\46\:32:*/
  494. {
  495. RECTL rcl;
  496. SHORT cxScreen, cyScreen, cxWindow, cyWindow;
  497. BITMAPINFOHEADER bmp;
  498.  
  499. WinRegisterClass(
  500.     hab,            /* Anchor block handle               */
  501.     WC_GBMV,        /* Window class name                 */
  502.     GbmVWndProc,        /* Responding procedure for class    */
  503.     CS_SIZEREDRAW,        /* Class style                       */
  504.     0);            /* Extra bytes to reserve for class  */
  505.  
  506. hwndFrame = WinCreateStdWindow(
  507.     HWND_DESKTOP,        /* Parent window handle              */
  508.     0L,            /* Style of frame window             */
  509.     &flFrameFlags,        /* Pointer to control data           */
  510.     WC_GBMV,        /* Client window class name          */
  511.     NULL,            /* Title bar text                    */
  512.     0L,            /* Style of client window            */
  513.     (HMODULE) NULL,        /* Module handle for resources       */
  514.     RID_STANDARD,        /* ID of resources                   */
  515.     &hwndClient);        /* Pointer to client window handle   */
  516.  
  517. strcpy(sz, argv [i]);
  518. if ( szOpt [0] )
  519.     {
  520.     strcat(sz, ",");
  521.     strcat(sz, szOpt);
  522.     }
  523. if ( fErrdiff )
  524.     strcat(sz, " -e");
  525. else if ( fHalftone )
  526.     strcat(sz, " -h");
  527. WinSetWindowText(hwndFrame, sz);
  528.  
  529. GpiQueryBitmapParameters(hbmBmp, &bmp);
  530.  
  531. rcl.xLeft   = 0L;
  532. rcl.xRight  = bmp.cx;
  533. rcl.yBottom = 0L;
  534. rcl.yTop    = bmp.cy;
  535. WinCalcFrameRect(hwndFrame, &rcl, FALSE);
  536.  
  537. cxWindow = (SHORT) (rcl.xRight - rcl.xLeft),
  538. cyWindow = (SHORT) (rcl.yTop - rcl.yBottom),
  539. cxScreen = (SHORT) WinQuerySysValue(HWND_DESKTOP, SV_CXSCREEN);
  540. cyScreen = (SHORT) WinQuerySysValue(HWND_DESKTOP, SV_CYSCREEN);
  541.  
  542. WinSetWindowPos(hwndFrame,
  543.         HWND_TOP,
  544.         (cxScreen - cxWindow) / 2,
  545.         (cyScreen - cyWindow) / 2,
  546.         cxWindow,
  547.         cyWindow,
  548.         SWP_MOVE | SWP_SIZE | SWP_ACTIVATE | SWP_SHOW);
  549.  
  550. while ( WinGetMsg(hab, &qMsg, (HWND) NULL, 0, 0) )
  551.     WinDispatchMsg(hab, &qMsg);
  552.  
  553. WinDestroyWindow(hwndFrame);
  554. }
  555. /*...e*/
  556. }
  557. /*...e*/
  558.         else
  559.             {
  560.             free(pbData);
  561.             Error(HWND_DESKTOP, "Out of memory");
  562.             }
  563.         }
  564.  
  565.     WinDestroyMsgQueue(hmq);
  566.     WinTerminate(hab);
  567.  
  568.     gbm_deinit();
  569.  
  570.     return ( 0 );
  571.     }
  572. /*...e*/
  573.