Skip to content

Commit

Permalink
feat: add wrapper for ImageMagick
Browse files Browse the repository at this point in the history
  • Loading branch information
Bionus committed Feb 3, 2024
1 parent 6069201 commit 494b04c
Show file tree
Hide file tree
Showing 2 changed files with 143 additions and 0 deletions.
110 changes: 110 additions & 0 deletions src/lib/src/external/image-magick.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,110 @@
#include "image-magick.h"
#include <QDir>
#include <QFile>
#include <QFileInfo>
#include <QProcess>
#include "functions.h"
#include "logger.h"


QString ImageMagick::version(int msecs)
{
QProcess process;
process.start("magick", { "-version" });

if (!process.waitForStarted(msecs)) {
return "";
}
if (!process.waitForFinished(msecs)) {
process.kill();
return "";
}
if (process.exitCode() != 0) {
return "";
}

const QString output = QString::fromLocal8Bit(process.readAllStandardOutput());
QString line = output.split("\n").first().trimmed();

if (line.startsWith("Version: ImageMagick ")) {
line = line.mid(21);
}

const qsizetype index = line.indexOf("https://");
if (index != -1) {
return line.left(index).trimmed();
}

return line.trimmed();
}


QString ImageMagick::convert(const QString &file, const QString &extension, bool deleteOriginal, int msecs)
{
// Since the method takes an extension, build an absolute path to the input file with that extension
const QFileInfo info(file);
QString destination = info.path() + QDir::separator() + info.completeBaseName() + "." + extension;

// Ensure the operation is safe to do
if (!QFile::exists(file)) {
log(QStringLiteral("Cannot convert file that does not exist: `%1`").arg(file), Logger::Error);
return file;
}
if (QFile::exists(destination)) {
log(QStringLiteral("Converting the file `%1` would overwrite another file: `%2`").arg(file, destination), Logger::Error);
return file;
}

// Execute the conversion command
const QStringList params = { file, destination };
if (!execute(params, msecs)) {
// Clean-up failed conversions
if (QFile::exists(destination)) {
log(QStringLiteral("Cleaning up failed conversion target file: `%1`").arg(destination), Logger::Warning);
QFile::remove(destination);
}

return file;
}

// Copy file creation information
setFileCreationDate(destination, info.lastModified());

// On success, delete the original file if requested
if (deleteOriginal) {
QFile::remove(file);
}

return destination;
}


bool ImageMagick::execute(const QStringList &params, int msecs)
{
QProcess process;
process.start("magick", params);

// Ensure the process started successfully
if (!process.waitForStarted(msecs)) {
log(QStringLiteral("Could not start ImageMagick"));
return false;
}

// Wait for FFmpeg to finish
bool finishedOk = process.waitForFinished(msecs);
bool didntCrash = process.exitStatus() == QProcess::NormalExit;
bool exitCodeOk = process.exitCode() == 0;
bool ok = finishedOk && didntCrash && exitCodeOk;

// Print stdout and stderr to the log
const QString standardOutput = QString::fromLocal8Bit(process.readAllStandardOutput()).trimmed();
if (!standardOutput.isEmpty()) {
log(QString("[ImageMagick] %1").arg(standardOutput), Logger::Debug);
}
const QString standardError = QString::fromLocal8Bit(process.readAllStandardError()).trimmed();
if (!standardError.isEmpty()) {
log(QString("[ImageMagick] %1").arg(standardError), Logger::Error);
}

return ok;
}
33 changes: 33 additions & 0 deletions src/lib/src/external/image-magick.h
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
#ifndef IMAGE_MAGICK_H
#define IMAGE_MAGICK_H

#include <QString>


class ImageMagick
{
public:
/**
* Get the version of ImageMagick.
*
* @param msecs The duration to wait in milliseconds for the version command to run.
* @return The version number found (ex: "7.0.10").
*/
static QString version(int msecs = 30000);

/**
* Convert a file to a different format.
*
* @param file The file to convert.
* @param extension The target extension (ex: "jpg").
* @param deleteOriginal Whether to delete the original file on success.
* @param msecs The duration to wait in milliseconds for the command to run.
* @return The destination file path on success, the original file path on error.
*/
static QString convert(const QString &file, const QString &extension, bool deleteOriginal = true, int msecs = 30000);

protected:
static bool execute(const QStringList &params, int msecs = 30000);
};

#endif // IMAGE_MAGICK_H

0 comments on commit 494b04c

Please # to comment.