2025-11-27 16:46:48 +09:00

441 lines
10 KiB
C++

// DIBManagerDoc.cpp : implementation of the CDIBManagerDoc class
//
#include "stdafx.h"
#include "DIBManager.h"
#include "DIBManagerDoc.h"
#include "MainFrm.h"
#include "DIBManagerView.h"
#include "ChildFrm.h"
#include "ProtectedFile.h"
#include "path.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CDIBManagerDoc
IMPLEMENT_DYNCREATE(CDIBManagerDoc, CDocument)
BEGIN_MESSAGE_MAP(CDIBManagerDoc, CDocument)
//{{AFX_MSG_MAP(CDIBManagerDoc)
// NOTE - the ClassWizard will add and remove mapping macros here.
// DO NOT EDIT what you see in these blocks of generated code!
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CDIBManagerDoc construction/destruction
CDIBManagerDoc::CDIBManagerDoc()
{
// TODO: add one-time construction code here
m_nDIBNumPage=0;
m_nXPage=0;
m_nYPage=0;
}
CDIBManagerDoc::~CDIBManagerDoc()
{
}
BOOL CDIBManagerDoc::OnNewDocument()
{
if (!CDocument::OnNewDocument())
return FALSE;
// TODO: add reinitialization code here
// (SDI documents will reuse this document)
return TRUE;
}
/////////////////////////////////////////////////////////////////////////////
// CDIBManagerDoc serialization
void CDIBManagerDoc::Serialize(CArchive& ar)
{
// use built-in functions to save/load DIB file to/from
// CFile which is associated with CArchive ar
ar.Flush();
if(ar.IsStoring())
{
m_dib.Write(ar.GetFile());
}
else
{
m_dib.Read(ar.GetFile());
}
}
/////////////////////////////////////////////////////////////////////////////
// CDIBManagerDoc diagnostics
#ifdef _DEBUG
void CDIBManagerDoc::AssertValid() const
{
CDocument::AssertValid();
}
void CDIBManagerDoc::Dump(CDumpContext& dc) const
{
CDocument::Dump(dc);
}
#endif //_DEBUG
/////////////////////////////////////////////////////////////////////////////
// CDIBManagerDoc commands
BOOL CDIBManagerDoc::OnSaveDocument(LPCTSTR lpszPathName)
{
// TODO: Add your specialized code here and/or call the base class
BOOL bSuccess=FALSE;
// try to open or create file
CFile m_file;
TRY
{
bSuccess=m_file.Open(lpszPathName,CFile::modeCreate|CFile::modeReadWrite);
}
CATCH(CFileException,e)
{
TCHAR szCause[255];
CString strFormatted;
e->GetErrorMessage(szCause, 255);
strFormatted = _T("CDIBManagerDoc::OnSaveDocument:exception: ");
strFormatted += szCause;
TRACE(strFormatted);
}
END_CATCH
if(!bSuccess)
{
AfxMessageBox(_T("Cannot open or create specified file!"),
MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
if(m_bProtected)
{
// if image is protected
// then try to save image using object of CProtectedFile class
TRY
{
CArchive ar(&m_file, CArchive::store);
bSuccess=m_dib.Write(ar);
ar.Close();
if(!bSuccess)
{
AfxMessageBox(_T("Cannot save image!"),MB_OK|MB_ICONEXCLAMATION);
return FALSE;
}
CProtectedFile m_protectedFile;
bSuccess=m_protectedFile.Save(&m_file);
}
CATCH(CFileException,e)
{
if(e->m_cause==CFileException::accessDenied)
{
e->Delete();
}
}
END_CATCH
}
else
{
// just save DIB file
CArchive ar(&m_file, CArchive::store);
bSuccess=m_dib.Write(ar);
ar.Close();
}
// to get the length of file
// we have to flush it
m_file.Flush();
if(bSuccess)
{
// in a case of protection the length of DIB file could change
// then recalculate it
COXPathSpec path;
path.SetPath(lpszPathName);
path.DoGetInfo();
m_dwImageSize=path.GetLength();
m_bInitiallyProtected=m_bProtected;
m_tf=TF_DIB;
SetModifiedFlag(FALSE);
}
return bSuccess;
}
BOOL CDIBManagerDoc::OnOpenDocument(LPCTSTR lpszPathName)
{
// TODO: Add your specialized creation code here
return OpenDocument(lpszPathName);
}
BOOL CDIBManagerDoc::OpenDocument(LPCTSTR lpszPathName, TypeFile tf)
{
CDIBManagerApp* pApp=(CDIBManagerApp*)AfxGetApp();
// try to open file on read
CFile m_file;
BOOL bSuccess=FALSE;
TRY
{
bSuccess=m_file.Open(lpszPathName,CFile::modeRead);
}
CATCH(CFileException, e)
{
TCHAR szCause[255];
CString strFormatted;
e->GetErrorMessage(szCause, 255);
strFormatted = _T("CDIBManagerDoc::OpenDocument:exception: ");
strFormatted += szCause;
TRACE(strFormatted);
bSuccess=FALSE;
}
END_CATCH
if(!bSuccess)
{
// notify system about error
// if error happens during loading of system
// then ErrorNotify() will hide splash window if it is active
pApp->ErrorNotify(_T("Cannot open file!"));
return FALSE;
}
return OpenDocument(&m_file,CString(lpszPathName),tf);
}
BOOL CDIBManagerDoc::OpenDocument(CFile* m_pFile, CString sFileName, TypeFile tf)
{
CDIBManagerApp* pApp=(CDIBManagerApp*)AfxGetApp();
m_bProtected=FALSE;
m_bInitiallyProtected=FALSE;
m_pFile->SeekToBegin();
// just try to read DIB file
if(!m_dib.Read(m_pFile))
{
// if error happened then suggest that we have to open
// protected image
TRY
{
m_pFile->SeekToBegin();
CProtectedFile m_protectedFile;
CMemFile tmpFile;
if(!m_protectedFile.CopyFile(&tmpFile,m_pFile))
return FALSE;
if(!m_protectedFile.Open(&tmpFile))
return FALSE;
m_bProtected=TRUE;
m_bInitiallyProtected=TRUE;
tmpFile.SeekToBegin();
// try to read DIB file by means of object of CProtectedFile class
if(!m_dib.Read(&tmpFile))
{
// if error happened then assume that file is not of DIB format
AfxThrowFileException(CFileException::badPath);
}
}
CATCH(CFileException,e)
{
if(e->m_cause==CFileException::badPath)
{
pApp->ErrorNotify(_T("Unknown file format!"));
}
return FALSE;
}
END_CATCH
}
m_sNameFile=sFileName;
m_tf=tf;
COXPathSpec path;
path.SetPath(m_sNameFile);
path.DoGetInfo();
m_dwImageSize=path.GetLength();
m_dibDither=NULL;
// if current video color palette is no more than 256 colors and
// DIB file uses no les than 256 color then create dithered copy
// of the file to render it on the display (this way we will get
// better output quality)
if(CheckUseDithered())
{
m_dibDither=m_dib;
m_dibDither.HalfToneDitherDIB();
}
return TRUE;
}
BOOL CDIBManagerDoc::SaveModified()
{
// TODO: Add your specialized code here and/or call the base class
// we can save only files of DIB format
if(m_tf!=TF_DIB)
{
SetModifiedFlag(FALSE);
}
return CDocument::SaveModified();
}
CPalette* CDIBManagerDoc::GetDIBPalette()
{
// depending on the current color palette
// return original palette or palette of dithered file
if(!CheckUseDithered())
{
return m_dib.GetPalette();
}
else
{
return m_dibDither.GetPalette();
}
}
CSize CDIBManagerDoc::GetDIBSize()
{
// depending on the current color palette
// return original size or size of dithered file
if(!CheckUseDithered())
{
return m_dib.GetSize();
}
else
{
return m_dibDither.GetSize();
}
}
UINT CDIBManagerDoc::CalcDIBNumPage(CDIBManagerView* pView, CDC* pDC)
{
// convert logical boundaries of image to corresponding boundaries
// for printer taking into account current zoom level
CSize sizeDIB=GetDIBSize();
CRect rect(0,0,sizeDIB.cx,sizeDIB.cy);
pView->NormalToScaled(&rect);
pView->NormalToPrinted(pDC,&rect);
// calculate the number of page based on the size of print page
int xPrinterRes=pDC->GetDeviceCaps(HORZRES);
int yPrinterRes=pDC->GetDeviceCaps(VERTRES);
m_nXPage=rect.Width()/xPrinterRes;
if(rect.Width()%xPrinterRes!=0)
{
m_nXPage++;
}
m_nYPage=rect.Height()/yPrinterRes;
if(rect.Height()%yPrinterRes!=0)
{
m_nYPage++;
}
// all pages
m_nDIBNumPage=m_nXPage*m_nYPage;
return m_nDIBNumPage;
}
// we would better have such function in COXDIB class
DWORD CDIBManagerDoc::CalcDIBSizeInMemory()
{
LPBITMAPINFOHEADER lpBI; // Pointer to DIB info structure
DWORD dwDIBSizeInMemory;
HDIB hDIB=m_dib.MakeCopy();
if (hDIB==NULL)
{
TRACE0("CDIBManagerDoc::CalcDIBSizeInMemory: cannot make copy of DIB handle\n");
return (DWORD)0;
}
// Get a pointer to the DIB memory, the first of which contains
// a BITMAPINFO structure
lpBI = (LPBITMAPINFOHEADER)::GlobalLock((HGLOBAL) hDIB);
if (lpBI == NULL)
{
TRACE0("CDIBManagerDoc::CalcDIBSizeInMemory: Out of memory\n");
::GlobalFree((HGLOBAL)hDIB);
return (DWORD)0;
}
// Calculating the size of the DIB is a bit tricky (if we want to
// do it right). The easiest way to do this is to call GlobalSize()
// on our global handle, but since the size of our global memory may have
// been padded a few bytes, we may end up writing out a few too
// many bytes to the file (which may cause problems with some apps).
//
// So, instead let's calculate the size manually (if we can)
//
// First, find size of header plus size of color table. Since the
// first DWORD in both BITMAPINFOHEADER and BITMAPCOREHEADER conains
// the size of the structure, let's use this.
// Partial Calculation
dwDIBSizeInMemory=*(LPDWORD)lpBI+m_dib.GetPaletteSize((LPSTR)lpBI);
// Now calculate the size of the image
if ((lpBI->biCompression == BI_RLE8) || (lpBI->biCompression == BI_RLE4))
{
// It's an RLE bitmap, we can't calculate size, so trust the
// biSizeImage field
dwDIBSizeInMemory+=lpBI->biSizeImage;
}
else
{
DWORD dwBmBitsSize; // Size of Bitmap Bits only
// It's not RLE, so size is Width (DWORD aligned) * Height
dwBmBitsSize=WIDTHBYTES((lpBI->biWidth)*((DWORD)lpBI->biBitCount))*
lpBI->biHeight;
dwDIBSizeInMemory+=dwBmBitsSize;
}
// Calculate the file size by adding the DIB size to sizeof(BITMAPFILEHEADER)
dwDIBSizeInMemory+=sizeof(BITMAPFILEHEADER);
::GlobalUnlock((HGLOBAL)hDIB);
::GlobalFree((HGLOBAL)hDIB);
return dwDIBSizeInMemory;
}
BOOL CDIBManagerDoc::CheckUseDithered()
{
CDIBManagerApp* pApp=(CDIBManagerApp*)AfxGetApp();
// if current video color palette is no more than 256 colors and
// DIB file uses no les than 256 color then create dithered copy
// of the file to render it on the display (this way we will get
// better output quality)
return (pApp->m_nColors<=8 && (m_dib.GetNumColors()==0 || m_dib.GetNumColors()==256));
}