头文件
#pragma once
#include <vector>
using namespace std;
typedef unsigned char* HMYBITMAP;
const CString FILE_TYPE_ERROR = "It is not bitmap file!";
const CString FILE_READ_ERROR = "Read file Error!";
const CString FILE_OPEN_ERROR = "Open file error!";
const int MAX_SIZE = 50;
const WORD PALVERSION = 0x300;
typedef struct tagBitmapPoint
{
int PointX;
int PointY;
HMYBITMAP pBitmapData;
}BitmapPoint,*LPBitmapPoint;
typedef vector<BitmapPoint> vBitmapPoint;
class CMyBitMap
{
public:
CMyBitMap(void);
virtual ~CMyBitMap(void);
// 读入位图文件
void ReadBitMap(const CString& strFileName,CString& strError);
private:
// 指向位图的句柄
HMYBITMAP hBitmap;
// 指向位图文件的头的指针
BITMAPINFOHEADER* pBitmapInfoHeader;
// 文件头结构
BITMAPFILEHEADER m_BitmapFileHeader;
// 当前读入位图的调色板
CPalette* pCPalette;
// 指向位图的数据区
HMYBITMAP hBitmapData;
public:
// 为当前位图创建调色板
void CreatePalette(void);
void PaintBitmap(CDC* pDC, int DestinationX, int DestinationY, DWORD Width, DWORD Height, int ResourceX, int ResourceY, UINT StartLine, UINT ScanLines, UINT ColorUse = DIB_RGB_COLORS);
ULONGLONG GetBitmapWidth(void);
ULONGLONG GetBitmapHeight(void);
HMYBITMAP GetBitmap(void);
// 将256色的图像变为2值图像
BOOL BitMapToBinaryMap(void);
// 获得表格图像偏转后最上端的点的像素坐标
CPoint GetTopAnglePoint(void);
private:
// 保存探测到的黑色点
vBitmapPoint m_vBitmapPoint;
public:
void SearchLeft(CPoint point, int& deep);
void SearchRight(CPoint point, int& deep);
};
实现文件
#include "StdAfx.h"
#include "./bitmap.h"
#include <math.h>
#include "MyLog.h"
const int MAX_DEEP = 200;
CMyBitMap::CMyBitMap(void)
: pBitmapInfoHeader(NULL)
, pCPalette(NULL)
,hBitmap(NULL)
,hBitmapData(NULL)
, m_vBitmapPoint(0)
{
}
CMyBitMap::~CMyBitMap(void)
{
}
// 读入位图文件
void CMyBitMap::ReadBitMap(const CString& strFileName,CString& strError)
{
CFile file;
if(file.Open(strFileName,CFile::modeReadWrite))
{
//读文件头,判断是不是位图文件
if(sizeof(BITMAPFILEHEADER) == file.Read(&m_BitmapFileHeader,sizeof(BITMAPFILEHEADER)))
{
if(m_BitmapFileHeader.bfType = 19778)
{
//为文件分配内存控件
ULONGLONG BitmapFileSize = file.GetLength() - sizeof(BITMAPFILEHEADER);
if(hBitmap != NULL)
{
delete []hBitmap;
hBitmap = NULL;
}
if(pCPalette != NULL)
{
delete pCPalette;
pCPalette = NULL;
}
hBitmap = (HMYBITMAP) new char[(size_t)BitmapFileSize];
if(file.Read(hBitmap,BitmapFileSize) == BitmapFileSize)
{
pBitmapInfoHeader = (BITMAPINFOHEADER*)hBitmap;
//创建调色板
hBitmapData = hBitmap + (m_BitmapFileHeader.bfOffBits - sizeof(BITMAPFILEHEADER));
CreatePalette();
}
else
{
strError = FILE_READ_ERROR;
}
}
else
{
strError = FILE_TYPE_ERROR;
}
}
else
{
strError = FILE_READ_ERROR;
}
}
else
{
strError = FILE_OPEN_ERROR;
}
file.Close();
}
// 为当前位图创建调色板
void CMyBitMap::CreatePalette(void)
{
pCPalette = new CPalette;
DOUBLE ColorNum = pow(2,pBitmapInfoHeader->biBitCount);
DOUBLE PaletteSize = sizeof(LOGPALETTE) + ColorNum * sizeof(PALETTEENTRY);
//定义逻辑调色板,并为其分配空间
PLOGPALETTE lpLogPalette = (PLOGPALETTE)new char[(size_t)PaletteSize];
//填充逻辑调色板
lpLogPalette->palVersion = PALVERSION;
lpLogPalette->palNumEntries = (WORD)ColorNum;
LPBITMAPINFO pPaletteEntry = (LPBITMAPINFO)hBitmap;
#ifdef NDEBUG
CMyLog Log;
CString PalColor;
char buf[10];
#endif
for(int i = 0;i<ColorNum;i++)
{
lpLogPalette->palPalEntry[i].peRed = pPaletteEntry->bmiColors[i].rgbRed;
lpLogPalette->palPalEntry[i].peGreen = pPaletteEntry->bmiColors[i].rgbGreen;
lpLogPalette->palPalEntry[i].peBlue = pPaletteEntry->bmiColors[i].rgbBlue;
lpLogPalette->palPalEntry[i].peFlags = 0;
#ifdef NDEBUG
PalColor = "The RedColor:BlueColor:GreenColor is:";
itoa((int)lpLogPalette->palPalEntry[i].peRed,buf,10);
PalColor += buf;
PalColor += ":";
itoa((int)lpLogPalette->palPalEntry[i].peBlue,buf,10);
PalColor += buf;
PalColor += ":";
itoa((int)lpLogPalette->palPalEntry[i].peGreen,buf,10);
PalColor += buf;
Log.WriteLog(PalColor);
#endif
}
//通过逻辑调色板创建实际的调色板
pCPalette->CreatePalette(lpLogPalette);
delete[] (char*)lpLogPalette;
}
void CMyBitMap::PaintBitmap(CDC* pDC, int DestinationX, int DestinationY, DWORD Width, DWORD Height, int ResourceX, int ResourceY, UINT StartLine, UINT ScanLines, UINT ColorUse)
{
::SetStretchBltMode(pDC->m_hDC, COLORONCOLOR);
//HPALETTE pPal = (HPALETTE)pCPalette->m_hObject;
//HPALETTE pOldPalette = ::SelectPalette(pDC->m_hDC,pPal,true);
CPalette* pOldPalette = pDC->SelectPalette(pCPalette,TRUE);
::SetDIBitsToDevice(pDC->m_hDC,DestinationX,DestinationY,Width,Height,ResourceX,ResourceY,StartLine,ScanLines,hBitmapData,(BITMAPINFO*)hBitmap,ColorUse);
pDC->SelectPalette(pOldPalette,TRUE);
}
ULONGLONG CMyBitMap::GetBitmapWidth(void)
{
ULONGLONG width = pBitmapInfoHeader->biWidth;
return ((width + 2)/4) * 4;
}
ULONGLONG CMyBitMap::GetBitmapHeight(void)
{
return pBitmapInfoHeader->biHeight;
}
HMYBITMAP CMyBitMap::GetBitmap(void)
{
return hBitmap;
}
// 将256色的图像变为2值图像
BOOL CMyBitMap::BitMapToBinaryMap(void)
{
int BitMapDataSize = m_BitmapFileHeader.bfSize - m_BitmapFileHeader.bfOffBits;
unsigned char* buf = hBitmapData;
for(int i = 0;i< BitMapDataSize;i++)
{
if(*buf != 0)
{
//if(i / pBitmapInfoHeader->biWidth < pBitmapInfoHeader->biHeight / 2)
{
*buf = 255;
}
}
buf++;
}
GetTopAnglePoint();
return TRUE;
}
// 获得表格图像偏转后最上端的点的像素坐标
CPoint CMyBitMap::GetTopAnglePoint(void)
{
//用直线扫描图形,当得到第一个黑色点之后,判断此点是在图的左半边还是图的右半边。然后增加步长,暂定为10行,如果第一个点是表格的角,那么增加步长10后应该可以扫描到至少两个分离开的点,这两个点欲第一个点组成的直线的夹角应该在90度范围左右。如果满足这一条件,那么可以确定的一个点就是表格的角点。
//当扫描到第一个点后,以此点为起点,向四周扫描,查看此点是孤立的点还是直线上的点。
if(hBitmap == NULL)
{
return CPoint(0,0);
}
unsigned char* pData = hBitmapData;
int Width = pBitmapInfoHeader->biWidth;
int Height = pBitmapInfoHeader->biHeight;
int deep = 0;
CPoint point;
for(int i = Height-1; i >= 0;i--)
{
pData = hBitmapData + i * Width;
for(int j = 0;j<Width;j++)
{
if(*pData == 0)
{
deep = 0;
point.x = j;
point.y = i;
if(j > Width / 2)
{
SearchLeft(point,deep);
}
else
{
SearchRight(point,deep);
}
if(deep >= MAX_DEEP)
{
return CPoint(i,j);
}
}
pData++;
}
}
return CPoint();
}
void CMyBitMap::SearchLeft(CPoint point, int& deep)
{
if(deep >= MAX_DEEP)
{
return;
}
if(point.x > pBitmapInfoHeader->biWidth || point.x < 0 || point.y < 0 || point.y > pBitmapInfoHeader->biHeight)
{
return;
}
if(*(hBitmapData + pBitmapInfoHeader->biWidth * point.y + point.x) == 0)
{
//*(hBitmapData + pBitmapInfoHeader->biWidth * point.y + point.x) = 255;
deep++;
SearchLeft(CPoint(point.x -1,point.y),deep);
SearchLeft(CPoint(point.x -1,point.y -1),deep);
SearchLeft(CPoint(point.x,point.y -1),deep);
}
else
{
return;
}
}
void CMyBitMap::SearchRight(CPoint point, int& deep)
{
if(deep >= MAX_DEEP)
{
return;
}
if(point.x > pBitmapInfoHeader->biWidth || point.x < 0 || point.y < 0 || point.y > pBitmapInfoHeader->biHeight)
{
return;
}
if(*(hBitmapData + pBitmapInfoHeader->biWidth * point.y + point.x) == 0)
{
//*(hBitmapData + pBitmapInfoHeader->biWidth * point.y + point.x) = 255;
deep++;
SearchRight(CPoint(point.x + 1,point.y),deep);
SearchRight(CPoint(point.x + 1,point.y -1),deep);
SearchRight(CPoint(point.x,point.y - 1),deep);
}
else
{
return;
}
}