home *** CD-ROM | disk | FTP | other *** search
/ Windows Graphics Programming / Feng_Yuan_Win32_GDI_DirectX.iso / Samples / include / Dib.cpp < prev    next >
C/C++ Source or Header  |  2000-05-12  |  28KB  |  1,118 lines

  1. //-----------------------------------------------------------------------------------//
  2. //              Windows Graphics Programming: Win32 GDI and DirectDraw               //
  3. //                             ISBN  0-13-086985-6                                   //
  4. //                                                                                   //
  5. //  Written            by  Yuan, Feng                             www.fengyuan.com   //
  6. //  Copyright (c) 2000 by  Hewlett-Packard Company                www.hp.com         //
  7. //  Published          by  Prentice Hall PTR, Prentice-Hall, Inc. www.phptr.com      //
  8. //                                                                                   //
  9. //  FileName   : dib.cpp                                                             //
  10. //  Description: Device independent Bitmap Handling                                  //
  11. //  Version    : 1.00.000, May 31, 2000                                              //
  12. //-----------------------------------------------------------------------------------//
  13.  
  14. #define STRICT
  15. #define _WIN32_WINNT 0x0500
  16. #define WINVER       0x500
  17. #define NOCRYPT
  18. #define OEMRESOURCE
  19.  
  20. #include <windows.h>
  21. #include <assert.h>
  22. #include <tchar.h>
  23. #include <math.h>
  24.  
  25. #include "Color.h"
  26. #include "Dib.h"
  27. #include "Affine.h"
  28. #include "BitmapInfo.h"
  29. #include "filedialog.h"
  30.  
  31. const TCHAR * mess_DIBFormat[] =
  32. {
  33.     _T("DIB_1BPP"),            //   2 color image, palette-based
  34.     _T("DIB_2BPP"),            //   4 color image, palttte-based
  35.     _T("DIB_4BPP"),            //  16 color image, palette-based
  36.     _T("DIB_4BPPRLE"),        //  16 color image, palette-based, RLE compressed
  37.     _T("DIB_8BPP"),            // 256 color image, palette-based 
  38.     _T("DIB_8BPPRLE"),        // 256 color image, palette-based, RLE compressed
  39.  
  40.     _T("DIB_16RGB555"),        // 15 bit RGB color image, 5-5-5
  41.     _T("DIB_16RGB565"),        // 16 bit RGB color image, 5-6-5, 1 bit unused
  42.     _T("DIB_24RGB888"),        // 24 bit RGB color image, 8-8-8
  43.     _T("DIB_32RGB888"),        // 32 bit RGB color image, 8-8-8, 8 bit unused
  44.  
  45.     _T("DIB_32RGBA8888"),    // 32 bit RGBA color image, 8-8-8-8
  46.  
  47.     _T("DIB_16RGBbitfields"),    // 16 bit RGB color image, non-standard bit masks, NT-only
  48.     _T("DIB_32RGBbitfields"),    // 32 bit RGB color image, non-standard bit masks, NT-only
  49.  
  50.     _T("DIB_JPEG"),                // embedded JPEG image
  51.     _T("DIB_PNG")                // embedded PNG image
  52. };
  53.  
  54. const TCHAR * PixelFormatName(int id)
  55. {
  56.     if ( (id>=DIB_1BPP) && (id<=DIB_PNG) )
  57.         return mess_DIBFormat[id - DIB_1BPP];
  58.     else
  59.         return _T("Unknown Pixel Format");
  60. }
  61.  
  62. KDIB::KDIB()
  63. {
  64.     m_pBMI         = NULL;
  65.     m_pBits        = NULL;
  66.     m_Flags           = 0;
  67.  
  68.     m_nWidth       = 0;
  69.     m_nHeight      = 0;
  70.     m_nPlanes      = 1;
  71.     m_nBitCount    = 1;
  72.     m_nColorDepth  = 1;
  73.     m_nImageSize   = 0;
  74.     m_nImageFormat = DIB_1BPP;
  75.  
  76.     m_pRGBTRIPLE   = NULL;
  77.     m_pRGBQUAD       = NULL;
  78. }
  79.  
  80. void KDIB::ReleaseDIB(void)
  81. {
  82.     if ( m_Flags & DIB_BMI_NEEDFREE )
  83.     {
  84.         delete [] (BYTE *) m_pBMI;
  85.         m_Flags &= ~ DIB_BMI_NEEDFREE;
  86.         m_pBMI   = NULL;
  87.     }
  88.  
  89.     if ( m_Flags & DIB_BITS_NEEDFREE )
  90.     {
  91.         delete [] m_pBits;
  92.         m_Flags &= ~ DIB_BITS_NEEDFREE;
  93.         m_pBits = NULL;
  94.     }
  95. }
  96.  
  97. KDIB::~KDIB()
  98. {
  99.     try
  100.     {
  101.         ReleaseDIB();
  102.     }
  103.     catch (...)
  104.     {
  105.     }
  106. }
  107.  
  108. bool KDIB::AttachDIB(BITMAPINFO * pDIB, BYTE * pBits, int flags)
  109. {
  110.     if ( IsBadReadPtr(pDIB, sizeof(BITMAPCOREHEADER)) )
  111.         return false;
  112.  
  113.     ReleaseDIB();
  114.     
  115.     m_pBMI      = pDIB;
  116.     m_Flags     = flags;
  117.  
  118.     DWORD size = * (DWORD *) pDIB; // always DWORD size, key to information header
  119.  
  120.     int compression;
  121.     // gather information from bitmap information header structures
  122.     switch ( size )
  123.     {
  124.         case sizeof(BITMAPCOREHEADER):
  125.         {
  126.             BITMAPCOREHEADER * pHeader = (BITMAPCOREHEADER *) pDIB;
  127.  
  128.             m_nWidth    = pHeader->bcWidth;
  129.             m_nHeight   = pHeader->bcHeight;
  130.             m_nPlanes   = pHeader->bcPlanes;
  131.             m_nBitCount = pHeader->bcBitCount;
  132.             m_nImageSize= 0;
  133.             compression = BI_RGB;
  134.  
  135.             if ( m_nBitCount <= 8 )
  136.             {
  137.                 m_nClrUsed   = 1 << m_nBitCount;
  138.                 m_nClrImpt   = m_nClrUsed;
  139.                 m_pRGBTRIPLE = (RGBTRIPLE *) ((BYTE *) m_pBMI + size);
  140.  
  141.                 m_pBits      = (BYTE *) & m_pRGBTRIPLE[m_nClrUsed];
  142.             }
  143.             else
  144.                 m_pBits      = (BYTE *) m_pBMI + size;
  145.             break;
  146.         }
  147.  
  148.         case sizeof(BITMAPINFOHEADER):
  149.         case sizeof(BITMAPV4HEADER):
  150.         case sizeof(BITMAPV5HEADER):
  151.         {
  152.             BITMAPINFOHEADER * pHeader = & m_pBMI->bmiHeader;
  153.  
  154.             m_nWidth    = pHeader->biWidth;
  155.             m_nHeight   = pHeader->biHeight;
  156.             m_nPlanes   = pHeader->biPlanes;
  157.             m_nBitCount = pHeader->biBitCount;
  158.             m_nImageSize= pHeader->biSizeImage;
  159.             compression = pHeader->biCompression;
  160.  
  161.             m_nClrUsed  = pHeader->biClrUsed;
  162.             m_nClrImpt  = pHeader->biClrImportant;
  163.  
  164.             if ( m_nBitCount<=8 )
  165.                 if ( m_nClrUsed==0 )    // 0 means full color table
  166.                     m_nClrUsed = 1 << m_nBitCount;
  167.  
  168.             if ( m_nClrUsed )    // has a color table
  169.             {
  170.                 if ( m_nClrImpt==0 )    // 0 means all important
  171.                     m_nClrImpt = m_nClrUsed;
  172.             
  173.                 if ( compression==BI_BITFIELDS )
  174.                 {
  175.                     m_pBitFields = (DWORD *) ((BYTE *)pDIB+size);
  176.                     m_pRGBQUAD = (RGBQUAD *) ((BYTE *)pDIB+size + 3*sizeof(DWORD));
  177.                 }
  178.                 else
  179.                     m_pRGBQUAD = (RGBQUAD *) ((BYTE *)pDIB+size);
  180.  
  181.                 m_pBits = (BYTE *) & m_pRGBQUAD[m_nClrUsed];
  182.             }
  183.             else
  184.             {
  185.                 if ( compression==BI_BITFIELDS )
  186.                 {
  187.                     m_pBitFields = (DWORD *) ((BYTE *)pDIB+size);
  188.                     m_pBits      = (BYTE *) m_pBMI + size + 3 * sizeof(DWORD);
  189.                 }
  190.                 else
  191.                     m_pBits      = (BYTE *) m_pBMI + size;
  192.             }
  193.             break;
  194.         }
  195.  
  196.         default:
  197.             return false;
  198.     }
  199.  
  200.     if ( pBits )
  201.         m_pBits = pBits;
  202.  
  203.     // precalculate information DIB parameters
  204.     m_nColorDepth = m_nPlanes * m_nBitCount;
  205.     m_nBPS          = (m_nWidth * m_nBitCount + 31) / 32 * 4;
  206.     
  207.     if (m_nHeight < 0 ) // top-down bitmap
  208.     {
  209.         m_nHeight = - m_nHeight;    // change to positive
  210.         m_nDelta  = m_nBPS;            // forward
  211.         m_pOrigin = m_pBits;        // scan0 .. scanN-1
  212.     }
  213.     else
  214.     {
  215.         m_nDelta  = - m_nBPS;        // backward
  216.         m_pOrigin = m_pBits + (m_nHeight-1) * m_nBPS * m_nPlanes;    // scanN-1..scan0
  217.     }
  218.  
  219.     if ( m_nImageSize==0 )
  220.         m_nImageSize = m_nBPS * m_nPlanes * m_nHeight;
  221.  
  222.     // convert compression mode to image format
  223.     switch ( m_nBitCount )
  224.     {
  225.         case 0:
  226.             if ( compression==BI_JPEG )
  227.                 m_nImageFormat = DIB_JPEG;
  228.             else if ( compression==BI_PNG )
  229.                 m_nImageFormat = DIB_PNG;
  230.             else
  231.                 return false;
  232.  
  233.         case 1:
  234.             m_nImageFormat = DIB_1BPP;
  235.             break;
  236.  
  237.         case 2:
  238.             m_nImageFormat = DIB_2BPP;
  239.             break;
  240.  
  241.         case 4:
  242.             if ( compression==BI_RLE4 )
  243.                 m_nImageFormat = DIB_4BPPRLE;
  244.             else
  245.                 m_nImageFormat = DIB_4BPP;
  246.             break;
  247.  
  248.         case 8:
  249.             if ( compression==BI_RLE8 )
  250.                 m_nImageFormat = DIB_8BPPRLE;
  251.             else
  252.                 m_nImageFormat = DIB_8BPP;
  253.             break;
  254.         
  255.         case 16:
  256.             if ( compression==BI_BITFIELDS )
  257.                 m_nImageFormat = DIB_16RGBbitfields;
  258.             else
  259.                 m_nImageFormat = DIB_16RGB555; // see below
  260.             break;
  261.         
  262.         case 24:
  263.             m_nImageFormat = DIB_24RGB888;
  264.             break;
  265.  
  266.         case 32:
  267.             if ( compression == BI_BITFIELDS )
  268.                 m_nImageFormat = DIB_32RGBbitfields;
  269.             else
  270.                 m_nImageFormat = DIB_32RGB888; // see below
  271.             break;
  272.  
  273.         default:
  274.             return false;
  275.     }
  276.  
  277.     // try to understand bit fields
  278.     if ( compression==BI_BITFIELDS )
  279.     {
  280.         DWORD red   = m_pBitFields[0];
  281.         DWORD green = m_pBitFields[1];
  282.         DWORD blue  = m_pBitFields[2];
  283.  
  284.         if (      (blue==0x001F) && (green==0x03E0) && (red==0x7C00) )
  285.             m_nImageFormat = DIB_16RGB555;
  286.         else if ( (blue==0x001F) && (green==0x07E0) && (red==0xF800) )
  287.             m_nImageFormat = DIB_16RGB565;
  288.         else if ( (blue==0x00FF) && (green==0xFF00) && (red==0xFF0000) )
  289.             m_nImageFormat = DIB_32RGB888;
  290.     }
  291.  
  292.     return true;
  293. }
  294.  
  295.  
  296. bool KDIB::LoadBitmap(HMODULE hModule, LPCTSTR pBitmapName)
  297. {
  298.     HRSRC   hRes = FindResource(hModule, pBitmapName, RT_BITMAP);
  299.  
  300.     if ( hRes==NULL )
  301.         return false;
  302.  
  303.     HGLOBAL hGlb = LoadResource(hModule, hRes);
  304.  
  305.     if ( hGlb==NULL )
  306.         return false;
  307.  
  308.     BITMAPINFO * pDIB = (BITMAPINFO *) LockResource(hGlb);
  309.  
  310.     if ( pDIB==NULL )
  311.         return false;
  312.  
  313.     return AttachDIB(pDIB, NULL, DIB_BMI_READONLY | DIB_BITS_READONLY);
  314. }
  315.  
  316.  
  317. bool KDIB::LoadFile(const TCHAR * pFileName)
  318. {
  319.     if ( pFileName==NULL )
  320.         return false;
  321.  
  322.     HANDLE handle = CreateFile(pFileName, GENERIC_READ, FILE_SHARE_READ, 
  323.         NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);
  324.     
  325.     if ( handle == INVALID_HANDLE_VALUE )
  326.         return false;
  327.  
  328.     BITMAPFILEHEADER bmFH;
  329.  
  330.     DWORD dwRead = 0;
  331.     ReadFile(handle, & bmFH, sizeof(bmFH), & dwRead, NULL);
  332.  
  333.     if ( (bmFH.bfType == 0x4D42) && (bmFH.bfSize<=GetFileSize(handle, NULL)) )
  334.     {
  335.         BITMAPINFO * pDIB = (BITMAPINFO *) new BYTE[bmFH.bfSize];
  336.         
  337.         if ( pDIB )
  338.         {
  339.             ReadFile(handle, pDIB, bmFH.bfSize, & dwRead, NULL);
  340.             CloseHandle(handle);
  341.  
  342.             return AttachDIB(pDIB, NULL, DIB_BMI_NEEDFREE);
  343.         }
  344.     }
  345.     CloseHandle(handle);
  346.  
  347.     return false;
  348. }
  349.  
  350.  
  351. BOOL KDIB::SaveFile(const TCHAR * pFileName)
  352. {
  353.     if ( m_pBMI )
  354.         return SaveDIBToFile(pFileName, m_pBMI, m_pBits);
  355.     else
  356.         return FALSE;
  357. }
  358.  
  359. void KDIB::DecodeDIBFormat(TCHAR mess[])
  360. {
  361.     wsprintf(mess, _T("DIB %dx%dx%dx%d "), m_nWidth, m_nHeight, 
  362.         m_nPlanes, m_nBitCount);
  363.  
  364.     if ( m_nImageSize < 1024 )
  365.         wsprintf(mess+_tcslen(mess), _T(", %d b"), m_nImageSize);
  366.     else if ( m_nImageSize < 1024 * 1024 )
  367.         wsprintf(mess+_tcslen(mess), _T(", %d,%03d b"), m_nImageSize/1024, m_nImageSize%1024);
  368.     else
  369.         wsprintf(mess+_tcslen(mess), _T(", %d,%03d,%03d b"), m_nImageSize/1024/1024, m_nImageSize/1024%1024, 
  370.             m_nImageSize%1024);
  371.  
  372.     _tcscat(mess, PixelFormatName(m_nImageFormat));
  373.     _tcscat(mess, _T(" "));
  374. }
  375.  
  376.  
  377. int GetDIBPixelSize(const BITMAPINFOHEADER & bmih)
  378. {
  379.     if ( bmih.biSizeImage )
  380.         return bmih.biSizeImage;
  381.     else
  382.         return ( bmih.biWidth * bmih.biBitCount + 31 ) / 32 * 4 * bmih.biPlanes * abs(bmih.biHeight);
  383. }
  384.  
  385. int GetDIBColorCount(const BITMAPINFOHEADER & bmih)
  386. {
  387.     if ( bmih.biBitCount <= 8 )
  388.         if ( bmih.biClrUsed )
  389.             return bmih.biClrUsed;
  390.         else
  391.             return 1 << bmih.biBitCount;
  392.     else if ( bmih.biCompression==BI_BITFIELDS )
  393.         return 3 + bmih.biClrUsed;
  394.     else
  395.         return bmih.biClrUsed;
  396. }
  397.  
  398.  
  399. BITMAPINFO * BitmapToDIB(HPALETTE hPal,    // palette for color conversion
  400.                    HBITMAP  hBmp,                            // DDB for convert
  401.                    int        nBitCount, int nCompression)    // format wanted
  402. {
  403.     typedef struct
  404.     {
  405.         BITMAPINFOHEADER bmiHeader;
  406.         RGBQUAD              bmiColors[256+3];
  407.     }    DIBINFO;
  408.  
  409.     BITMAP  ddbinfo;
  410.     DIBINFO dibinfo;
  411.  
  412.     // retrieve DDB information
  413.     if ( GetObject(hBmp, sizeof(BITMAP), & ddbinfo)==0 )
  414.         return NULL;
  415.  
  416.     // fill out BITMAPINFOHEADER based on size and required format
  417.     memset(&dibinfo, 0, sizeof(dibinfo));
  418.  
  419.     dibinfo.bmiHeader.biSize        = sizeof(BITMAPINFOHEADER);
  420.     dibinfo.bmiHeader.biWidth       = ddbinfo.bmWidth;
  421.     dibinfo.bmiHeader.biHeight      = ddbinfo.bmHeight;
  422.     dibinfo.bmiHeader.biPlanes      = 1;
  423.     dibinfo.bmiHeader.biBitCount    = nBitCount;
  424.     dibinfo.bmiHeader.biCompression = nCompression;
  425.  
  426.     HDC     hDC = GetDC(NULL); // screen DC
  427.     HGDIOBJ hpalOld;
  428.     
  429.     if ( hPal )
  430.         hpalOld = SelectPalette(hDC, hPal, FALSE);
  431.     else
  432.         hpalOld = NULL;
  433.  
  434.     // query GDI for image size
  435.     GetDIBits(hDC, hBmp, 0, ddbinfo.bmHeight, NULL, (BITMAPINFO *) & dibinfo, DIB_RGB_COLORS);
  436.  
  437.     int nInfoSize  = sizeof(BITMAPINFOHEADER) + sizeof(RGBQUAD) * GetDIBColorCount(dibinfo.bmiHeader);
  438.     int nTotalSize = nInfoSize + GetDIBPixelSize(dibinfo.bmiHeader);
  439.  
  440.     BYTE * pDIB = new BYTE[nTotalSize];
  441.  
  442.     if ( pDIB )
  443.     {
  444.         memcpy(pDIB, & dibinfo, nInfoSize);
  445.         
  446.         if ( ddbinfo.bmHeight != GetDIBits(hDC, hBmp, 0, ddbinfo.bmHeight, pDIB + nInfoSize, (BITMAPINFO *) pDIB, DIB_RGB_COLORS) )
  447.         {
  448.             delete [] pDIB;
  449.             pDIB = NULL;
  450.         }
  451.     }
  452.  
  453.     if ( hpalOld )
  454.         SelectObject(hDC, hpalOld);
  455.  
  456.     ReleaseDC(NULL, hDC);
  457.  
  458.     return (BITMAPINFO *) pDIB;
  459. }
  460.  
  461.  
  462. int PixelFormat(HDC hdc)
  463. {
  464.     typedef struct
  465.     {
  466.         BITMAPINFOHEADER bmiHeader;
  467.         RGBQUAD              bmiColors[256+3];
  468.     }    DIBINFO;
  469.  
  470.     DIBINFO dibinfo;
  471.  
  472.     HBITMAP hBmp = CreateCompatibleBitmap(hdc, 1, 1);
  473.     
  474.     if ( hBmp==NULL )
  475.         return -1;
  476.  
  477.     memset(&dibinfo, 0, sizeof(dibinfo));
  478.  
  479.     dibinfo.bmiHeader.biSize = sizeof(BITMAPINFOHEADER);
  480.  
  481.     // 1st call to get hdc biBitCount.
  482.     GetDIBits(hdc, hBmp, 0, 1, NULL, (BITMAPINFO*) & dibinfo, DIB_RGB_COLORS);
  483.        
  484.     // 2nd calls to get color table or bitfields
  485.     GetDIBits(hdc, hBmp, 0, 1, NULL, (BITMAPINFO*) & dibinfo, DIB_RGB_COLORS);
  486.        
  487.     DeleteObject(hBmp);
  488.  
  489.     // try to understand bit fields
  490.     if ( dibinfo.bmiHeader.biBitCount==BI_BITFIELDS )
  491.     {
  492.         DWORD * pBitFields = (DWORD *) dibinfo.bmiColors;
  493.         DWORD red   = pBitFields[0];
  494.         DWORD green = pBitFields[1];
  495.         DWORD blue  = pBitFields[2];
  496.  
  497.         if (      (blue==0x001F) && (green==0x03E0) && (red==0x7C00) )
  498.             return DIB_16RGB555;
  499.         else if ( (blue==0x001F) && (green==0x007E) && (red==0xF800) )
  500.             return DIB_16RGB565;
  501.         else if ( (blue==0x00FF) && (green==0xFF00) && (red==0xFF0000) )
  502.             return DIB_32RGB888;
  503.         else
  504.             return -1;
  505.     }
  506.  
  507.     switch ( dibinfo.bmiHeader.biBitCount )
  508.     {
  509.         case 1:    return DIB_1BPP;
  510.         case 2: return DIB_2BPP;
  511.         case 4:    return DIB_4BPP;
  512.         case 8: return DIB_8BPP;
  513.        case 24: return DIB_24RGB888;
  514.        case 16: return DIB_16RGB555;
  515.        case 32: return DIB_32RGB888;
  516.  
  517.        default: return -1;
  518.     }
  519. }
  520.  
  521.  
  522. HBITMAP CaptureWindow(HWND hWnd)
  523. {
  524.     RECT wnd;
  525.  
  526.     if ( ! GetWindowRect(hWnd, & wnd) )
  527.         return NULL;
  528.  
  529.     HDC hDC = GetWindowDC(hWnd);
  530.  
  531.     HBITMAP hBmp = CreateCompatibleBitmap(hDC, wnd.right - wnd.left, wnd.bottom - wnd.top);
  532.  
  533.     if ( hBmp )
  534.     {
  535.         HDC hMemDC   = CreateCompatibleDC(hDC);
  536.         HGDIOBJ hOld = SelectObject(hMemDC, hBmp);
  537.  
  538.         BitBlt(hMemDC, 0, 0, wnd.right - wnd.left, wnd.bottom - wnd.top, 
  539.             hDC, 0, 0, SRCCOPY);
  540.  
  541.         SelectObject(hMemDC, hOld);
  542.         DeleteObject(hMemDC);
  543.     }
  544.     
  545.     ReleaseDC(hWnd, hDC);
  546.  
  547.     return hBmp;
  548. }
  549.  
  550.  
  551. BOOL SaveDIBToFile(const TCHAR * pFileName, const BITMAPINFO * pBMI, const void * pBits)
  552. {
  553.     KFileDialog fi;
  554.  
  555.     if ( pFileName==NULL )
  556.     {
  557.         if ( ! fi.GetSaveFileName(NULL, _T("bmp"), _T("Bitmap Files")) )
  558.             return FALSE;
  559.  
  560.         pFileName = fi.m_TitleName;
  561.     }
  562.  
  563.     HANDLE handle = CreateFile(pFileName, GENERIC_WRITE, FILE_SHARE_READ, 
  564.         NULL, CREATE_NEW, FILE_ATTRIBUTE_NORMAL, NULL);
  565.     
  566.     if ( handle == INVALID_HANDLE_VALUE )
  567.         return FALSE;
  568.  
  569.     BITMAPFILEHEADER bmFH;
  570.  
  571.     int nHeadSize = sizeof(BITMAPINFOHEADER) + 
  572.                         sizeof(RGBQUAD) * GetDIBColorCount(pBMI->bmiHeader);
  573.  
  574.     bmFH.bfType      = 0x4D42;
  575.     bmFH.bfSize      = nHeadSize + GetDIBPixelSize(pBMI->bmiHeader);
  576.     bmFH.bfReserved1 = 0;
  577.     bmFH.bfReserved2 = 0;
  578.     bmFH.bfOffBits   = nHeadSize + sizeof(BITMAPFILEHEADER);
  579.  
  580.     DWORD dwRead = 0;
  581.     WriteFile(handle, & bmFH, sizeof(bmFH), & dwRead, NULL);
  582.  
  583.     if ( pBits==NULL ) // packed DIB
  584.         pBits = (BYTE *) pBMI + nHeadSize;
  585.     
  586.     WriteFile(handle, pBMI,  nHeadSize,                           & dwRead, NULL);
  587.     WriteFile(handle, pBits, GetDIBPixelSize(pBMI->bmiHeader), & dwRead, NULL);
  588.  
  589.     CloseHandle(handle);
  590.  
  591.     return TRUE;
  592. }
  593.  
  594. void SaveWindowToDIB(HWND hWnd, int nBitCount, int nCompression)
  595. {
  596.     HBITMAP hBmp = CaptureWindow(hWnd);
  597.  
  598.     if ( hBmp )
  599.     {
  600.         BITMAPINFO * pDIB = BitmapToDIB(NULL, hBmp, nBitCount, nCompression);
  601.  
  602.         if ( pDIB )
  603.         {
  604.             SaveDIBToFile(NULL, pDIB, NULL);
  605.             delete [] (BYTE *) pDIB;
  606.         }
  607.  
  608.         DeleteObject(hBmp);
  609.     }
  610. }
  611.  
  612. const BYTE Shift1bpp[] = { 7,     6,     5,     4,     3,     2,     1,     0     };
  613. const BYTE Mask1bpp [] = { ~0x80, ~0x40, ~0x20, ~0x10, ~0x08, ~0x04, ~0x02, ~0x01 };
  614.  
  615. const BYTE Shift2bpp[] = { 6,     4,     2,     0     };
  616. const BYTE Mask2bpp [] = { ~0xC0, ~0x30, ~0x0C, ~0x03 };
  617.  
  618. const BYTE Shift4bpp[] = { 4, 0 };
  619. const BYTE Mask4bpp [] = { ~0xF0, ~0x0F };
  620.  
  621.  
  622. DWORD KDIB::GetPixelIndex(int x, int y) const
  623. {
  624.     if ( (x<0) || (x>=m_nWidth) )
  625.         return -1;
  626.  
  627.     if ( (y<0) || (y>=m_nHeight) )
  628.         return -1;
  629.  
  630.     BYTE * pPixel = m_pOrigin + y * m_nDelta;
  631.  
  632.     switch ( m_nImageFormat )
  633.     {
  634.         case DIB_1BPP:
  635.             return ( pPixel[x/8] >> Shift1bpp[x%8] ) & 0x01;
  636.  
  637.         case DIB_2BPP:
  638.             return ( pPixel[x/4] >> Shift2bpp[x%4] ) & 0x03;
  639.  
  640.         case DIB_4BPP:
  641.             return ( pPixel[x/2] >> Shift4bpp[x%4] ) & 0x0F;
  642.  
  643.         case DIB_8BPP:
  644.             return pPixel[x];
  645.  
  646.         case DIB_16RGB555:
  647.         case DIB_16RGB565:
  648.             return ((WORD *)pPixel)[x];
  649.  
  650.         case DIB_24RGB888:
  651.             pPixel += x * 3;
  652.             return (pPixel[0]) | (pPixel[1] << 8) | (pPixel[2] << 16);
  653.         
  654.         case DIB_32RGB888:
  655.         case DIB_32RGBA8888:
  656.             return ((DWORD *)pPixel)[x];
  657.     }
  658.  
  659.     return -1;
  660. }
  661.  
  662. BOOL  KDIB::SetPixelIndex(int x, int y, DWORD index)
  663. {
  664.     if ( (x<0) || (x>=m_nWidth) )
  665.         return FALSE;
  666.  
  667.     if ( (y<0) || (y>=m_nHeight) )
  668.         return FALSE;
  669.  
  670.     BYTE * pPixel = m_pOrigin + y * m_nDelta;
  671.     
  672.     switch ( m_nImageFormat )
  673.     {
  674.         case DIB_1BPP:
  675.             pPixel[x/8] = (BYTE) ( ( pPixel[x/8] & Mask1bpp[x%8] ) | ( (index & 1) << Shift1bpp[x%8] ) );
  676.             break;
  677.  
  678.         case DIB_2BPP:
  679.             pPixel[x/4] = (BYTE) ( ( pPixel[x/4] & Mask2bpp[x%4] ) | ( (index & 3) << Shift2bpp[x%4] ) );
  680.             break;
  681.  
  682.         case DIB_4BPP:
  683.             pPixel[x/2] = (BYTE) ( ( pPixel[x/2] & Mask4bpp[x%2] ) | ( (index & 15) << Shift4bpp[x%2] ) );
  684.             break;
  685.  
  686.         case DIB_8BPP:
  687.             pPixel[x] = (BYTE) index;
  688.             break;
  689.  
  690.         case DIB_16RGB555:
  691.         case DIB_16RGB565:
  692.             ((WORD *)pPixel)[x] = (WORD) index;
  693.             break;
  694.  
  695.         case DIB_24RGB888:
  696.             ((RGBTRIPLE *)pPixel)[x] = * ((RGBTRIPLE *) & index);
  697.             break;
  698.  
  699.         case DIB_32RGB888:
  700.         case DIB_32RGBA8888:
  701.             ((DWORD *)pPixel)[x] = index;
  702.             break;
  703.  
  704.         default:
  705.             return FALSE;
  706.     }
  707.  
  708.     return TRUE;
  709. }
  710.  
  711.  
  712. BOOL KDIB::PlgBlt(const POINT * pPoint, 
  713.                    KDIB * pSrc, int nXSrc, int nYSrc, int nWidth, int nHeight)
  714. {
  715.     KReverseAffine map(pPoint);
  716.  
  717.     map.Setup(nXSrc, nYSrc, nWidth, nHeight);
  718.  
  719.     for (int dy=map.miny; dy<=map.maxy; dy++)
  720.     for (int dx=map.minx; dx<=map.maxx; dx++)
  721.     {
  722.         float sx, sy;
  723.         map.Map(dx, dy, sx, sy);
  724.  
  725.         if ( (sx>=nXSrc) && (sx<(nXSrc+nWidth))  )
  726.         if ( (sy>=nYSrc) && (sy<(nYSrc+nHeight)) )
  727.             SetPixelIndex(dx, dy, pSrc->GetPixelIndex( (int)sx, (int)sy));
  728.     }
  729.  
  730.     return TRUE;
  731. }
  732.  
  733.  
  734. BOOL KDIB::PlgBltGetPixel(const POINT * pPoint, 
  735.                    HDC hSrc, int nXSrc, int nYSrc, int nWidth, int nHeight, HDC hDst)
  736. {
  737.     KReverseAffine map(pPoint);
  738.  
  739.     map.Setup(nXSrc, nYSrc, nWidth, nHeight);
  740.  
  741.     for (int dy=map.miny; dy<=map.maxy; dy++)
  742.     for (int dx=map.minx; dx<=map.maxx; dx++)
  743.     {
  744.         float sx, sy;
  745.         map.Map(dx, dy, sx, sy);
  746.  
  747.         if ( (sx>=nXSrc) && (sx<(nXSrc+nWidth))  )
  748.         if ( (sy>=nYSrc) && (sy<(nYSrc+nHeight)) )
  749.             SetPixel(hDst, dx, dy, GetPixel(hSrc, (int)sx, (int)sy));
  750.     }
  751.  
  752.     return TRUE;
  753. }
  754.  
  755.  
  756. BOOL KDIB::PlgBlt24(const POINT * pPoint, 
  757.                    KDIB * pSrc, int nXSrc, int nYSrc, int nWidth, int nHeight)
  758. {
  759.     // factor to change FLOAT to fixed point
  760.     const int FACTOR = 65536;
  761.  
  762.     // generate reverse transformation from destination to source
  763.     KReverseAffine map(pPoint);
  764.  
  765.     map.Setup(nXSrc, nYSrc, nWidth, nHeight);
  766.  
  767.     // make sure within destination bitmap dimension
  768.     if ( map.minx < 0 )         map.minx = 0;
  769.     if ( map.maxx > m_nWidth )  map.maxx = m_nWidth;
  770.  
  771.     if ( map.miny < 0 )         map.miny = 0;
  772.     if ( map.maxy > m_nHeight ) map.maxy = m_nHeight;
  773.  
  774.     // source rectangle in fixed point
  775.     int sminx = nXSrc * FACTOR;
  776.     int sminy = nYSrc * FACTOR;
  777.     int smaxx = ( nXSrc + nWidth  ) * FACTOR;
  778.     int smaxy = ( nYSrc + nHeight ) * FACTOR;
  779.  
  780.     // transformation matrix in fixed point
  781.     int m11 = (int) (map.m_xm.eM11 * FACTOR);
  782.     int m12 = (int) (map.m_xm.eM12 * FACTOR);
  783.     int m21 = (int) (map.m_xm.eM21 * FACTOR);
  784.     int m22 = (int) (map.m_xm.eM22 * FACTOR);
  785.     int mdx = (int) (map.m_xm.eDx  * FACTOR);
  786.     int mdy = (int) (map.m_xm.eDy  * FACTOR);
  787.  
  788.     BYTE * SOrigin = pSrc->m_pOrigin;
  789.     int    SDelta  = pSrc->m_nDelta;
  790.  
  791.     // in destination bitmap, scan from first to last scanline
  792.     for (int dy=map.miny; dy<map.maxy; dy++)
  793.     {
  794. /*
  795.         // search for the first pixel on the scanline within source rectangle
  796.         int sx = m11 * map.minx + m21 * dy + mdx;
  797.         int sy = m12 * map.minx + m22 * dy + mdy;
  798.  
  799.         for (int dx=map.minx; dx<map.maxx; dx++, sx+=m11, sy+=m12)
  800.             // if within source rectangle
  801.             if ( (sx>=sminx) && (sx<smaxx) )
  802.             if ( (sy>=sminy) && (sy<smaxy) )
  803.                 break;
  804.  
  805.         int minx = dx;
  806.  
  807.         // search for the last pixel on the scaneline within source rectangle
  808.         sx = m11 * map.maxx + m21 * dy + mdx;
  809.         sy = m12 * map.maxx + m22 * dy + mdy;
  810.  
  811.         for (dx=map.maxx; dx>=map.minx; dx--, sx-=m11, sy-=m12)
  812.             // if within source rectangle
  813.             if ( (sx>=sminx) && (sx<smaxx) )
  814.             if ( (sy>=sminy) && (sy<smaxy) )
  815.                 break;
  816.  
  817.         int maxx = dx;
  818. */
  819.         // precalculate destination pixel address for first pixel
  820.         BYTE * pDPixel = m_pOrigin + dy * m_nDelta + map.minx * 3;
  821.  
  822.         // source pixel address for the first pixel
  823.         int sx = m11 * map.minx + m21 * dy + mdx;
  824.         int sy = m12 * map.minx + m22 * dy + mdy;
  825.  
  826.         // go through each pixel on the scan line
  827.         for (int dx=map.minx; dx<map.maxx; dx++, pDPixel+=3, sx+=m11, sy+=m12)
  828.             if ( (sx>=sminx) && (sx<smaxx) )
  829.             if ( (sy>=sminy) && (sy<smaxy) )
  830.             {
  831.                 // source pixel address
  832.                 BYTE * pSPixel = SOrigin + (sy/FACTOR) * SDelta;
  833.  
  834.                 // copy three bytes
  835.                 * ((RGBTRIPLE *)pDPixel) = ((RGBTRIPLE *)pSPixel)[sx/FACTOR];
  836.             }
  837.     }
  838.  
  839.     return TRUE;
  840. }
  841.  
  842. BOOL KDIB::Create(int width, int height, int bitcount)
  843. {
  844.     KBitmapInfo dibinfo;
  845.  
  846.     dibinfo.SetFormat(width, height, bitcount, BI_RGB);
  847.  
  848.     int nBitsSize = ( width * bitcount + 31 ) /32 * 4 * height;
  849.     BYTE * pBits = new BYTE[nBitsSize];
  850.     
  851.     if ( pBits )
  852.         return AttachDIB(dibinfo.CopyBMI(), pBits, 0);
  853.     else
  854.         return FALSE;
  855. }
  856.  
  857. void Map(XFORM * xm, int x, int y, int & rx, int & ry)
  858. {
  859.     rx = (int) ( xm->eM11 * x + xm->eM21 * y + xm->eDx );
  860.     ry = (int) ( xm->eM12 * x + xm->eM22 * y + xm->eDy );
  861. }
  862.  
  863. BOOL Invert(XFORM & xm)
  864. {
  865.     FLOAT det = xm.eM11 * xm.eM22 - xm.eM21 * xm.eM12;
  866.  
  867.     if ( det==0 )
  868.         return FALSE;
  869.  
  870.     XFORM old = xm;
  871.  
  872.     xm.eM11 =   old.eM22 / det;
  873.     xm.eM12 = - old.eM12 / det;
  874.     xm.eM21 = - old.eM21 / det;
  875.     xm.eM22 =   old.eM11 / det;
  876.     
  877.     xm.eDx  = - ( xm.eM11 * old.eDx + xm.eM21 * old.eDy );
  878.     xm.eDy  = - ( xm.eM12 * old.eDx + xm.eM22 * old.eDy );
  879.  
  880.     return TRUE;
  881. }
  882.  
  883. DWORD dibtick;
  884.  
  885. HBITMAP KDIB::TransformBitmap(XFORM * xm, COLORREF crBack, int method)
  886. {
  887.     int x0, y0, x1, y1, x2, y2, x3, y3;
  888.  
  889.     Map(xm, 0,        0,         x0, y0);  // 0    1
  890.     Map(xm, m_nWidth, 0,         x1, y1);  //
  891.     Map(xm, 0,        m_nHeight, x2, y2);  // 2    3
  892.     Map(xm, m_nWidth, m_nHeight, x3, y3);
  893.  
  894.     int xmin, xmax;
  895.     int ymin, ymax;
  896.  
  897.     minmax(x0, x1, x2, x3, xmin, xmax);
  898.     minmax(y0, y1, y2, y3, ymin, ymax);
  899.  
  900.     int destwidth  = xmax - xmin;
  901.     int destheight = ymax - ymin;
  902.  
  903.     KBitmapInfo dest;
  904.     dest.SetFormat(destwidth, destheight, m_pBMI->bmiHeader.biBitCount, m_pBMI->bmiHeader.biCompression);
  905.  
  906.     if ( m_nClrUsed )
  907.         memcpy(dest.m_dibinfo.bmiColors, m_pRGBQUAD, sizeof(RGBQUAD) * m_nClrUsed);
  908.  
  909.     // create destination DIB section
  910.     BYTE * pBits;
  911.     HBITMAP hBitmap = CreateDIBSection(NULL, dest.GetBMI(), DIB_RGB_COLORS, (void **) & pBits, NULL, NULL);
  912.     if ( hBitmap==NULL )
  913.     {
  914.         assert(false);
  915.         return NULL;
  916.     }
  917.  
  918.     // For testing GDI GetPixel speed, we need a HDC for the source bitmap
  919.     HBITMAP hSrcBmp = NULL;
  920.     HDC     hSrcDC  = NULL;
  921.     HGDIOBJ hSrcOld = NULL;
  922.  
  923.     if ( method==method_gdi )
  924.     {
  925.         hSrcBmp = CreateDIBSection(NULL, m_pBMI, DIB_RGB_COLORS, (void **) & pBits, NULL, NULL);
  926.         assert(hSrcBmp);
  927.  
  928.         hSrcDC  = CreateCompatibleDC(NULL);
  929.         hSrcOld = SelectObject(hSrcDC, hSrcBmp);
  930.  
  931.         // copy pixels from DIB to source DIB section
  932.         DrawDIB(hSrcDC, 0, 0, m_nWidth, m_nHeight, 0, 0, m_nWidth, m_nHeight, SRCCOPY);
  933.     }
  934.  
  935.     // clear DIB section to background color
  936.     HDC     hDstDC  = CreateCompatibleDC(NULL);
  937.     HGDIOBJ hDstOld = SelectObject(hDstDC, hBitmap);
  938.  
  939.     HBRUSH hBrush = CreateSolidBrush(crBack);
  940.     RECT rect = { 0, 0,  destwidth, destheight };
  941.     FillRect(hDstDC, & rect, hBrush);
  942.     DeleteObject(hBrush);
  943.  
  944.     KDIB destDIB;
  945.     destDIB.AttachDIB(dest.GetBMI(), pBits, 0);
  946.  
  947.     POINT P[3] = { { x0-xmin, y0-ymin }, { x1-xmin, y1-ymin }, { x2-xmin, y2-ymin } };
  948.  
  949.     dibtick = GetTickCount();
  950.     
  951.     if ( (m_nBitCount<=8) && (method==method_24bpp) )
  952.         method = method_direct;
  953.  
  954.     switch ( method )
  955.     {
  956.         case method_gdi:
  957.             destDIB.PlgBltGetPixel(P, hSrcDC, 0, 0, m_nWidth, m_nHeight, hDstDC);
  958.             break;   
  959.  
  960.         case method_direct:    
  961.             destDIB.PlgBlt(P, this, 0, 0, m_nWidth, m_nHeight);
  962.             break;   
  963.  
  964.         case method_24bpp:
  965.             destDIB.PlgBlt24(P, this, 0, 0, m_nWidth, m_nHeight);
  966.             break;
  967.     }
  968.  
  969.     dibtick = GetTickCount() - dibtick;
  970.  
  971.     SelectObject(hDstDC, hDstOld);
  972.     DeleteObject(hDstDC);
  973.  
  974.     if ( method==method_gdi )
  975.     {
  976.         SelectObject(hSrcDC, hSrcOld);
  977.  
  978.         DeleteObject(hSrcDC);
  979.         DeleteObject(hSrcBmp);
  980.     }
  981.  
  982.     return hBitmap;
  983. }
  984.  
  985.  
  986. // Calculate DIB pixel offset
  987. inline int GetOffset(BITMAPINFO * pBMI, int x, int y)
  988. {
  989.     if ( pBMI->bmiHeader.biHeight > 0 )    // for bottom up, reflect y
  990.         y = pBMI->bmiHeader.biHeight - 1 - y;
  991.     
  992.     return ( pBMI->bmiHeader.biWidth * pBMI->bmiHeader.biBitCount + 31 ) / 32 * 4 * y + 
  993.            ( pBMI->bmiHeader.biBitCount / 8 ) * x;
  994. }
  995.  
  996.  
  997. // Alpha Blending between two 32-bpp DIBs
  998. BOOL AlphaBlend3232(BITMAPINFO * pBMIDst, BYTE * pBitsDst, int dx, int dy, int w, int h,
  999.                     BITMAPINFO * pBMISrc, BYTE * pBitsSrc, int sx, int sy,
  1000.                     BLENDFUNCTION blend)
  1001. {
  1002.     int alpha = blend.SourceConstantAlpha;    // constant alpha
  1003.     int beta  = 255 - alpha;                // constant beta
  1004.     int format;
  1005.  
  1006.     if ( blend.AlphaFormat==0 )
  1007.         format = 0;
  1008.     else if ( alpha==255 )
  1009.         format = 1;
  1010.     else 
  1011.         format = 2;
  1012.  
  1013.     for (int j=0; j<h; j++)
  1014.     {
  1015.         BYTE * D = pBitsDst + GetOffset(pBMIDst, dx, j + dy);
  1016.         BYTE * S = pBitsSrc + GetOffset(pBMISrc, sx, j + sy);
  1017.         
  1018.         int i;
  1019.  
  1020.         switch ( format )
  1021.         {
  1022.             case 0: // constant alpha only
  1023.                 for (i=0; i<w; i++)
  1024.                 {
  1025.                     D[0] = ( S[0] * alpha + beta * D[0] + 127 ) / 255;
  1026.                     D[1] = ( S[1] * alpha + beta * D[1] + 127 ) / 255;
  1027.                     D[2] = ( S[2] * alpha + beta * D[2] + 127 ) / 255;
  1028.                     D[3] = ( S[3] * alpha + beta * D[3] + 127 ) / 255;
  1029.                     D += 4; S += 4;
  1030.                 }
  1031.                 break;
  1032.  
  1033.             case 1: // alpha channel only
  1034.                 for (i=0; i<w; i++)
  1035.                 {
  1036.                     beta  = 255 - S[3];
  1037.                     D[0] = S[0] + ( beta * D[0] + 127 ) / 255;
  1038.                     D[1] = S[1] + ( beta * D[1] + 127 ) / 255;
  1039.                     D[2] = S[2] + ( beta * D[2] + 127 ) / 255;
  1040.                     D[3] = S[3] + ( beta * D[3] + 127 ) / 255;
  1041.                     D += 4; S += 4;
  1042.                 }
  1043.                 break;
  1044.             
  1045.             case 2: // both constant alpha and alpha channel
  1046.                 for (i=0; i<w; i++)
  1047.                 {
  1048.                     beta  = 255 - ( S[3] * alpha + 127 ) / 255;
  1049.                     
  1050.                     D[0] = ( S[0] * alpha + beta * D[0] + 127 ) / 255;
  1051.                     D[1] = ( S[1] * alpha + beta * D[1] + 127 ) / 255;
  1052.                     D[2] = ( S[2] * alpha + beta * D[2] + 127 ) / 255;
  1053.                     D[3] = ( S[3] * alpha + beta * D[3] + 127 ) / 255;
  1054.                     D += 4; S += 4;
  1055.                 }
  1056.         }
  1057.     }
  1058.  
  1059.     return FALSE;
  1060. }
  1061.  
  1062.  
  1063. // AlphaBlending a 32-bpp DIB to hdc
  1064. BOOL AlphaBlend(HDC hdc, int x0, int y0, const BITMAPINFO *pbmpInfo, const void * pAlphaImageData)
  1065. {
  1066.     if ( pbmpInfo->bmiHeader.biBitCount!=32 )
  1067.         return FALSE;
  1068.  
  1069.     if ( pbmpInfo->bmiHeader.biCompression!=BI_RGB )
  1070.         return FALSE;
  1071.  
  1072.     int width  = pbmpInfo->bmiHeader.biWidth;
  1073.     int height = pbmpInfo->bmiHeader.biHeight;
  1074.  
  1075.     BITMAPINFOHEADER bmih = { sizeof(BITMAPINFOHEADER), width, height, 1, 24 };
  1076.  
  1077.     VOID * pBits;
  1078.  
  1079.     HBITMAP hBmp = CreateDIBSection(NULL, (BITMAPINFO *) & bmih, DIB_RGB_COLORS, & pBits, NULL, NULL);
  1080.  
  1081.     if ( hBmp==NULL )
  1082.         return FALSE;
  1083.  
  1084.     HDC hMemDC = CreateCompatibleDC(hdc);
  1085.     HGDIOBJ hOld = SelectObject(hMemDC, hBmp);
  1086.  
  1087.     BitBlt(hMemDC, 0, 0, width, height, hdc, x0, y0, SRCCOPY); // copy destination, not working on printer
  1088.  
  1089.     const BYTE * psrc = (const BYTE *) pAlphaImageData;
  1090.           BYTE * pdst = (BYTE *) pBits;
  1091.  
  1092.     for (int y = 0; y < abs(height); y++)
  1093.     {
  1094.         for (int x = width; x>0; x--)
  1095.         {
  1096.             BYTE alpha  = psrc[3]; //Get alpha channel byte.
  1097.             BYTE salpha = 255 - alpha;
  1098.  
  1099.             pdst[0] = (BYTE)(( psrc[0] * alpha + pdst[0] * salpha) / 255);
  1100.             pdst[1] = (BYTE)(( psrc[1] * alpha + pdst[1] * salpha) / 255);
  1101.             pdst[2] = (BYTE)(( psrc[2] * alpha + pdst[2] * salpha) / 255);
  1102.  
  1103.             pdst += 3;
  1104.             psrc += 4;
  1105.         }
  1106.  
  1107.         pdst += width % 3;
  1108.     }
  1109.  
  1110.     BOOL rslt = BitBlt(hdc, x0, y0, width, height, hMemDC, 0, 0, SRCCOPY);
  1111.  
  1112.     SelectObject(hMemDC, hOld);
  1113.     DeleteObject(hBmp);
  1114.     DeleteObject(hMemDC);
  1115.  
  1116.     return rslt;
  1117. }
  1118.