⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 dvdbitmapcontrol.cpp

📁 rle静态图片压缩DELPHI代码,可以对DEPHI程序员了解有很大帮助
💻 CPP
字号:
// DVDBitmapControl.cpp : implementation file
//

#include "stdafx.h"
#include "DVDBitmapControl.h"

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// CDVDBitmapControl

CDVDBitmapControl::CDVDBitmapControl()
{
   // create the mempry device context
   m_dc.CreateCompatibleDC(NULL);
   m_hbm = NULL;
}

CDVDBitmapControl::~CDVDBitmapControl()
{
   SelectObject(m_dc.m_hDC, m_hbm_default);

   if ( m_hbm != NULL)
      DeleteObject(m_hbm); // destroy the bitmap object
}


BEGIN_MESSAGE_MAP(CDVDBitmapControl, CStatic)
	//{{AFX_MSG_MAP(CDVDBitmapControl)
	ON_WM_PAINT()
	ON_WM_SIZE()
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CDVDBitmapControl message handlers

void CDVDBitmapControl::OnPaint() 
{
	CPaintDC dc(this); // device context for painting
	
	// TODO: Add your message handler code here
   if ( !m_hbm)
   {
      dc.Rectangle(&dc.m_ps.rcPaint);
      dc.FillSolidRect( dc.m_ps.rcPaint.left + 1,
                     dc.m_ps.rcPaint.top + 1,
                     dc.m_ps.rcPaint.right - dc.m_ps.rcPaint.left - 2,
                     dc.m_ps.rcPaint.bottom - dc.m_ps.rcPaint.top -2,
                     RGB(255,255,255) );
   }
   else
   {
      RECT rect;
      GetClientRect(&rect);
   
      BOOL result = dc.StretchBlt(0, 0, rect.right, rect.bottom , &m_dc,
                                  0, 0, m_dib.dsBmih.biWidth , m_dib.dsBmih.biHeight, SRCCOPY);
    }

	// Do not call CStatic::OnPaint() for painting messages
}

BOOL CDVDBitmapControl::LoadBitmapFile(CString filepath)
{

   if (m_hbm != NULL) // delete previous bitmap loaded
   {
      SelectObject(m_dc.m_hDC, m_hbm_default);
      DeleteObject(m_hbm);
   }

   m_hbm = (HBITMAP)LoadImage(NULL, filepath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); 

   if (m_hbm == NULL) // open bitmap file error !
      return FALSE; 
   

   // select the opened bitmap into the memory dc
   m_hbm_default = (HBITMAP)SelectObject( m_dc.m_hDC , m_hbm);

   // get source bitmap info
   GetObject(m_hbm, sizeof(DIBSECTION), &m_dib);

   // re-draw self
   Invalidate();
   UpdateWindow();
 
   return TRUE;
}

SIZE CDVDBitmapControl::GetBitmapSize()
{
   SIZE size;
   if (m_hbm == NULL)
   {
      size.cx = 0;
      size.cy = 0;
   }
   else
   {
      size.cx = m_dib.dsBmih.biWidth;
      size.cy = m_dib.dsBmih.biHeight;
   }
   return size;
}

BOOL CDVDBitmapControl::SaveBitmapFile(CString filename)
{
   // this can only compress 256 color bitmap
   if ( m_dib.dsBmih.biBitCount != 8)
      return FALSE;

   int size;
   CByteArray RLE8_bitmaps_bits;
   RLE8_bitmaps_bits.SetSize(4194304, 4194304); // initial 40k
     
   // compress the bitmap bits use Run-Legth-Ecoding (8 bit)
   this->CompressInRLE8( (BYTE*)m_dib.dsBm.bmBits, RLE8_bitmaps_bits, size);

   _8Bit_BITMAPINFO _8bit_bmi;
   _8bit_bmi.bmi.bmiHeader = m_dib.dsBmih; // copy the entire sturcture
   _8bit_bmi.bmi.bmiHeader.biCompression = BI_RLE8;
   _8bit_bmi.bmi.bmiHeader.biSizeImage = size ; // size in bytes after RLE8 compression

   // retrieve color tables entries
   GetDIBColorTable(m_dc, 0, _8bit_bmi.bmi.bmiHeader.biClrUsed, _8bit_bmi.bmi.bmiColors );
   
   HANDLE hf;                 // file handle 
   BITMAPFILEHEADER hdr;       // bitmap file-header 
   PBITMAPINFOHEADER pbih;     // bitmap info-header 
   DWORD dwTmp;

   pbih = (PBITMAPINFOHEADER) &_8bit_bmi;

   // Create the .BMP file. 
    hf = CreateFile(filename, 
                   GENERIC_READ | GENERIC_WRITE, 
                   (DWORD) 0, 
                    NULL, 
                   CREATE_ALWAYS, 
                   FILE_ATTRIBUTE_NORMAL, 
                   (HANDLE) NULL); 

    if (hf == INVALID_HANDLE_VALUE) 
        return FALSE;

    hdr.bfType = 0x4d42;  // 0x42 = "B" 0x4d = "M" 
    // Compute the size of the entire file. 
    hdr.bfSize = (DWORD) (sizeof(BITMAPFILEHEADER) + 
                 pbih->biSize + pbih->biClrUsed 
                 * sizeof(RGBQUAD) + pbih->biSizeImage); 
    hdr.bfReserved1 = 0; 
    hdr.bfReserved2 = 0;

    // Compute the offset to the array of color indices. 
    hdr.bfOffBits = (DWORD) sizeof(BITMAPFILEHEADER) + 
                    pbih->biSize + pbih->biClrUsed 
                    * sizeof (RGBQUAD); 

    // Copy the BITMAPFILEHEADER into the .BMP file. 
    if (!WriteFile(hf, (LPVOID) &hdr, sizeof(BITMAPFILEHEADER), 
        (LPDWORD) &dwTmp,  NULL)) 
    {
       CloseHandle(hf);
       return 0;
    }

    // Copy the BITMAPINFOHEADER and RGBQUAD array into the file. 
    if (!WriteFile(hf, (LPVOID) pbih, sizeof(BITMAPINFOHEADER) 
                  + pbih->biClrUsed * sizeof (RGBQUAD), 
                  (LPDWORD) &dwTmp,  NULL)   ) 
    {
       CloseHandle(hf);
       return 0;
    } 

    // Copy the array of color indices into the .BMP file. 
    if (!WriteFile(hf, (LPSTR) RLE8_bitmaps_bits.GetData(), (int) pbih->biSizeImage, (LPDWORD) &dwTmp,NULL)) 
    {
       CloseHandle(hf);
       return 0;
    }

    // Close the .BMP file. 
     CloseHandle(hf); 

     // debug,  load the file into memory again, and compare with the original bitmap
#ifdef _DEBUG
     BOOL success = CompareWithFile(filename);
#endif
     ASSERT( success != 0);

   return 1;
}

BOOL CDVDBitmapControl::EndOfLine(int pos)
{ 
   if ( 0 != m_dib.dsBmih.biWidth % 4 )
   {
      int scanline_width = m_dib.dsBmih.biWidth;
      scanline_width = scanline_width + ( 4 - (scanline_width%4));
      pos %= scanline_width;
   }
   
   return 0 == ((pos+1)% m_dib.dsBmih.biWidth);
}

void CDVDBitmapControl::CompressInRLE8(BYTE* pSrcBits, CByteArray& pRLEBits, int& RLE_size)
{
   int line;
   int src_index = 0, dst_index = 0, counter, i;
   // in RLE8 every pixel is one byte

   for ( line = 0;  line < m_dib.dsBmih.biHeight; line++)
   {

state_start:  // just at the start of a block

      if ( EndOfLine(src_index)) // this is the last pixel of the line
      {
         pRLEBits[dst_index++] = 1; // block of length 1
         pRLEBits[dst_index++] = pSrcBits[src_index];

         src_index++;
         goto end_of_line;
      }

      // now the block length is at least 2, look ahead to decide next state
      // next two same pixels are the same, enter compress mode
      if (pSrcBits[src_index] == pSrcBits[src_index+1])
         goto state_compress;

      if ( EndOfLine(src_index+1)) // the last 2 pixel of the line
      {  // these 2 pixel are not the same
         pRLEBits[dst_index++] = 1; // block of length 1
         pRLEBits[dst_index++] = pSrcBits[src_index++];
         pRLEBits[dst_index++] = 1; // block of length 1
         pRLEBits[dst_index++] = pSrcBits[src_index++];
         goto end_of_line;
      }

      // now the block length is at least 3
      // in next 3 pixels, the last 2 consecutive pixel are the same
      if (pSrcBits[src_index+1] == pSrcBits[src_index+2])
      {
         pRLEBits[dst_index++] = 1; // block of length 1
         pRLEBits[dst_index++] = pSrcBits[src_index++];
         goto state_compress;
      }
      else // in these 3 pixel, no 2 consecutive pixel are the same
         goto state_no_compress; // un-compressed block need at least 3 pixel
      
state_compress:  // compress mode

      // src_index is the first pixel of a compressd block
      // counter is the number of additional pixels following currrent pixel
      // (src_index+counter) point to the last pixel of current block
      for ( counter = 1; counter <= 254; counter++)
      {
         // must check this condition first, or a BUG occur!
         if ( pSrcBits[src_index+counter] != pSrcBits[src_index] )
            break;
         if ( EndOfLine(src_index+counter) ) // reach end of line
         {
            pRLEBits[dst_index++] = counter+1; // block length is (counter+1)
            pRLEBits[dst_index++] = pSrcBits[src_index];
            src_index += counter +1;
            goto end_of_line;
         }
         
      }
      // now pSrcBits[src_index+counter] falls out of block
      pRLEBits[dst_index++] = counter; // block length is (counter)
      pRLEBits[dst_index++] = pSrcBits[src_index];
      src_index += counter;
      goto state_start;
      
state_no_compress:
      // src_index is the first pixel of a un-compressd block
      // un-compressed block need at least 3 pixel
      // counter is the number of additional pixels following currrent pixel
      for (counter = 2; counter <= 254; counter++)
      {
         if ( EndOfLine(src_index+counter) ) // reach end of line
         {
            pRLEBits[dst_index++] = 0; // escape character for un-compress block
            pRLEBits[dst_index++] = counter + 1; // block length is (counter+1)
            for (i = counter + 1; i > 0; i--)
               pRLEBits[dst_index++] = pSrcBits[src_index++];
            if ( 0 != ((counter+1) % 2) ) // block length is odd
               pRLEBits[dst_index++];     // padd with a zero byte
            goto end_of_line;
         }

         if ( EndOfLine(src_index+counter+1)  ||
            pSrcBits[src_index+counter] != pSrcBits[src_index+counter+1] )
            continue;   // still no 2 consecutive pixel are the same, 
                        // therefore continue to extend the un-compress block
          // we found two pixels are the same
         if ( EndOfLine(src_index+counter+2) ||
              pSrcBits[src_index+counter+1] != pSrcBits[src_index+counter+2] )
            continue; // the third pixel is not the same, no need to exit un-compressed mode
         else
         {  // // now pSrcBits[src_index+counter] and following 2 pixel are the same
            // now we need to exit the un-compressed mode
            if ( counter > 2)  
               counter--; // we can shrink the block one pixel (go backward)
            pRLEBits[dst_index++] = 0; // escape character for un-compress block
            pRLEBits[dst_index++] = counter+1; // block length is (counter+1)
            for (i = counter+1; i > 0; i--)
               pRLEBits[dst_index++] = pSrcBits[src_index++];
            if ( 0 != ((counter+1) % 2) ) // block length is odd
               pRLEBits[dst_index++];     // padd with a zero byte
            goto state_compress;
         }
      } // end of for (counter = 2; counter <= 254; counter++)

      // now we have a full block of 255 pixels
      pRLEBits[dst_index++] = 0; // escape character for un-compress block
      pRLEBits[dst_index++] = counter; // block length is (counter)
      for (i = counter; i > 0; i--)
         pRLEBits[dst_index++] = pSrcBits[src_index++];
      if ( 0 != ((counter) % 2) )   // block length is odd
            pRLEBits[dst_index++];  // padd with a zero byte
      goto state_start;
 
end_of_line:

      if ( 0 != (src_index % 4 )) // each scan line is dword align
      {
         int pad =  4 - (src_index%4);
         src_index += pad;
      }

      // src_index already point to the start of next line
      pRLEBits[dst_index++] = 0; // mark end-of-line
      pRLEBits[dst_index++] = 0;
   }

   pRLEBits[dst_index++] = 0; // mark end-of-bitmap
   pRLEBits[dst_index++] = 1;

   RLE_size = dst_index; // image size
}

// compare this bitmap with a bitmap file,
// assume color table are the same , used in debug only
BOOL CDVDBitmapControl::CompareWithFile(CString filepath)
{
   HBITMAP hbm = (HBITMAP)LoadImage(NULL, filepath, IMAGE_BITMAP, 0, 0, LR_LOADFROMFILE | LR_CREATEDIBSECTION); 

   if (hbm == NULL) // open bitmap file error !
      return FALSE; 

   // get source bitmap size
   DIBSECTION  dib;
   GetObject(hbm, sizeof(DIBSECTION), &dib);
   if (dib.dsBmih.biWidth     != m_dib.dsBmih.biWidth     ||
       dib.dsBmih.biHeight    != m_dib.dsBmih.biHeight    ||
       dib.dsBmih.biBitCount  != m_dib.dsBmih.biBitCount  ||
       dib.dsBmih.biCompression!=m_dib.dsBmih.biCompression )
   {
      DeleteObject(hbm); // destroy the bitmap object
      return FALSE;
   }

   BYTE *ptr1 = (BYTE*)dib.dsBm.bmBits;
   BYTE *ptr2 = (BYTE*)m_dib.dsBm.bmBits;
   long size = dib.dsBmih.biWidth * dib.dsBmih.biHeight * (dib.dsBmih.biBitCount /8);
   for ( ; size > 0; size--)
   {
      if (*ptr1++  != *ptr2++)
         break;
   }

   DeleteObject(hbm); // destroy the bitmap object !!!

   if ( size > 0 )
      return FALSE; 
   else
      return TRUE; // success
}

void CDVDBitmapControl::OnSize(UINT nType, int cx, int cy) 
{
	CStatic::OnSize(nType, cx, cy);
	
	// TODO: Add your message handler code here
   Invalidate();
   UpdateWindow();
}





⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -