How to get barcode text by DTWAIN_EI_BARCODETEXT
case DTWAIN_TN_TRANSFERDONE: { DTWAIN_ARRAY AllBarCodes; DTWAIN_InitExtImageInfo( Source ); //if ( DTWAIN_GetExtImageInfoData( Source, TWEI_BARCODETYPE, &AllBarCodes) ) //if ( DTWAIN_GetExtImageInfoData( Source, TWEI_BARCODETEXTLENGTH, &AllBarCodes) ) if ( DTWAIN_GetExtImageInfoData( Source, DTWAIN_EI_BARCODETEXT, &AllBarCodes) ) { qDebug()<<"Count: "<<DTWAIN_ArrayGetCount( AllBarCodes ); DTWAIN_STRING CurBarCode; DTWAIN_ArrayGetAt( AllBarCodes, 0, &CurBarCode ); qDebug()<<"CurBarCode"<<CurBarCode; DTWAIN_ArrayDestroy( AllBarCodes ); } DTWAIN_FreeExtImageInfo( Source ); } Count return 1, but CurBarCode NULL. I hava make sure support barcode OK. I need help, thank you !
Please state the make and model of the scanner you are using. Getting barcode information is somewhat tricky, and I currently do not have a barcode scanner to test with on-hand. What DTWAIN has done is interpret what the TWAIN specification states on how to retrieve the barcode strings, and it is expected that DTWAIN has followed the TWAIN specfication correctly for all barcode TWAIN scanners that are compliant.
Also, make sure you are using the latest version of DTWAIN (5.5.0).
Since the array count is 1, DTWAIN did retrieve the data, and the barcode item does exist, but you may not be retrieving the item correctly in terms of strings.
Since barcode strings are not actually returned as strings, but as handles to string data, we need to make sure what is in the array is actually a string, or an address to a handle. If it is a string, then it is simple to get the string -- if it's a handle, then it becomes a little bit more involved.
First, make sure the array returned is one that supports strings (I believe it should be). Check DTWAIN_ArrayGetType and check the return value. Then you can use DTWAIN_ArrayGetStringLength to get the length of the string.
Since retrieving strings is a bit more convoluted using DTWAIN_ArrayGetAt than the other non-string data types, there are helper functions to make this easier.
If the string is 8-bit (ANSI) string, use DTWAIN_ArrayGetAtANSIString(AllBarCodes, 0, CurBarCode);
The final step in getting this to work if this is not adequate is to get the source code to DTWAIN, build it, and see what the device does when getting the barcode data.
Thanks for your help! I am using an avision scanner(aw2000). Barcode strings maybe returned as handles to string data. How can i get it? qDebug()<<"GetCount: "<<DTWAIN_ArrayGetCount( AllBarCodes ); qDebug()<<"GetType: "<<DTWAIN_ArrayGetType( AllBarCodes ); qDebug()<<"StringLength: "<<DTWAIN_ArrayGetStringLength(AllBarCodes,0); LPCTSTR CurBarCode; CurBarCode = DTWAIN_ArrayGetAtStringPtr(AllBarCodes, 0); qDebug()<<"CurBarCode:"<<CurBarCode; output: GetCount: 1 GetType: 6 StringLength: 0 CurBarCode: 0x647ff30
It is going to be difficult for me to diagnose this, as I would really need the device to see what is going on. I don't have a TWAIN device that does barcode scanning, and it seems the Avision scanner is not easily unavailable.
You can try the Windows API function GlobalLock on the returned CurBarCode to see if
- The GlobalLock() doesn't fail and
- if you see text if GlobalLock() doesn't fail.
Right now, the best person to see what is going on would be the person who has the equipment and the DTWAIN source code and debug what is going on. What I can do is direct you to where the processing takes place.
The processing occurs here. This is where the actual calling of the triplet to get the extended image information is done. The call to Execute() is where you would place a breakpoint, as that is where DTWAIN will actually call TWAIN to get the barcode information. After the TWAIN call is done, it is expected that this line and the processing of the returned data from the scanner is done.
Sorry that I can't be of more help, but it is difficult to diagnose this myself without the actual equipment.
Just to add, from what I have researched, the Avision scanners use a barcode SDK from a third-party to read the barcodes, thus the barcode reading is not internally done by the scanner itself.
I can take a chance and see if I can get an Avision 176+ or similar (the AW 2000 is just not easily available). But I can't guarantee it will have barcode capabilities, as there are many Avision models. So right now, you're still in a better situation than myself if the code needs to be debugged.
Thank you very much for your help! I would like to try a third-party open-source plugin (e.g. zbar, zxing). TWEI_BARCODETEXT(TWAIN-2.2-Spec): Description: The text of a bar code found on a page. Value Type: TWTY_HANDLE Allowed Values: Any handle to a string Best wishes for you!
Description: The text of a bar code found on a page.
Value Type: TWTY_HANDLE
Allowed Values: Any handle to a string
Yes, that is exactly what the DTWAIN source code is following.
The tricky part is that TWTY_HANDLE can mean several things. It could be simply memory allocated that requires a GlobalLock() for access, or it could be a normal pointer that just needs to be casted to a string (where the length also comes in as a separate piece of information). The DTWAIN source code follows the second method for TWEI_BARCODETEXT, and attempts to cast the TWTY_HANDLE to a string and extract the information.
I believe DTWAIN is getting the value, but possibly not treating the value correctly. I have confidence that the issue has a very simple fix (if it needs to be fixed), but requires an actual device to verify the fix.
Having said this, I should be able to get an Avision 176+ scanner, but won't be able to do any testing with it for about a week (depending on when I get the scanner). Hopefully it has barcode support, similar to the AW2000.
Also, since you are reading the TWAIN specification, you can directly make calls to the TWAIN Data Source Manager, bypassing what DTWAIN is doing. The call to DTWAIN_CallDSMProc can be done in your code. You will see an example of this function's usage at the link.
You can then experiment yourself when you call the DG_IMAGE / DAT_EXTIMAGEINFO / MSG_GET triplet, and then tailor your own code to get the barcode text correctly. The DTWAIN_CallDSMProc was designed for issues like this.
Of course, you won't have any other DTWAIN functions to help you -- you will have to process the triplet information yourself, but at least you will have total control of what is being done.
Just to update you, I will have an Avision 176U to test with in the next few days. However as my last comment suggested, you can bypass and/or diagnose the issue by issuing calls to DTWAIN_CallDSMProc and attempt to get the barcode data.
You should call DTWAIN_CallDSMProc() when the DTWAIN_TN_TRANSFERDONE notification is sent to you (hopefully you have notifications on). The TWAIN specification states that DG_IMAGE / DAT_EXTIMAGEINFO / MSG_GET triplet can only be called when the TWAIN Source is in State 7, and DTWAIN_TN_TRANSFERDONE is when state 7 is invoked.
I now have the Avision 176U in house. Here is what I found when initially testing the Barcode support.
-
There definitely are issues with the DTWAIN implementation of obtaining some of the extended image information. This will be corrected in the next version of DTWAIN (5.5.3 or 5.5.4).
-
After correcting those issues in the local build that I have, there is a problem getting the barcode text that is not related to DTWAIN. Here are the issues:
For 32-bit:
-
The TWEI_BARCODETEXT2 extended capability is what you should be using, however, this capability fails to return any barcode text from the scanner. What is returned are handles, and no matter what I have tried, none of those handles points to valid text. So either the TWAIN driver failed to pick up the text and is returning NULL, or there is a bug in the barcode text detection in the Avision driver.
-
All of the other barcode information (position, number and type of barcodes, etc.) were detected and returned using the appropriate capabilities (TWEI_BARCODEX, TWEI_BARCODEY, etc.)
For 64-bit:
- There is a bug in the 64-bit Avision driver, in the zxing library (I never heard of it before, so I had to google it). This library is used to read barcode information, and for some reason, Avision throws a "ReedSolomonException" exception when attempting to read the barcode data. The exception occurs on TWEI_BARCODETEXT2 when Avision attempts to set the barcode text.
So basically, all I can do is provide whatever fixes required to get the barcode information, but there is no guarantee of getting the barcode text.
As mentioned previously, you can do all of this yourself by bypassing the internal DTWAIN routines and instead attempt to call DTWAIN_CallDSMProc with the information that the TWAIN specification states as to what you should provide. You would want to call DTWAIN_CallDSMProc when the DTWAIN_TN_TRANSFERDONE notification (State 7) is sent to your callback handler.
If you are also unable to get the barcode text after doing this, then there is nothing more than DTWAIN can do at this point.
Also, Avision comes with bundled software (AVscanX) that scans images. The barcode detection option that this software has is done on the scanned bitmap -- it isn't done within the Avision TWAIN driver's detection of barcodes, which is what DTWAIN is relying on. So the issue is internally within Avision's driver, and not AVScanX.
After some more work on the Avision scanner and barcodes, Avision does seem to use TWEI_BARCODETEXT, but only partially support TWEI_BARCODETEXT2.
So I tried TWEI_BARCODETEXT, and had a little bit more success. Here is the sample code I tried, and was able to get the text (this is described in the TWAIN specification):
DTWAIN_SOURCE g_CurrentSource;
//....
// Assume g_CurrentSource is pointing to a valid TWAIN Source
//...
// Declare DTWAIN Arrays
DTWAIN_ARRAY barCodeText = NULL;
DTWAIN_ARRAY barCodeLengths = NULL;
DTWAIN_ARRAY barCodeCount = NULL;
// Start up the extended information queries
DTWAIN_InitExtImageInfo(g_CurrentSource);
DTWAIN_GetExtImageInfo(g_CurrentSource);
// Query the barcode text and text lengths
DTWAIN_GetExtImageInfoData(g_CurrentSource, TWEI_BARCODETEXT, &barCodeText);
DTWAIN_GetExtImageInfoData(g_CurrentSource, TWEI_BARCODETEXTLENGTH, &barCodeLengths);
DTWAIN_GetExtImageInfoData(g_CurrentSource, TWEI_BARCODECOUNT, &barCodeCount);
// Get the count
LONG count;
LONG lastLen = 0;
if (DTWAIN_ArrayGetCount(barCodeCount) > 0)
{
DTWAIN_ArrayGetAtLong(barCodeCount, 0, &count);
for (int i = 0; i < count; ++i)
{
char szBarText[512];
DTWAIN_HANDLE sHandle;
LONG length;
// Get the HANDLE to the text
DTWAIN_ArrayGetAt(barCodeText, i, &sHandle);
// Get the length of the text
DTWAIN_ArrayGetAtLong(barCodeLengths, i, &length);
// GlobalLock the handle
char* pText = (char*)GlobalLock(sHandle);
// copy over the text to the buffer;
memcpy(szBarText, pText + lastLen, length);
szBarText[length] = 0;
printf("The string is %s\n", szBarText);
// Update position in the text
lastLen += length;
// Unlock the buffer
GlobalUnlock(sHandle);
}
}
DTWAIN_FreeExtImageInfo(g_CurrentSource);
So basically you need all of the length information, since the text is actually one big string (see TwainSpecification for TWEI_BARCODETEXT).
I only tested this with the build I am working on, which has not been released yet. You can test this with the current version of DTWAIN, but I can't guarantee it will get the correct information.
What you can do is call DTWAIN_CallDSMProc with the TW_EXTIMAGEINFO setup according to the TWAIN specification and emulate the code you see here, but as soon as the version of DTWAIN I am working on is released, the code above is what you would need to retrieve the barcode text (at least from the Avision scanner).
You can try the experimental 5.5.3 binaries. This version addresses several issues with the TWEI_... handling.
The Avision 176U 64-bit driver has bugs when attempting to get certain string related extended image information values. For example, TWEI_CAMERA does not work for 64-bit Avision, but it does work for 32-bit (the TWEI_CAMERA should return the "TOP" string, but it doesn't do this for 64-bit, which violates the TWAIN standard).
As mentioned in the previous comment, there is a barcode rendering/detection bug in the Avision software, where they do not handle the exceptions being used in the internal barcode detection software they are using.
Other than that, I successfully tested the barcode text retrieval using code similar to the previous comment.
Thank you for your help! Update DTWAIN to version 5.5.3, Successfully obtained barcode text using the code you provided. Best wishes for you!
LRESULT CALLBACK MyCallback(WPARAM w, LPARAM lp, LONG_PTR lng) { switch (w) { case 1038: { TW_STATUS m_Status; LONG RetVal = DTWAIN_CallDSMProc(DTWAIN_GetTwainAppID(), DTWAIN_GetSourceID(Source), DG_CONTROL, DAT_STATUS, MSG_GET, &m_Status); //Get State //TWCC_PAPERJAM 20 //TWCC_PAPERDOUBLEFEED 21 //TWCC_SUCCESS 0 //TWCC_NOMEDIA 29 qDebug() << "m_Status.ConditionCode" << m_Status.ConditionCode << m_Status.Data; qDebug() << "DTWAIN_GetLastError" << w << lp << lng << DTWAIN_GetLastError(); } break;
case DTWAIN_TN_TRANSFERDONE:
{
// Declare DTWAIN Arrays
DTWAIN_ARRAY barCodeText = NULL;
DTWAIN_ARRAY barCodeLengths = NULL;
DTWAIN_ARRAY barCodeCount = NULL;
// Start up the extended information queries
DTWAIN_InitExtImageInfo(Source);
DTWAIN_GetExtImageInfo(Source);
// Query the barcode text and text lengths
DTWAIN_GetExtImageInfoData(Source, TWEI_BARCODETEXT, &barCodeText);
DTWAIN_GetExtImageInfoData(Source, TWEI_BARCODETEXTLENGTH, &barCodeLengths);
DTWAIN_GetExtImageInfoData(Source, TWEI_BARCODECOUNT, &barCodeCount);
// Get the count
LONG count;
LONG lastLen = 0;
if (DTWAIN_ArrayGetCount(barCodeCount) > 0)
{
DTWAIN_ArrayGetAtLong(barCodeCount, 0, &count);
for (int i = 0; i < count; ++i)
{
char szBarText[512];
DTWAIN_HANDLE sHandle;
LONG length;
// Get the HANDLE to the text
DTWAIN_ArrayGetAt(barCodeText, i, &sHandle);
qDebug() << "sHandle" << sHandle;
// Get the length of the text
DTWAIN_ArrayGetAtLong(barCodeLengths, i, &length);
// GlobalLock the handle
char* pText = (char*)GlobalLock(sHandle);
qDebug() << "sHandle" << sHandle;
// copy over the text to the buffer;
memcpy(szBarText, pText + lastLen, length);
szBarText[length] = 0;
qDebug() << "szBarText" << szBarText;
printf("The string is %s", szBarText);
// Update position in the text
lastLen += length;
// Unlock the buffer
GlobalUnlock(sHandle);
}
}
DTWAIN_FreeExtImageInfo(Source);
}
break;
case DTWAIN_TN_QUERYPAGEDISCARD:
{
HANDLE h = DTWAIN_GetCurrentAcquiredImage(Source);
}
break;
}
return 1;
}
Thanks. As soon as version 5.5.3 is released, I will close this issue.
Closing issue. The latest version 5.5.3 has corrected the issues.