Click here to Skip to main content
15,891,725 members
Articles / Programming Languages / C++

A Copy Utility using TWAIN

Rate me:
Please Sign up or sign in to vote.
4.54/5 (10 votes)
14 Jul 20042 min read 100K   6.8K   47  
Example for a simple encapsulation of the TWAIN interface
///////////////////////////////////////////////////////////////////////////////
//
//		CTCopyDlg
//		----------
//		Dialog of copy TWAIN utility
//
////Holger Kloos, 2004/////////////////////////////////////////////////////////


#include "stdafx.h"
#include "TCopy.h"
#include "AboutDlg.h"
#include "TCopyDlg.h"
#include "DlgHelper.h"
#include "FindFax.h"

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

const UINT WU_FINISHINIT		= WM_APP + 1;
const char* STR_BITMAPFILETYPE	= "Bitmap (*.BMP)|*.BMP||";
const char* STR_BRIGHTNESS		= "Brightness";
const char* STR_CONTRAST		= "Contrast";
const char* STR_PICTURE			= "Bild";



/////////////////////////////////////////////////////////////////////////////
// CTCopyDlg dialog

CTCopyDlg::CTCopyDlg(int nDlgResource, CWnd* pParent /*=NULL*/)
	: CDialog(nDlgResource, pParent)
	, m_TwainPP(AfxGetAppName(), &m_TraceFile)
	, m_ComboPrinterSelect(m_PrinterAccess)
{
	//{{AFX_DATA_INIT(CTCopyDlg)
	m_sStateInfo = _T("");
	m_RCImageColorSelect = 1;
	m_RCModusSelect = 0;
	m_RCResolution = 1;
	//}}AFX_DATA_INIT
	m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
	m_bPrintImageAutomatic = FALSE;
	m_bFaxSelect = FALSE;

	m_nBrightnessOffset = 0;
	m_nContrastOffset = 0;
}

void CTCopyDlg::DoDataExchange(CDataExchange* pDX)
{
	CDialog::DoDataExchange(pDX);
	//{{AFX_DATA_MAP(CTCopyDlg)
	DDX_Control(pDX, IDC_SPIN_SCALING, m_SpinCtrlScaling);
	DDX_Control(pDX, IDC_EC_SCALING, m_ECScaling);
	DDX_Control(pDX, IDC_SLIDER_CONTRAST, m_ContrastSlider);
	DDX_Control(pDX, IDC_SLIDER_BRIGHTNESS, m_BrightnessSlider);
	DDX_Control(pDX, IDC_CB_PRINTERSELECT, m_ComboPrinterSelect);
	DDX_Control(pDX, IDC_BITMAP_PREVIEW, m_ctlrShowBitmap);
	DDX_Text(pDX, IDC_SC_STATEINFO, m_sStateInfo);
	DDX_Radio(pDX, IDC_RC_IMAGE_COLOR, m_RCImageColorSelect);
	DDX_Radio(pDX, IDC_RC_MODUS_FAST, m_RCModusSelect);
	DDX_Radio(pDX, IDC_RC_RESOLUTION_96, m_RCResolution);
	//}}AFX_DATA_MAP
}

BEGIN_MESSAGE_MAP(CTCopyDlg, CDialog)
	//{{AFX_MSG_MAP(CTCopyDlg)
	ON_WM_SYSCOMMAND()
	ON_WM_PAINT()
	ON_WM_QUERYDRAGICON()
	ON_BN_CLICKED(IDC_BTN_COPY, OnBtnCopy)
	ON_COMMAND(IDM_ABOUT, OnMenuAbout)
	ON_UPDATE_COMMAND_UI(IDM_COPY, OnMenuUpdateCopy)
	ON_COMMAND(IDM_COPY, OnMenuCopy)
	ON_WM_CLOSE()
	ON_BN_CLICKED(IDC_BTN_PRINTEROPTIONS, OnBtnPrinterOptions)
	ON_MESSAGE(WU_FINISHINIT, OnFinishInit)
	ON_BN_CLICKED(IDC_BTN_PREVIEW, OnBtnPreview)
	ON_BN_CLICKED(IDC_RC_MODUS_DLG, OnRcModusChange)
	ON_COMMAND(IDM_FINISH, OnFinish)
	ON_BN_CLICKED(IDC_BTN_PRINT, OnBtnPrint)
	ON_COMMAND(IDM_FILESAVEAS, OnMenuFileSave)
	ON_COMMAND(IDM_FILELOAD, OnMenuFileLoad)
	ON_CBN_SELCHANGE(IDC_CB_PRINTERSELECT, OnPrinterSelection)
	ON_BN_CLICKED(IDC_BTN_FAX, OnBtnFax)
	ON_BN_CLICKED(IDC_RC_MODUS_FAST, OnRcModusChange)
	ON_COMMAND(IDM_PRINT, OnBtnPrint)
	ON_COMMAND(IDM_SAVEDEFAULTS, OnMenuSaveDefaults)
	ON_COMMAND(IDM_RESETDEFAULTS, OnMenuResetDefaults)
	//}}AFX_MSG_MAP
END_MESSAGE_MAP()

/////////////////////////////////////////////////////////////////////////////
// CTCopyDlg message handlers


BOOL CTCopyDlg::OnInitDialog()
{
	CDialog::OnInitDialog();

	// Add "About..." menu item to system menu.

	// IDM_ABOUTBOX must be in the system command range.
	ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
	ASSERT(IDM_ABOUTBOX < 0xF000);

	CString sAppPath = AfxGetApp()->m_pszHelpFilePath;
	sAppPath = sAppPath.Left(sAppPath.ReverseFind('\\'));
	 
	m_TraceFile.OpenTraceFile(sAppPath + "\\Trace.log");

	CMenu* pSysMenu = GetSystemMenu(FALSE);
	if (pSysMenu != NULL)
	{
		CString strAboutMenu;
		strAboutMenu = LoadString(IDS_ABOUTBOX);
		if (!strAboutMenu.IsEmpty())
		{
			pSysMenu->AppendMenu(MF_SEPARATOR);
			pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
		}
	}

	SetIcon(m_hIcon, TRUE);			// Set big icon
	SetIcon(m_hIcon, FALSE);		// Set small icon

	m_BrightnessSlider.SetTicFreq(200);
	m_BrightnessSlider.SetRange(-400,400, TRUE);
		
	m_ContrastSlider.SetTicFreq(200);
	m_ContrastSlider.SetRange(-400,400, TRUE);

	m_SpinCtrlScaling.SetBuddy(&m_ECScaling);
	m_SpinCtrlScaling.SetPos(100);

	if (!IsPrinterValid())
	{
		SetStateInfo(IDS_NOPRINTER);
		EnableCtrlsOfGroupBox(this, IDC_SC_PRINTERSELECT, false);
	}

	PostMessage(WU_FINISHINIT, 0, 0);
	SetStateInfo(IDS_INITSCANNER);

	return TRUE;  // return TRUE  unless you set the focus to a control
}

LPARAM CTCopyDlg::OnFinishInit(WPARAM, LPARAM)
{
	BOOL bTwain = m_TwainPP.Create(m_hWnd, this) && m_TwainPP.OpenSource();
	if (bTwain)
	{
		ReadDefaults();

		OnRcModusChange();
		EnableCtrlsOfGroupBox(this, IDC_ST_SELECTCONFIGMODE, !IsDlgModusSelected());
		
		EnableCtrlWithId(this, IDC_BTN_COPY, IsPrinterValid());
		EnableCtrlWithId(this, IDC_BTN_PREVIEW, true);
		
		SetStateInfo(IDS_READYTOSCANWITHSCANNER, m_TwainPP.GetSourceName());

		OnPrinterSelection();

		CFindFax findFax(m_PrinterAccess);
		EnableCtrlWithId(this, IDC_BTN_FAX, findFax.GetFaxName(m_sFax));
	}
	else
		SetStateInfo(IDS_NOSCANNER);

	return 1;
}

void CTCopyDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
	if ((nID & 0xFFF0) == IDM_ABOUTBOX)
	{
		CAboutDlg dlgAbout;
		dlgAbout.DoModal();
	}
	else
	{
		CDialog::OnSysCommand(nID, lParam);
	}
}

// If you add a minimize button to your dialog, you will need the code below
//  to draw the icon.  For MFC applications using the document/view model,
//  this is automatically done for you by the framework.

void CTCopyDlg::OnPaint() 
{
	if (IsIconic())
	{
		CPaintDC dc(this); // device context for painting

		SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);

		// Center icon in client rectangle
		int cxIcon = GetSystemMetrics(SM_CXICON);
		int cyIcon = GetSystemMetrics(SM_CYICON);
		CRect rect;
		GetClientRect(&rect);
		int x = (rect.Width() - cxIcon + 1) / 2;
		int y = (rect.Height() - cyIcon + 1) / 2;

		// Draw the icon
		dc.DrawIcon(x, y, m_hIcon);
	}
	else
	{
		CDialog::OnPaint();
	}
}

HCURSOR CTCopyDlg::OnQueryDragIcon()
{
	return (HCURSOR) m_hIcon;
}

void CTCopyDlg::OnBtnCopy() 
{
	UpdateData(TRUE);
	GetBitmap(TRUE);
}

void CTCopyDlg::OnTwainImageInfo(int /*nSizeX*/, int /*nSizeY*/)
{
/*	CString sInfo;
	sInfo.Format("		(%d x %d)", nSizeX, nSizeY);
	SetStateInfo(IDS_SCANNING, sInfo);
*/	
	SetStateInfo(IDS_SCANNING);
}

BOOL CTCopyDlg::OnTwainBitmap(HDIB hDIB)
{
	BOOL bRes = m_DIBUse.SetDIB(hDIB) 
			 && m_ctlrShowBitmap.SetDIBitmap(m_DIBUse);

	EnableMenuItems(TRUE);
	EnableCtrlWithId(this, IDC_BTN_PRINT, IsPrinterValid());

	if (m_bPrintImageAutomatic)
	{
		if (DoPrint())
			return FALSE;
	}
	SetStateInfo(IDS_READYTOSCAN);

	return bRes;
}

void CTCopyDlg::OnTwainError(CTwainPP::ETWainError eTwainError)
{
	SelectFax(FALSE);

	switch (eTwainError)
	{
	case CTwainPP::eNoTwain:
		SetStateInfo(IDS_NOSCANNER);
		break;
	case CTwainPP::eCancel:
		SetStateInfo(IDS_SCANCANCELED);
		break;
	case CTwainPP::eGetCapability:
		SetStateInfo(IDS_ERRORGETOPTION);
		break;
	case CTwainPP::eSetCapability:
		SetStateInfo(IDS_ERRORSETOPTION);
		break;
	case CTwainPP::eDeviceNotReady:
		SetStateInfo(IDS_ERRORDEVICENOTREADY);
		break;
	case CTwainPP::eErrorReading:
		SetStateInfo(IDS_ERRORREADING);
		break;
	}
}


void CTCopyDlg::EnableMenuItems(BOOL bEnable)
{
	CMenu* pMenu = GetMenu();
	if (pMenu)
	{
		UINT nFlag = bEnable ? MF_ENABLED : MF_DISABLED;

		pMenu->EnableMenuItem(IDM_COPY, nFlag);
		pMenu->EnableMenuItem(IDM_PRINT, nFlag);
		pMenu->EnableMenuItem(IDM_FILESAVEAS, nFlag);
	}
}

void CTCopyDlg::OnMenuAbout() 
{
	CAboutDlg aboutDlg;
	aboutDlg.DoModal();
}

void CTCopyDlg::OnMenuUpdateCopy(CCmdUI* pCmdUI) 
{
	pCmdUI->Enable(m_DIBUse.IsValid());
}

void CTCopyDlg::OnMenuCopy() 
{
	if (!OpenClipboard())
		return;

	EmptyClipboard();

	SetClipboardData(CF_DIB, m_DIBUse.GetDIBHandle());

	CloseClipboard();
}

void CTCopyDlg::OnClose() 
{
	m_TwainPP.Close();

	if (OpenClipboard())
	{
		if (GetClipboardData(CF_DIB) == m_DIBUse.GetDIBHandle())
		{
			m_DIBUse.Detach();
//			EmptyClipboard();
		}
		CloseClipboard();
	}
	
	CDialog::OnClose();
}

void CTCopyDlg::OnBtnPrinterOptions() 
{
	UpdateData(TRUE);
	m_PrinterAccess.ShowConfigDialog(GetPrinterName(), this);
	
}

const CString CTCopyDlg::LoadString(UINT nId) const
{
	CTCopyApp* pCopyApp = dynamic_cast<CTCopyApp*>(AfxGetApp());

	return pCopyApp->LoadString(nId);
}

void CTCopyDlg::SetStateInfo(UINT nID, const char* pAddInfo)
{
	m_sStateInfo = LoadString(nID);
	if (pAddInfo)
		m_sStateInfo += pAddInfo;

	m_TraceFile.MakeTrace(m_sStateInfo);

	UpdateData(FALSE);
}

void CTCopyDlg::OnBtnPreview() 
{
	UpdateData(TRUE);
	GetBitmap(FALSE);
}

BOOL CTCopyDlg::IsPrinterValid() const
{
	return m_ComboPrinterSelect.IsWindowEnabled();
}

BOOL CTCopyDlg::GetResolution()
{
	UpdateData(TRUE);
	switch (m_RCResolution)
	{
	case 0:
		return 96;
	case 1:
		return 360;
	case 2:
		return 720;
	}
	return 360;
}

BOOL CTCopyDlg::GetBitmap(BOOL bPrint)
{
	SetStateInfo(IDS_STARTSCANNING);

	m_bPrintImageAutomatic = bPrint;

	CTwainPP::EImageType eImageType = (CTwainPP::EImageType)m_RCImageColorSelect;

	CTwainPP::SBitmapOptions Options;
	Options.eImageType = eImageType;
	Options.nResolution = GetResolution();
	Options.nBrightness = m_BrightnessSlider.GetPos() + m_nBrightnessOffset;
	Options.nContrast = m_ContrastSlider.GetPos() + m_nContrastOffset;

	const SIZE printSize = m_PrinterAccess.GetPrintSizeMM(GetPrinterName());

	double f = 10.0 / m_SpinCtrlScaling.GetPos();			// [mm] -> [cm]
	Options.fSizeX = float(printSize.cx * f);
	Options.fSizeY = float(printSize.cy * f);

	return m_TwainPP.GetBitmap(IsDlgModusSelected(), Options);
}

void CTCopyDlg::OnRcModusChange() 
{
	UpdateData(TRUE);
	BOOL bEnable = !IsDlgModusSelected();

	EnableCtrlsOfGroupBox(this, IDC_ST_SELECTCOLORMODE, bEnable);
	EnableCtrlsOfGroupBox(this, IDC_ST_SELECTRESOLUTION, bEnable);
	EnableCtrlsOfGroupBox(this, IDC_ST_BRIGHTNESS, bEnable);
	EnableCtrlsOfGroupBox(this, IDC_ST_CONTRAST, bEnable);
	EnableCtrlsOfGroupBox(this, IDC_ST_SCALING, bEnable);
}

void CTCopyDlg::OnFinish() 
{
	EndDialog(IDOK);
}

BOOL CTCopyDlg::DoPrint()
{
	SetStateInfo(IDS_PRINTING);

	CString sJobName;
	GetWindowText(sJobName);

	CString sPrinterName = GetPrinterName();
	SelectFax(FALSE);

	if (!m_PrinterAccess.PrintDIB(sJobName, sPrinterName, m_DIBUse))
	{
		SetStateInfo(IDS_ERRORPRINTING);
		return FALSE;
	}
	return TRUE;
}

void CTCopyDlg::OnBtnPrint() 
{
	DoPrint();
}

BOOL CTCopyDlg::DoWriteFile(const char* pFileName) const
{
	CFile file;
	if (!file.Open(pFileName, CFile::modeReadWrite | CFile::modeCreate))
		return FALSE;
		
	HDIB hDIB = m_DIBUse.GetDIBHandle();
	const BITMAPINFO* pDIB = (const BITMAPINFO*)GlobalLock(hDIB);
	if (!pDIB)
		return FALSE;

	BOOL bRes = TRUE;
	try
	{
		BITMAPFILEHEADER header;
		if (m_DIBUse.FillFileHeader(header))
		{
			file.Write(&header, sizeof(BITMAPFILEHEADER));
			file.Write(pDIB, pDIB->bmiHeader.biSizeImage);
		}
		else
			bRes = FALSE;
	}
	catch(CFileException*)
	{
		bRes = FALSE;
	}

	GlobalUnlock(hDIB);

	return bRes;
}

BOOL CTCopyDlg::DoLoadFile(const char* pFileName)
{
	CFile file;
	if (!file.Open(pFileName, CFile::modeRead))
		return FALSE;

	BITMAPFILEHEADER header;
	if (file.Read(&header, sizeof(BITMAPFILEHEADER)) != sizeof(BITMAPFILEHEADER) || header.bfType != MARK_BMP)
		return FALSE;

	DWORD nBitmapSize = header.bfSize - sizeof(BITMAPFILEHEADER);
	HDIB hDIB = GlobalAlloc(GMEM_MOVEABLE, nBitmapSize);
	if (!hDIB)
		return FALSE;

	BITMAPINFO* pDIB = (BITMAPINFO*)GlobalLock(hDIB);
	if (!pDIB)
		return FALSE;

	BOOL bRes = file.Read(pDIB, nBitmapSize) >= pDIB->bmiHeader.biSizeImage;

	GlobalUnlock(hDIB);

	if (!bRes || !m_DIBUse.SetDIB(hDIB)) 
		GlobalFree(hDIB);

	m_ctlrShowBitmap.SetDIBitmap(m_DIBUse);

	return bRes;
}

void CTCopyDlg::OnMenuFileSave() 
{
	CFileDialog SaveDlg(FALSE, ".bmp", STR_PICTURE, OFN_OVERWRITEPROMPT, STR_BITMAPFILETYPE);

	if (SaveDlg.DoModal() == IDOK)
	{
		SetStateInfo(IDS_WRITEFILE);
		if (DoWriteFile(SaveDlg.m_ofn.lpstrFile))
			SetStateInfo(IDS_READYTOSCAN);
		else
			SetStateInfo(IDS_ERRORWRITINGFILE);
	}
}

void CTCopyDlg::OnMenuFileLoad() 
{
	CFileDialog LoadDlg(TRUE, ".bmp", STR_PICTURE, OFN_FILEMUSTEXIST, STR_BITMAPFILETYPE);
	if (LoadDlg.DoModal() == IDOK)
	{
		SetStateInfo(IDS_LOADFILE);
		if (DoLoadFile(LoadDlg.m_ofn.lpstrFile))
			SetStateInfo(IDS_READYTOSCAN);
		else
			SetStateInfo(IDS_ERRORLOADINGFILE);
	}
}

void CTCopyDlg::OnPrinterSelection() 
{
	float fMaxScanWidth;
	float fMaxScanHeight;

	int nMinScaling  = 100;

	if (m_TwainPP.GetMaxImageSize(fMaxScanWidth, fMaxScanHeight))
	{
		SIZE paperSize = m_PrinterAccess.GetPrintSizeMM(GetPrinterName());
		nMinScaling = int(100.0 * max(paperSize.cx / (fMaxScanWidth * 10.0), paperSize.cy / (fMaxScanHeight * 10.0)));
	}

	int nLower;
	int nUpper;
	m_SpinCtrlScaling.GetRange32(nLower, nUpper);
	if (nLower != nMinScaling)
		m_SpinCtrlScaling.SetRange32(nMinScaling, 400);
}

const CString CTCopyDlg::GetPrinterName() const
{
	if (m_bFaxSelect)
		return m_sFax;

	return m_ComboPrinterSelect.GetSelectedPrinter();
}

void CTCopyDlg::SelectFax(BOOL bSelect)
{
	m_bFaxSelect = bSelect;

	EnableCtrlsOfGroupBox(this, IDC_SC_PRINTERSELECT, !bSelect);
}

void CTCopyDlg::OnBtnFax() 
{
	if (!m_sFax.IsEmpty())
	{
		SelectFax(TRUE);

		OnBtnCopy();
	}
}

BOOL CTCopyDlg::WriteIniFileData(int nBrightness, int nContrast) const
{
	CTCopyApp* pCopyApp = dynamic_cast<CTCopyApp*>(AfxGetApp());

	return pCopyApp->WriteIniFileValue(STR_BRIGHTNESS, nBrightness)
		&& pCopyApp->WriteIniFileValue(STR_CONTRAST, nContrast);
}


void CTCopyDlg::ReadDefaults()
{
	CTCopyApp* pCopyApp = dynamic_cast<CTCopyApp*>(AfxGetApp());

	pCopyApp->ReadIniFileValue(STR_BRIGHTNESS, m_nBrightnessOffset);
	pCopyApp->ReadIniFileValue(STR_CONTRAST, m_nContrastOffset);
}

void CTCopyDlg::OnMenuSaveDefaults() 
{
	UpdateData(TRUE);

	m_nBrightnessOffset += m_BrightnessSlider.GetPos();
	m_nContrastOffset += m_ContrastSlider.GetPos();
	WriteIniFileData(m_nBrightnessOffset, m_nContrastOffset);

	m_BrightnessSlider.SetPos(0);
	m_ContrastSlider.SetPos(0);

	UpdateData(FALSE);
}

void CTCopyDlg::OnMenuResetDefaults() 
{
	m_nBrightnessOffset = m_nContrastOffset = 0;
	WriteIniFileData(0,0);
}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article has no explicit license attached to it but may contain usage terms in the article text or the download files themselves. If in doubt please contact the author via the discussion board below.

A list of licenses authors might use can be found here


Written By
United Kingdom United Kingdom
This member has not yet provided a Biography. Assume it's interesting and varied, and probably something to do with programming.

Comments and Discussions