Closed VIIICENTURY closed 3 years ago
In my QT app I create a QImage and then convert that to a QPixMap. Something like:
BYTE* pImageData;
switch (pixelType)
{
case TWPT_RGB: // Full Color RGB (24 bit | 8-bit/pixel)
_sourceImage = QImage(pImageData, width, height, QImage::Format_RGB888);
break;
case TWPT_GRAY: // Grayscale (8-bit)
_sourceImage = QImage(pImageData, width, std::abs(height), QImage::Format_Grayscale8);
// Set the palette
for (int i = 0; i < 256; ++i)
{
_sourceImage.setColor(i, qRgb(i, i, i));
}
break;
case TWPT_BW: // Black & White (1-bit)
_sourceImage = QImage(pImageData, width, height, QImage::Format_Mono);
// Set the palette
_sourceImage.setColor(0, qRgb(0, 0, 0));
_sourceImage.setColor(1, qRgb(255, 255, 255));
break;
}
To convert it to a QPixmap for use in a QLabel I do:
_ui->lblImageDisplayArea->setPixmap(QPixmap::fromImage(_sourceImage).scaled(_ui->lblImageDisplayArea->width(), _ui->lblImageDisplayArea->height(), Qt::KeepAspectRatio));
What am I doing wrong?
DTWAIN_SysInitialize();
DTWAIN_SOURCE Source = DTWAIN_SelectSource();
DTWAIN_ARRAY images;
if (Source)
{
images = DTWAIN_AcquireNative(Source, DTWAIN_PT_RGB, DTWAIN_MAXACQUIRE, TRUE, TRUE, NULL);
QImage result = QImage(static_cast<BYTE*>(images), 150,150, QImage::Format_RGB888);
ui->label->setPixmap(QPixmap::fromImage(result).scaled(ui->label->width(), ui->label->height(), Qt::KeepAspectRatio));
}
DTWAIN_SysDestroy();
I get this result:
@VIIICENTURY
The DTWAIN_AcquireNative returns an array of acquisitions, and each acquisition can contain multiple images. Your last code is using a DTWAIN_ARRAY of DTWAIN_ARRAY's, not a separate image.
You should look at the first code posted:
images = DTWAIN_AcquireNative(Source, DTWAIN_PT_RGB, DTWAIN_MAXACQUIRE, TRUE, TRUE, NULL);
HANDLE hDib = DTWAIN_GetAcquiredImage(images, 0, 0); // handle to first DIB acquired is returned
The hDib
is what you should be working with. The DTWAIN_GetAcquiredImages allows you to easily get the actual image handle from the aquisition array.
Since Dcreeron has demonstrated how to handle this, here is a detailed explanation of what is going on in the DTWAIN side of things:
Once you have the hDib
, then you need to know using the language or image library you're using, how to handle Device Independent Bitmaps. The handle that is returned requires the Windows GlobalLock
function to return a pointer to the underyling image, given the handle. Again, this is illustrated in the first example you had. The return value of GlobalLock
is a pointer to the actual image data.
Here is another small snippet of code (albeit longer than Dcreeron's) that will convert the device independent bitmap into a Device Dependent Bitmap (a DIB with a bitmap header). The return value is a vector
#include <vector>
#include <algorithm>
#include <iterator>
#include <cstring>
#include <windows.h> // may not be needed, but just in case Qt doesn't include this header
//...
int CalculateUsedPaletteEntries(int bit_count) {
if ((bit_count >= 1) && (bit_count <= 8))
return 1 << bit_count;
return 0;
}
std::vector<unsigned char> get_image_as_BMP(HANDLE hDib) // This is the passed in `hDib`)
{
std::vector<unsigned char> retval;
if (!hDib)
return retval;
BITMAPFILEHEADER fileheader;
LPBITMAPINFOHEADER lpbi = NULL;
memset((char *)&fileheader, 0, sizeof(BITMAPFILEHEADER));
fileheader.bfType = 0x4D42;
// Fill in the fields of the file header. Note the call to GlobalLock
BYTE *pImage2 = (BYTE *)GlobalLock(hDib);
lpbi = reinterpret_cast<LPBITMAPINFOHEADER>(pImage2);
fileheader.bfSize = (DWORD)GlobalSize(hDib) + sizeof(BITMAPFILEHEADER);
fileheader.bfReserved1 = 0;
fileheader.bfReserved2 = 0;
fileheader.bfOffBits = (DWORD)sizeof(BITMAPFILEHEADER) +
lpbi->biSize + CalculateUsedPaletteEntries(lpbi->biBitCount) * sizeof(RGBQUAD);
// Write the file header
char *ptrFileheader = reinterpret_cast<char *>(&fileheader);
std::copy(ptrFileheader, ptrFileheader + sizeof(BITMAPFILEHEADER), std::back_inserter(retval));
// Write the data
DWORD gSize = static_cast<DWORD>(GlobalSize(hDib));
std::copy(pImage2, pImage2 + gSize, std::back_inserter(retval));
// Now unlock the data
GlobalUnlock(hDib);
return retval;
}
Then you can call it like this:
// This will get a handle to the first image of the first set of acquisitions
HANDLE hDib = DTWAIN_GetAcquiredImage(image, 0, 0);
if ( hDib )
{
QPixmap pixmap;
std::vector<unsigned_char> imageData = get_image_as_BMP(hDib);
pixmap.loadFromData( imageData.data(), imageData.size() );
//...
// Do stuff with pixmap
ui->label->setPixmap(pixmap.scaled(ui->label->width(), ui->label->height(), Qt::KeepAspectRatio));
}
Just to let you know, the next version of DTWAIN will have a routine available to convert from DIB to DDB, so the code above won't be necessary.
I thought I had mentioned in my original response that I'm using the DTWAIN_AcquireBuffered() call; looks like I missed pointing that out though. In my code that handles the various DTWAIN Notifications I do things very similar to what dynarithmic has shown in his posts (creating the Device Dependent Bitmap, etc.).
Sorry that I didn't clarify that earlier.
@dynarithmic @Dcreeron
Thank you very much! You were very helpful, and your explanations helped to understand the issue.
The issue is resolved and can be closed.
I'm using Qt and I need to get the image directly without saving it as a file, so that after scanning it will display it on the form. To do this, I need to cast it to the QPixmap type. The DTWAIN description contains the following code example: `
` But I don't understand how I can cast this to the QPixmap type.