5

Edit: Are there any tutorials on how to use WIA or TWAIN in c++, that explain how to scan pages, adjust settings (DPI, using automatic feeder etc.) and save them as PNG files?

I'd like to use WIA to scan pages and store them as png files. If the scanner supports automatic feeding I'd also like to use that feature. Currently I am following the steps of this tutorial and am stuck at the section Transferring Image Data in WIA 2.0.

So far my scanner has been found and I am able to create the device, and an IWiaItem2* has been created. How can use it to scan at 300dpi and store the result as png file?

The tutorial is not clear about how to start the scan process or how to set dpi for scanning, so I hope someone can help me with the code.

This is essentially the code for getting all local devices:

bool init(IWiaDevMgr2* devMgr)
{
    //creating the device manager
    *devMgr = 0; 
    CoCreateInstance( CLSID_WiaDevMgr2, 0, CLSCTX_LOCAL_SERVER, IID_IWiaDevMgr2, (void**)&devMgr); 

    //enumerating wia devices
    IEnumWIA_DEV_INFO* enumDevInfo = 0; 
    HRESULT hr = devMgr->EnumDeviceInfo( WIA_DEVINFO_ENUM_LOCAL, &enumDevInfo); 

    if(SUCCEEDED(hr))
    {
        //loop until an error occurs or end of list
        while(hr == S_OK)
        {
            IWiaPropertyStorage* storage = 0; 
            hr = enumDevInfo->Next( 1, &storage, 0); 

            if(hr == S_OK)
            {
                readProperties(storage); 
                storage->Release(); 
                storage = 0; 
            }
        }

        //set hr to ok, so no error code is returned
        if(hr == S_FALSE) hr = S_OK; 

        enumDevInfo->Release();
        enumDevInfo = 0; 
    }
    return SUCCEEDED(hr); 
}

void readProperties(IWiaPropertyStorage* storage)
{
    PROPSPEC propSpec[2] = {0};
    PROPVARIANT propVar[2] = {0};

    const ULONG propCount = sizeof(propSpec) / sizeof(propSpec[0]); 

    propSpec[0].ulKind = PRSPEC_PROPID;
    propSpec[0].propid = WIA_DIP_DEV_ID; 

    propSpec[1].ulKind = PRSPEC_PROPID; 
    propSpec[1].propid = WIA_DIP_DEV_NAME; 

    HRESULT hr = storage->ReadMultiple(propCount, propSpec, propVar); 

    if(SUCCEEDED(hr))
    {
        Device* dev = new Device(propVar[0].bstrVal, propVar[1].bstrVal); 
        devices.push_back( dev ); 
        FreePropVariantArray( propCount, propVar ); 
    }
}

Afterwards a device is initialized like this:

bool createDevice(BSTR id, IWiaItem2** item)
{
*item = 0; 
HRESULT hr = devMgr->CreateDevice( 0, deviceId, item); 
return SUCCEEDED(hr); 
}

Then the items are enumerated:

bool enumerateItems(IWiaItem2* item)
{
    LONG itemType = 0; 
    HRESULT hr = item->GetItemType(&itemType); 

    if(SUCCEEDED(hr))
    {
        if(itemType & WiaItemTypeFolder || itemType & WiaItemTypeHasAttachments)
        {
            IEnumWiaItem2* enumItem = 0; 
            hr = item->EnumChildItems(0, &enumItem );

            while(hr == S_OK)
            {
                IWiaItem2* child = 0; 
                hr = enumItem->Next( 1, &child, 0 ); 

                if(hr == S_OK)
                {
                    hr = enumerateItems( child ); 

                    child->Release();
                    child = 0; 
                }
            }

            if(hr == S_FALSE) hr = S_OK; 

            enumItem->Release(); 
            enumItem = 0; 
        }
    }

    return SUCCEEDED(hr); 
}

Now that everything has been initialized I'd like to implement a scan function. However, the code provided at the tutorial is for transferring files and folders and not for scanning images.

void scanAndSaveAsPNG(IWiaItem2* item, unsigned int dpi, std::string targetPath)
{

}

EDIT: I installed the latest version available of the scanner driver (WIA and TWAIN) and after checking the supported commands using this code

void printCommands(IWiaItem2* i)
{
    IEnumWIA_DEV_CAPS* caps = 0; 
    HRESULT h = item->EnumDeviceCapabilities(WIA_DEVICE_COMMANDS, &caps);  

    if(SUCCEEDED(h))
    {
        ULONG count = 0;
        caps->GetCount(&count); 

        if(count > 0)
        {
            WIA_DEV_CAP* cap = new WIA_DEV_CAP[ count ]; 
            ULONG fetched; 
            caps->Next(count, cap, &fetched); 

            for(int i = 0; i < fetched; i++)
            {
                std::cout << bstr_t( cap[i].bstrName ) << "\n"; 
            }
        }

        caps->Release();
    }
}

I noticed it only lists WIA Synchronize command. I am not sure if I didn't initialize the device correctly, or if the device doesn't support all WIA commands although the driver is installed.

So unless this problem is solved I am alternatively also looking for the same code based on TWAIN.

Pedro
  • 3,898
  • 10
  • 48
  • 93
  • Not sure whether you considered using a commercial SDK. With some TWAIN controls, you can do the tasks you listed in several lines of code and within 1 hour. My company has Dynamic Web TWAIN. I recommend you try it. – flysakura Feb 13 '12 at 06:28
  • See VBS example http://ru.stackoverflow.com/a/1024162/17974 here – nick_n_a Sep 13 '19 at 11:49

1 Answers1

0

You want to use IWiaItem2::DeviceCommand which sends a command to the image capture device. The list of commands you can send are listed here.

zdan
  • 25,964
  • 5
  • 54
  • 67
  • When I execute `IWiaItem2* p = 0; item->DeviceCommand(0, &WIA_CMD_TAKE_PICTURE, &p);` I get an error with code 0x80004001 with the message 'not implemented'. How can I fix that? The device I send the command to definitely is able to scan documents. – Pedro Jan 13 '12 at 02:39