File indexing completed on 2025-01-19 12:59:18
0001 /************************************************************************ 0002 * * 0003 * This file is part of Kooka, a scanning/OCR application using * 0004 * Qt <http://www.qt.io> and KDE Frameworks <http://www.kde.org>. * 0005 * * 0006 * Copyright (C) 1999-2016 Klaas Freitag <freitag@suse.de> * 0007 * Jonathan Marten <jjm@keelhaul.me.uk> * 0008 * * 0009 * Kooka is free software; you can redistribute it and/or modify it * 0010 * under the terms of the GNU Library General Public License as * 0011 * published by the Free Software Foundation and appearing in the * 0012 * file COPYING included in the packaging of this file; either * 0013 * version 2 of the License, or (at your option) any later version. * 0014 * * 0015 * As a special exception, permission is given to link this program * 0016 * with any version of the KADMOS OCR/ICR engine (a product of * 0017 * reRecognition GmbH, Kreuzlingen), and distribute the resulting * 0018 * executable without including the source code for KADMOS in the * 0019 * source distribution. * 0020 * * 0021 * This program is distributed in the hope that it will be useful, * 0022 * but WITHOUT ANY WARRANTY; without even the implied warranty of * 0023 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * 0024 * GNU General Public License for more details. * 0025 * * 0026 * You should have received a copy of the GNU General Public * 0027 * License along with this program; see the file COPYING. If * 0028 * not, see <http://www.gnu.org/licenses/>. * 0029 * * 0030 ************************************************************************/ 0031 0032 #include "kscandevice.h" 0033 0034 #include <qimage.h> 0035 #include <qfileinfo.h> 0036 #include <qapplication.h> 0037 #include <qsocketnotifier.h> 0038 #include <qstandardpaths.h> 0039 0040 #include <klocalizedstring.h> 0041 #include <kconfig.h> 0042 #include <kpassworddialog.h> 0043 0044 #include "scanglobal.h" 0045 #include "scandevices.h" 0046 #include "kgammatable.h" 0047 #include "kscancontrols.h" 0048 #include "kscanoption.h" 0049 #include "kscanoptset.h" 0050 #include "deviceselector.h" 0051 #include "scansettings.h" 0052 #include "libkookascan_logging.h" 0053 0054 extern "C" { 0055 #include <sane/saneopts.h> 0056 } 0057 0058 #define MIN_PREVIEW_DPI 75 0059 #define MAX_PROGRESS 100 0060 0061 0062 // Debugging options 0063 #define DEBUG_OPTIONS 0064 #undef DEBUG_RELOAD 0065 #undef DEBUG_CREATE 0066 #define DEBUG_PARAMS 0067 0068 #ifdef DEBUG_OPTIONS 0069 #include <iostream> 0070 #endif // DEBUG_OPTIONS 0071 0072 0073 // Accessing GUI options 0074 // --------------------- 0075 0076 // Used only by ScanParams::slotVirtScanModeSelect() 0077 void KScanDevice::guiSetEnabled(const QByteArray &name, bool state) 0078 { 0079 KScanOption *so = getExistingGuiElement(name); 0080 if (so==nullptr) return; 0081 0082 QWidget *w = so->widget(); 0083 if (w==nullptr) return; 0084 0085 w->setEnabled(state && so->isSoftwareSettable()); 0086 } 0087 0088 0089 KScanOption *KScanDevice::getOption(const QByteArray &name, bool create) 0090 { 0091 QByteArray alias = aliasName(name); 0092 0093 if (mCreatedOptions.contains(alias)) 0094 { 0095 #ifdef DEBUG_CREATE 0096 qCDebug(LIBKOOKASCAN_LOG) << "already exists" << alias; 0097 #endif // DEBUG_CREATE 0098 return (mCreatedOptions.value(alias)); 0099 } 0100 0101 if (!create) 0102 { 0103 #ifdef DEBUG_CREATE 0104 qCDebug(LIBKOOKASCAN_LOG) << "does not exist" << alias; 0105 #endif // DEBUG_CREATE 0106 return (nullptr); 0107 } 0108 0109 #ifdef DEBUG_CREATE 0110 qCDebug(LIBKOOKASCAN_LOG) << "creating new" << alias; 0111 #endif // DEBUG_CREATE 0112 KScanOption *so = new KScanOption(alias, this); 0113 mCreatedOptions.insert(alias, so); 0114 return (so); 0115 } 0116 0117 0118 KScanOption *KScanDevice::getExistingGuiElement(const QByteArray &name) const 0119 { 0120 KScanOption *ret = nullptr; 0121 QByteArray alias = aliasName(name); 0122 0123 for (OptionHash::const_iterator it = mCreatedOptions.constBegin(); 0124 it!=mCreatedOptions.constEnd(); ++it) 0125 { 0126 KScanOption *opt = it.value(); 0127 if (opt->isGuiElement() && opt->getName()==alias) 0128 { 0129 ret = opt; 0130 break; 0131 } 0132 } 0133 0134 return (ret); 0135 } 0136 0137 0138 KScanOption *KScanDevice::getGuiElement(const QByteArray &name, QWidget *parent) 0139 { 0140 if (name.isEmpty()) return (nullptr); 0141 if (!optionExists(name)) return (nullptr); 0142 0143 //qCDebug(LIBKOOKASCAN_LOG) << "for" << name; 0144 0145 KScanOption *so = getExistingGuiElement(name); // see if already exists 0146 if (so!=nullptr) return (so); // if so, just return that 0147 0148 so = getOption(name); // create a new scan option 0149 if (so->isValid()) // option was created 0150 { 0151 QWidget *w = so->createWidget(parent); // create widget for option 0152 if (w!=nullptr) w->setEnabled(so->isActive() && so->isSoftwareSettable()); 0153 else qCDebug(LIBKOOKASCAN_LOG) << "no widget created for" << name; 0154 } 0155 else // option not valid 0156 { // (not known by scanner?) 0157 qCDebug(LIBKOOKASCAN_LOG) << "option invalid" << name; 0158 so = nullptr; 0159 } 0160 0161 return (so); 0162 } 0163 0164 0165 // Constructor & destructor 0166 // ------------------------ 0167 0168 KScanDevice::KScanDevice(QObject *parent) 0169 : QObject(parent) 0170 { 0171 qCDebug(LIBKOOKASCAN_LOG); 0172 0173 ScanGlobal::self()->init(); // do sane_init() first of all 0174 0175 mScannerHandle = nullptr; 0176 mScannerInitialised = false; // is device opened yet? 0177 mScannerName = ""; 0178 0179 mScanningState = KScanDevice::ScanIdle; 0180 0181 mScanBuf = nullptr; // image data buffer while scanning 0182 mScanImage.clear(); // temporary image to scan into 0183 mTestFormat = ScanImage::None; // format deduced from scan 0184 0185 mSocketNotifier = nullptr; // socket notifier for async scanning 0186 0187 mBytesRead = 0; 0188 mBytesUsed = 0; 0189 mPixelX = 0; 0190 mPixelY = 0; 0191 } 0192 0193 0194 KScanDevice::~KScanDevice() 0195 { 0196 // TODO: need to check and do closeDevice() here? 0197 ScanGlobal::self()->setScanDevice(nullptr); // going away, don't call me 0198 0199 qCDebug(LIBKOOKASCAN_LOG) << "done"; 0200 } 0201 0202 0203 // Opening/closing the scanner device 0204 // ---------------------------------- 0205 0206 KScanDevice::Status KScanDevice::openDevice(const QByteArray &backend) 0207 { 0208 KScanDevice::Status stat = KScanDevice::Ok; 0209 0210 qCDebug(LIBKOOKASCAN_LOG) << "backend" << backend; 0211 0212 mSaneStatus = SANE_STATUS_UNSUPPORTED; 0213 if (backend.isEmpty()) return (KScanDevice::ParamError); 0214 0215 // search for scanner 0216 if (ScanDevices::self()->deviceInfo(backend)==nullptr) return (KScanDevice::NoDevice); 0217 0218 mScannerName = backend; // set now for authentication 0219 QApplication::setOverrideCursor(Qt::WaitCursor); // potential lengthy operation 0220 ScanGlobal::self()->setScanDevice(this); // for possible authentication 0221 mSaneStatus = sane_open(backend.constData(), &mScannerHandle); 0222 0223 if (mSaneStatus==SANE_STATUS_ACCESS_DENIED) // authentication failed? 0224 { 0225 clearSavedAuth(); // clear any saved password 0226 qCDebug(LIBKOOKASCAN_LOG) << "retrying authentication"; // try again once more 0227 mSaneStatus = sane_open(backend.constData(), &mScannerHandle); 0228 } 0229 0230 if (mSaneStatus==SANE_STATUS_GOOD) 0231 { 0232 stat = findOptions(); // fill dictionary with options 0233 mScannerInitialised = true; // note scanner opened OK 0234 } 0235 else 0236 { 0237 stat = KScanDevice::OpenDevice; 0238 mScannerName = ""; 0239 } 0240 0241 QApplication::restoreOverrideCursor(); 0242 return (stat); 0243 } 0244 0245 0246 void KScanDevice::closeDevice() 0247 { 0248 emit sigCloseDevice(); // tell callers we're closing 0249 0250 //qCDebug(LIBKOOKASCAN_LOG) << "Saving default scan settings"; 0251 saveStartupConfig(); // save config for next startup 0252 0253 if (mScannerHandle!=nullptr) 0254 { 0255 if (mScanningState!=KScanDevice::ScanIdle) 0256 { 0257 qCDebug(LIBKOOKASCAN_LOG) << "Scanner is still active, calling sane_cancel()"; 0258 sane_cancel(mScannerHandle); 0259 } 0260 sane_close(mScannerHandle); // close the SANE device 0261 mScannerHandle = nullptr; // scanner no longer open 0262 } 0263 0264 // clear lists of options 0265 QList<KScanOption *> opts = mCreatedOptions.values(); 0266 while (!opts.isEmpty()) delete opts.takeFirst(); 0267 mCreatedOptions.clear(); 0268 mKnownOptions.clear(); 0269 0270 mScannerName = ""; 0271 mScannerInitialised = false; 0272 } 0273 0274 0275 // Scanner and image information 0276 // ----------------------------- 0277 0278 QString KScanDevice::scannerDescription() const 0279 { 0280 QString ret; 0281 0282 if (!mScannerName.isNull() && mScannerInitialised) 0283 { 0284 ret = ScanDevices::self()->deviceDescription(mScannerName); 0285 } 0286 else 0287 { 0288 ret = i18n("No scanner selected"); 0289 } 0290 0291 return (ret); 0292 } 0293 0294 0295 QSize KScanDevice::getMaxScanSize() 0296 { 0297 QSize s; 0298 double min, max; 0299 0300 KScanOption *so_w = getOption(SANE_NAME_SCAN_BR_X); 0301 so_w->getRange(&min, &max); 0302 s.setWidth(static_cast<int>(max)); 0303 0304 KScanOption *so_h = getOption(SANE_NAME_SCAN_BR_Y); 0305 so_h->getRange(&min, &max); 0306 s.setHeight(static_cast<int>(max)); 0307 0308 return (s); 0309 } 0310 0311 0312 void KScanDevice::getCurrentFormat(int *format, int *depth) 0313 { 0314 sane_get_parameters(mScannerHandle, &mSaneParameters); 0315 *format = mSaneParameters.format; 0316 *depth = mSaneParameters.depth; 0317 } 0318 0319 0320 // Listing the available options 0321 // ----------------------------- 0322 0323 KScanDevice::Status KScanDevice::findOptions() 0324 { 0325 SANE_Int n; 0326 SANE_Int opt; 0327 0328 if (sane_control_option(mScannerHandle, 0, SANE_ACTION_GET_VALUE, 0329 &n, &opt)!=SANE_STATUS_GOOD) 0330 { 0331 qCWarning(LIBKOOKASCAN_LOG) << "cannot read option 0 (count)"; 0332 return (KScanDevice::ControlError); 0333 } 0334 0335 mKnownOptions.clear(); 0336 for (int i = 1; i<n; i++) 0337 { 0338 const SANE_Option_Descriptor *d = sane_get_option_descriptor(mScannerHandle, i); 0339 if (d==nullptr) continue; // could not get descriptor 0340 0341 QByteArray name; 0342 if (d->name!=nullptr && strlen(d->name)>0) name = d->name; 0343 0344 if (d->type==SANE_TYPE_GROUP) // option is a group, 0345 { // give it a dummy name 0346 name = "group-"; 0347 name += QByteArray::number(i); 0348 } 0349 0350 if (!name.isEmpty()) // must now have a name 0351 { 0352 #ifdef DEBUG_OPTIONS 0353 qCDebug(LIBKOOKASCAN_LOG) << "Option" << i << "is" << name; 0354 #endif // DEBUG_OPTIONS 0355 mKnownOptions.insert(i, name); 0356 } 0357 else qCWarning(LIBKOOKASCAN_LOG) << "Invalid option" << i << "(no name and not a group)"; 0358 } 0359 0360 return (KScanDevice::Ok); 0361 } 0362 0363 0364 QList<QByteArray> KScanDevice::getAllOptions() const 0365 { 0366 return (mKnownOptions.values()); 0367 } 0368 0369 0370 QList<QByteArray> KScanDevice::getCommonOptions() const 0371 { 0372 QList<QByteArray> opts; 0373 0374 for (OptionHash::const_iterator it = mCreatedOptions.constBegin(); 0375 it!=mCreatedOptions.constEnd(); ++it) 0376 { 0377 KScanOption *so = it.value(); 0378 if (so->isCommonOption()) opts.append(it.key()); 0379 } 0380 0381 return (opts); 0382 } 0383 0384 0385 QList<QByteArray> KScanDevice::getAdvancedOptions() const 0386 { 0387 QList<QByteArray> opts; 0388 0389 for (OptionHash::const_iterator it = mCreatedOptions.constBegin(); 0390 it!=mCreatedOptions.constEnd(); ++it) 0391 { 0392 KScanOption *so = it.value(); 0393 if (!so->isCommonOption()) opts.append(it.key()); 0394 } 0395 0396 return (opts); 0397 } 0398 0399 0400 // Controlling options 0401 // ------------------- 0402 0403 int KScanDevice::getOptionIndex(const QByteArray &name) const 0404 { 0405 return (mKnownOptions.key(name)); 0406 } 0407 0408 0409 bool KScanDevice::optionExists(const QByteArray &name) const 0410 { 0411 if (name.isEmpty()) return (false); 0412 QByteArray alias = aliasName(name); 0413 return (mKnownOptions.key(alias)!=0); 0414 } 0415 0416 0417 /* This function tries to find name aliases which appear from backend to backend. 0418 * Example: Custom-Gamma is for epson backends 'gamma-correction' - not a really 0419 * cool thing :-| 0420 * Maybe this helps us out ? 0421 */ 0422 QByteArray KScanDevice::aliasName( const QByteArray& name ) const 0423 { 0424 if (mCreatedOptions.contains(name)) return (name); 0425 0426 QByteArray ret = name; 0427 if (name == SANE_NAME_CUSTOM_GAMMA) 0428 { 0429 if (mCreatedOptions.contains("gamma-correction")) ret = "gamma-correction"; 0430 } 0431 0432 if (ret!=name) qCDebug(LIBKOOKASCAN_LOG) << "Found alias for" << name << "which is" << ret; 0433 return (ret); 0434 } 0435 0436 0437 void KScanDevice::applyOption(KScanOption *opt) 0438 { 0439 bool reload = true; // is a reload needed? 0440 0441 if (opt!=nullptr) // an option is specified 0442 { 0443 #ifdef DEBUG_RELOAD 0444 qCDebug(LIBKOOKASCAN_LOG) << "option" << opt->getName(); 0445 #endif // DEBUG_APPLY 0446 reload = opt->apply(); // apply this option 0447 } 0448 0449 if (!reload) // need to reload now? 0450 { 0451 #ifdef DEBUG_RELOAD 0452 qCDebug(LIBKOOKASCAN_LOG) << "Reload of others not needed"; 0453 #endif // DEBUG_RELOAD 0454 return; 0455 } 0456 // reload of all others needed 0457 for (OptionHash::const_iterator it = mCreatedOptions.constBegin(); 0458 it!=mCreatedOptions.constEnd(); ++it) 0459 { 0460 KScanOption *so = it.value(); 0461 if (!so->isGuiElement()) continue; 0462 if (opt==nullptr || so!=opt) 0463 { 0464 #ifdef DEBUG_RELOAD 0465 qCDebug(LIBKOOKASCAN_LOG) << "Reloading" << so->getName(); 0466 #endif // DEBUG_RELOAD 0467 so->reload(); 0468 so->redrawWidget(); 0469 } 0470 } 0471 0472 #ifdef DEBUG_RELOAD 0473 qCDebug(LIBKOOKASCAN_LOG) << "Finished"; 0474 #endif // DEBUG_RELOAD 0475 } 0476 0477 0478 void KScanDevice::reloadAllOptions() 0479 { 0480 #ifdef DEBUG_RELOAD 0481 qCDebug(LIBKOOKASCAN_LOG); 0482 #endif // DEBUG_RELOAD 0483 applyOption(nullptr); 0484 } 0485 0486 0487 // Scanning control 0488 // ---------------- 0489 0490 void KScanDevice::slotStopScanning() 0491 { 0492 qCDebug(LIBKOOKASCAN_LOG); 0493 mScanningState = KScanDevice::ScanStopNow; 0494 } 0495 0496 0497 // Preview image 0498 // ------------- 0499 0500 const QString KScanDevice::previewFile() const 0501 { 0502 // TODO: this doesn't work if that directory doesn't exist, 0503 // and nothing ever creates that directory! 0504 // 0505 // Do we want this feature to work? 0506 // If so, create the directory in savePreviewImage() below 0507 QString dir = QStandardPaths::writableLocation(QStandardPaths::AppDataLocation)+"/previews/"; 0508 QString sname(scannerDescription()); 0509 sname.replace('/', "_"); 0510 return (dir+sname); 0511 } 0512 0513 0514 QImage KScanDevice::loadPreviewImage() const 0515 { 0516 const QString prevFile = previewFile(); 0517 qCDebug(LIBKOOKASCAN_LOG) << "Loading preview from" << prevFile; 0518 return (QImage(prevFile)); 0519 } 0520 0521 0522 // TODO: take a ScanImage::Ptr 0523 bool KScanDevice::savePreviewImage(const QImage &image) const 0524 { 0525 if (image.isNull()) return (false); 0526 0527 const QString prevFile = previewFile(); 0528 qCDebug(LIBKOOKASCAN_LOG) << "Saving preview to" << prevFile; 0529 return (image.save(prevFile, "BMP")); 0530 } 0531 0532 0533 // Displaying scan options 0534 // ----------------------- 0535 // 0536 // For debugging. Originally showOptions() was called prepareScan() and had 0537 // the comment: 0538 // 0539 // prepareScan tries to set as much as parameters as possible. 0540 // 0541 // Function which applies all Options which need to be applied. 0542 // See SANE-Documentation Table 4.5, description for SANE_CAP_SOFT_DETECT. 0543 // The function sets the options which have SANE_CAP_AUTOMATIC set 0544 // to automatic adjust. 0545 // 0546 // But this wasn't true - it only reports the current state of the options. 0547 0548 #ifdef DEBUG_OPTIONS 0549 0550 inline const char *optionNotifyString(int opt) 0551 { 0552 return (opt!=0 ? " X |" : " - |"); 0553 } 0554 0555 0556 void KScanDevice::showOptions() 0557 { 0558 qCDebug(LIBKOOKASCAN_LOG) << "for" << mScannerName; 0559 std::cerr << "----------------------------------+---+---+---+---+---+---+---+---+-------" << std::endl; 0560 std::cerr << " Option |SSL|HSL|SDT|EMU|AUT|INA|ADV|PRI| Value" << std::endl; 0561 std::cerr << "----------------------------------+---+---+---+---+---+---+---+---+-------" << std::endl; 0562 0563 QList<QByteArray> optionNames = mCreatedOptions.keys(); 0564 std::sort(optionNames.begin(), optionNames.end()); 0565 for (QList<QByteArray>::const_iterator it = optionNames.constBegin(); 0566 it!=optionNames.constEnd(); ++it) 0567 { 0568 QByteArray optionName = (*it); 0569 const KScanOption *so = mCreatedOptions.value(optionName); 0570 if (so->isGroup()) continue; 0571 0572 int cap = so->getCapabilities(); 0573 std::cerr << 0574 " " << qPrintable(optionName.left(31).leftJustified(32)) << " |" << 0575 optionNotifyString((cap & SANE_CAP_SOFT_SELECT)) << 0576 optionNotifyString((cap & SANE_CAP_HARD_SELECT)) << 0577 optionNotifyString((cap & SANE_CAP_SOFT_DETECT)) << 0578 optionNotifyString((cap & SANE_CAP_EMULATED)) << 0579 optionNotifyString((cap & SANE_CAP_AUTOMATIC)) << 0580 optionNotifyString((cap & SANE_CAP_INACTIVE)) << 0581 optionNotifyString((cap & SANE_CAP_ADVANCED)) << 0582 optionNotifyString(so->isPriorityOption()) << 0583 " " << qPrintable(so->get()) << std::endl; 0584 } 0585 std::cerr << "----------------------------------+---+---+---+---+---+---+---+---+-------" << std::endl; 0586 } 0587 0588 #endif // DEBUG_OPTIONS 0589 0590 0591 // ------------------------------------------------ 0592 0593 // Deduce the scanned image type from the SANE parameters. 0594 // The logic is very similar to ScanImage::imageType(), 0595 // except that the image type cannot be LowColour. 0596 static ScanImage::ImageType getImageFormat(const SANE_Parameters *p) 0597 { 0598 if (p==nullptr) return (ScanImage::None); 0599 0600 if (p->depth==1) // Line art (bitmap) 0601 { 0602 return (ScanImage::BlackWhite); 0603 } 0604 else if (p->depth==8) // 8 bit RGB 0605 { 0606 if (p->format==SANE_FRAME_GRAY) // Grey scale 0607 { 0608 return (ScanImage::Greyscale); 0609 } 0610 else // True colour 0611 { 0612 return (ScanImage::HighColour); 0613 } 0614 } 0615 else // Error, no others supported 0616 { 0617 qCWarning(LIBKOOKASCAN_LOG) << "Only bit depths 1 or 8 supported!"; 0618 return (ScanImage::None); 0619 } 0620 } 0621 0622 0623 // Create a new image to receive the scan or preview 0624 KScanDevice::Status KScanDevice::createNewImage(const SANE_Parameters *p) 0625 { 0626 QImage::Format fmt; 0627 ScanImage::ImageType itype = getImageFormat(p); // what format should this be? 0628 switch (itype) // choose QImage option for that 0629 { 0630 default: 0631 case ScanImage::None: return (KScanDevice::ParamError); 0632 case ScanImage::BlackWhite: fmt = QImage::Format_Mono; break; 0633 case ScanImage::Greyscale: fmt = QImage::Format_Indexed8; break; 0634 case ScanImage::HighColour: fmt = QImage::Format_RGB32; break; 0635 } 0636 0637 // mScanImage is the master allocated image for the result of the scan. 0638 // Once the QSharedPointer has been reset() to point to the image, it 0639 // must only be copied or passed around using the QSharedPointer. The 0640 // image will automatically be deleted when the last QSharedPointer to 0641 // it is clear()'ed or destroyed. 0642 // 0643 // An image can also be allocated in acquireScan() in virtual scanner 0644 // mode. The same restriction applies. 0645 ScanImage *newImage = new ScanImage(p->pixels_per_line, p->lines, fmt); 0646 if (newImage==nullptr) return (KScanDevice::NoMemory); 0647 0648 mScanImage.clear(); // remove reference to previous 0649 mScanImage.reset(newImage); // capture the new image pointer 0650 mScanImage->setImageType(itype); // remember the image format 0651 0652 if (itype==ScanImage::BlackWhite) // line art (bitmap) 0653 { 0654 mScanImage->setColor(0,qRgb(0x00,0x00,0x00)); // set black/white palette 0655 mScanImage->setColor(1,qRgb(0xFF,0xFF,0xFF)); 0656 } 0657 else if (itype==ScanImage::Greyscale) // 8 bit grey 0658 { // set grey scale palette 0659 for (int i = 0; i<256; i++) mScanImage->setColor(i,qRgb(i,i,i)); 0660 } 0661 0662 return (KScanDevice::Ok); 0663 } 0664 0665 0666 // Acquiring preview/scan image 0667 // ---------------------------- 0668 0669 KScanDevice::Status KScanDevice::acquirePreview(bool forceGray, int dpi) 0670 { 0671 KScanOptSet savedOptions("SavedForPreview"); 0672 0673 /* set Preview = ON if exists */ 0674 KScanOption *prev = getOption(SANE_NAME_PREVIEW, false); 0675 if (prev!=nullptr) 0676 { 0677 prev->set(true); 0678 prev->apply(); 0679 prev->set(false); // Ensure that it gets restored 0680 savedOptions.backupOption(prev); // back to 'false' after previewing 0681 } 0682 0683 // TODO: this block doesn't make sense (set the option to true if 0684 // it is already true?) 0685 /* Gray-Preview only done by widget? */ 0686 KScanOption *so = getOption(SANE_NAME_GRAY_PREVIEW, false); 0687 if (so!=nullptr) 0688 { 0689 if (so->get()=="true") 0690 { 0691 /* Gray preview on */ 0692 so->set(true); 0693 qCDebug(LIBKOOKASCAN_LOG) << "Setting GrayPreview ON"; 0694 } 0695 else 0696 { 0697 so->set(false); 0698 qCDebug(LIBKOOKASCAN_LOG) << "Setting GrayPreview OFF"; 0699 } 0700 so->apply(); 0701 } 0702 0703 KScanOption *mode = getOption(SANE_NAME_SCAN_MODE, false); 0704 if (mode!=nullptr) 0705 { 0706 qCDebug(LIBKOOKASCAN_LOG) << "Scan mode before preview is" << mode->get(); 0707 savedOptions.backupOption(mode); 0708 /* apply if it has a widget, or apply always? */ 0709 if (mode->isGuiElement()) mode->apply(); 0710 } 0711 0712 /* Some sort of Scan Resolution option should always exist */ 0713 KScanOption *xres = getOption(SANE_NAME_SCAN_X_RESOLUTION, false); 0714 if (xres==nullptr) xres = getOption(SANE_NAME_SCAN_RESOLUTION, false); 0715 if (xres!=nullptr) 0716 { 0717 qCDebug(LIBKOOKASCAN_LOG) << "Scan resolution before preview is" << xres->get(); 0718 savedOptions.backupOption(xres); 0719 0720 int preview_dpi = dpi; 0721 if (dpi==0) // preview DPI not specified 0722 { 0723 double min, max; 0724 if (!xres->getRange(&min, &max)) 0725 { 0726 qCDebug(LIBKOOKASCAN_LOG) << "Could not retrieve resolution range!"; 0727 min = 75.0; // hope every scanner can do this 0728 } 0729 0730 preview_dpi = (int) min; 0731 if (preview_dpi<MIN_PREVIEW_DPI) preview_dpi = MIN_PREVIEW_DPI; 0732 qCDebug(LIBKOOKASCAN_LOG) << "Resolution range" << min << "-" << max << "preview at" << preview_dpi; 0733 } 0734 0735 KScanOption *yres = getOption(SANE_NAME_SCAN_Y_RESOLUTION, false); 0736 if (yres!=nullptr) 0737 { 0738 /* if active ? */ 0739 savedOptions.backupOption(yres); 0740 yres->set(preview_dpi); 0741 yres->apply(); 0742 yres->get(&mCurrScanResolutionY); 0743 } 0744 else mCurrScanResolutionY = 0; 0745 0746 /* Resolution bind switch? */ 0747 KScanOption *bind = getOption(SANE_NAME_RESOLUTION_BIND, false); 0748 if (bind!=nullptr) 0749 { 0750 /* Switch binding on if available */ 0751 savedOptions.backupOption(bind); 0752 bind->set(true); 0753 bind->apply(); 0754 } 0755 0756 xres->set(preview_dpi); 0757 xres->apply(); 0758 0759 /* Store the resulting preview for additional image information */ 0760 xres->get(&mCurrScanResolutionX); 0761 if (mCurrScanResolutionY==0) mCurrScanResolutionY = mCurrScanResolutionX; 0762 } 0763 0764 KScanDevice::Status status = acquireData(true); // perform the preview 0765 loadOptionSet(&savedOptions); // restore original scan settings 0766 return (status); 0767 } 0768 0769 0770 void KScanDevice::applyAllOptions(bool prio) 0771 { 0772 for (OptionHash::const_iterator it = mCreatedOptions.constBegin(); 0773 it!=mCreatedOptions.constEnd(); ++it) 0774 { 0775 KScanOption *so = it.value(); 0776 if (!so->isGuiElement()) continue; 0777 if (so->isPriorityOption() ^ prio) continue; 0778 if (so->isActive() && so->isSoftwareSettable()) so->apply(); 0779 } 0780 } 0781 0782 0783 /* Starts scanning 0784 * depending on if a filename is given or not, the function tries to open 0785 * the file using the Qt-Image-IO or really scans the image. 0786 */ 0787 KScanDevice::Status KScanDevice::acquireScan(const QString &filename) 0788 { 0789 if (filename.isEmpty()) // real scan 0790 { 0791 applyAllOptions(true); // apply priority options 0792 applyAllOptions(false); // apply non-priority options 0793 0794 // Some scanners seem to forget the scan area options after certain 0795 // other options have been applied (which means that they should be 0796 // considered to be priority options or flagged as 'reload', but this 0797 // is not always the case). The area options do not get applied above 0798 // because they will have already been applied (so their KScanOption's 0799 // are clean) when the scan area is selected. Ensure that they are 0800 // applied after all other options. 0801 // 0802 // Seen with the HP OfficeJet 8610 via HPLIP. 0803 KScanOption *opt; 0804 opt = getOption(SANE_NAME_SCAN_TL_X, false); if (opt!=nullptr) opt->apply(); 0805 opt = getOption(SANE_NAME_SCAN_TL_Y, false); if (opt!=nullptr) opt->apply(); 0806 opt = getOption(SANE_NAME_SCAN_BR_X, false); if (opt!=nullptr) opt->apply(); 0807 opt = getOption(SANE_NAME_SCAN_BR_Y, false); if (opt!=nullptr) opt->apply(); 0808 0809 // One of the Scan Resolution parameters should always exist. 0810 KScanOption *xres = getOption(SANE_NAME_SCAN_X_RESOLUTION, false); 0811 if (xres==nullptr) xres = getOption(SANE_NAME_SCAN_RESOLUTION, false); 0812 if (xres!=nullptr) 0813 { 0814 xres->get(&mCurrScanResolutionX); 0815 0816 KScanOption *yres = getOption(SANE_NAME_SCAN_Y_RESOLUTION, false); 0817 if (yres!=nullptr) yres->get(&mCurrScanResolutionY); 0818 else mCurrScanResolutionY = mCurrScanResolutionX; 0819 } 0820 0821 return (acquireData(false)); // perform the scan 0822 } 0823 else // virtual scan from image file 0824 { 0825 QFileInfo file(filename); 0826 if (!file.exists()) 0827 { 0828 qCWarning(LIBKOOKASCAN_LOG) << "virtual file" << filename << "does not exist"; 0829 return (KScanDevice::ParamError); 0830 } 0831 0832 QImage img(filename); 0833 if (img.isNull()) 0834 { 0835 qCWarning(LIBKOOKASCAN_LOG) << "virtual file" << filename << "could not load"; 0836 return (KScanDevice::ParamError); 0837 } 0838 0839 // See createNewImage() for further information regarding the 0840 // allocated image and shared pointer. 0841 ScanImage *newImage = new ScanImage(img); 0842 if (newImage==nullptr) return (KScanDevice::NoMemory); 0843 0844 mScanImage.clear(); // remove reference to previous 0845 mScanImage.reset(newImage); // capture the new image pointer 0846 0847 // Copy the resolution from the original image 0848 mScanImage->setXResolution(DPM_TO_DPI(img.dotsPerMeterX())); 0849 mScanImage->setYResolution(DPM_TO_DPI(img.dotsPerMeterY())); 0850 // Set the original image file name as the scanner name 0851 mScanImage->setScannerName(QFile::encodeName(filename)); 0852 emit sigNewImage(mScanImage); 0853 return (KScanDevice::Ok); 0854 } 0855 } 0856 0857 0858 #ifdef DEBUG_PARAMS 0859 static void dumpParams(const QString &msg, const SANE_Parameters *p) 0860 { 0861 QByteArray formatName("UNKNOWN"); 0862 switch (p->format) 0863 { 0864 case SANE_FRAME_GRAY: formatName = "GREY"; break; 0865 case SANE_FRAME_RGB: formatName = "RGB"; break; 0866 case SANE_FRAME_RED: formatName = "RED"; break; 0867 case SANE_FRAME_GREEN: formatName = "GREEN"; break; 0868 case SANE_FRAME_BLUE: formatName = "BLUE"; break; 0869 } 0870 0871 qCDebug(LIBKOOKASCAN_LOG) << msg.toLatin1().constData(); 0872 qCDebug(LIBKOOKASCAN_LOG) << " format: " << p->format << "=" << formatName.constData(); 0873 qCDebug(LIBKOOKASCAN_LOG) << " last_frame: " << p->last_frame; 0874 qCDebug(LIBKOOKASCAN_LOG) << " lines: " << p->lines; 0875 qCDebug(LIBKOOKASCAN_LOG) << " depth: " << p->depth; 0876 qCDebug(LIBKOOKASCAN_LOG) << " pixels_per_line: " << p->pixels_per_line; 0877 qCDebug(LIBKOOKASCAN_LOG) << " bytes_per_line: " << p->bytes_per_line; 0878 } 0879 #endif // DEBUG_PARAMS 0880 0881 0882 KScanDevice::Status KScanDevice::acquireData(bool isPreview) 0883 { 0884 KScanDevice::Status stat = KScanDevice::Ok; 0885 int frames = 0; 0886 0887 #ifdef DEBUG_OPTIONS 0888 showOptions(); // dump the current noptions 0889 #endif 0890 0891 mScanningPreview = isPreview; 0892 mScanningState = KScanDevice::ScanStarting; 0893 mBytesRead = 0; 0894 mBlocksRead = 0; 0895 0896 ScanGlobal::self()->setScanDevice(this); // for possible authentication 0897 0898 // Tell the application that scanning is about to start. 0899 ScanImage::ImageType fmt = ScanImage::None; 0900 if (!isPreview) // scanning to eventually save 0901 { 0902 mSaneStatus = sane_get_parameters(mScannerHandle, &mSaneParameters); 0903 if (mSaneStatus==SANE_STATUS_GOOD) // get pre-scan parameters 0904 { 0905 #ifdef DEBUG_PARAMS 0906 dumpParams("Before scan:", &mSaneParameters); 0907 #endif // DEBUG_PARAMS 0908 0909 if (mSaneParameters.lines>=1 && mSaneParameters.pixels_per_line>0) 0910 { // check for a plausible image 0911 fmt = getImageFormat(&mSaneParameters); // find format it will have 0912 if (fmt==ScanImage::None) // scan format not recognised? 0913 { 0914 stat = KScanDevice::ParamError; // no point starting scan 0915 scanFinished(stat); // clean up anything started 0916 return (stat); 0917 } 0918 } 0919 } 0920 0921 if (mTestFormat!=ScanImage::None) 0922 { 0923 fmt = mTestFormat; 0924 qCDebug(LIBKOOKASCAN_LOG) << "Testing with image format" << fmt; 0925 } 0926 } 0927 else fmt = ScanImage::Preview; // special to indicate preview 0928 emit sigScanStart(fmt); // now tell the application 0929 0930 // The application may have prompted for a file name. 0931 // If the user cancelled that, it will have called our 0932 // slotStopScanning() which sets mScanningState to 0933 // KScanDevice::ScanStopNow. If that is the case, 0934 // then finish here. 0935 if (mScanningState==KScanDevice::ScanStopNow) 0936 { // user cancelled save dialogue 0937 qCDebug(LIBKOOKASCAN_LOG) << "user cancelled before start"; 0938 stat = KScanDevice::Cancelled; 0939 scanFinished(stat); // clean up anything started 0940 return (stat); 0941 } 0942 0943 while (true) // loop while frames available 0944 { 0945 QApplication::setOverrideCursor(Qt::WaitCursor); 0946 // potential lengthy operation 0947 mSaneStatus = sane_start(mScannerHandle); 0948 if (mSaneStatus==SANE_STATUS_ACCESS_DENIED) // authentication failed? 0949 { 0950 qCDebug(LIBKOOKASCAN_LOG) << "retrying authentication"; 0951 clearSavedAuth(); // clear any saved password 0952 mSaneStatus = sane_start(mScannerHandle); // try again once more 0953 } 0954 0955 if (mSaneStatus==SANE_STATUS_GOOD) 0956 { 0957 mSaneStatus = sane_get_parameters(mScannerHandle, &mSaneParameters); 0958 if (mSaneStatus==SANE_STATUS_GOOD) 0959 { 0960 #ifdef DEBUG_PARAMS 0961 dumpParams(QString("For frame %1:").arg(frames+1), &mSaneParameters); 0962 #endif // DEBUG_PARAMS 0963 0964 // TODO: implement "Hand Scanner" support 0965 if (mSaneParameters.lines<1) 0966 { 0967 qCWarning(LIBKOOKASCAN_LOG) << "Hand Scanner not supported"; 0968 stat = KScanDevice::NotSupported; 0969 } 0970 else if (mSaneParameters.pixels_per_line==0) 0971 { 0972 qCWarning(LIBKOOKASCAN_LOG) << "Nothing to acquire!"; 0973 stat = KScanDevice::EmptyPic; 0974 } 0975 } 0976 else 0977 { 0978 stat = KScanDevice::OpenDevice; 0979 qCDebug(LIBKOOKASCAN_LOG) << "sane_get_parameters() error" << lastSaneErrorMessage(); 0980 } 0981 } 0982 else 0983 { 0984 stat = KScanDevice::OpenDevice; 0985 qCDebug(LIBKOOKASCAN_LOG) << "sane_start() error" << lastSaneErrorMessage(); 0986 } 0987 QApplication::restoreOverrideCursor(); 0988 0989 if (stat==KScanDevice::Ok && mScanningState==KScanDevice::ScanStarting) 0990 { // first time through loop 0991 // Create image to receive scan, based on real SANE parameters 0992 stat = createNewImage(&mSaneParameters); 0993 0994 // Create/reinitialise buffer for scanning one line 0995 if (stat==KScanDevice::Ok) 0996 { 0997 if (mScanBuf!=nullptr) delete [] mScanBuf; 0998 mScanBuf = new SANE_Byte[mSaneParameters.bytes_per_line+4]; 0999 if (mScanBuf==nullptr) stat = KScanDevice::NoMemory; 1000 } // can this ever happen? 1001 1002 if (stat==KScanDevice::Ok) 1003 { 1004 int fd = 0; 1005 // Don't assume that sane_get_select_fd() will succeed even if 1006 // sane_set_io_mode() successfully sets I/O mode to noblocking - 1007 // bug 159300 1008 if (sane_set_io_mode(mScannerHandle, SANE_TRUE)==SANE_STATUS_GOOD) 1009 { 1010 if (sane_get_select_fd(mScannerHandle, &fd)==SANE_STATUS_GOOD) 1011 { 1012 qCDebug(LIBKOOKASCAN_LOG) << "using read socket notifier"; 1013 mSocketNotifier = new QSocketNotifier(fd, QSocketNotifier::Read, this); 1014 connect(mSocketNotifier, &QSocketNotifier::activated, this, &KScanDevice::doProcessABlock); 1015 } 1016 else qCDebug(LIBKOOKASCAN_LOG) << "not using socket notifier (sane_get_select_fd() failed)"; 1017 } 1018 else qCDebug(LIBKOOKASCAN_LOG) << "not using socket notifier (sane_set_io_mode() failed)"; 1019 } 1020 } 1021 1022 if (stat!=KScanDevice::Ok) // some problem getting started 1023 { 1024 // Scanning could not start - give up now 1025 qCDebug(LIBKOOKASCAN_LOG) << "Scanning failed to start, status" << stat; 1026 scanFinished(stat); // clean up anything started 1027 return (stat); 1028 } 1029 1030 if (mScanningState==KScanDevice::ScanStarting) // first time through loop 1031 { 1032 QApplication::setOverrideCursor(Qt::BusyCursor); 1033 emit sigAcquireStart(); 1034 } 1035 1036 emit sigScanProgress(0); // signal the progress dialog 1037 qApp->processEvents(); // update the progress window 1038 1039 mPixelX = 0; 1040 mPixelY = 0; 1041 mBytesUsed = 0; 1042 1043 // Set internal status to indicate scanning in progress. 1044 // This status might be changed, e.g. by pressing Stop on a 1045 // GUI dialog displayed during scanning. 1046 mScanningState = KScanDevice::ScanInProgress; 1047 1048 // As originally coded, if using the socket notifier 1049 // sane_get_parameters() was only called once at the beginning of 1050 // the scan - just after sane_start() above. If not using the socket 1051 // notifier on the other hand, sane_get_parameters() was called after 1052 // each doProcessABlock() in the loop below. 1053 // 1054 // According to the SANE documentation text, sane_get_parameters() 1055 // needs to be called once after sane_start() to get the exact 1056 // parameters, but not necessarily in the reading loop that just 1057 // needs to call sane_read() repeatedly. The diagram above, though, 1058 // seems to imply that sane_get_parameters() should be done in the 1059 // reading loop. 1060 // 1061 // Doing the sane_get_parameters() just once seems to work with all 1062 // of the scanners that I have available to test, both using the 1063 // socket notifier and not. So that is what we now do, in this 1064 // much simpler loop. 1065 1066 while (true) // loop for one scanned frame 1067 { 1068 if (mSocketNotifier!=nullptr) // using the socket notifier 1069 { 1070 qApp->processEvents(); // let it fire away 1071 } 1072 else // not using socket notifier 1073 { 1074 doProcessABlock(); // may block while reading 1075 } 1076 // exit loop when frame done 1077 if (mScanningState==KScanDevice::ScanIdle || 1078 mScanningState==KScanDevice::ScanStopNow || 1079 mScanningState==KScanDevice::ScanNextFrame) break; 1080 } 1081 1082 ++frames; // count up this frame 1083 // more frames to do 1084 if (mScanningState==KScanDevice::ScanNextFrame) continue; 1085 break; // scan done, exit loop 1086 } 1087 1088 if (mScanningState==KScanDevice::ScanStopNow) 1089 { 1090 stat = KScanDevice::Cancelled; 1091 } 1092 else 1093 { 1094 if (mSaneStatus!=SANE_STATUS_GOOD && mSaneStatus!=SANE_STATUS_EOF) 1095 { 1096 stat = KScanDevice::ScanError; 1097 } 1098 } 1099 1100 qCDebug(LIBKOOKASCAN_LOG) << "Scan read" << mBytesRead << "bytes in" 1101 << mBlocksRead << "blocks," << frames << "frames, status" << stat; 1102 1103 scanFinished(stat); // scan is now finished 1104 return (stat); 1105 } 1106 1107 1108 /* This function calls at least sane_read and converts the read data from the scanner 1109 * to the qimage. 1110 * The function needs: 1111 * QImage img valid 1112 * the data-buffer set to a appropriate size 1113 **/ 1114 1115 // TODO: probably needs to be extended for 16-bit scanner support 1116 1117 void KScanDevice::doProcessABlock() 1118 { 1119 int val,i; 1120 QRgb col, newCol; 1121 1122 SANE_Byte *rptr = nullptr; 1123 SANE_Int bytes_read = 0; 1124 int chan = 0; 1125 mSaneStatus = SANE_STATUS_GOOD; 1126 uchar eight_pix = 0; 1127 1128 if (mScanningState==KScanDevice::ScanIdle) return; // scan finished, no more to do 1129 // block notifications while working 1130 if (mSocketNotifier!=nullptr) mSocketNotifier->setEnabled(false); 1131 1132 while (true) 1133 { 1134 mSaneStatus = sane_read(mScannerHandle, 1135 (mScanBuf+mBytesUsed), 1136 mSaneParameters.bytes_per_line, 1137 &bytes_read); 1138 if (mSaneStatus!=SANE_STATUS_GOOD) 1139 { 1140 if (mSaneStatus!=SANE_STATUS_EOF) // this is OK, just stop 1141 { // any other error 1142 qCDebug(LIBKOOKASCAN_LOG) << "sane_read() error" << lastSaneErrorMessage() 1143 << "bytes read" << bytes_read; 1144 } 1145 break; 1146 } 1147 1148 if (bytes_read<1) break; // no data, finish loop 1149 1150 ++mBlocksRead; 1151 mBytesRead += bytes_read; 1152 1153 int red = 0; 1154 int green = 0; 1155 int blue = 0; 1156 1157 rptr = mScanBuf; // start of scan data 1158 switch (mSaneParameters.format) 1159 { 1160 case SANE_FRAME_RGB: 1161 if (mSaneParameters.lines<1) break; 1162 bytes_read += mBytesUsed; // die übergebliebenen Bytes dazu 1163 mBytesUsed = bytes_read % 3; 1164 1165 for (val = 0; val<((bytes_read-mBytesUsed)/3); val++) 1166 { 1167 red = *rptr++; 1168 green = *rptr++; 1169 blue = *rptr++; 1170 1171 if (mPixelX>=mSaneParameters.pixels_per_line) 1172 { // reached end of a row 1173 mPixelX = 0; 1174 mPixelY++; 1175 } 1176 if (mPixelY<mScanImage->height()) // within image height 1177 { 1178 mScanImage->setPixel(mPixelX, mPixelY, qRgb(red, green, blue)); 1179 } 1180 mPixelX++; 1181 } 1182 1183 for (val = 0; val<mBytesUsed; val++) // Copy the remaining bytes down 1184 { // to the beginning of the block 1185 *(mScanBuf+val) = *rptr++; 1186 } 1187 break; 1188 1189 case SANE_FRAME_GRAY: 1190 for (val = 0; val<bytes_read ; val++) 1191 { 1192 if (mPixelY>=mSaneParameters.lines) break; 1193 if (mSaneParameters.depth==8) // Greyscale 1194 { 1195 if (mPixelX>=mSaneParameters.pixels_per_line) 1196 { // reached end of a row 1197 mPixelX = 0; 1198 mPixelY++; 1199 } 1200 mScanImage->setPixel(mPixelX, mPixelY, *rptr++); 1201 mPixelX++; 1202 } 1203 else // Lineart (bitmap) 1204 { // needs to be converted to byte 1205 eight_pix = *rptr++; 1206 for (i = 0; i<8; i++) 1207 { 1208 if (mPixelY<mSaneParameters.lines) 1209 { 1210 chan = (eight_pix & 0x80)>0 ? 0 : 1; 1211 eight_pix = eight_pix << 1; 1212 mScanImage->setPixel(mPixelX, mPixelY, chan); 1213 mPixelX++; 1214 if( mPixelX>=mSaneParameters.pixels_per_line) 1215 { 1216 mPixelX = 0; 1217 mPixelY++; 1218 break; 1219 } 1220 } 1221 } 1222 } 1223 } 1224 break; 1225 1226 case SANE_FRAME_RED: 1227 case SANE_FRAME_GREEN: 1228 case SANE_FRAME_BLUE: 1229 for (val = 0; val<bytes_read ; val++) 1230 { 1231 if (mPixelX>=mSaneParameters.pixels_per_line) 1232 { // reached end of a row 1233 mPixelX = 0; 1234 mPixelY++; 1235 } 1236 1237 if (mPixelY<mSaneParameters.lines) 1238 { 1239 col = mScanImage->pixel(mPixelX, mPixelY); 1240 1241 red = qRed(col); 1242 green = qGreen(col); 1243 blue = qBlue(col); 1244 chan = *rptr++; 1245 1246 switch (mSaneParameters.format) 1247 { 1248 case SANE_FRAME_RED: newCol = qRgba(chan, green, blue, 0xFF); 1249 break; 1250 1251 case SANE_FRAME_GREEN: newCol = qRgba(red, chan, blue, 0xFF); 1252 break; 1253 1254 case SANE_FRAME_BLUE: newCol = qRgba(red, green, chan, 0xFF); 1255 break; 1256 1257 default: newCol = qRgba(0xFF, 0xFF, 0xFF, 0xFF); 1258 break; 1259 } 1260 mScanImage->setPixel(mPixelX, mPixelY, newCol); 1261 mPixelX++; 1262 } 1263 } 1264 break; 1265 1266 default: qCWarning(LIBKOOKASCAN_LOG) << "Undefined SANE format" << mSaneParameters.format; 1267 break; 1268 } // switch of scan format 1269 1270 if ((mSaneParameters.lines>0) && ((mSaneParameters.lines*mPixelY)>0)) 1271 { 1272 int progress = (int)(((double)MAX_PROGRESS)/mSaneParameters.lines*mPixelY); 1273 if (progress<MAX_PROGRESS) emit sigScanProgress(progress); 1274 } 1275 1276 // cannot get here, bytes_read and EOF tested above 1277 //if( bytes_read == 0 || mSaneStatus == SANE_STATUS_EOF ) 1278 //{ 1279 // //qCDebug(LIBKOOKASCAN_LOG) << "mSaneStatus not OK:" << sane_stat; 1280 // break; 1281 //} 1282 1283 if (mScanningState==KScanDevice::ScanStopNow) 1284 { 1285 /* mScanningState is set to ScanStopNow due to hitting slStopScanning */ 1286 /* Mostly that one is fired by the STOP-Button in the progress dialog. */ 1287 1288 /* This is also hit after the normal finish of the scan. Most probably, 1289 * the QSocketnotifier fires for a few times after the scan has been 1290 * cancelled. Does it matter ? To see it, just uncomment the qDebug msg. 1291 */ 1292 //qCDebug(LIBKOOKASCAN_LOG) << "Stopping the scan progress"; 1293 //mScanningState = KScanDevice::ScanIdle; 1294 break; 1295 } 1296 } // end of main loop 1297 1298 // Here when scanning is finished or has had an error 1299 if (mSaneStatus==SANE_STATUS_EOF) // end of scan pass 1300 { 1301 if (mSaneParameters.last_frame) // end of scanning run 1302 { 1303 /** Everything is okay, the picture is ready **/ 1304 qCDebug(LIBKOOKASCAN_LOG) << "Last frame reached, scan successful"; 1305 mScanningState = KScanDevice::ScanIdle; 1306 } 1307 else 1308 { 1309 /** EOF und nicht letzter Frame -> Parameter neu belegen und neu starten **/ 1310 mScanningState = KScanDevice::ScanNextFrame; 1311 qCDebug(LIBKOOKASCAN_LOG) << "EOF, but another frame to scan"; 1312 } 1313 } 1314 else if (mSaneStatus!=SANE_STATUS_GOOD) 1315 { 1316 mScanningState = KScanDevice::ScanIdle; 1317 qCDebug(LIBKOOKASCAN_LOG) << "Scan error or cancelled, status" << mSaneStatus; 1318 } 1319 1320 if (mSocketNotifier!=nullptr) mSocketNotifier->setEnabled(true); 1321 } 1322 1323 1324 void KScanDevice::scanFinished(KScanDevice::Status status) 1325 { 1326 qCDebug(LIBKOOKASCAN_LOG) << "status" << status; 1327 1328 emit sigScanProgress(MAX_PROGRESS); 1329 QApplication::restoreOverrideCursor(); 1330 1331 if (mSocketNotifier!=nullptr) // clean up if in use 1332 { 1333 delete mSocketNotifier; 1334 mSocketNotifier = nullptr; 1335 } 1336 1337 if (mScanBuf!=nullptr) 1338 { 1339 delete[] mScanBuf; 1340 mScanBuf = nullptr; 1341 } 1342 1343 // If the scan succeeded, finish off the result image and tell the 1344 // application that it is ready. 1345 if (status==KScanDevice::Ok && !mScanImage.isNull()) 1346 { 1347 mScanImage->setXResolution(mCurrScanResolutionX); 1348 mScanImage->setYResolution(mCurrScanResolutionY); 1349 mScanImage->setScannerName(mScannerName); 1350 1351 if (mScanningPreview) 1352 { 1353 savePreviewImage(*mScanImage); 1354 emit sigNewPreview(mScanImage); 1355 } 1356 else 1357 { 1358 emit sigNewImage(mScanImage); 1359 } 1360 } 1361 1362 // TODO: Should this be called here, even for normal scan termination? 1363 // It seems to have side effects, such as feeding through anything remaining 1364 // in the ADF even if only one page has been requested to be scanned. 1365 sane_cancel(mScannerHandle); 1366 1367 // Tell the application that the scan has finished. 1368 emit sigScanFinished(status); 1369 1370 // Nothing needs to be done to clean up the image that was allocated 1371 // in createNewImage(), the QSharedPointer will take care of reference 1372 // counting and deletion. 1373 1374 mScanningState = KScanDevice::ScanIdle; 1375 } 1376 1377 1378 // Configuration 1379 // ------------- 1380 1381 void KScanDevice::saveStartupConfig() 1382 { 1383 if (mScannerName.isNull()) return; // do not save for no scanner 1384 1385 KScanOptSet optSet(KScanOptSet::startupSetName()); 1386 getCurrentOptions(&optSet); 1387 optSet.saveConfig(mScannerName, i18n("Default startup configuration")); 1388 } 1389 1390 1391 void KScanDevice::loadOptionSetInternal(const KScanOptSet *optSet, bool prio) 1392 { 1393 for (KScanOptSet::const_iterator it = optSet->constBegin(); 1394 it!=optSet->constEnd(); ++it) 1395 { 1396 const QByteArray name = it.key(); 1397 if (!optionExists(name)) continue; // only for options that exist 1398 1399 KScanOption *so = getOption(name, false); 1400 if (so==nullptr) continue; // we don't have this option 1401 if (so->isGroup()) continue; // nothing to do here 1402 if (so->isPriorityOption() ^ prio) continue; // check whether requested priority 1403 1404 so->set(it.value()); 1405 if (so->isInitialised() && so->isSoftwareSettable() && so->isActive()) so->apply(); 1406 } 1407 } 1408 1409 1410 void KScanDevice::loadOptionSet(const KScanOptSet *optSet) 1411 { 1412 if (optSet==nullptr) return; 1413 1414 qCDebug(LIBKOOKASCAN_LOG) << "Loading set" << optSet->getSetName() << "with" << optSet->count() << "options"; 1415 loadOptionSetInternal(optSet, true); 1416 loadOptionSetInternal(optSet, false); 1417 } 1418 1419 1420 // Retrieve the current options from the scanner, i.e. all of those that 1421 // have an associated GUI element and also any others (e.g. the TL_X and 1422 // other scan area settings) that have been apply()'ed but do not have 1423 // a GUI. 1424 1425 void KScanDevice::getCurrentOptions(KScanOptSet *optSet) const 1426 { 1427 if (optSet==nullptr) return; 1428 1429 for (OptionHash::const_iterator it = mCreatedOptions.constBegin(); 1430 it!=mCreatedOptions.constEnd(); ++it) 1431 { 1432 KScanOption *so = it.value(); 1433 if (!so->isReadable()) continue; 1434 1435 if (so->isGuiElement() || so->isApplied()) 1436 { 1437 if (so->isActive()) optSet->backupOption(so); 1438 so->setApplied(false); 1439 } 1440 } 1441 } 1442 1443 1444 KConfigGroup KScanDevice::configGroup(const QString &groupName) 1445 { 1446 Q_ASSERT(!groupName.isEmpty()); 1447 return (ScanSettings::self()->config()->group(groupName)); 1448 } 1449 1450 // SANE Authentication 1451 // ------------------- 1452 // 1453 // According to the SANE documentation, this may be requested for any use of 1454 // sane_open(), sane_control_option() or sane_start() on a scanner device 1455 // that requires authentication. 1456 // 1457 // The only uses of sane_open() and sane_start() are here in this file, and 1458 // they set the current scanner using setScanDevice() before performing the 1459 // SANE operation. 1460 // 1461 // This does not happen for all uses of sane_control_option(), either here or 1462 // in KScanOption, so there is a slight possibility that if authentication is 1463 // needed for those (and has not been previously requested by sane_open() or 1464 // sane_start()) then it will use the wrong scanner device or will not prompt 1465 // at all. However, Kooka only supports one scanner open at a time, and does 1466 // sane_open() before any use of sane_control_option(). So hopefully this 1467 // will not be a problem. 1468 1469 bool KScanDevice::authenticate(QByteArray *retuser, QByteArray *retpass) 1470 { 1471 qCDebug(LIBKOOKASCAN_LOG) << "for" << mScannerName; 1472 1473 // TODO: use KWallet for username/password? 1474 KConfigGroup grp = configGroup(mScannerName); 1475 QByteArray user = QByteArray::fromBase64(grp.readEntry("user", QString()).toLocal8Bit()); 1476 QByteArray pass = QByteArray::fromBase64(grp.readEntry("pass", QString()).toLocal8Bit()); 1477 1478 if (!user.isEmpty() && !pass.isEmpty()) 1479 { 1480 qCDebug(LIBKOOKASCAN_LOG) << "have saved username/password"; 1481 } 1482 else 1483 { 1484 qCDebug(LIBKOOKASCAN_LOG) << "asking for username/password"; 1485 1486 KPasswordDialog dlg(nullptr, KPasswordDialog::ShowKeepPassword|KPasswordDialog::ShowUsernameLine); 1487 dlg.setPrompt(xi18nc("@info", "The scanner<nl/><icode>%1</icode><nl/>requires authentication.", mScannerName.constData())); 1488 dlg.setWindowTitle(i18n("Scanner Authentication")); 1489 1490 if (!user.isEmpty()) dlg.setUsername(user); 1491 if (!pass.isEmpty()) dlg.setPassword(pass); 1492 1493 if (!dlg.exec()) return (false); 1494 1495 user = dlg.username().toLocal8Bit(); 1496 pass = dlg.password().toLocal8Bit(); 1497 if (dlg.keepPassword()) 1498 { 1499 grp.writeEntry("user", user.toBase64()); 1500 grp.writeEntry("pass", pass.toBase64()); 1501 } 1502 } 1503 1504 *retuser = user; 1505 *retpass = pass; 1506 return (true); 1507 } 1508 1509 1510 void KScanDevice::clearSavedAuth() 1511 { 1512 KConfigGroup grp = configGroup(mScannerName); 1513 grp.deleteEntry("user"); 1514 grp.deleteEntry("pass"); 1515 grp.sync(); 1516 } 1517 1518 1519 // Error reporting 1520 // --------------- 1521 1522 QString KScanDevice::lastSaneErrorMessage() const 1523 { 1524 return (sane_strstatus(mSaneStatus)); 1525 } 1526 1527 1528 QString KScanDevice::statusMessage(KScanDevice::Status stat) 1529 { 1530 switch (stat) 1531 { 1532 case KScanDevice::Ok: return (i18n("OK")); // shouldn't be reported 1533 case KScanDevice::NoDevice: return (i18n("No device")); // never during scanning 1534 case KScanDevice::ParamError: return (i18n("Bad parameter")); 1535 case KScanDevice::OpenDevice: return (i18n("Cannot open device")); 1536 case KScanDevice::ControlError: return (i18n("sane_control_option() failed")); 1537 case KScanDevice::ScanError: return (i18n("Error while scanning")); 1538 case KScanDevice::EmptyPic: return (i18n("Empty picture")); 1539 case KScanDevice::NoMemory: return (i18n("Out of memory")); 1540 case KScanDevice::Reload: return (i18n("Needs reload")); // never during scanning 1541 case KScanDevice::Cancelled: return (i18n("Cancelled")); // shouldn't be reported 1542 case KScanDevice::OptionNotActive: return (i18n("Not active")); // never during scanning 1543 case KScanDevice::NotSupported: return (i18n("Not supported")); 1544 default: return (i18n("Unknown status %1", stat)); 1545 } 1546 }