基于WIA的QT扫描仪程序

基于WIA的扫描仪程序,QT编写的,调用WIA api获取扫描仪属性,控制扫描仪,WIA提供了自带界面的方法,因为要嵌入自己的程序,所以我没有使用WIA自带的界面,Demo在Github上面,Github自取。详细资料请看官方文档。

目录

  1. 简介
  2. 创建WIA设备管理器
  3. 枚举系统设备
  4. 读取设备属性
  5. 创建设备
  6. 传输图像数据

1.简介

Windows图像采集(WIA)是Windows操作系统家族中的静止图像采集平台,从Windows Millennium Edition(Windows Me)和Windows XP开始。WIA平台使成像/图形应用程序可以与成像硬件进行交互,并标准化不同应用程序和扫描仪之间的交互。这允许那些不同的应用程序与这些不同的扫描仪进行对话并交互,而无需应用程序编写器和扫描仪制造商针对每种应用程序-设备组合自定义其应用程序或驱动程序。
基于WIA的QT扫描仪程序_第1张图片

  1. Windows为WIA驱动程序运行认证过程,因此,可以确保WIA应用程序与所有基于WIA的扫描仪基本兼容。
  2. WIA驱动程序已加载到WIA服务进程中,从而提供了更稳定的驱动程序环境。
  3. 可以通过WIA子系统支持的推送事件从扫描仪扫描按钮启动应用程序。
  4. WIA包括所有驱动程序都可以利用的默认分段过滤器;这样,应用程序不必为进行多区域扫描而编写代码,而无需将诸如散布在平板扫描仪上的大量照片分离出来的目的。
    基于WIA的QT扫描仪程序_第2张图片

2.创建WIA设备管理器

使用Windows Image Acquisition(WIA)服务的第一步是获取IWiaDevMgr接口指针,CLSID_WiaDevMgr和IID_IWiaDevMgr是WIA常数表示类ID和的接口ID IWiaDevMgr分别。CoCreateInstance调用的dwClsContext参数的值必须为CLSCTX_LOCAL_SERVER。

IWiaDevMgr *pWiaDevMgr = nullptr;
HRESULT hr = CoCreateInstance( CLSID_WiaDevMgr, NULL, CLSCTX_LOCAL_SERVER, IID_IWiaDevMgr, (void**)&pWiaDevMgr );

3.枚举系统设备

使用IWiaDevMgr :: EnumDeviceInfo方法来枚举系统上安装的Windows Image Acquisition(WIA)设备。此方法为设备的属性创建一个枚举对象,并返回一个指向该枚举对象支持的IEnumWIA_DEV_INFO接口的指针。然后,可以使用IEnumWIA_DEV_INFO接口的方法来获取系统上安装的每个设备的IWiaPropertyStorage接口指针。

 IEnumWIA_DEV_INFO *pWiaEnumDevInfo = NULL;
 HRESULT hr = pWiaDevMgr->EnumDeviceInfo( WIA_DEVINFO_ENUM_ALL, &pWiaEnumDevInfo );
 if (SUCCEEDED(hr))
 {
	// Loop until you get an error or pWiaEnumDevInfo->Next returns
	// S_FALSE to signal the end of the list.
	 while (S_OK == hr)
	 {
		// Get the next device's property storage interface pointer
   	 	IWiaPropertyStorage *pWiaPropertyStorage = NULL;
   		hr = pWiaEnumDevInfo->Next( 1, &pWiaPropertyStorage, NULL );
   		//..................接下来是获取设备信息并且创建设备,见第4节与第5节
 	 }
 }

4.读取设备属性

IWiaPropertyStorage接口读取和写入设备属性,设备属性包括有关设备的信息,这些信息描述了设备的功能和设置。有关这些属性的列表,请参见设备属性。

		PROPSPEC PropSpec[3] = {0};
        PROPVARIANT PropVar[3] = {0};

        //
        // How many properties are you querying for?
        //
        const ULONG c_nPropertyCount = sizeof(PropSpec)/sizeof(PropSpec[0]);

        //
        // Define which properties you want to read:
        // Device ID.  This is what you would use to create
        // the device.
        //
        PropSpec[0].ulKind = PRSPEC_PROPID;
        PropSpec[0].propid = WIA_DIP_DEV_ID;

        //
        // Device Name
        //
        PropSpec[1].ulKind = PRSPEC_PROPID;
        PropSpec[1].propid = WIA_DIP_DEV_NAME;

        //
        // Device description
        //
        PropSpec[2].ulKind = PRSPEC_PROPID;
        PropSpec[2].propid = WIA_DIP_DEV_DESC;

        //
        // Ask for the property values
        //
        HRESULT hr = pWiaPropertyStorage->ReadMultiple( c_nPropertyCount, PropSpec, PropVar );
        if (SUCCEEDED(hr))
        {
            //
            // IWiaPropertyStorage::ReadMultiple will return S_FALSE if some
            // properties could not be read, so you have to check the return
            // types for each requested item.
            //

            //
            // Check the return type for the device ID
            //
            if (VT_BSTR == PropVar[0].vt)
            {
                //
                // Do something with the device ID
                //
                _tprintf( TEXT("WIA_DIP_DEV_ID: %ws\n"), PropVar[0].bstrVal );
            }

            //
            // Check the return type for the device name
            //
            if (VT_BSTR == PropVar[1].vt)
            {
                //
                // Do something with the device name
                //
                _tprintf( TEXT("WIA_DIP_DEV_NAME: %ws\n"), PropVar[1].bstrVal );
            }

            //
            // Check the return type for the device description
            //
            if (VT_BSTR == PropVar[2].vt)
            {
                //
                // Do something with the device description
                //
                _tprintf( TEXT("WIA_DIP_DEV_DESC: %ws\n"), PropVar[2].bstrVal );
            }

            //
            // Free the returned PROPVARIANTs
            //
            FreePropVariantArray( c_nPropertyCount, PropVar );
        }

应用程序设置PROPVARIANT数组(分别为PropSpec和PropVar)来保存属性信息。这些数组作为参数传递给IWiaPropertyStorage指针pIWiaPropStg的IPropertyStorage :: ReadMultiple方法的调用。PropSpec数组的每个元素都包含设备属性的类型和名称。返回时,PropVar的每个元素都包含由PropSpec数组的相应元素表示的设备属性的值。然后,该应用程序调用IWiaPropertyStorage指针pWiaPropertyStorage的IPropertyStorage :: ReadMultiple属性以检索属性信息。

5.创建设备

一旦应用程序具有给定设备的设备ID,它就可以调用IWiaDevMgr :: CreateDevice,该方法将创建代表成像设备以及图像扫描床和文件夹的IWiaItem。

		//
        // Create the WIA Device
        //bstrDeviceID为上一节获取的设备ID
        IWiaItem *pWiaDevice=NULL;
        HRESULT hr = pWiaDevMgr->CreateDevice( bstrDeviceID, &pWiaDevice );

6. 传输图像数据

传输图像数据是最复杂的,需要创建一个类实现IWiaDataCallback接口,主要方法如下代码。

    // The IWiaDataTransfer::idtGetBandedData method periodically 
    // calls the IWiaDataCallback::BandedDataCallback method with
    // status messages. It sends the callback method a data header
    // message followed by one or more data messages to transfer 
    // data. It concludes by sending a termination message.

HRESULT _stdcall DeviceModel::BandedDataCallback(
    LONG lMessage,
    LONG lStatus,
    LONG lPercentComplete,
    LONG lOffset,
    LONG lLength,
    LONG lReserved,
    LONG lResLength,
    BYTE* pbData)
{
	UNREFERENCED_PARAMETER(lReserved);
	UNREFERENCED_PARAMETER(lResLength);
	switch (lMessage)
	{
	case IT_MSG_DATA_HEADER:
	{
		//
		// The data header contains the image's final size.
		//
		PWIA_DATA_CALLBACK_HEADER pHeader = reinterpret_cast(pbData);
		if (pHeader && pHeader->lBufferSize)
		{
			//
			// Allocate a block of memory to hold the image
			//
			m_pBuffer = reinterpret_cast(LocalAlloc(LPTR, pHeader->lBufferSize));
			if (m_pBuffer)
			{
				//
				// Save the buffer size.
				//
				m_nBufferLength = pHeader->lBufferSize;

				//
				// Initialize the bytes transferred count.
				//
				m_nBytesTransfered = 0;

				//
				// Save the file format.
				//
				m_guidFormat = pHeader->guidFormatID;
			}
		}
	}
	break;

	case IT_MSG_DATA:
	{
		//
		// Make sure a block of memory has been created.
		//
		if (NULL != m_pBuffer)
		{
			//
			// Copy the new band.
			//
			CopyMemory(m_pBuffer + lOffset, pbData, lLength);

			//
			// Increment the byte count.
			//
			m_nBytesTransfered += lLength;
		}
	}
	break;

	case IT_MSG_STATUS:
	{
		//
		// Display transfer phase
		//
		if (lStatus & IT_STATUS_TRANSFER_FROM_DEVICE)
		{
			//_tprintf(TEXT("Transfer from device\n"));
		}
		else if (lStatus & IT_STATUS_PROCESSING_DATA)
		{
			//_tprintf(TEXT("Processing Data\n"));
		}
		else if (lStatus & IT_STATUS_TRANSFER_TO_CLIENT)
		{
			//_tprintf(TEXT("Transfer to Client\n"));
		}
		//
		// Display percent complete
		//
		//_tprintf(TEXT("lPercentComplete: %d\n"), lPercentComplete);
	}
	break;
	}
	return S_OK;
}
HRESULT DeviceModel::EnumerateItems(IWiaItem* pWiaItem, vector* pItems)
{
    //
    // Validate arguments
    //
    if (NULL == pWiaItem)
    {
        return E_INVALIDARG;
    }
    //
    // Get the item type for this item.
    //
    LONG lItemType = 0;
    HRESULT hr = pWiaItem->GetItemType(&lItemType);
    if (SUCCEEDED(hr))
    {
        //
        // If it is a folder, or it has attachments, enumerate its children.
        //
        if (lItemType & WiaItemTypeFolder || lItemType & WiaItemTypeHasAttachments)
        {
            //
            // Get the child item enumerator for this item.
            //
            IEnumWiaItem* pEnumWiaItem = NULL; //vista and later
            hr = pWiaItem->EnumChildItems(&pEnumWiaItem);
            if (SUCCEEDED(hr))
            {
                //
                // Loop until you get an error or pEnumWiaItem->Next returns
                // S_FALSE to signal the end of the list.
                //
                while (S_OK == hr)
                {
                    //
                    // Get the next child item.
                    //
                    IWiaItem* pChildWiaItem = NULL; //vista and laster
                    hr = pEnumWiaItem->Next(1, &pChildWiaItem, NULL);
                    //
                    // pEnumWiaItem->Next will return S_FALSE when the list is
                    // exhausted, so check for S_OK before using the returned
                    // value.
                    //
                    if (S_OK == hr)
                    {
                        //
                        // Recurse into this item.
                        //
                        hr = EnumerateItems(pChildWiaItem, pItems);
                        //
                        // Release this item.
                        //
                        //pChildWiaItem->Release();
                        //pChildWiaItem = NULL;
                    }
                }
                //
                // If the result of the enumeration is S_FALSE (which
                // is normal), change it to S_OK.
                //
                if (S_FALSE == hr)
                {
                    hr = S_OK;
                }
                //
                // Release the enumerator.
                //
                //pEnumWiaItem->Release();
                //pEnumWiaItem = NULL;
            }
        }
        else pItems->push_back(pWiaItem);
    }
    return  hr;
}
void DeviceModel::ScanningSlot(int source, int pictrueType, int brightness, int contrast, int dpi, int size)
{
    //CoInitialize(NULL);
    vector imageWiaItems;
    m_pWiaItemRoot->AnalyzeItem(0);
    HRESULT hr = EnumerateItems(m_pWiaItemRoot, &imageWiaItems);
    if (hr == S_OK)
    {
        for (int i = 0; i < imageWiaItems.size(); ++i)
        {
            IWiaPropertyStorage* pGetWiaProperty = nullptr;
            hr = imageWiaItems[i]->QueryInterface(IID_IWiaPropertyStorage, (void**)&pGetWiaProperty);
            if (hr != S_OK) continue;
            PROPSPEC propSpec[9];
            PROPVARIANT propVar[9];
            propSpec[0].ulKind = PRSPEC_PROPID;
            propSpec[0].propid = WIA_IPA_TYMED;
            propSpec[1].ulKind = PRSPEC_PROPID;
            propSpec[1].propid = WIA_IPA_FORMAT;
            propSpec[2].ulKind = PRSPEC_PROPID;
            propSpec[2].propid = WIA_DPS_PREVIEW;
            //propSpec[3].ulKind = PRSPEC_PROPID;
            //propSpec[3].propid = WIA_DPS_DOCUMENT_HANDLING_SELECT;
            propSpec[3].ulKind = PRSPEC_PROPID;
            propSpec[3].propid = WIA_IPS_CUR_INTENT;
            propSpec[4].ulKind = PRSPEC_PROPID;
            propSpec[4].propid = WIA_IPS_BRIGHTNESS;
            propSpec[5].ulKind = PRSPEC_PROPID;
            propSpec[5].propid = WIA_IPS_CONTRAST;
            propSpec[6].ulKind = PRSPEC_PROPID;
            propSpec[6].propid = WIA_IPS_XRES;
            propSpec[7].ulKind = PRSPEC_PROPID;
            propSpec[7].propid = WIA_IPS_YRES;
            propSpec[8].ulKind = PRSPEC_PROPID;
            propSpec[8].propid = WIA_IPS_PAGE_SIZE;

            CLSID guidOutputFormat1 = WiaImgFmt_MEMORYBMP;
            propVar[0].vt = VT_I4;
            propVar[0].lVal = TYMED_CALLBACK;
            propVar[1].vt = VT_CLSID;
            propVar[1].puuid = &guidOutputFormat1;
            propVar[2].vt = VT_I4;
            propVar[2].lVal = 0;
            //propVar[3].vt = VT_I4;
            //if (source == 0) propVar[3].lVal = FLATBED;
            //else propVar[3].lVal = FEEDER;
            propVar[3].vt = VT_I4;
            if (pictrueType == 0) propVar[3].lVal = WIA_INTENT_IMAGE_TYPE_COLOR;
            else if (pictrueType == 1) propVar[3].lVal = WIA_INTENT_IMAGE_TYPE_GRAYSCALE;
            else propVar[3].lVal = WIA_INTENT_IMAGE_TYPE_TEXT;
            propVar[4].vt = VT_I4;
            propVar[4].lVal = brightness;
            propVar[5].vt = VT_I4;
            propVar[5].lVal = contrast;
            propVar[6].vt = VT_I4;
            propVar[6].lVal = dpi;
            propVar[7].vt = VT_I4;
            propVar[7].lVal = dpi;
            propVar[8].vt = VT_I4;
            if (size == 0) propVar[8].lVal = WIA_PAGE_A4;
            else if (size == 1) propVar[8].lVal = WIA_PAGE_ISO_A5;
            else propVar[8].lVal = WIA_PAGE_ISO_A6;

            hr = pGetWiaProperty->WriteMultiple(sizeof(propSpec) / sizeof(propSpec[0]), propSpec, propVar, WIA_IPA_FIRST);
            if (hr != S_OK) continue;

            IWiaDataTransfer* pIWiaDataTransfer = nullptr;
            hr = imageWiaItems[i]->QueryInterface(IID_IWiaDataTransfer, (void**)&pIWiaDataTransfer);
            if (hr != S_OK) continue;

			PWIA_DATA_TRANSFER_INFO pdti = new WIA_DATA_TRANSFER_INFO;
			pdti->ulSize = sizeof(WIA_DATA_TRANSFER_INFO);
			pdti->ulBufferSize = 1024 * 1024;
			pdti->ulSection = 0;
			pdti->bDoubleBuffer = true;
			pdti->ulReserved1 = 0;
			pdti->ulReserved2 = 0;
			pdti->ulReserved3 = 0;

            while (true)
            {
                hr = pIWiaDataTransfer->idtGetBandedData(pdti, this);
                if (hr == S_OK) WriteFile();
                else break;
            }
			
            if (pGetWiaProperty) pGetWiaProperty->Release();
            if (pIWiaDataTransfer) pIWiaDataTransfer->Release();
            imageWiaItems[i]->Release();
        }
    }
}

你可能感兴趣的:(C,qt,c++)