File indexing completed on 2024-04-28 04:32:19

0001 /*
0002  * SPDX-FileCopyrightText: 2002-2003 Stephan Stapel <stephan dot stapel at web dot de>
0003  * SPDX-FileCopyrightText: 2008-2009 Gilles Caulier <caulier dot gilles at gmail dot com>
0004  * SPDX-FileCopyrightText: 2009, 2017 Kare Sars <kare dot sars at iki dot fi>
0005  *
0006  * SPDX-License-Identifier: LGPL-2.1-only OR LGPL-3.0-only OR LicenseRef-KDE-Accepted-LGPL
0007  */
0008 
0009 // I renamed the class to KSaneWidgetPrivate to remove
0010 // the need for a wrapper class with this name. (Kare)
0011 
0012 #include "twainiface.h"
0013 
0014 #include "ksanewidget.h"
0015 
0016 #define TWCPP_ANYCOUNT   (-1)
0017 #define TWCPP_CANCELTHIS (1)
0018 #define TWCPP_CANCELALL  (2)
0019 #define TWCPP_DOTRANSFER (0)
0020 
0021 #include <QString>
0022 #include <QImage>
0023 #include <QDebug>
0024 
0025 #include <cstring>
0026 
0027 #define saneDebug() if (0) qDebug()
0028 
0029 namespace KSaneIface
0030 {
0031 
0032 KSaneWidgetPrivate::KSaneWidgetPrivate(): QWidget(0)
0033 {
0034     // This is a dummy widget not visible. We use Qwidget to dispatch Windows event to
0035     // Twain interface. This is not possible to do it using QObject as well.
0036 
0037     m_hMessageWnd     = 0;
0038     m_hTwainDLL       = NULL;
0039     m_pDSMProc        = NULL;
0040     m_bDSOpen         = false;
0041     m_bDSMOpen        = false;
0042     m_bSourceEnabled  = false;
0043     m_bModalUI        = true;
0044     m_nImageCount     = TWCPP_ANYCOUNT;
0045 
0046     InitTwain();
0047 }
0048 
0049 KSaneWidgetPrivate::~KSaneWidgetPrivate()
0050 {
0051     ReleaseTwain();
0052 }
0053 
0054 bool KSaneWidgetPrivate::nativeEvent(const QByteArray &eventType, void *message, long *result)
0055 {
0056     if (eventType == "windows_generic_MSG") {
0057         return ProcessMessage(*(MSG*)message);
0058     }
0059     return true;
0060 }
0061 
0062 
0063 /** Initializes TWAIN interface . Is already called from the constructor.
0064     It should be called again if ReleaseTwain is called.
0065     hWnd is the window which has to subclassed in order to receive
0066     Twain messaged. Normally - this would be your main application window.
0067  */
0068 bool KSaneWidgetPrivate::InitTwain()
0069 {
0070     char libName[512];
0071 
0072     if ((m_hTwainDLL && m_pDSMProc)) {
0073         return true;
0074     }
0075 
0076     memset(&m_AppId, 0, sizeof(m_AppId));
0077 
0078     if (!IsWindow((HWND)this->winId()))    {
0079         return false;
0080     }
0081 
0082     m_hMessageWnd = (HWND)this->winId();
0083     strcpy(libName, "TWAIN_32.DLL");
0084 
0085     m_hTwainDLL = LoadLibraryA(libName);
0086     if (m_hTwainDLL != NULL) {
0087         if (!(m_pDSMProc = (DSMENTRYPROC)GetProcAddress(m_hTwainDLL, (LPCSTR)MAKEINTRESOURCE(1)))) {
0088             FreeLibrary(m_hTwainDLL);
0089             m_hTwainDLL = NULL;
0090         }
0091     }
0092 
0093     if ((m_hTwainDLL && m_pDSMProc)) {
0094         // Expects all the fields in m_AppId to be set except for the id field.
0095         m_AppId.Id               = 0; // Initialize to 0 (Source Manager will assign real value)
0096         m_AppId.Version.MajorNum = 0; // Your app's version number
0097         m_AppId.Version.MinorNum = 2;
0098         m_AppId.Version.Language = TWLG_USA;
0099         m_AppId.Version.Country  = TWCY_USA;
0100         strcpy(m_AppId.Version.Info, "libksane");
0101 
0102         m_AppId.ProtocolMajor    = TWON_PROTOCOLMAJOR;
0103         m_AppId.ProtocolMinor    = TWON_PROTOCOLMINOR;
0104         m_AppId.SupportedGroups  = DG_IMAGE | DG_CONTROL;
0105         strcpy(m_AppId.Manufacturer,  "KDE");
0106         strcpy(m_AppId.ProductFamily, "Generic");
0107         strcpy(m_AppId.ProductName,   "libksane");
0108 
0109         m_bDSMOpen = CallTwainProc(&m_AppId, NULL, DG_CONTROL,
0110                                    DAT_PARENT, MSG_OPENDSM, (TW_MEMREF)&m_hMessageWnd);
0111         return true;
0112     } else {
0113         return false;
0114     }
0115 }
0116 
0117 /** Releases the twain interface . Need not be called unless you
0118     want to specifically shut it down.
0119  */
0120 void KSaneWidgetPrivate::ReleaseTwain()
0121 {
0122     if ((m_hTwainDLL && m_pDSMProc)) {
0123         CloseDSM();
0124         FreeLibrary(m_hTwainDLL);
0125         m_hTwainDLL = NULL;
0126         m_pDSMProc  = NULL;
0127     }
0128 }
0129 
0130 /** Entry point into Twain. For a complete description of this
0131     routine  please refer to the Twain specification 1.8
0132  */
0133 bool KSaneWidgetPrivate::CallTwainProc(pTW_IDENTITY pOrigin, pTW_IDENTITY pDest,
0134                                        TW_UINT32 DG, TW_UINT16 DAT, TW_UINT16 MSG, TW_MEMREF pData)
0135 {
0136     saneDebug() << "CallTwainProc" << pOrigin << pDest << DG << DAT << MSG << pData;
0137     if (!(m_hTwainDLL && m_pDSMProc)) {
0138         m_returnCode = TWRC_FAILURE;
0139         return false;
0140     }
0141 
0142     m_returnCode = (*m_pDSMProc)(pOrigin, pDest, DG, DAT, MSG, pData);
0143 
0144     if (m_returnCode == TWRC_FAILURE) {
0145         saneDebug() << "CallTwainProc m_returnCode == TWRC_FAILURE";
0146         (*m_pDSMProc)(pOrigin, pDest, DG_CONTROL, DAT_STATUS, MSG_GET, &m_Status);
0147     }
0148     return (m_returnCode == TWRC_SUCCESS);
0149 }
0150 
0151 /** Called to display a dialog box to select the Twain source to use.
0152     This can be overridden if a list of all sources is available
0153     to the application. These sources can be enumerated by Twain.
0154     it is not yet supported by KSaneWidgetPrivate.
0155  */
0156 QString KSaneWidgetPrivate::SelectSource()
0157 {
0158     TW_IDENTITY src;
0159     memset(&src, 0, sizeof(src));
0160 
0161     // debug printouts
0162     //bool ret_ok = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETFIRST, &src);
0163     //while (ret_ok) {
0164     //    saneDebug() << QLatin1String(src.ProductName);
0165     //    ret_ok = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETNEXT, &src);
0166     //}
0167 
0168     // set the default entry selected
0169     CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETDEFAULT, &src);
0170 
0171     // now open the selection dialog
0172     if (!CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_USERSELECT, &src)) {
0173         return QString();
0174     }
0175 
0176     QString source;
0177     source += QLatin1String(src.ProductName);
0178     source += QLatin1Char(';');
0179     source += QLatin1String(src.ProductFamily);
0180     source += QLatin1Char(';');
0181     source += QLatin1String(src.Manufacturer);
0182     saneDebug()<< source;
0183     return source;
0184 }
0185 
0186 /** Closes the Data Source
0187  */
0188 void KSaneWidgetPrivate::CloseDS()
0189 {
0190     saneDebug() << "CloseDS";
0191     if (DSIsOpen()) {
0192         if (m_bSourceEnabled) {
0193             TW_USERINTERFACE twUI;
0194             if (CallTwainProc(&m_AppId, &m_Source, DG_CONTROL,
0195                               DAT_USERINTERFACE, MSG_DISABLEDS, &twUI)) {
0196                 m_bSourceEnabled = false;
0197             }
0198         }
0199         CallTwainProc(&m_AppId, NULL, DG_CONTROL,
0200                       DAT_IDENTITY, MSG_CLOSEDS, (TW_MEMREF)&m_Source);
0201         m_bDSOpen = false;
0202     }
0203 }
0204 
0205 /** Closes the Data Source Manager */
0206 void KSaneWidgetPrivate::CloseDSM()
0207 {
0208     saneDebug() << "CloseDSM";
0209     if (m_hTwainDLL && m_pDSMProc && m_bDSMOpen) {
0210         CloseDS();
0211         CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_PARENT, MSG_CLOSEDSM, (TW_MEMREF)&m_hMessageWnd);
0212         m_bDSMOpen = false;
0213     }
0214 }
0215 
0216 /** Returns true if the Data Source is Open */
0217 bool KSaneWidgetPrivate::DSIsOpen() const
0218 {
0219     saneDebug() << "DSOpen:" << m_hTwainDLL << m_pDSMProc << m_bDSMOpen << m_bDSOpen;
0220     return (m_hTwainDLL && m_pDSMProc) && m_bDSMOpen && m_bDSOpen;
0221 }
0222 
0223 /** Opens a Data Source */
0224 bool KSaneWidgetPrivate::OpenSource(const QString &source)
0225 {
0226     saneDebug() << "OpenSource:" << source;
0227     if (source.isEmpty()) {
0228         return false;
0229     }
0230 
0231     QStringList splited = source.split(QLatin1Char(';'));
0232     if (splited.size() != 3) {
0233         return false;
0234     }
0235 
0236     // go thorough the list and check if the source is available
0237     bool ret_ok = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETFIRST, &m_Source);
0238     while (ret_ok) {
0239         saneDebug() << m_Source.Id << m_Source.Version.MajorNum << m_Source.Version.MinorNum;
0240         saneDebug() << m_Source.Manufacturer << m_Source.ProductFamily << m_Source.ProductName;
0241         if (QLatin1String(m_Source.ProductName) == splited[0]) {
0242             break;
0243         }
0244         ret_ok = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_GETNEXT, &m_Source);
0245     }
0246 
0247     if (!ret_ok) {
0248         saneDebug() << "CallTwainProc failed when reading beyond the last source";
0249         // CallTwainProc failed when reading beyond the last source
0250         return false;
0251     }
0252 
0253     // open the source
0254     if (m_hTwainDLL && m_pDSMProc && m_bDSMOpen) {
0255         m_bDSOpen = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, (TW_MEMREF)&m_Source);
0256         saneDebug() << "OpenSource(qst..) m_bDSOpen" <<  m_bDSOpen;
0257     }
0258 
0259     SetImageCount(TWCPP_ANYCOUNT);
0260 
0261     return DSIsOpen();
0262 }
0263 
0264 /** Re-Opens a Data Source */
0265 bool KSaneWidgetPrivate::ReOpenDialog()
0266 {
0267     saneDebug() << "ReOpenSource:" << m_hTwainDLL << m_pDSMProc << m_bDSMOpen << m_bDSOpen;
0268 
0269     if (DSIsOpen()) {
0270         // already open
0271         return true;
0272     }
0273     // open the source
0274     if (m_hTwainDLL && m_pDSMProc && m_bDSMOpen) {
0275         m_bDSOpen = CallTwainProc(&m_AppId, NULL, DG_CONTROL, DAT_IDENTITY, MSG_OPENDS, (TW_MEMREF)&m_Source);
0276         //saneDebug() << "ReOpenSource() m_bDSOpen" <<  m_bDSOpen;
0277     }
0278 
0279     SetImageCount(TWCPP_ANYCOUNT);
0280 
0281     if (DSIsOpen()) {
0282         return EnableSource(true);
0283     }
0284     //else
0285     return false;
0286 }
0287 
0288 /** Should be called from the main message loop of the application. Can always be called,
0289     it will not process the message unless a scan is in progress. */
0290 bool KSaneWidgetPrivate::ProcessMessage(MSG msg)
0291 {
0292     // TODO: don't really know why...
0293     if (msg.message == 528) {
0294         return false;
0295     }
0296     if (msg.message == 289) {
0297         return false;
0298     }
0299 
0300     if (m_hMessageWnd == 0) {
0301         return false;
0302     }
0303 
0304     saneDebug() << "ProcessMessage:" << msg.message << m_bSourceEnabled;
0305 
0306     if (m_bSourceEnabled)  {
0307         TW_UINT16  twRC = TWRC_NOTDSEVENT;
0308 
0309         TW_EVENT twEvent;
0310         twEvent.pEvent = (TW_MEMREF)&msg;
0311         //memset(&twEvent, 0, sizeof(TW_EVENT));
0312         twEvent.TWMessage = MSG_NULL;
0313 
0314         CallTwainProc(&m_AppId, &m_Source, DG_CONTROL,
0315                       DAT_EVENT, MSG_PROCESSEVENT, (TW_MEMREF)&twEvent);
0316 
0317         saneDebug() << "ProcessMessage: retcode= " << m_returnCode;
0318         if (m_returnCode != TWRC_NOTDSEVENT) {
0319             TranslateMessage(twEvent);
0320         }
0321         return (twRC == TWRC_DSEVENT);
0322     }
0323     return false;
0324 }
0325 
0326 /** Queries the capability of the Twain Data Source */
0327 bool KSaneWidgetPrivate::GetCapability(TW_CAPABILITY &twCap, TW_UINT16 cap, TW_UINT16 conType)
0328 {
0329     saneDebug() << "GetCapability";
0330     if (DSIsOpen()) {
0331         twCap.Cap        = cap;
0332         twCap.ConType    = conType;
0333         twCap.hContainer = NULL;
0334 
0335         if (CallTwainProc(&m_AppId, &m_Source, DG_CONTROL,
0336                           DAT_CAPABILITY, MSG_GET, (TW_MEMREF)&twCap)) {
0337             return true;
0338         }
0339     }
0340     return false;
0341 }
0342 
0343 /** Queries the capability of the Twain Data Source */
0344 bool KSaneWidgetPrivate::GetCapability(TW_UINT16 cap, TW_UINT32 &value)
0345 {
0346     saneDebug() << "GetCapability2";
0347     TW_CAPABILITY twCap;
0348     if (GetCapability(twCap, cap)) {
0349         pTW_ONEVALUE pVal;
0350         pVal = (pTW_ONEVALUE)GlobalLock(twCap.hContainer);
0351 
0352         if (pVal) {
0353             value = pVal->Item;
0354             GlobalUnlock(pVal);
0355             GlobalFree(twCap.hContainer);
0356             return true;
0357         }
0358     }
0359     return false;
0360 }
0361 
0362 /** Sets the capability of the Twain Data Source */
0363 bool KSaneWidgetPrivate::SetCapability(TW_UINT16 cap, TW_UINT16 value, bool sign)
0364 {
0365     saneDebug() << "SetCapability";
0366     if (DSIsOpen()) {
0367         TW_CAPABILITY twCap;
0368         pTW_ONEVALUE pVal;
0369         bool ret_value   = false;
0370         twCap.Cap        = cap;
0371         twCap.ConType    = TWON_ONEVALUE;
0372         twCap.hContainer = GlobalAlloc(GHND, sizeof(TW_ONEVALUE));
0373 
0374         if (twCap.hContainer) {
0375             pVal           = (pTW_ONEVALUE)GlobalLock(twCap.hContainer);
0376             pVal->ItemType = sign ? TWTY_INT16 : TWTY_UINT16;
0377             pVal->Item     = (TW_UINT32)value;
0378             GlobalUnlock(twCap.hContainer);
0379             ret_value      = SetCapability(twCap);
0380             GlobalFree(twCap.hContainer);
0381         }
0382         return ret_value;
0383     }
0384     return false;
0385 }
0386 
0387 /** Sets the capability of the Twain Data Source */
0388 bool KSaneWidgetPrivate::SetCapability(TW_CAPABILITY &cap)
0389 {
0390     saneDebug() << "SetCapability2";
0391     if (DSIsOpen()) {
0392         return CallTwainProc(&m_AppId, &m_Source, DG_CONTROL,
0393                              DAT_CAPABILITY, MSG_SET, (TW_MEMREF)&cap);
0394     }
0395     return false;
0396 }
0397 
0398 /** Sets the number of images which can be accepted by the application at one time */
0399 bool KSaneWidgetPrivate::SetImageCount(TW_INT16 nCount)
0400 {
0401     saneDebug() << "SetImageCount" << nCount << (TW_UINT16)nCount;
0402     if (SetCapability(CAP_XFERCOUNT, (TW_UINT16)nCount, true)) {
0403         saneDebug() << "SetImageCount: nCount" << nCount;
0404         m_nImageCount = nCount;
0405         return true;
0406     } else {
0407         saneDebug() << "SetImageCount: failed:" << m_returnCode;
0408         if (m_returnCode == TWRC_CHECKSTATUS) {
0409             TW_UINT32 count;
0410 
0411             if (GetCapability(CAP_XFERCOUNT, count)) {
0412                 nCount = (TW_INT16)count;
0413 
0414                 if (SetCapability(CAP_XFERCOUNT, nCount)) {
0415                     m_nImageCount = nCount;
0416                     return true;
0417                 }
0418             }
0419         }
0420     }
0421     return false;
0422 }
0423 
0424 /** Called to enable the Twain Acquire Dialog. This too can be
0425  * overridden but is a helluva job. */
0426 bool KSaneWidgetPrivate::OpenDialog()
0427 {
0428     saneDebug() << "OpenDialog";
0429     EnableSource(true);
0430     return true;
0431 }
0432 
0433 /** Called to enable the Twain Acquire Dialog. This too can be
0434  * overridden but is a helluva job. */
0435 bool KSaneWidgetPrivate::EnableSource(bool showUI)
0436 {
0437     saneDebug() << "EnableSource: DSIsOpen() =" << DSIsOpen();
0438     if (DSIsOpen() && !m_bSourceEnabled) {
0439         TW_USERINTERFACE twUI;
0440         twUI.ShowUI  = showUI;
0441         twUI.hParent = (TW_HANDLE)m_hMessageWnd;
0442 
0443         if (CallTwainProc(&m_AppId, &m_Source, DG_CONTROL,
0444                           DAT_USERINTERFACE, MSG_ENABLEDS, (TW_MEMREF)&twUI)) {
0445             m_bSourceEnabled = true;
0446             m_bModalUI       = twUI.ModalUI;
0447         } else {
0448             m_bSourceEnabled = false;
0449             m_bModalUI       = true;
0450         }
0451         saneDebug() << "EnableSource: ModalUI=" << twUI.ModalUI << m_returnCode;
0452         return m_bSourceEnabled;
0453     }
0454     return false;
0455 }
0456 
0457 /** Called by ProcessMessage to Translate a TWAIN message */
0458 void KSaneWidgetPrivate::TranslateMessage(TW_EVENT &twEvent)
0459 {
0460     saneDebug() << "TranslateMessage: twEvent.TWMessage =" << twEvent.TWMessage;
0461     switch (twEvent.TWMessage) {
0462     case MSG_XFERREADY:
0463         saneDebug() << "MSG_XFERREADY";
0464         TransferImage();
0465         break;
0466 
0467     case MSG_CLOSEDSREQ:
0468         saneDebug() << "MSG_CLOSEDSREQ";
0469         CloseDS();
0470         break;
0471     }
0472 }
0473 
0474 /** Gets Imageinfo for an image which is about to be transferred. */
0475 bool KSaneWidgetPrivate::GetImageInfo(TW_IMAGEINFO &info)
0476 {
0477     saneDebug() << "GetImageInfo";
0478     if (m_bSourceEnabled) {
0479         return CallTwainProc(&m_AppId, &m_Source, DG_IMAGE,
0480                              DAT_IMAGEINFO, MSG_GET, (TW_MEMREF)&info);
0481     }
0482     return false;
0483 }
0484 
0485 /** Transfers the image or cancels the transfer depending on the state of the TWAIN system */
0486 void KSaneWidgetPrivate::TransferImage()
0487 {
0488     saneDebug() << "TransferImage()";
0489     TW_IMAGEINFO info;
0490     bool bContinue = true;
0491 
0492     while (bContinue) {
0493         if (GetImageInfo(info)) {
0494             int permission = TWCPP_DOTRANSFER;
0495 
0496             switch (permission) {
0497             case TWCPP_CANCELTHIS:
0498                 bContinue = EndTransfer();
0499                 break;
0500 
0501             case TWCPP_CANCELALL:
0502                 CancelTransfer();
0503                 bContinue = false;
0504                 break;
0505 
0506             case TWCPP_DOTRANSFER:
0507                 bContinue = GetImage(info);
0508                 break;
0509             }
0510         }
0511     }
0512 }
0513 
0514 /** Ends the current transfer.
0515     Returns true if the more images are pending */
0516 bool KSaneWidgetPrivate::EndTransfer()
0517 {
0518     saneDebug() << "EndTransfer";
0519     TW_PENDINGXFERS twPend;
0520     if (CallTwainProc(&m_AppId, &m_Source, DG_CONTROL,
0521                       DAT_PENDINGXFERS, MSG_ENDXFER, (TW_MEMREF)&twPend)) {
0522         return twPend.Count != 0;
0523     }
0524     return false;
0525 }
0526 
0527 /** Aborts all transfers */
0528 void KSaneWidgetPrivate::CancelTransfer()
0529 {
0530     saneDebug() << "CancelTransfer";
0531     TW_PENDINGXFERS twPend;
0532     CallTwainProc(&m_AppId, &m_Source, DG_CONTROL, DAT_PENDINGXFERS, MSG_RESET, (TW_MEMREF)&twPend);
0533 }
0534 
0535 /** Calls TWAIN to actually get the image */
0536 bool KSaneWidgetPrivate::GetImage(TW_IMAGEINFO &info)
0537 {
0538     saneDebug() << "GetImage";
0539     TW_MEMREF pdata;
0540     CallTwainProc(&m_AppId, &m_Source, DG_IMAGE, DAT_IMAGENATIVEXFER, MSG_GET, &pdata);
0541 
0542     switch (m_returnCode) {
0543     case TWRC_XFERDONE:
0544         saneDebug()<< "GetImage:TWRC_XFERDONE";
0545         ImageData(pdata, info);
0546         break;
0547 
0548     case TWRC_CANCEL:
0549         saneDebug()<< "GetImage:TWRC_CANCEL";
0550         break;
0551 
0552     case TWRC_FAILURE:
0553         saneDebug()<< "GetImage:TWRC_FAILURE";
0554         CancelTransfer();
0555         return false;
0556         break;
0557 
0558     default:
0559         saneDebug()<< "GetImage:" << m_returnCode;
0560     }
0561 
0562     GlobalFree(pdata);
0563     return EndTransfer();
0564 }
0565 
0566 void KSaneWidgetPrivate::ImageData(TW_MEMREF pdata, TW_IMAGEINFO &info)
0567 {
0568     saneDebug() << "ImageData";
0569     if (pdata && (info.ImageWidth != -1) && (info.ImageLength != - 1)) {
0570         // Under Windows, Twain interface return a DIB data structure.
0571         // See http://en.wikipedia.org/wiki/Device-independent_bitmap#DIBs_in_memory for details.
0572         HGLOBAL hDIB     = (HGLOBAL)(qptrdiff)pdata;
0573         int size         = (int)GlobalSize(hDIB);
0574         const char *bits = (const char *)GlobalLock(hDIB);
0575 
0576         // DIB is BMP without header. we will add it to load data in QImage using std loader from Qt.
0577         QByteArray baBmp;
0578         QDataStream ds(&baBmp, QIODevice::WriteOnly);
0579 
0580         ds.writeRawData("BM", 2);
0581 
0582         qint32 filesize = size + 14;
0583         ds << filesize;
0584 
0585         qint16 reserved = 0;
0586         ds << reserved;
0587         ds << reserved;
0588 
0589         qint32 pixOffset = 14 + 40 + 0;
0590         ds << pixOffset;
0591 
0592         ds.writeRawData(bits, size);
0593 
0594         Q_EMIT ImageReady(baBmp, 0, 0, 0, (int)KSaneWidget::FormatBMP);
0595         Q_EMIT qImageReady(QImage::fromData(baBmp, "BMP"));
0596 
0597         GlobalUnlock(hDIB);
0598 
0599     }
0600 }
0601 
0602 }
0603 
0604 #include "moc_twainiface.cpp"