diff --git a/src/KSaneImageSaver.h b/src/KSaneImageSaver.h --- a/src/KSaneImageSaver.h +++ b/src/KSaneImageSaver.h @@ -29,24 +29,25 @@ #include #include #include +#include class KSaneImageSaver : public QThread { Q_OBJECT public: - explicit KSaneImageSaver(QObject *parent = 0); + explicit KSaneImageSaver(KSaneIface::KSaneWidget* sane_widget, QObject *parent = nullptr); ~KSaneImageSaver(); - bool savePng(const QString &name, const QByteArray &data, int width, int height, int format, int dpi); + bool savePngAsync(const QUrl &url, const QString &name, const QByteArray &data, const QImage &img, int width, int height, int bpl, int dpi, int format, const QString& fileFormat, int quality); - bool savePngSync(const QString &name, const QByteArray &data, int width, int height, int format, int dpi); + bool savePngSync(const QUrl &url, const QString &name, const QByteArray &data, const QImage &img, int width, int height, int bpl, int dpi, int format, const QString &fileFormat, int quality); - bool saveTiff(const QString &name, const QByteArray &data, int width, int height, int format); + bool saveTiffAsync(const QUrl &url, const QString &name, const QByteArray &data, const QImage &img, int width, int height, int bpl, int dpi, int format, const QString& fileFormat, int quality); - bool saveTiffSync(const QString &name, const QByteArray &data, int width, int height, int format); + bool saveTiffSync(const QUrl &url, const QString &name, const QByteArray &data, const QImage &img, int width, int height, int bpl, int dpi, int format, const QString& fileFormat, int quality); Q_SIGNALS: - void imageSaved(bool success); + void imageSaved(const QUrl &url, const QString &name, bool success); protected: void run() Q_DECL_OVERRIDE; @@ -54,6 +55,7 @@ private: struct Private; Private *const d; + KSaneIface::KSaneWidget *const m_sane_widget; }; diff --git a/src/KSaneImageSaver.cpp b/src/KSaneImageSaver.cpp --- a/src/KSaneImageSaver.cpp +++ b/src/KSaneImageSaver.cpp @@ -30,6 +30,8 @@ #include #include +#include +#include struct KSaneImageSaver::Private { enum ImageType { @@ -39,22 +41,28 @@ bool m_savedOk; QMutex m_runMutex; - KSaneImageSaver *q; + QUrl m_url; QString m_name; QByteArray m_data; + QImage m_img; int m_width; int m_height; - int m_format; + int m_bpl; int m_dpi; + int m_format; + QString m_fileFormat; + int m_quality; ImageType m_type; + KSaneImageSaver *q; + bool savePng(); bool saveTiff(); }; // ------------------------------------------------------------------------ -KSaneImageSaver::KSaneImageSaver(QObject *parent) : QThread(parent), d(new Private) +KSaneImageSaver::KSaneImageSaver(KSaneIface::KSaneWidget *sane_widget, QObject *parent) : QThread(parent), d(new Private), m_sane_widget(sane_widget) { d->q = this; } @@ -65,27 +73,32 @@ delete d; } -bool KSaneImageSaver::savePng(const QString &name, const QByteArray &data, int width, int height, int format, int dpi) +bool KSaneImageSaver::savePngAsync(const QUrl &url, const QString &name, const QByteArray &data, const QImage &img, int width, int height, int bpl, int dpi, int format, const QString& fileFormat, int quality) { if (!d->m_runMutex.tryLock()) { return false; } + d->m_url = url; d->m_name = name; d->m_data = data; + d->m_img = img; d->m_width = width; d->m_height = height; - d->m_format = format; + d->m_bpl = bpl; d->m_dpi = dpi; + d->m_format = format; + d->m_fileFormat = fileFormat; + d->m_quality = quality; d->m_type = Private::ImageTypePNG; start(); return true; } -bool KSaneImageSaver::savePngSync(const QString &name, const QByteArray &data, int width, int height, int format, int dpi) +bool KSaneImageSaver::savePngSync(const QUrl &url, const QString &name, const QByteArray &data, const QImage &img, int width, int height, int bpl, int dpi, int format, const QString& fileFormat, int quality) { - if (!savePng(name, data, width, height, format, dpi)) { + if (!savePngAsync(url, name, data, img, width, height, bpl, dpi, format, fileFormat, quality)) { qDebug() << "fail"; return false; } @@ -93,17 +106,23 @@ return d->m_savedOk; } -bool KSaneImageSaver::saveTiff(const QString &name, const QByteArray &data, int width, int height, int format) +bool KSaneImageSaver::saveTiffAsync(const QUrl &url, const QString &name, const QByteArray &data, const QImage &img, int width, int height, int bpl, int dpi, int format, const QString& fileFormat, int quality) { if (!d->m_runMutex.tryLock()) { return false; } + d->m_url = url; d->m_name = name; d->m_data = data; + d->m_img = img; d->m_width = width; d->m_height = height; + d->m_bpl = bpl; + d->m_dpi = dpi; d->m_format = format; + d->m_fileFormat = fileFormat; + d->m_quality = quality; d->m_type = Private::ImageTypeTIFF; qDebug() << "saving Tiff images is not yet supported"; @@ -111,9 +130,9 @@ return false; } -bool KSaneImageSaver::saveTiffSync(const QString &name, const QByteArray &data, int width, int height, int format) +bool KSaneImageSaver::saveTiffSync(const QUrl &url, const QString &name, const QByteArray &data, const QImage &img, int width, int height, int bpl, int dpi, int format, const QString& fileFormat, int quality) { - if (!saveTiff(name, data, width, height, format)) { + if (!saveTiffAsync(url, name, data, img, width, height, bpl, dpi, format, fileFormat, quality)) { return false; } wait(); @@ -122,14 +141,35 @@ void KSaneImageSaver::run() { - if (d->m_type == Private::ImageTypeTIFF) { - d->m_savedOk = d->saveTiff(); - emit imageSaved(d->m_savedOk); - } - else { - d->m_savedOk = d->savePng(); - emit imageSaved(d->m_savedOk); + if ((d->m_format == KSaneIface::KSaneWidget::FormatRGB_16_C) || + (d->m_format == KSaneIface::KSaneWidget::FormatGrayScale16)) { + + if (d->m_type == Private::ImageTypeTIFF) { + d->m_savedOk = d->saveTiff(); + emit imageSaved(d->m_url, d->m_name, d->m_savedOk); + } + else { + d->m_savedOk = d->savePng(); + emit imageSaved(d->m_url, d->m_name, d->m_savedOk); + } + } else { + if (d->m_img.width() < 1) { + if ((d->m_format == KSaneIface::KSaneWidget::FormatRGB_16_C) || (d->m_format == KSaneIface::KSaneWidget::FormatGrayScale16)) { + emit m_sane_widget->userMessage(KSaneIface::KSaneWidget::ErrorGeneral, + i18n("The image data contained 16 bits per color, " + "but the color depth has been truncated to 8 bits per color.")); + } + d->m_img = KSaneIface::KSaneWidget::toQImageSilent(d->m_data, d->m_width, d->m_height, d->m_bpl, d->m_dpi, (KSaneIface::KSaneWidget::ImageFormat) d->m_format); + } + if (d->m_img.save(d->m_name, d->m_fileFormat.toStdString().c_str(), d->m_quality)) { + //m_showImgDialog->close(); // calling close() on a closed window does nothing. + } + else { + //perrorMessageBox(i18n("Failed to save image")); + return; + } } + d->m_runMutex.unlock(); } diff --git a/src/skanlite.h b/src/skanlite.h --- a/src/skanlite.h +++ b/src/skanlite.h @@ -31,6 +31,7 @@ #include "ui_settings.h" #include "DBusInterface.h" +#include "KSaneImageSaver.h" class ShowImageDialog; class SaveLocation; @@ -64,6 +65,7 @@ void getDir(); void imageReady(QByteArray &, int, int, int, int); void saveImage(); + void imageSaved(const QUrl &url, const QString &name, bool success); void showAboutDialog(); void saveWindowSize(); @@ -93,6 +95,7 @@ private: KAboutData *m_aboutData; KSaneWidget *m_ksanew = nullptr; + KSaneImageSaver *m_image_saver = nullptr; Ui::SkanliteSettings m_settingsUi; QDialog *m_settingsDialog = nullptr; ShowImageDialog *m_showImgDialog = nullptr; diff --git a/src/skanlite.cpp b/src/skanlite.cpp --- a/src/skanlite.cpp +++ b/src/skanlite.cpp @@ -24,7 +24,6 @@ #include "skanlite.h" -#include "KSaneImageSaver.h" #include "SaveLocation.h" #include "showimagedialog.h" @@ -79,6 +78,9 @@ connect(m_ksanew, &KSaneWidget::userMessage, this, &Skanlite::alertUser); connect(m_ksanew, &KSaneWidget::buttonPressed, this, &Skanlite::buttonPressed); + m_image_saver = new KSaneImageSaver(m_ksanew, this); + connect(m_image_saver, &KSaneImageSaver::imageSaved, this, &Skanlite::imageSaved); + mainLayout->addWidget(m_ksanew); mainLayout->addWidget(dlgButtonBoxBottom); @@ -372,18 +374,39 @@ } } +bool pathExists(const QString& dir, QWidget* parent) +{ + // propose directory creation if doesn't exists + QUrl dirUrl(dir); + if (dirUrl.isLocalFile()) { + QDir path(dirUrl.toLocalFile()); + if (!path.exists()) { + if (KMessageBox::questionYesNo(parent, i18n("Directory doesn't exist, do you wish to create it?")) == KMessageBox::ButtonCode::Yes ) { + if (!path.mkpath(QLatin1String("."))) { + KMessageBox::error(parent, i18n("Could not create directory %1", path.path())); + return false; + } + } + } + } + return true; +} + void Skanlite::saveImage() { // ask the first time if we are in "ask on first" mode - if ((m_settingsUi.saveModeCB->currentIndex() == SaveModeAskFirst) && m_firstImage) { + QString dir = QDir::cleanPath(m_saveLocation->u_urlRequester->url().url()).append(QLatin1Char('/')); //make sure whole value is processed as path to directory + + while ((m_firstImage && (m_settingsUi.saveModeCB->currentIndex() == SaveModeAskFirst)) || + !pathExists(dir, this)) { if (m_saveLocation->exec() != QFileDialog::Accepted) { m_ksanew->scanCancel(); // In case we are cancelling a document feeder scan return; } + dir = QDir::cleanPath(m_saveLocation->u_urlRequester->url().url()).append(QLatin1Char('/')); m_firstImage = false; } - QString dir = QDir::cleanPath(m_saveLocation->u_urlRequester->url().url()).append(QLatin1Char('/')); //make sure whole value is processed as path to directory QString prefix = m_saveLocation->u_imgPrefix->text(); QString imgFormat = m_saveLocation->u_imgFormat->currentText().toLower(); int fileNumber = m_saveLocation->u_numStartFrom->value(); @@ -487,9 +510,9 @@ QString localName; QString suffix = QFileInfo(fileUrl.fileName()).suffix(); - const char *fileFormat = nullptr; + QString fileFormat; if (suffix.isEmpty()) { - fileFormat = "png"; + fileFormat = QLatin1String("png"); } if (!fileUrl.isLocalFile()) { @@ -508,31 +531,19 @@ } // Save - if ((m_format == KSaneIface::KSaneWidget::FormatRGB_16_C) || - (m_format == KSaneIface::KSaneWidget::FormatGrayScale16)) { - KSaneImageSaver saver; - if (saver.savePngSync(localName, m_data, m_width, m_height, m_format, m_ksanew->currentDPI())) { - m_showImgDialog->close(); // closing the window if it is closed should not be a problem. - } - else { - perrorMessageBox(i18n("Failed to save image")); - return; - } - } - else { - // create the image if needed. - if (m_img.width() < 1) { - m_img = m_ksanew->toQImage(m_data, m_width, m_height, m_bytesPerLine, (KSaneIface::KSaneWidget::ImageFormat)m_format); - } - if (m_img.save(localName, fileFormat, quality)) { - m_showImgDialog->close(); // calling close() on a closed window does nothing. - } - else { - perrorMessageBox(i18n("Failed to save image")); - return; - } + m_image_saver->savePngAsync(fileUrl, localName, m_data, m_img, m_width, m_height, m_bytesPerLine, (int) m_ksanew->currentDPI(), m_format, fileFormat, quality); +} + +void Skanlite::imageSaved(const QUrl &fileUrl, const QString &localName, bool success) +{ + if (!success) { + perrorMessageBox(i18n("Failed to save image")); + return; } + m_showImgDialog->close(); // calling close() on a closed window does nothing. + + if (!fileUrl.isLocalFile()) { QFile tmpFile(localName); tmpFile.open(QIODevice::ReadOnly); @@ -542,7 +553,7 @@ tmpFile.close(); tmpFile.remove(); if (!ok) { - KMessageBox::sorry(0, i18n("Failed to upload image")); + KMessageBox::sorry(nullptr, i18n("Failed to upload image")); } else { emit m_dbusInterface.imageSaved(fileUrl.toString()); @@ -562,7 +573,7 @@ // Save the number QString fileNumStr = QFileInfo(fileUrl.fileName()).completeBaseName(); fileNumStr.remove(baseName); - fileNumber = fileNumStr.toInt(); + int fileNumber = fileNumStr.toInt(); if (fileNumber) { m_saveLocation->u_numStartFrom->setValue(fileNumber + 1); }