📄 dvdbitmapcontrol.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 + -