📄 dibdoc.cpp
字号:
// Start a blob with this line.
CBlob *pBlobNew = lineNew.m_pBlob = new CBlob;
pBlobNew->m_nOpenLines = 1;
pBlobNew->m_pFirstLine = &lineNew;
pBlobNew->m_ppLastLine = &(lineNew.m_pNextLineSameBlob);
pBlobNew->m_nLoops = 0;
}
}
linedone:
if (pLineOld) {
while (TRUE) {
// Finish all old lines.
CBlob *pBlobOld = pLineOld->m_pBlob;
if (--(pBlobOld->m_nOpenLines) == 0) {
AddBlob(pBlobOld);
}
if (clpviOld == clpviOldEnd) break;
pLineOld = *clpviOld++;
}
}
// Finally, record the end of the new list as the
// end of the old list to be.
clpviOldEnd = clpviNew;
}
// At the end, we've got one last raster of lines to finish.
CLinePointerVector &clpvLast = clpvRaster[nOldLineIndex];
for (CLinePointerVectorIterator clpvi = clpvLast.begin();
clpvi != clpviOldEnd;) {
// Finish all old lines.
CBlob *pBlobOld = (*clpvi++)->m_pBlob;
if (--(pBlobOld->m_nOpenLines) == 0) {
AddBlob(pBlobOld);
}
}
// and finally, segmentation is complete
}
/////////////////////////////////////////////////////////////////////////////
// CDIBDoc - This implements CImageDoc for a device independent bitmap.
IMPLEMENT_DYNCREATE(CDIBDoc, CImageDoc)
//-----------------------------------------------------------------
//
// CDIBDoc::CDIBDoc - constructor
//
//-----------------------------------------------------------------
CDIBDoc::CDIBDoc()
{
m_pMonochromeBitmap = NULL;
m_hFileMapping = NULL;
m_pFile = NULL;
m_pBMFH = NULL;
m_pBMI = NULL;
m_eThresholdMethod = eWhiteBackground;
m_nThreshold = 128*3;
}
//-----------------------------------------------------------------
//
// CDIBDoc::OnNewDocument - This resets the doc when it gets reused.
//
//-----------------------------------------------------------------
BOOL CDIBDoc::OnNewDocument()
{
if (! CImageDoc::OnNewDocument()) return FALSE;
if (m_file.m_hFile != CFile::hFileNull) {
CloseFile();
ASSERT(m_file.m_hFile == CFile::hFileNull);
}
return TRUE;
}
CDIBDoc::~CDIBDoc()
{
if (! IsEmpty())
CloseFile();
if (m_pMonochromeBitmap) delete m_pMonochromeBitmap;
}
BEGIN_MESSAGE_MAP(CDIBDoc, CImageDoc)
//{{AFX_MSG_MAP(CDIBDoc)
ON_COMMAND(ID_IMAGE_HISTOGRAM, OnImageHistogram)
ON_UPDATE_COMMAND_UI(ID_IMAGE_HISTOGRAM, OnUpdateImageHistogram)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDIBDoc diagnostics
#ifdef _DEBUG
void CDIBDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CDIBDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CDIBDoc commands
//-----------------------------------------------------------------
//
// CDIBDoc::OnOpenDocument - Open a DIB directly. Don't go through
// MFC serialize. We map the file into
// memory and let its consumers hack it.
//
// lpszPathName - open this file.
//
//-----------------------------------------------------------------
BOOL CDIBDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
if (!CDocument::OnOpenDocument(lpszPathName))
return FALSE;
if (m_file.m_hFile != CFile::hFileNull) CloseFile();
CFileException e;
if (! m_file.Open(lpszPathName,CFile::modeRead|CFile::shareDenyWrite,&e)) {
AfxThrowFileException(e.m_cause,e.m_lOsError,lpszPathName);
}
m_hFileMapping = CreateFileMapping((HANDLE)(m_file.m_hFile),NULL,PAGE_READONLY,0,0,NULL);
if (m_hFileMapping == NULL) {
m_file.Close();
CFileException::ThrowOsError(GetLastError(),lpszPathName);
}
m_pFile = MapViewOfFile(m_hFileMapping,FILE_MAP_READ,0,0,0);
if (m_pFile == NULL) {
m_file.Close();
CFileException::ThrowOsError(GetLastError(),lpszPathName);
}
// Here's a bunch of useful pointers.
m_pBMFH = (BITMAPFILEHEADER *)m_pFile;
if (m_pBMFH->bfType != 0x4d42) {
CString csz;
AfxFormatString1(csz,IDS_FILE_TYPE_ERROR,lpszPathName);
AfxMessageBox(csz);
return FALSE;
}
m_pBMI = (BITMAPINFO *)(m_pBMFH + 1);
if (m_pBMI->bmiHeader.biSize != sizeof(BITMAPINFOHEADER) ||
m_pBMI->bmiHeader.biCompression != BI_RGB ||
m_pBMI->bmiHeader.biPlanes != 1) {
CString csz;
AfxFormatString1(csz,IDS_FILE_FORMAT_NOT_SUPPORTED,lpszPathName);
AfxMessageBox(csz);
return FALSE;
}
m_pBits = ((char *)(m_pFile)) + m_pBMFH->bfOffBits;
if (m_pMonochromeBitmap) {
delete m_pMonochromeBitmap;
m_pMonochromeBitmap = NULL;
}
m_bThresholdTable.SetSize(0);
switch(m_pBMI->bmiHeader.biBitCount) {
default: {
CString csz;
AfxFormatString1(csz,IDS_FILE_FORMAT_NOT_SUPPORTED,lpszPathName);
return FALSE;
}
case 1:
m_nRasterWidthInBytes = (m_pBMI->bmiHeader.biWidth + 7) / 8;
m_pMonochromeBitmap = new CDIB1MonochromeBitmap;
break;
case 4:
m_nRasterWidthInBytes = (m_pBMI->bmiHeader.biWidth + 1) / 2;
m_pMonochromeBitmap = new CDIB4MonochromeBitmap;
if (m_pBMI->bmiHeader.biClrUsed == 0) {
m_bThresholdTable.SetSize(16);
} else {
m_bThresholdTable.SetSize(m_pBMI->bmiHeader.biClrUsed);
}
break;
case 8:
m_nRasterWidthInBytes = m_pBMI->bmiHeader.biWidth;
m_pMonochromeBitmap = new CDIB8MonochromeBitmap;
if (m_pBMI->bmiHeader.biClrUsed == 0) {
m_bThresholdTable.SetSize(256);
} else {
m_bThresholdTable.SetSize(m_pBMI->bmiHeader.biClrUsed);
}
break;
#ifdef NOTYET
case 16:
m_nRasterWidthInBytes = m_pBMI->bmiHeader.biWidth * 2;
break;
case 24:
m_nRasterWidthInBytes = m_pBMI->bmiHeader.biWidth * 3;
break;
case 32:
m_nRasterWidthInBytes = m_pBMI->bmiHeader.biWidth * 4;
break;
#endif
}
m_pMonochromeBitmap->SetDoc(*this);
m_nRasterWidthInBytes = ((m_nRasterWidthInBytes + 3) / 4) * 4;
BuildThresholdTable();
return TRUE;
}
//-----------------------------------------------------------------
//
// CDIBDoc::CloseFile - Close the file and back out its mapping.
//
//-----------------------------------------------------------------
void CDIBDoc::CloseFile()
{
if (m_pFile) {
ASSERT(m_hFileMapping);
ASSERT(m_file.m_hFile != CFile::hFileNull);
if (! UnmapViewOfFile(m_pFile)) {
CFileException::ThrowOsError(GetLastError(),GetPathName());
}
m_pFile = NULL;
m_hFileMapping = NULL;
}
m_file.Close();
}
//-----------------------------------------------------------------
//
// CDIBDoc::StretchBlt - Paint a device independent bitmap onto
// the given DC
//
// dc - paint onto this device context
// crDest - paint onto this rectangle
// crSrc - paint only the portion in this rect on the DIB
// dwROP - raster operation to use (see BitBlt, for instance)
//
//-----------------------------------------------------------------
void CDIBDoc::StretchBlt(CDC &dc,CRect &crDest, CRect &crSrc,DWORD dwROP)
{
if (m_file.m_hFile == CFile::hFileNull) return;
int nBitmapTop = Height() - crSrc.bottom;
if (::StretchDIBits(dc.m_hDC,
crDest.left,
crDest.top,
crDest.Width(),
crDest.Height(),
crSrc.left,
nBitmapTop,
crSrc.Width(),
crSrc.Height(),
m_pBits,
m_pBMI,
DIB_RGB_COLORS,
dwROP) == GDI_ERROR) {
CFileException::ThrowOsError(GetLastError(),NULL);
}
}
//-----------------------------------------------------------------
//
// CDIBDoc::GetBitmapInfo - return the bitmap info structure for
// the DIB.
//
//-----------------------------------------------------------------
BITMAPINFO * CDIBDoc::GetBitmapInfo()
{
ASSERT(m_pBMI);
return m_pBMI;
}
//-----------------------------------------------------------------
//
// CDIBDoc::GetBitmapBits - Return the pointer to the actual bitmap
// data.
//
//-----------------------------------------------------------------
LPVOID CDIBDoc::GetBitmapBits()
{
ASSERT(m_pBits);
return m_pBits;
}
//-----------------------------------------------------------------
//
// CDIBDoc::GetRasterWidthInBytes - Return the number of bytes
// needed to map one raster of data.
//
//-----------------------------------------------------------------
int CDIBDoc::GetRasterWidthInBytes()
{
return m_nRasterWidthInBytes;
}
//-----------------------------------------------------------------
//
// CDIBDoc::GetThresholdTable - The threshold table contains one
// boolean (TRUE for above threshold/FALSE for below)
// for each color in the bitmap.
//
//-----------------------------------------------------------------
const CByteArray & CDIBDoc::GetThresholdTable()
{
return m_bThresholdTable;
}
//-----------------------------------------------------------------
//
// CDIBDoc::GetMonochromeBitmap - return a reference to the monochrome
// bitmap (used to generically hack an image)
// that we built for this DIB.
//
//-----------------------------------------------------------------
CMonochromeBitmap &CDIBDoc::GetMonochromeBitmap()
{
ASSERT(m_pMonochromeBitmap);
return *m_pMonochromeBitmap;
}
//-----------------------------------------------------------------
//
// BYTE * CDIBDoc - Return a pointer to a raster of bitmap data. Note
// that these will be in different formats for
// different bitmap # of bits.
//
// nLine - Y coordinate of raster to fetch.
//-----------------------------------------------------------------
const BYTE * CDIBDoc::GetRaster(int nLine)
{
ASSERT(m_pBits);
ASSERT(m_pBMI);
return ((const BYTE *)m_pBits) + (m_pBMI->bmiHeader.biHeight - nLine - 1) * m_nRasterWidthInBytes;
}
//-----------------------------------------------------------------
//
// CDIBDoc::Width - # of pixels per raster.
//
//-----------------------------------------------------------------
int CDIBDoc::Width()
{
if (IsEmpty()) return 0;
return m_pBMI->bmiHeader.biWidth;
}
//-----------------------------------------------------------------
//
// CDIBDoc::Height - # of rasters in bitmap
//
//-----------------------------------------------------------------
int CDIBDoc::Height()
{
if (IsEmpty()) return 0;
return m_pBMI->bmiHeader.biHeight;
}
//-----------------------------------------------------------------
//
// CDIBDoc::IsEmpty - returns TRUE if this is the null document.
//
//-----------------------------------------------------------------
BOOL CDIBDoc::IsEmpty()
{
return (m_file.m_hFile == CFile::hFileNull);
}
//-----------------------------------------------------------------
//
// CDIBDoc::OnImageHistogram - Display a histogram indicating how
// many pixels are at each brightness.
// The dialog box allows the user to
// eyeball the histogram and set the
// threshold.
//
//-----------------------------------------------------------------
void CDIBDoc::OnImageHistogram()
{
CHistogramDlg dlg;
vector<int> vBrightness;
GetMonochromeBitmap().GetBrightnessHistogram(dlg.m_wndHistogram.m_vHistogram,vBrightness);
for (int i = 0; i < vBrightness.size() && vBrightness[i] < m_nThreshold; i++);
dlg.m_wndHistogram.m_nBound = i;
if (dlg.DoModal() == IDOK) {
m_nThreshold = vBrightness[dlg.m_wndHistogram.m_nBound];
BuildThresholdTable();
m_pMonochromeBitmap->ClearBlobList();
m_pMonochromeBitmap->BuildBlobList();
UpdateAllViews(NULL);
}
}
//-----------------------------------------------------------------
//
// CDIBDoc::OnUpdateImageHistogram - Only allow this for non-monochrome
// bitmaps.
//
//-----------------------------------------------------------------
void CDIBDoc::OnUpdateImageHistogram(CCmdUI* pCmdUI)
{
pCmdUI->Enable((! IsEmpty()) && m_pBMI->bmiHeader.biBitCount > 1);
}
//-----------------------------------------------------------------
//
// CDIBDoc::BuildThresholdTable - Build the boolean table that tells
// whether a color is above or below
// threshold.
//
//-----------------------------------------------------------------
void CDIBDoc::BuildThresholdTable()
{
const RGBQUAD *pRGBQ = m_pBMI->bmiColors;
for (int i = 0; i < m_bThresholdTable.GetSize(); i++) {
switch(m_eThresholdMethod) {
case eBlackBackground:
if (pRGBQ[i].rgbRed + pRGBQ[i].rgbGreen + pRGBQ[i].rgbBlue > m_nThreshold) {
m_bThresholdTable[i] = TRUE;
} else {
m_bThresholdTable[i] = FALSE;
}
break;
case eWhiteBackground:
if (pRGBQ[i].rgbRed + pRGBQ[i].rgbGreen + pRGBQ[i].rgbBlue > m_nThreshold) {
m_bThresholdTable[i] = FALSE;
} else {
m_bThresholdTable[i] = TRUE;
}
break;
}
}
}
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -