From 84c6358222d67596befc3a9bda7554bebab6a22e Mon Sep 17 00:00:00 2001 From: hama Date: Sat, 30 May 2015 18:41:53 +0200 Subject: [PATCH] reimgconvert: image processing --- appl/reimgconvert/about.ui | 74 ++++ appl/reimgconvert/aboutdialog.cpp | 20 + appl/reimgconvert/aboutdialog.hpp | 29 ++ appl/reimgconvert/aboutdialog.ui | 117 ++++++ appl/reimgconvert/converter.cpp | 490 ++++++++++++---------- appl/reimgconvert/converter.hpp | 99 ++--- appl/reimgconvert/main.cpp | 16 +- appl/reimgconvert/mainwindow.cpp | 239 ++++++----- appl/reimgconvert/mainwindow.hpp | 41 +- appl/reimgconvert/mainwindow.ui | 645 +++++++++++++++-------------- appl/reimgconvert/reimgconvert.pro | 17 +- base/ReQStringUtil.cpp | 35 +- base/ReQStringUtil.hpp | 1 + 13 files changed, 1112 insertions(+), 711 deletions(-) create mode 100644 appl/reimgconvert/about.ui create mode 100644 appl/reimgconvert/aboutdialog.cpp create mode 100644 appl/reimgconvert/aboutdialog.hpp create mode 100644 appl/reimgconvert/aboutdialog.ui diff --git a/appl/reimgconvert/about.ui b/appl/reimgconvert/about.ui new file mode 100644 index 0000000..a6d80c5 --- /dev/null +++ b/appl/reimgconvert/about.ui @@ -0,0 +1,74 @@ + + + AboutDialog + + + + 0 + 0 + 400 + 225 + + + + About + + + + + 20 + 20 + 351 + 141 + + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ReFind</span> for searching files in a directory tree</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is a program of the project &quot;<span style=" font-weight:600;">Re</span>al <span style=" font-weight:600;">Pub</span>lic <span style=" font-weight:600;">Lib</span>rary&quot;.</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sources are public domain and available under https://github.com/republib</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Implemented in QT (C++) 5.x</p></body></html> + + + + + + 280 + 180 + 93 + 27 + + + + &OK + + + + + &OK + + + + + + + action_OK + triggered() + AboutDialog + close() + + + -1 + -1 + + + 199 + 112 + + + + + diff --git a/appl/reimgconvert/aboutdialog.cpp b/appl/reimgconvert/aboutdialog.cpp new file mode 100644 index 0000000..f6820d4 --- /dev/null +++ b/appl/reimgconvert/aboutdialog.cpp @@ -0,0 +1,20 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. + */ + +#include "aboutdialog.hpp" +#include "ui_aboutdialog.h" + +AboutDialog::AboutDialog(const QString& version, QWidget *parent) : + QDialog(parent), ui(new Ui::AboutDialog){ + ui->setupUi(this); + ui->labelVersion->setText(version); +} + +AboutDialog::~AboutDialog(){ + delete ui; +} diff --git a/appl/reimgconvert/aboutdialog.hpp b/appl/reimgconvert/aboutdialog.hpp new file mode 100644 index 0000000..2c8baec --- /dev/null +++ b/appl/reimgconvert/aboutdialog.hpp @@ -0,0 +1,29 @@ +/* + * Licence: + * You can use and modify this file without any restriction. + * There is no warranty. + * You also can use the licence from http://www.wtfpl.net/. + * The original sources can be found on https://github.com/republib. + */ + +#ifndef ABOUTDIALOG_HPP +#define ABOUTDIALOG_HPP + +#include + +namespace Ui { +class AboutDialog; +} + +class AboutDialog: public QDialog { + Q_OBJECT + +public: + explicit AboutDialog(const QString& version, QWidget *parent = 0); + ~AboutDialog(); + +private: + Ui::AboutDialog *ui; +}; + +#endif // ABOUTDIALOG_HPP diff --git a/appl/reimgconvert/aboutdialog.ui b/appl/reimgconvert/aboutdialog.ui new file mode 100644 index 0000000..a4e82da --- /dev/null +++ b/appl/reimgconvert/aboutdialog.ui @@ -0,0 +1,117 @@ + + + AboutDialog + + + + 0 + 0 + 423 + 289 + + + + Dialog + + + true + + + + + 20 + 20 + 381 + 221 + + + + true + + + <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd"> +<html><head><meta name="qrichtext" content="1" /><style type="text/css"> +p, li { white-space: pre-wrap; } +</style></head><body style=" font-family:'Sans Serif'; font-size:9pt; font-weight:400; font-style:normal;"> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">ReImgConvert</span> for converting images to smaller dimensions/size.</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">This is a program of the project</p> +<p align="center" style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-weight:600;">Re</span>al <span style=" font-weight:600;">Pub</span>lic <span style=" font-weight:600;">Lib</span>rary (RePubLib)</p> +<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Sources are public domain and available under</p> +<p align="center" style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><a href="https://github.com/republib"><span style=" text-decoration: underline; color:#0000ff;">https://github.com/republib</span></a> </p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Implemented in QT (C++) 5.x</p> +<p style=" margin-top:12px; margin-bottom:12px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;">Icons: Mark James, <a href="http://famfamfam.com"><span style=" text-decoration: underline; color:#0000ff;">http://famfamfam.com</span></a> </p></body></html> + + + false + + + Qt::LinksAccessibleByMouse|Qt::TextSelectableByMouse + + + + + + 20 + 250 + 381 + 29 + + + + + + + Version: + + + + + + + 2015.05.00 + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + &OK + + + + + + + + + + pushButtonOK + clicked() + AboutDialog + close() + + + 196 + 183 + + + 199 + 108 + + + + + diff --git a/appl/reimgconvert/converter.cpp b/appl/reimgconvert/converter.cpp index a871baf..c1faf61 100644 --- a/appl/reimgconvert/converter.cpp +++ b/appl/reimgconvert/converter.cpp @@ -4,11 +4,13 @@ * There is no warranty. * You also can use the licence from http://www.wtfpl.net/. * The original sources can be found on https://github.com/republib. -*/ - + */ +#include "../../base/rebase.hpp" #include "converter.hpp" #include "mainwindow.hpp" +#include +#include /** @mainpage A converter for images. * @@ -33,14 +35,13 @@ * * @section install_sec Installation * - * Copy rplshrink and img_conv.pl into a directory inserted in the executable + * Copy reimgconvert into a directory inserted in the executable * path, e.g. /usr/local/bin and give them the right "executable". * * @subsection req_sec Requirements * *
    *
  • ImageMagick
  • - *
  • Perl
  • *
* * @section prog_sec Programming Features @@ -61,7 +62,7 @@ * *
    *
  • V1.0 Basic version. Predefined (static) values of the combo boxes. - * User language is German only. + * User language is English only. *
  • *
* @@ -78,13 +79,12 @@ * @brief Implements a specific exception for the converter. * * Will be used on errors. -*/ + */ /** @class ConvertLogger converter.hpp "converter.hpp" * * @brief Implements an abstract base class for logging. -*/ - + */ /** @class Converter converter.hpp "converter.hpp" * @@ -99,6 +99,8 @@ * */ +QString sizeToString(qint64 size); + /** * @brief Constructor. * @@ -114,32 +116,35 @@ * @param mainWindow the window. Will be used for output */ Converter::Converter(const QString& directory, const QString& targetDirectory, - int landscapeX, int landscapeY, - int portraitX, int portraitY, - int squareX, int quality, - MainWindow* mainWindow) : - m_dir(directory), - m_targetDir(targetDirectory.indexOf(QDir::separator()) >= 0 - ? targetDirectory - : directory + QDir::separator() + targetDirectory), - m_landscapeWidth(landscapeX), - m_landscapeHeight(landscapeY), - m_portraitWidth(portraitX), - m_portraitHeight(portraitY), - m_squareWidth(squareX), - m_quality(quality), - m_mainWindows(mainWindow), - m_script(new QProcess()), - m_shouldStop(false) -{ + const QString& sourcePattern, const QString& targetType, int landscapeX, + int landscapeY, int portraitX, int portraitY, int squareX, int quality, + MainWindow* mainWindow) : + m_dir(directory), + m_targetDir( + targetDirectory.indexOf(QDir::separator()) >= 0 ? + targetDirectory : + directory + QDir::separator() + targetDirectory), + m_sourcePattern(sourcePattern), + m_targetType(targetType), + m_landscapeWidth(landscapeX), + m_landscapeHeight(landscapeY), + m_portraitWidth(portraitX), + m_portraitHeight(portraitY), + m_squareWidth(squareX), + m_quality(targetType == "jpg" ? quality : 0), + m_mainWindows(mainWindow), + m_shouldStop(false), + m_imageInfo( + new QRegularExpression(" (PNG|GIF|JPEG) (\\d+)x(\\d+) ")), + m_groupWidth(2), + m_groupHeight(3){ } /** * @brief Destructor. */ -Converter::~Converter() -{ - delete m_script; +Converter::~Converter(){ + delete m_imageInfo; } /** @@ -149,234 +154,291 @@ Converter::~Converter() * @param prefix the string starting the argument * @param value the value of the argument */ -void addArg(QStringList& args, const char* prefix, int value) -{ - QString arg; - arg.sprintf("%s%d", prefix, value); - args << arg; +void addArg(QStringList& args, const char* prefix, int value){ + QString arg; + arg.sprintf("%s%d", prefix, value); + args << arg; } /** - * @brief Builds the arguments of the script call. + * @brief Changes the state of the thread. * - * @return true: OK
- * false: error occurred + * @param state the new state + * @param info an info about the change */ -bool Converter::buildArgs() -{ - bool rc = true; - m_args.clear(); - m_args << "-v"; - if (m_landscapeHeight > 0) - addArg(m_args, "-lw", m_landscapeHeight); - else if (m_landscapeWidth > 0) - addArg(m_args, "-lh", m_landscapeWidth); - else - rc = error("keine/falsche Maximalangabe beim Breitformat"); - - if (m_portraitWidth > 0) - addArg(m_args, "-pw", m_portraitWidth); - else if (m_portraitHeight > 0) - addArg(m_args, "-ph", m_portraitHeight); - else - rc = error("keine/falsche Maximalangabe beim Hochformat"); - - if (m_squareWidth > 0) - addArg(m_args, "-sw", m_squareWidth); - else - rc = error("keine/falsche Maximalangabe beim Hochformat"); - - if (m_quality < 10 || m_quality > 100) - rc = error("keine/falsche Qualität"); - else - addArg(m_args, "-q", m_quality); - - return rc; +void Converter::changeState(Converter::State state, const QString& info){ + m_mainWindows->on_threadStateChanged(state, info); } /** - * @brief Changes the state of the thread. + * Reads the image properties from an image file. * - * @param state the new state - * @param info an info about the change + * @param name filename with path + * @param width OUT: the width of the image + * @param height OUT: the height of the image + * @param info OUT: information of the image + * @return true: success
+ * false: cannot retrieve the image data */ -void Converter::changeState(Converter::State state, const QString& info) -{ - m_mainWindows->on_threadStateChanged(state, info); +/** + * Converts an image into another format. + * + * @param source the source filename with path + * @param target the target filename with path + * @param width the old width of the image + * @param height the old height of the image + * @param widthNew the new width of the image + * @param heightNew the new height of the image + * @param quality 0 or quality in % (only for JPEG targets) + */ +void Converter::convert(const QString& source, const QString& target, int width, + int height, int widthNew, int heightNew, int quality){ + QStringList args; + // convert -size 100x200 source.png -resize 50x100 target.jpg"; + args << "-size" << QString::number(width) + "x" + QString::number(height); + args << source; + if (quality > 0) + args << "-quality" << QString::number(quality); + args << "-resize" + << QString::number(widthNew) + "x" + QString::number(heightNew); + args << target; + QProcess process; + process.start("/usr/bin/convert", args); + QByteArray output; + while (process.waitForReadyRead()){ + output = process.readAll(); + } + output = process.readAllStandardError(); + if (!output.isEmpty()) + error(output); + process.close(); } /** - * @brief Runs the thread's task. + * @brief Converts one file. * - *
    - *
  • Makes the target directory (if necessary)
  • - *
  • Search the images *.png / *.jpg and converts them
  • - *
      + * @param source the file's name with path + * @param target the new filename with path + * @param size the size of the file (in byte) */ -void Converter::run() -{ - QString msg; - int no = 0; - try { - if (! m_dir.exists()) - error("Verzeichnis existiert nicht: " + m_dir.absolutePath()); - if (! m_targetDir.exists()){ - QString parentName = m_targetDir.path(); - QString subdir = m_targetDir.dirName(); - QDir parent(m_targetDir.path()); - parent.cdUp(); - parent.mkdir(subdir); - } - if (! m_targetDir.exists()){ - error("Kann Zielverzeichnis nicht anlegen: " + m_targetDir.absolutePath()); - } - QStringList names; - names.append("*.jpg"); - names.append("*.JPG"); - names.append("*.png"); - names.append("*.PNG"); - changeState(Converter::STATE_STARTING, ""); - buildArgs(); - m_shouldStop = false; - QDirIterator it(m_dir.absolutePath(), names); - while(it.hasNext()){ - if (m_shouldStop){ - log("Abbruch durch Benutzer"); - break; +void Converter::convertOneFile(const QString& source, const QString& target, + qint64 size){ + int width = 0; + int height = 0; + QString info; + clock_t start = clock(); + if (readProperties(source, width, height, info)){ + bool doConvert = false; + int widthNew, heightNew; + if (abs(width - height) < 5){ + // Square format: + doConvert = width > m_squareWidth; + if (doConvert) + widthNew = heightNew = m_squareWidth; + }else if (width > height){ + // Landscape: + doConvert = width > m_landscapeWidth || height > m_landscapeHeight; + if (doConvert){ + if (width > m_landscapeWidth && m_landscapeWidth > 0){ + widthNew = m_landscapeWidth; + heightNew = height * m_landscapeWidth / width; + }else{ + heightNew = m_landscapeHeight; + widthNew = width * m_landscapeHeight / height; } - no++; - it.next(); - QString path = it.path(); - qint64 length = it.fileInfo().size(); - path += QDir::separator(); - path += it.fileName(); - convertOneFile(path, length); - - msg.sprintf("%4d Datei(en) konvertiert", no); - changeState(Converter::STATE_SUB_TASK_STOPPED, msg); - } - } catch(ConverterException exc){ - log("Abarbeitung wegen Fehlers gestoppt: " + exc.message()); - } - msg.sprintf("%d Datei(en) konvertiert", no); - changeState(Converter::STATE_READY, msg); + } + }else{ + // Portrait + doConvert = width > m_portraitWidth || height > m_portraitHeight; + if (doConvert){ + if (width > m_portraitWidth && m_portraitWidth > 0){ + widthNew = m_portraitWidth; + heightNew = height * m_portraitWidth / width; + }else{ + heightNew = m_portraitHeight; + widthNew = width * m_portraitHeight / height; + } + } + } + log( + source + " " + info + " " + sizeToString(size) + + QString(" -> %1x%2 ").arg(widthNew).arg(heightNew)); + convert(source, target, width, height, widthNew, heightNew, m_quality); + struct stat info; + if (stat(target.toUtf8().constData(), &info) == 0) + m_mainWindows->logAppendLast(sizeToString(info.st_size) + " "); + } + m_mainWindows->logAppendLast( + QString("").sprintf("%.3f sec", + double(clock() - start) / CLOCKS_PER_SEC)); } /** - * Reads the image properties from an image file. + * @brief Logs an error message. * - * @param name filename with path - * @param width OUT: the width of the image - * @param height OUT: the height of the image - * @param info OUT: information of the image + * @param message the message to log + * @return false + * @throws ConverterException */ -void Converter::readProperties(const QString& name, int& width, int& height, QString& info) -{ - +bool Converter::error(const QString& message){ + m_mainWindows->log(message); + throw ConverterException(message); + return false; } /** - * @brief Search for the Perl script which make the conversion itself. + * @brief Logs a message. * - * @param node the name of script without path. - * @return the full name of the script (with path) + * @param message the message to log + * @return true */ -QString findScript(const QString& node) -{ - static QString rc; - if (rc.isEmpty()){ - - QDir dir = QDir::current(); - QFile scriptFile(dir.filePath(node)); - if (! scriptFile.exists()) - { - extern char** g_argv; - dir.setPath(g_argv[0]); - dir.cdUp(); - scriptFile.setFileName(dir.filePath(node)); - } - if (scriptFile.exists()) - rc = scriptFile.fileName(); - } - return rc; +bool Converter::log(const QString& message){ + printf("%s\n", message.toUtf8().constData()); + m_mainWindows->log(message); + return true; } + /** - * @brief Converts the size into a human readable string. + * Reads the image properties using the external program "identify". * - * @param size the size in bytes - * @return the size as human readable string, e.g. "2MiByte" + * @param name the filename with path + * @param width OUT: the width of the image + * @param height OUT: the height of the image + * @param info OUT: an info about the image + * @return true: success + * false: properties not readable */ -QString sizeToString(qint64 size) -{ - QString rc; - if (size < 10*1024) - rc.sprintf("%d Bytes", (int) size); - else if (size < qint64(10*1024*1024)) - rc.sprintf("%d KiBytes", (int) (size / 1024)); - else if (size < qint64(10*1024*1024)*1024) - rc.sprintf("%d MiBytes", (int) (size / 1024 / 1024)); - else - rc.sprintf("%d GiBytes", (int) (size / 1024 / 1024 / 1024)); - return rc; +bool Converter::readProperties(const QString& name, int& width, int& height, + QString& info){ + QStringList args; + args << name; + QProcess process; + process.start("/usr/bin/identify", args); + QByteArray output; + bool rc = false; + while (process.waitForReadyRead()){ + output = process.readAll(); + QRegularExpressionMatch match = m_imageInfo->match(output); + if (!match.hasMatch()) + error( + QObject::tr("I am confused (wrong image data):\n%1\nExpected: %2").arg( + output.constData()).arg(m_imageInfo->pattern())); + else{ + width = match.captured(m_groupWidth).toInt(); + height = match.captured(m_groupHeight).toInt(); + rc = true; + info = QString("%1x%2").arg(width).arg(height); + break; + } + } + output = process.readAll(); + output = process.readAllStandardError(); + if (!output.isEmpty()) + error(output); + process.close(); + return rc; } /** - * @brief Converts one file. + * @brief Runs the thread's task. * - * @param file the file's name - * @param size the size of the file (in byte) + *
        + *
      • Makes the target directory (if necessary)
      • + *
      • Search the images *.png / *.jpg and converts them
      • + *
          */ -void Converter::convertOneFile(const QString& file, qint64 size) -{ - QString node("img_trans.pl"); - log(file + " " + sizeToString(size)); - QString script(findScript(node)); - if (script.isEmpty()) - error("Script nicht gefunden: " + node); - else { - QStringList args; - args << script << m_args << file << m_targetDir.absolutePath(); - m_script->start("/usr/bin/perl", args); - QByteArray output; - while (m_script->waitForReadyRead()){ - output = m_script->readAll(); - QList lines = output.split('\n'); - QList::iterator it; - for (it = lines.begin(); it != lines.end(); it++){ - log(*it); - } - } - output = m_script->readAllStandardError(); - if (!output.isEmpty()) - error(output); - m_script->close(); - } +void Converter::run(){ + QString msg; + int no = 0; + try{ + if (!m_dir.exists()) + error( + QObject::tr("Directory does not exist: ") + m_dir.absolutePath()); + if (!m_targetDir.exists()){ + QString parentName = m_targetDir.path(); + QString subdir = m_targetDir.dirName(); + QDir parent(m_targetDir.path()); + parent.cdUp(); + parent.mkdir(subdir); + } + if (!m_targetDir.exists()){ + error( + QObject::tr("Cannot create the target directory: ") + + m_targetDir.absolutePath()); + } + changeState(Converter::STATE_STARTING, ""); + m_shouldStop = false; + QDirIterator it(m_dir.absolutePath()); + QRegExp regExpr(m_sourcePattern, Qt::CaseInsensitive, QRegExp::Wildcard); + while (it.hasNext()){ + if (m_shouldStop){ + log(QObject::tr("Canceled by the user")); + break; + } + it.next(); + if (it.fileInfo().isDir()) + continue; + QString node = it.fileName(); + if (regExpr.indexIn(node) >= 0){ + no++; + QString path = m_dir.absoluteFilePath(node); + qint64 length = it.fileInfo().size(); + QString nodeTarget = ReQStringUtil::replaceExtension(node, + "." + m_targetType); + QString target = m_targetDir.absoluteFilePath(nodeTarget); + convertOneFile(path, target, length); + } + } + changeState(Converter::STATE_SUB_TASK_STOPPED, msg); + } catch (ConverterException exc){ + log( + QObject::tr("Execution stopped because of error(s): ") + + exc.message()); + } + msg = QObject::tr("%1 file(s) converted").arg(no); + changeState(Converter::STATE_READY, msg); + m_mainWindows->switchRun(true); } /** - * @brief Logs a message. + * @brief Search for the Perl script which make the conversion itself. * - * @param message the message to log - * @return true + * @param node the name of script without path. + * @return the full name of the script (with path) */ -bool Converter::log(const QString& message) -{ - printf ("%s\n", message.toUtf8().constData()); - m_mainWindows->log(message); - return true; -} +QString findScript(const QString& node){ + static QString rc; + if (rc.isEmpty()){ + QDir dir = QDir::current(); + QFile scriptFile(dir.filePath(node)); + if (!scriptFile.exists()){ + extern char** g_argv; + dir.setPath(g_argv[0]); + dir.cdUp(); + scriptFile.setFileName(dir.filePath(node)); + } + if (scriptFile.exists()) + rc = scriptFile.fileName(); + } + return rc; +} /** - * @brief Logs an error message. + * @brief Converts the size into a human readable string. * - * @param message the message to log - * @return false - * @throws ConverterException + * @param size the size in bytes + * @return the size as human readable string, e.g. "2MiByte" */ -bool Converter::error(const QString& message) -{ - m_mainWindows->log(message); - throw ConverterException(message); - return false; +QString sizeToString(qint64 size){ + QString rc; + if (size < 10 * 1024) + rc.sprintf("%d Bytes", (int) size); + else if (size < qint64(10 * 1024 * 1024)) + rc.sprintf("%d KiBytes", (int) (size / 1024)); + else if (size < qint64(10 * 1024 * 1024) * 1024) + rc.sprintf("%d MiBytes", (int) (size / 1024 / 1024)); + else + rc.sprintf("%d GiBytes", (int) (size / 1024 / 1024 / 1024)); + return rc; } diff --git a/appl/reimgconvert/converter.hpp b/appl/reimgconvert/converter.hpp index e4e7140..ace17eb 100644 --- a/appl/reimgconvert/converter.hpp +++ b/appl/reimgconvert/converter.hpp @@ -4,8 +4,7 @@ * There is no warranty. * You also can use the licence from http://www.wtfpl.net/. * The original sources can be found on https://github.com/republib. -*/ - + */ #ifndef CONVERTER_HPP #define CONVERTER_HPP @@ -18,65 +17,69 @@ #include class MainWindow; -class ConverterException{ +class ConverterException { public: - ConverterException(const QString& message) : m_message(message) - {} - const QString& message() const - { return m_message; } + ConverterException(const QString& message) : + m_message(message){ + } + const QString& message() const{ + return m_message; + } private: - QString m_message; + QString m_message; }; -class ConvertLogger{ +class ConvertLogger { public: - virtual bool log(const QString& message) = 0; - virtual bool error(const QString& message) = 0; + virtual bool log(const QString& message) = 0; + virtual bool error(const QString& message) = 0; }; -class Converter : public QThread -{ - Q_OBJECT +class Converter: public QThread { + Q_OBJECT public: - enum State { - STATE_UNDEF, - STATE_STARTING, - STATE_SUB_TASK_STOPPED, - STATE_READY, - }; + enum State { + STATE_UNDEF, STATE_STARTING, STATE_SUB_TASK_STOPPED, STATE_READY, + }; public: - Converter(const QString& directory, const QString& targetDirectory, - int landscapeX, int landscapey, - int portraitX, int portraitY, - int squareX, int quality, MainWindow* mainWindows); - ~Converter(); + Converter(const QString& directory, const QString& targetDirectory, + const QString& sourcePattern, const QString& targetType, int landscapeX, + int landscapey, int portraitX, int portraitY, int squareX, int quality, + MainWindow* mainWindows); + ~Converter(); public: - bool log(const QString& message); - bool error(const QString& message); - void run(); - void stop(){ - m_shouldStop = true; - } + bool error(const QString& message); + bool log(const QString& message); + void run(); + void stop(){ + m_shouldStop = true; + } protected: - void readProperties(const QString& name, int &width, int &height, QString &info); - void convertOneFile(const QString& name, qint64 size); - bool buildArgs(); - void changeState(State state, const QString& info); + bool buildArgs(); + void changeState(State state, const QString& info); + void convert(const QString& source, const QString& target, int width, + int height, int widthNew, int heightNew, int quality); + void convertOneFile(const QString& source, const QString& target, + qint64 size); + bool readProperties(const QString& name, int &width, int &height, + QString &info); private: - QDir m_dir; - QDir m_targetDir; - int m_landscapeWidth; - int m_landscapeHeight; - int m_portraitWidth; - int m_portraitHeight; - int m_squareWidth; - int m_quality; - MainWindow* m_mainWindows; - QProcess* m_script; - QStringList m_args; - bool m_shouldStop; + QDir m_dir; + QDir m_targetDir; + QString m_sourcePattern; + QString m_targetType; + int m_landscapeWidth; + int m_landscapeHeight; + int m_portraitWidth; + int m_portraitHeight; + int m_squareWidth; + int m_quality; + MainWindow* m_mainWindows; + bool m_shouldStop; + QRegularExpression* m_imageInfo; + int m_groupWidth; + int m_groupHeight; }; - #endif // CONVERTER_HPP diff --git a/appl/reimgconvert/main.cpp b/appl/reimgconvert/main.cpp index fd61925..6d571f3 100644 --- a/appl/reimgconvert/main.cpp +++ b/appl/reimgconvert/main.cpp @@ -4,18 +4,16 @@ * There is no warranty. * You also can use the licence from http://www.wtfpl.net/. * The original sources can be found on https://github.com/republib. -*/ - + */ #include "mainwindow.hpp" #include char** g_argv; -int main(int argc, char *argv[]) -{ - g_argv = argv; - QApplication a(argc, argv); - MainWindow w; - w.show(); +int main(int argc, char *argv[]){ + g_argv = argv; + QApplication a(argc, argv); + MainWindow w; + w.show(); - return a.exec(); + return a.exec(); } diff --git a/appl/reimgconvert/mainwindow.cpp b/appl/reimgconvert/mainwindow.cpp index a8bc2d6..4ffd4af 100644 --- a/appl/reimgconvert/mainwindow.cpp +++ b/appl/reimgconvert/mainwindow.cpp @@ -4,11 +4,13 @@ * There is no warranty. * You also can use the licence from http://www.wtfpl.net/. * The original sources can be found on https://github.com/republib. -*/ - + */ #include "mainwindow.hpp" #include "ui_mainwindow.h" +#include "aboutdialog.hpp" + +const QString VERSION("2015.05.31"); /** @class MainWindow mainwindow.hpp "mainwindow.hpp" * @@ -25,54 +27,77 @@ * @param parent NULL or the parent (who destroys the objects at the end) */ MainWindow::MainWindow(QWidget *parent) : - QMainWindow(parent), - ui(new Ui::MainWindow), - m_converter(NULL) -{ - ui->setupUi(this); - QStringList defaultX; - defaultX.append("*"); - defaultX.append("1024"); - defaultX.append("1920"); - defaultX.append("800"); - QStringList defaultY; - defaultY.append("*"); - defaultY.append("768"); - defaultY.append("1050"); - defaultY.append("600"); - QStringList quality; - quality.append("70"); - quality.append("85"); - quality.append("100"); - QStringList target; - target.append("normal"); - target.append("mini"); - target.append("1024"); - target.append("1920"); - ui->comboLandscapeX->addItems(defaultX); - ui->comboLandscapeY->addItems(defaultY); - ui->comboPortraitX->addItems(defaultX); - ui->comboPortraitY->addItems(defaultY); - ui->comboSquareX->addItems(defaultX); - ui->comboQuality->addItems(quality); - ui->comboTarget->addItems(target); - ui->comboLandscapeX->setCurrentText("1024"); - ui->comboLandscapeY->setCurrentText("*"); - ui->comboPortraitX->setCurrentText("*"); - ui->comboPortraitY->setCurrentText("768"); - ui->comboSquareX->setCurrentText("768"); - ui->comboQuality->setCurrentText("70"); - ui->comboTarget->setCurrentText("normal"); - ui->buttonStop->hide(); + QMainWindow(parent), ui(new Ui::MainWindow), m_converter(NULL){ + ui->setupUi(this); + switchRun(true); + QStringList defaultX; + defaultX.append("*"); + defaultX.append("1024"); + defaultX.append("1920"); + defaultX.append("800"); + QStringList defaultY; + defaultY.append("*"); + defaultY.append("768"); + defaultY.append("1050"); + defaultY.append("600"); + QStringList quality; + quality.append("70"); + quality.append("85"); + quality.append("100"); + QStringList target; + target.append("normal"); + target.append("mini"); + target.append("1024"); + target.append("1920"); + ui->comboLandscapeX->addItems(defaultX); + ui->comboLandscapeY->addItems(defaultY); + ui->comboPortraitX->addItems(defaultX); + ui->comboPortraitY->addItems(defaultY); + ui->comboSquareX->addItems(defaultX); + ui->comboQuality->addItems(quality); + ui->comboTarget->addItems(target); + ui->comboLandscapeX->setCurrentText("1024"); + ui->comboLandscapeY->setCurrentText("*"); + ui->comboPortraitX->setCurrentText("*"); + ui->comboPortraitY->setCurrentText("768"); + ui->comboSquareX->setCurrentText("768"); + ui->comboQuality->setCurrentText("70"); + ui->comboTarget->setCurrentText("normal"); + ui->buttonStop->hide(); + + connect(ui->actionSelectDestination, SIGNAL(triggered()), this, + SLOT(selectDestination())); + connect(ui->pushButtonSelectDest, SIGNAL(clicked()), this, + SLOT(selectDestination())); + connect(ui->actionAbout, SIGNAL(triggered()), this, SLOT(about())); + +} + +/** + * Selects the destination directory with a dialog. + */ +void MainWindow::selectDestination(){ + QString dir = QFileDialog::getExistingDirectory(this, + tr("Select Destination Directory"), ui->comboTarget->currentText(), + QFileDialog::ShowDirsOnly); + if (!dir.isEmpty()) + ui->comboTarget->setCurrentText(dir); } /** * @brief Destructor */ -MainWindow::~MainWindow() -{ - delete ui; - delete m_converter; +MainWindow::~MainWindow(){ + delete ui; + delete m_converter; +} + +/** + * Starts the about dialog. + */ +void MainWindow::about(){ + AboutDialog dialog(VERSION); + dialog.exec(); } /** @@ -81,31 +106,58 @@ MainWindow::~MainWindow() * @param message the message to log * @return true */ -bool MainWindow::log(const QString& message) -{ - ui->listWidget->addItem(message); - return true; +bool MainWindow::log(const QString& message){ + ui->listWidget->insertItem(0, message); + return true; +} + +/** + * @brief Logs a message + * + * @param message the message to log + * @return true + */ +bool MainWindow::logAppendLast(const QString& message){ + QListWidgetItem* item = ui->listWidget->item(0); + item->setText(item->text() + " " + message); + return true; +} + +/** + * Enables/disables the buttons/actions relevant for running. + * + * @param runActive true: the conversion is possible + */ +void MainWindow::switchRun(bool runActive){ + if (runActive){ + ui->buttonConvert->show(); + ui->buttonStop->hide(); + }else{ + ui->buttonConvert->hide(); + ui->buttonStop->show(); + } + ui->actionConvert->setEnabled(runActive); + ui->actionStop->setEnabled(not runActive); } /** * @brief Handles the button click on "convert". */ -void MainWindow::on_buttonConvert_clicked() -{ - ui->buttonConvert->hide(); - ui->buttonStop->show(); - delete m_converter; - m_converter = new Converter(ui->comboSourceDir->currentText(), - ui->comboLandscapeX->currentText(), - atol(ui->comboLandscapeX->currentText().toLatin1().constData()), - atol(ui->comboLandscapeY->currentText().toLatin1().constData()), - atol(ui->comboPortraitX->currentText().toLatin1().constData()), - atol(ui->comboPortraitY->currentText().toLatin1().constData()), - atol(ui->comboSquareX->currentText().toLatin1().constData()), - atol(ui->comboQuality->currentText().toLatin1().constData()), - this); - // start the thread: - m_converter->start(); +void MainWindow::on_buttonConvert_clicked(){ + switchRun(false); + delete m_converter; + m_converter = new Converter(ui->comboSourceDir->currentText(), + ui->comboLandscapeX->currentText(), + ui->comboBoxSourcePattern->currentText(), + ui->comboBoxDestType->currentText(), + atol(ui->comboLandscapeX->currentText().toLatin1().constData()), + atol(ui->comboLandscapeY->currentText().toLatin1().constData()), + atol(ui->comboPortraitX->currentText().toLatin1().constData()), + atol(ui->comboPortraitY->currentText().toLatin1().constData()), + atol(ui->comboSquareX->currentText().toLatin1().constData()), + atol(ui->comboQuality->currentText().toLatin1().constData()), this); + // start the thread: + m_converter->start(); } /** @@ -114,32 +166,29 @@ void MainWindow::on_buttonConvert_clicked() * @param state the new state of the thread * @param info info about the new state. Not used */ -void MainWindow::on_threadStateChanged(Converter::State state, - const QString&) -{ - switch(state){ - case Converter::STATE_READY: - ui->buttonConvert->show(); - ui->buttonStop->hide(); - //ui->statusBar->showMessage(info); - break; - case Converter::STATE_SUB_TASK_STOPPED: - //ui->statusBar->showMessage(info); - break; - case Converter::STATE_STARTING: - default: - break; - } +void MainWindow::on_threadStateChanged(Converter::State state, const QString&){ + switch (state) { + case Converter::STATE_READY: + ui->buttonConvert->show(); + ui->buttonStop->hide(); + //ui->statusBar->showMessage(info); + break; + case Converter::STATE_SUB_TASK_STOPPED: + //ui->statusBar->showMessage(info); + break; + case Converter::STATE_STARTING: + default: + break; + } } /** * @brief Handles the click on the button "stop". */ -void MainWindow::on_buttonStop_clicked() -{ - m_converter->stop(); - ui->buttonConvert->show(); - ui->buttonStop->hide(); +void MainWindow::on_buttonStop_clicked(){ + m_converter->stop(); + ui->buttonConvert->show(); + ui->buttonStop->hide(); } /** @@ -148,15 +197,13 @@ void MainWindow::on_buttonStop_clicked() * Shows a selection dialog for directories and sets the source directory * onto the selected directory. */ -void MainWindow::on_buttonFileSelect_clicked() -{ - QFileDialog selection; - selection.setFileMode(QFileDialog::DirectoryOnly); - QString dir = ui->comboSourceDir->currentText(); - if (! dir.isEmpty()) - selection.setDirectory(dir); - if (selection.exec()) - ui->comboSourceDir->setCurrentText(selection.selectedFiles().at(0)); +void MainWindow::on_buttonFileSelect_clicked(){ + QFileDialog selection; + selection.setFileMode(QFileDialog::DirectoryOnly); + QString dir = ui->comboSourceDir->currentText(); + if (!dir.isEmpty()) + selection.setDirectory(dir); + if (selection.exec()) + ui->comboSourceDir->setCurrentText(selection.selectedFiles().at(0)); } - diff --git a/appl/reimgconvert/mainwindow.hpp b/appl/reimgconvert/mainwindow.hpp index 66e1ee5..43f957f 100644 --- a/appl/reimgconvert/mainwindow.hpp +++ b/appl/reimgconvert/mainwindow.hpp @@ -4,8 +4,7 @@ * There is no warranty. * You also can use the licence from http://www.wtfpl.net/. * The original sources can be found on https://github.com/republib. -*/ - + */ #ifndef MAINWINDOW_HPP #define MAINWINDOW_HPP @@ -18,30 +17,30 @@ namespace Ui { class MainWindow; } -class MainWindow : public QMainWindow, public ConvertLogger -{ - Q_OBJECT +class MainWindow: public QMainWindow, public ConvertLogger { + Q_OBJECT public: - explicit MainWindow(QWidget *parent = 0); - ~MainWindow(); + explicit MainWindow(QWidget *parent = 0); + ~MainWindow(); public: - bool log(const QString& message); - bool error(const QString& message){ - log("+++ " + message); return false; - } -private slots: - void on_buttonFileSelect_clicked(); - - void on_buttonStop_clicked(); - - void on_buttonConvert_clicked(); -public slots: - void on_threadStateChanged(Converter::State state, const QString& info); + bool error(const QString& message){ + log("+++ " + message); + return false; + } + bool log(const QString& message); + bool logAppendLast(const QString& message); + void switchRun(bool runActive);private slots: + void about(); + void on_buttonFileSelect_clicked(); + void on_buttonStop_clicked(); + void on_buttonConvert_clicked(); + void selectDestination();public slots: + void on_threadStateChanged(Converter::State state, const QString& info); private: - Ui::MainWindow *ui; - Converter* m_converter; + Ui::MainWindow *ui; + Converter* m_converter; }; #endif // MAINWINDOW_HPP diff --git a/appl/reimgconvert/mainwindow.ui b/appl/reimgconvert/mainwindow.ui index ccfc44e..34b0e9b 100644 --- a/appl/reimgconvert/mainwindow.ui +++ b/appl/reimgconvert/mainwindow.ui @@ -6,8 +6,8 @@ 0 0 - 735 - 532 + 772 + 556 @@ -23,7 +23,7 @@ - + @@ -135,6 +135,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -242,6 +255,19 @@ + + + + Qt::Horizontal + + + + 40 + 20 + + + + @@ -301,19 +327,6 @@ - - - - Qt::Horizontal - - - - 40 - 20 - - - - @@ -333,301 +346,309 @@ Others: - - - - 640 - 70 - 51 - 27 - - - - ... - - - - - - 0 - 30 - 221 - 28 - - - - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - Quality (%) - - - - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - true - - - - - - - - - 0 - 70 - 631 - 28 - - - - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - Destination: - - - - - - - true - - - - - - - - - - - - 0 - 110 - 631 - 28 - - - - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - Template: - - - - - - - - Website: 1024x768 + + + + + + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + Quality (%) + + + + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + true + + + + + + + + + Qt::Horizontal - - - - Website II: 800x600 + + + 40 + 20 + - - - - Photo: 2048x1536 + + + + + + QFormLayout::AllNonFixedFieldsGrow - - - - Photo II: 3072x2304 + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + File Pattern: + + + + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + A pattern of the source files with wildcards '*' (anything) and '?' (exact one char) + + + true + + + + *.jpg + + + + + *.png + + + + + *.gif + + + + + + + + + + Qt::Horizontal - - - - Midi: 600x400 + + + 40 + 20 + - - - - Mini: 150x100 + + + + + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + Dest. Type: + + + + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + + jpg + + + + + png + + + + + + + + + + + + + + + 100 + 0 + - - - - - - - - - 240 - 30 - 209 - 28 - - - - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - Source Type: - - - - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - true - - - - jpg + + + 100 + 16777215 + - - - png + Destination: - - - - gif + + + + + + true - - - - - - - - - 480 - 30 - 211 - 28 - - - - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - Dest. Type: - - - - - - - - 100 - 0 - - - - - 100 - 16777215 - - - - - jpg + + + + + + + + + + 50 + 0 + + + + + 50 + 16777215 + - - - png + ... - - - - - + + + + + + + + + + + + + 100 + 0 + + + + + 100 + 16777215 + + + + Template: + + + + + + + + Website: 1024x768 + + + + + Website II: 800x600 + + + + + Photo: 2048x1536 + + + + + Photo II: 3072x2304 + + + + + Midi: 600x400 + + + + + Mini: 150x100 + + + + + + + + + - + @@ -670,20 +691,20 @@ - - - Qt::Horizontal - - - - 40 - 20 - - - - - - + + + + + Qt::Vertical + + + + 20 + 40 + + + + @@ -755,7 +776,7 @@ 0 0 - 735 + 772 23 @@ -912,8 +933,8 @@ close() - 367 - 265 + -1 + -1 367 diff --git a/appl/reimgconvert/reimgconvert.pro b/appl/reimgconvert/reimgconvert.pro index 03d6873..075cbef 100644 --- a/appl/reimgconvert/reimgconvert.pro +++ b/appl/reimgconvert/reimgconvert.pro @@ -11,17 +11,24 @@ greaterThan(QT_MAJOR_VERSION, 4): QT += widgets TARGET = reimgconvert TEMPLATE = app +INCLUDEPATH = ../.. /usr/include/c++/4.9 SOURCES += main.cpp\ - mainwindow.cpp \ - converter.cpp + ../../base/ReException.cpp \ + ../../base/ReQStringUtil.cpp \ + ../../base/ReLogger.cpp \ + mainwindow.cpp \ + converter.cpp \ + aboutdialog.cpp HEADERS += mainwindow.hpp \ - converter.hpp + converter.hpp \ + aboutdialog.hpp -FORMS += mainwindow.ui +FORMS += mainwindow.ui \ + aboutdialog.ui RESOURCES += \ - reimgconvert.qrc + reimgconvert.qrc OTHER_FILES += diff --git a/base/ReQStringUtil.cpp b/base/ReQStringUtil.cpp index 1bc55da..8fd5025 100644 --- a/base/ReQStringUtil.cpp +++ b/base/ReQStringUtil.cpp @@ -55,15 +55,20 @@ QString& ReQStringUtil::ensureLastChar(QString& value, QChar lastChar){ */ ReString ReQStringUtil::extensionOf(const ReString& filename){ QString rc; - int index = filename.lastIndexOf('.'); + int index2 = 0; if (index > 0){ - int index2 = filename.lastIndexOf('/'); - if (index2 < index){ -#if defined WIN32 + index2 = filename.lastIndexOf('/'); + if (index2 >= 0){ + if (index > index2) + rc = filename.mid(index); + } else { +#if defined __linux__ + rc = filename.mid(index); +#elif defined WIN32 index2 = filename.lastIndexOf('\\'); - if (index2 < index) - rc = filename.mid(index); + if (index2 < 0 || index > index2) + rc = filename.mid(index); #endif } } @@ -413,6 +418,24 @@ QString ReQStringUtil::pathAppend(const QString& base, const QString& path){ return rc; } +/** + * Replaces the file extension of a filename. + * + * @param path the filename to change + * @param ext the new file extension, e.g. ".txt" + * @return path with a new file extension + */ + +QString ReQStringUtil::replaceExtension(const QString& path, const QString& ext) +{ + QString oldExt = extensionOf(path); + QString rc; + if (oldExt.isEmpty()) + rc = path + ext; + else + rc = path.mid(0, path.size() - oldExt.size()) + ext; + return rc; +} /** * Replaces placeholders by their values. * diff --git a/base/ReQStringUtil.hpp b/base/ReQStringUtil.hpp index e3a221c..fc00085 100644 --- a/base/ReQStringUtil.hpp +++ b/base/ReQStringUtil.hpp @@ -45,6 +45,7 @@ public: } static ReString nodeOf(const ReString& filename); static QString pathAppend(const QString& base, const QString& path); + static QString replaceExtension(const QString& path, const QString& ext); static bool replacePlaceholders(QString& text, const QMap & placeholders, QString* error); static void skipExpected(const ReString& text, QChar expected, int& index, -- 2.39.5