home *** CD-ROM | disk | FTP | other *** search
/ Windows Graphics Programming / Feng_Yuan_Win32_GDI_DirectX.iso / Samples / include / Image.cpp < prev    next >
Encoding:
C/C++ Source or Header  |  2000-05-11  |  13.8 KB  |  565 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   : image.cpp                                                                //
  10. //  Description: Generic Image Processing Classes                                    //
  11. //  Version    : 1.00.000, May 31, 2000                                              //
  12. //-----------------------------------------------------------------------------------//
  13.  
  14. #define STRICT
  15. #define WIN32_LEAN_AND_MEAN
  16.  
  17. #include <windows.h>
  18. #include <math.h>
  19. #include <tchar.h>
  20.  
  21. #include "DIB.h"
  22. #include "Image.h"
  23.  
  24. //////////////////////////////////////////////////
  25. //                                                //
  26. //           C O N V O L U T I O N                //
  27. //                                                //
  28. //////////////////////////////////////////////////
  29.  
  30. bool KImage::Convolution(KFilter * pFilter)
  31. {
  32.     BYTE * pDestBits = new BYTE[m_nImageSize];
  33.  
  34.     if ( pDestBits==NULL )
  35.         return false;
  36.  
  37.     for (int y=0; y<m_nHeight; y++)
  38.     {
  39.         unsigned char * pBuffer = (unsigned char *) m_pBits   + m_nBPS * y;
  40.         unsigned char * pDest   = (unsigned char *) pDestBits + m_nBPS * y;
  41.  
  42.         if (  (y>=pFilter->GetHalf()) && (y<(m_nHeight- pFilter->GetHalf())) )
  43.             switch ( m_nImageFormat )
  44.             {
  45.                 case DIB_8BPP:
  46.                     pFilter->Filter8bpp(pDest, pBuffer, m_nWidth, m_nBPS);
  47.                     break;
  48.  
  49.                 case DIB_24RGB888:    // 24-bpp RGB
  50.                     pFilter->Filter24bpp(pDest, pBuffer, m_nWidth, m_nBPS);
  51.                     break;
  52.  
  53.                 case DIB_32RGBA8888: // 32-bpp RGBA
  54.                 case DIB_32RGB888:   // 32-bpp RGB
  55.                     pFilter->Filter32bpp(pDest, pBuffer, m_nWidth, m_nBPS);
  56.                     break;
  57.  
  58.                 default:
  59.                     delete [] pDestBits;
  60.                     return false;
  61.             }
  62.         else
  63.             memcpy(pDest, pBuffer, m_nBPS); // copy unprocessed scanlines
  64.     }
  65.     
  66.     memcpy(m_pBits, pDestBits, m_nImageSize); // overwrite source pixel array
  67.     delete [] pDestBits;
  68.  
  69.     return true;
  70. }
  71.  
  72. //////////////////////////////////////////////////
  73. //                                                //
  74. //   P I X E L   T R A N S F O R M A T I O N    //
  75. //                                                //
  76. //////////////////////////////////////////////////
  77.  
  78. BITMAPINFO * KImage::SplitChannel(Operator oper)
  79. {
  80.     KChannel channel;
  81.  
  82.     return channel.Split(* this, oper);
  83. }
  84.  
  85.  
  86. bool KImage::PixelTransform(KPixelMapper & map)
  87. {
  88.     if ( m_pRGBTRIPLE )
  89.         map.SetColorTable((BYTE *) m_pRGBTRIPLE, sizeof(RGBTRIPLE), m_nClrUsed);
  90.     else if ( m_pRGBQUAD )
  91.         map.SetColorTable((BYTE *) m_pRGBQUAD, sizeof(RGBQUAD), m_nClrUsed);
  92.  
  93.     for (int y=0; y<m_nHeight; y++)
  94.     {
  95.         unsigned char * pBuffer = (unsigned char *) m_pBits + m_nBPS * y;
  96.     
  97.         if ( ! map.StartLine(y) )
  98.             break;
  99.  
  100.         switch ( m_nImageFormat )
  101.         {
  102.             case DIB_1BPP:
  103.                 map.Map1bpp(pBuffer, m_nWidth);
  104.                 break;
  105.  
  106.             case DIB_2BPP:
  107.                 map.Map2bpp(pBuffer, m_nWidth);
  108.                 break;
  109.  
  110.             case DIB_4BPP:
  111.                 map.Map4bpp(pBuffer, m_nWidth);
  112.                 break;
  113.  
  114.             case DIB_8BPP:
  115.                 map.Map8bpp(pBuffer, m_nWidth);
  116.                 break;
  117.  
  118.             case DIB_16RGB555:     // 15 bit RGB color image, 5-5-5, 1 bit unused
  119.                 map.Map555(pBuffer, m_nWidth);
  120.                 break;
  121.  
  122.             case DIB_16RGB565:    // 16 bit RGB color image, 5-6-5
  123.                 map.Map565(pBuffer, m_nWidth);
  124.                 break;
  125.  
  126.             case DIB_24RGB888:    // 24-bpp RGB
  127.                 map.Map24bpp(pBuffer, m_nWidth);
  128.                 break;
  129.  
  130.             case DIB_32RGBA8888: // 32-bpp RGBA
  131.             case DIB_32RGB888:   // 32-bpp RGB
  132.                 map.Map32bpp(pBuffer, m_nWidth);
  133.                 break;
  134.  
  135.             default:
  136.                 return false;
  137.         }
  138.     }
  139.     
  140.     return true;
  141. }
  142.  
  143. //////////////////////////////////////////////////
  144. //                                                //
  145. //   C O L O R   T R A N S F O R M A T I O N    //
  146. //                                                //
  147. //////////////////////////////////////////////////
  148.  
  149. template <class Dummy>
  150. bool ColorTransform(KDIB * dib, Dummy map)
  151. {
  152.     // support OS/2 DIB color table: 1-bpp, 4-bpp, 8-bpp, include RLE compression
  153.     if ( dib->m_pRGBTRIPLE )
  154.     {
  155.         for (int i=0; i<dib->m_nClrUsed; i++)
  156.             map(dib->m_pRGBTRIPLE[i].rgbtRed, dib->m_pRGBTRIPLE[i].rgbtGreen, dib->m_pRGBTRIPLE[i].rgbtBlue);
  157.  
  158.         return true;
  159.     }
  160.  
  161.     // support Windows DIB color table: 1-bpp, 2-bpp, 4-bpp, 8-bpp, include RLE compression
  162.     if ( dib->m_pRGBQUAD )
  163.     {
  164.         for (int i=0; i<dib->m_nClrUsed; i++)
  165.             map(dib->m_pRGBQUAD[i].rgbRed, dib->m_pRGBQUAD[i].rgbGreen, dib->m_pRGBQUAD[i].rgbBlue);
  166.  
  167.         return true;
  168.     }
  169.     
  170.     for (int y=0; y<dib->m_nHeight; y++)
  171.     {
  172.         int width = dib->m_nWidth;
  173.         unsigned char * pBuffer = (unsigned char *) dib->m_pBits + dib->m_nBPS * y;
  174.         
  175.         switch ( dib->m_nImageFormat )
  176.         {
  177.             case DIB_16RGB555:     // 15 bit RGB color image, 5-5-5, 1 bit unused
  178.                 for (; width>0; width--)
  179.                 {
  180.                     BYTE red   = ( (* (WORD *) pBuffer) & 0x7C00 ) >> 7;
  181.                     BYTE green = ( (* (WORD *) pBuffer) & 0x03E0 ) >> 2;
  182.                     BYTE blue  = ( (* (WORD *) pBuffer) & 0x001F ) << 3;
  183.                     
  184.                     map( red, green, blue );
  185.                     
  186.                     * ( WORD *) pBuffer = ( ( red >> 3 ) << 10 ) | ( ( green >> 3 ) << 5 ) | ( blue >> 3 );
  187.                     
  188.                     pBuffer += 2;
  189.                 }
  190.                 break;
  191.  
  192.             case DIB_16RGB565:    // 16 bit RGB color image, 5-6-5
  193.                 for (; width>0; width--)
  194.                 {
  195.                     const DWORD StandardMask565[] =  { 0x00F800, 0x0007E0, 0x00001F };
  196.  
  197.                     BYTE red   = ( (* (WORD *) pBuffer) & 0xF800 ) >> 8;
  198.                     BYTE green = ( (* (WORD *) pBuffer) & 0x07E0 ) >> 3;
  199.                     BYTE blue  = ( (* (WORD *) pBuffer) & 0x001F ) << 3;
  200.                     
  201.                     map( red, green, blue );
  202.                     
  203.                     * ( WORD *) pBuffer = ( ( red >> 3 ) << 11 ) | ( ( green >> 2 ) << 5 ) | ( blue >> 3 );
  204.                     
  205.                     pBuffer += 2;
  206.                 }
  207.                 break;
  208.  
  209.             case DIB_24RGB888:    // 24-bpp RGB
  210.                 for (; width>0; width--)
  211.                 {
  212.                     map( pBuffer[2], pBuffer[1], pBuffer[0] );
  213.                     pBuffer += 3;
  214.                 }
  215.                 break;
  216.  
  217.             case DIB_32RGBA8888: // 32-bpp RGBA
  218.             case DIB_32RGB888:   // 32-bpp RGB
  219.                 for (; width>0; width--)
  220.                 {
  221.                     map( pBuffer[2], pBuffer[1], pBuffer[0] );
  222.                     pBuffer += 4;
  223.                 }
  224.                 break;
  225.  
  226.             default:
  227.                 return false;
  228.         }
  229.     }
  230.     
  231.     return true;
  232. }
  233.  
  234.  
  235. bool KImage::ToGreyScale(void)
  236. {
  237.     return ColorTransform(this, MaptoGray);
  238. }
  239.  
  240.  
  241. BYTE   redGammaRamp[256];
  242. BYTE greenGammaRamp[256];
  243. BYTE  blueGammaRamp[256];
  244.  
  245. inline void MapGamma(BYTE & red, BYTE & green, BYTE & blue)
  246. {
  247.     red   =   redGammaRamp[red];
  248.     green = greenGammaRamp[green];
  249.     blue  =  blueGammaRamp[blue];
  250. }
  251.  
  252.  
  253. BYTE gamma(double g, int index)
  254. {
  255.     return min(255, (int) ( (255.0 * pow(index/255.0, 1.0/g)) + 0.5 ) ); 
  256.     
  257. bool KImage::GammaCorrect(double redgamma, double greengamma, double bluegamma)
  258. {
  259.     for (int i=0; i<256; i++)
  260.     {
  261.           redGammaRamp[i] = gamma(  redgamma, i);
  262.         greenGammaRamp[i] = gamma(greengamma, i);
  263.          blueGammaRamp[i] = gamma( bluegamma, i);
  264.     }
  265.  
  266.     return ColorTransform(this, MapGamma);
  267. }
  268.  
  269.  
  270. bool KImage::Lighten(void)
  271. {
  272.     return ColorTransform(this, LightenColor);
  273. }
  274.  
  275.  
  276. //////////////////////////////////////////////////////////////
  277.  
  278.  
  279. void KPixelMapper::Map1bpp(BYTE * pBuffer, int width)
  280. {
  281.     BYTE mask  = 0x80;
  282.     int  shift = 7;
  283.  
  284.     for (; width>0; width--)
  285.     {
  286.         BYTE index = ( ( pBuffer[0] & mask ) >> shift ) & 0x1;
  287.  
  288.         if ( MapIndex(index) )
  289.             pBuffer[0] =  ( pBuffer[0] & ~ mask ) || (( index & 0x0F) << shift);
  290.  
  291.         mask  >>= 1;
  292.         shift -= 1;
  293.  
  294.         if ( mask==0 )
  295.         {
  296.             pBuffer ++; mask = 0x80; shift = 7;
  297.         }
  298.     }
  299. }
  300.  
  301.  
  302. void KPixelMapper::Map2bpp(BYTE * pBuffer, int width)
  303. {
  304.     BYTE mask  = 0xC0;
  305.     int  shift = 6;
  306.  
  307.     for (; width>0; width--)
  308.     {
  309.         BYTE index = ( ( pBuffer[0] & mask ) >> shift ) & 0x3;
  310.  
  311.         if ( MapIndex(index) )
  312.             pBuffer[0] =  ( pBuffer[0] & ~ mask ) || (( index & 0x0F) << shift);
  313.  
  314.         mask  >>= 2;
  315.         shift -= 2;
  316.  
  317.         if ( mask==0 )
  318.         {
  319.             pBuffer ++; mask = 0xC0; shift = 6;
  320.         }
  321.     }
  322. }
  323.  
  324.  
  325. void KPixelMapper::Map4bpp(BYTE * pBuffer, int width)
  326. {
  327.     BYTE mask  = 0xF0;
  328.     int  shift = 4;
  329.  
  330.     for (; width>0; width--)
  331.     {
  332.         BYTE index = ( ( pBuffer[0] & mask ) >> shift ) & 0x0F;
  333.  
  334.         if ( MapIndex(index) )
  335.             pBuffer[0] =  ( pBuffer[0] & ~ mask ) || (( index & 0x0F) << shift);
  336.  
  337.         mask  = ~ mask;
  338.         shift = 4 - shift;
  339.  
  340.         if ( mask==0xF0 )
  341.             pBuffer ++;
  342.     }
  343. }
  344.  
  345.  
  346. void KPixelMapper:: Map8bpp(BYTE * pBuffer, int width)
  347. {
  348.     for (; width>0; width--)
  349.     {
  350.         MapIndex(pBuffer[0]);
  351.         pBuffer ++;
  352.     }
  353. }
  354.  
  355.  
  356. void KPixelMapper::Map555(BYTE * pBuffer, int width)
  357. {
  358.     for (; width>0; width--)
  359.     {
  360.         BYTE red   = ( (* (WORD *) pBuffer) & 0x7C00 ) >> 7;
  361.         BYTE green = ( (* (WORD *) pBuffer) & 0x03E0 ) >> 2;
  362.         BYTE blue  = ( (* (WORD *) pBuffer) & 0x001F ) << 3;
  363.                     
  364.         if ( MapRGB( red, green, blue ) )
  365.             * ( WORD *) pBuffer = ( ( red >> 3 ) << 10 ) | ( ( green >> 3 ) << 5 ) | ( blue >> 3 );
  366.                     
  367.         pBuffer += 2;
  368.     }
  369. }
  370.  
  371.  
  372. void KPixelMapper::Map565(BYTE * pBuffer, int width)
  373. {
  374.     for (; width>0; width--)
  375.     {
  376.         BYTE red   = ( (* (WORD *) pBuffer) & 0xF800 ) >> 8;
  377.         BYTE green = ( (* (WORD *) pBuffer) & 0x07E0 ) >> 3;
  378.         BYTE blue  = ( (* (WORD *) pBuffer) & 0x001F ) << 3;
  379.                     
  380.         if ( MapRGB( red, green, blue ) )
  381.             * ( WORD *) pBuffer = ( ( red >> 3 ) << 11 ) | ( ( green >> 2 ) << 5 ) | ( blue >> 3 );
  382.                     
  383.         pBuffer += 2;
  384.     }
  385. }
  386.  
  387.  
  388. void KPixelMapper::Map24bpp(BYTE * pBuffer, int width)
  389. {
  390.     for (; width>0; width--)
  391.     {
  392.         MapRGB( pBuffer[2], pBuffer[1], pBuffer[0] );
  393.         pBuffer += 3;
  394.     }
  395. }
  396.  
  397.  
  398. void KPixelMapper::Map32bpp(BYTE * pBuffer, int width)
  399. {
  400.     for (; width>0; width--)
  401.     {
  402.         MapRGB( pBuffer[2], pBuffer[1], pBuffer[0] );
  403.         pBuffer += 4;
  404.     }
  405. }
  406.  
  407.  
  408. BITMAPINFO * KChannel::Split(KImage & dib, Operator oper)
  409. {
  410.     m_Operator = oper;
  411.     m_nBPS     = (dib.GetWidth() + 3) / 4 * 4;    // scanline size for 8-bpp DIB
  412.     
  413.     int headsize = sizeof(BITMAPINFOHEADER) + 256 * sizeof(RGBQUAD);
  414.  
  415.     BITMAPINFO * pNewDIB = (BITMAPINFO *) new BYTE[headsize + m_nBPS * abs(dib.GetHeight())];
  416.  
  417.     memset(pNewDIB, 0, headsize);
  418.  
  419.     pNewDIB->bmiHeader.biSize         = sizeof(BITMAPINFOHEADER); 
  420.     pNewDIB->bmiHeader.biWidth         = dib.GetWidth(); 
  421.     pNewDIB->bmiHeader.biHeight         = dib.GetHeight(); 
  422.     pNewDIB->bmiHeader.biPlanes         = 1; 
  423.     pNewDIB->bmiHeader.biBitCount     = 8; 
  424.     pNewDIB->bmiHeader.biCompression = BI_RGB; 
  425.  
  426.     for (int c=0; c<256; c++)
  427.     {
  428.         pNewDIB->bmiColors[c].rgbRed   = c;
  429.         pNewDIB->bmiColors[c].rgbGreen = c;
  430.         pNewDIB->bmiColors[c].rgbBlue  = c;
  431.     }
  432.  
  433.     m_pBits  = (BYTE*) & pNewDIB->bmiColors[256];
  434.     
  435.     if ( pNewDIB==NULL )
  436.         return NULL;
  437.  
  438.     dib.PixelTransform(* this);
  439.  
  440.     return pNewDIB;
  441. }
  442.  
  443.  
  444. void KHistogram::Sample(KImage & dib)
  445. {
  446.     memset(m_FreqRed,   0, sizeof(m_FreqRed));
  447.     memset(m_FreqGreen, 0, sizeof(m_FreqGreen));
  448.     memset(m_FreqBlue,  0, sizeof(m_FreqBlue));
  449.     memset(m_FreqGray,  0, sizeof(m_FreqGray));
  450.     
  451.     dib.PixelTransform(* this);
  452. }
  453.  
  454.  
  455. void KFilter::Filter8bpp(BYTE * pDest, BYTE * pSource, int nWidth, int dy)
  456. {
  457.     memcpy(pDest, pSource, m_nHalf); 
  458.     pDest   += m_nHalf; 
  459.     pSource += m_nHalf;
  460.  
  461.     for (int i=nWidth - 2 * m_nHalf; i>0; i--)
  462.         * pDest ++ = Kernel(pSource++, 1, dy);
  463.         
  464.     memcpy(pDest, pSource, m_nHalf); 
  465. }
  466.  
  467.  
  468. void KFilter::Filter24bpp(BYTE * pDest, BYTE * pSource, int nWidth, int dy)
  469. {
  470.     memcpy(pDest, pSource, m_nHalf * 3);
  471.     pDest   += m_nHalf * 3;
  472.     pSource += m_nHalf * 3;
  473.  
  474.     for (int i=nWidth - 2 * m_nHalf; i>0; i--)
  475.     {
  476.         * pDest ++ = Kernel(pSource++, 3, dy);
  477.         * pDest ++ = Kernel(pSource++, 3, dy);
  478.         * pDest ++ = Kernel(pSource++, 3, dy);
  479.     }
  480.  
  481.     memcpy(pDest, pSource, m_nHalf * 3);
  482. }
  483.  
  484.  
  485. void KFilter::Filter32bpp(BYTE * pDest, BYTE * pSource, int nWidth, int dy)
  486. {
  487.     memcpy(pDest, pSource, m_nHalf * 4);
  488.     pDest   += m_nHalf * 4;
  489.     pSource += m_nHalf * 4;
  490.  
  491.     for (int i=nWidth - 2 * m_nHalf; i>0; i--)
  492.     {
  493.         * pDest ++ = Kernel(pSource++, 4, dy);
  494.         * pDest ++ = Kernel(pSource++, 4, dy);
  495.         * pDest ++ = Kernel(pSource++, 4, dy);
  496.         * pDest ++ = * pSource++;                // copy alpha channel
  497.     }
  498.  
  499.     memcpy(pDest, pSource, m_nHalf * 4);
  500. }
  501.  
  502.  
  503. void Describe33Filter(HDC hDC, int x, int y, const int * matrix, TCHAR * name, int weight, int add)
  504. {
  505.     SelectObject(hDC, GetStockObject(SYSTEM_FIXED_FONT));
  506.  
  507.     TextOut(hDC, x, y, name, _tcslen(name)); 
  508.  
  509.     if ( matrix )
  510.     {
  511.         y+=20;
  512.  
  513.         TCHAR number[32];
  514.  
  515.         for (int i=0; i<3; i++)
  516.         {
  517.             wsprintf(number, _T("%c |%2d %2d %2d|"), 
  518.                 (i==1) ? '*' : ' ',
  519.                 matrix[i*3], matrix[i*3+1], matrix[i*3+2]);
  520.             TextOut(hDC, x + 5, y + i * 15, number, _tcslen(number));
  521.         }
  522.  
  523.         if ( add )
  524.             wsprintf(number, _T("/ %d + %d"), weight, add);
  525.         else
  526.             wsprintf(number, _T("/ %d"), weight);
  527.     
  528.         TextOut(hDC, x+5, y + 50, number, _tcslen(number));
  529.     }
  530. }
  531.     
  532.  
  533. TCHAR szSmooth[]        = _T("Smooth");
  534. TCHAR szGuasianSmooth[] = _T("Guasian Smooth");
  535. TCHAR szSharpening[]    = _T("Sharpening");
  536. TCHAR szLaplasian[]     = _T("Laplasian");
  537. TCHAR szEmboss135[]     = _T("Emboss 135░");
  538. TCHAR szEmboss90[]      = _T("Emboss 90░ 50%");
  539.  
  540. K33Filter< 1,  1,  1,  1,  1,  1,  1,  1,  1, 9,   0, false, szSmooth        > filter33_smooth;
  541. K33Filter< 0,  1,  0,  1,  4,  1,  0,  1,  0, 8,   0, false, szGuasianSmooth > filter33_guasiansmooth;
  542. K33Filter< 0, -1,  0, -1,  9, -1,  0, -1,  0, 5,   0, true,  szSharpening    > filter33_sharpening;
  543. K33Filter<-1, -1, -1, -1,  8, -1, -1, -1, -1, 1, 128, true,  szLaplasian     > filter33_laplasian;
  544. K33Filter< 1,  0,  0,  0,  0,  0,  0,  0, -1, 1, 128, true,  szEmboss135     > filter33_emboss135;
  545. K33Filter< 0,  1,  0,  0,  0,  0,  0, -1,  0, 2, 128, true,  szEmboss90      > filter33_emboss90;
  546.  
  547. KDilation filter_dilation;
  548. KErosion  filter_erosion;
  549. KOutline  filter_outline;
  550.  
  551. KFilter * StockFilters[] = {
  552.     NULL,
  553.     & filter33_smooth,
  554.     & filter33_guasiansmooth,
  555.     & filter33_sharpening,
  556.     & filter33_laplasian,
  557.     & filter33_emboss135,
  558.     & filter33_emboss90,
  559.     & filter_dilation,
  560.     & filter_erosion,
  561.     & filter_outline
  562. };
  563.  
  564.