add support to export slide show animation to movie file via ffmpeg

This commit is contained in:
Axel Kohlmeyer
2023-09-24 15:09:14 -04:00
parent c50dcf6129
commit 5588c121f4
6 changed files with 62 additions and 5 deletions

View File

@ -225,11 +225,13 @@ displays the images created by LAMMPS as they are written.
:align: center :align: center
:scale: 50% :scale: 50%
The various buttons at the bottom right of the window allow either The various buttons at the bottom right of the window allow single
single stepping through the sequence of images or playing an animation stepping through the sequence of images or playing an animation (as a
(as a continuous loop or once from first to last). It is also possible continuous loop or once from first to last). It is also possible to
to zoom in or zoom out of the displayed images. The slide show window zoom in or zoom out of the displayed images, and to export the slide
will be closed when a new file is loaded. show animation to a movie file, if `ffmpeg <https://ffmpeg.org/>`_ is
installed. The slide show window will be closed when a new file is
loaded.
Variable Info Variable Info
------------- -------------

Binary file not shown.

After

Width:  |  Height:  |  Size: 5.0 KiB

View File

@ -858,6 +858,7 @@ void LammpsGui::logupdate()
slideshow->hide(); slideshow->hide();
} else { } else {
slideshow->setWindowTitle(QString("LAMMPS-GUI - Slide Show: ") + current_file); slideshow->setWindowTitle(QString("LAMMPS-GUI - Slide Show: ") + current_file);
if (QSettings().value("viewslide", true).toBool()) slideshow->show();
} }
slideshow->add_image(imagefile); slideshow->add_image(imagefile);
} }

View File

@ -24,6 +24,7 @@
<file>edit-undo.png</file> <file>edit-undo.png</file>
<file>emblem-photos.png</file> <file>emblem-photos.png</file>
<file>expand-text.png</file> <file>expand-text.png</file>
<file>export-movie.png</file>
<file>format-indent-less-3.png</file> <file>format-indent-less-3.png</file>
<file>go-first.png</file> <file>go-first.png</file>
<file>go-last.png</file> <file>go-last.png</file>

View File

@ -13,7 +13,11 @@
#include "slideshow.h" #include "slideshow.h"
#include "helpers.h"
#include <QDialogButtonBox> #include <QDialogButtonBox>
#include <QDir>
#include <QFileDialog>
#include <QFileInfo> #include <QFileInfo>
#include <QGuiApplication> #include <QGuiApplication>
#include <QHBoxLayout> #include <QHBoxLayout>
@ -21,11 +25,13 @@
#include <QImageReader> #include <QImageReader>
#include <QLabel> #include <QLabel>
#include <QPalette> #include <QPalette>
#include <QProcess>
#include <QPushButton> #include <QPushButton>
#include <QScreen> #include <QScreen>
#include <QSettings> #include <QSettings>
#include <QShortcut> #include <QShortcut>
#include <QSpacerItem> #include <QSpacerItem>
#include <QTemporaryFile>
#include <QTimer> #include <QTimer>
#include <QVBoxLayout> #include <QVBoxLayout>
@ -58,6 +64,10 @@ SlideShow::SlideShow(const QString &fileName, QWidget *parent) :
auto *dummy = new QPushButton(QIcon(), ""); auto *dummy = new QPushButton(QIcon(), "");
dummy->hide(); dummy->hide();
auto *tomovie = new QPushButton(QIcon(":/export-movie.png"), "");
tomovie->setToolTip("Export to movie file");
tomovie->setEnabled(has_exe("ffmpeg"));
auto *gofirst = new QPushButton(QIcon(":/go-first.png"), ""); auto *gofirst = new QPushButton(QIcon(":/go-first.png"), "");
gofirst->setToolTip("Go to first Image"); gofirst->setToolTip("Go to first Image");
auto *goprev = new QPushButton(QIcon(":/go-previous-2.png"), ""); auto *goprev = new QPushButton(QIcon(":/go-previous-2.png"), "");
@ -83,6 +93,7 @@ SlideShow::SlideShow(const QString &fileName, QWidget *parent) :
auto *normal = new QPushButton(QIcon(":/gtk-zoom-fit.png"), ""); auto *normal = new QPushButton(QIcon(":/gtk-zoom-fit.png"), "");
normal->setToolTip("Reset zoom to normal"); normal->setToolTip("Reset zoom to normal");
connect(tomovie, &QPushButton::released, this, &SlideShow::movie);
connect(gofirst, &QPushButton::released, this, &SlideShow::first); connect(gofirst, &QPushButton::released, this, &SlideShow::first);
connect(goprev, &QPushButton::released, this, &SlideShow::prev); connect(goprev, &QPushButton::released, this, &SlideShow::prev);
connect(goplay, &QPushButton::released, this, &SlideShow::play); connect(goplay, &QPushButton::released, this, &SlideShow::play);
@ -96,6 +107,7 @@ SlideShow::SlideShow(const QString &fileName, QWidget *parent) :
navLayout->addSpacerItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum)); navLayout->addSpacerItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum));
navLayout->addWidget(dummy); navLayout->addWidget(dummy);
navLayout->addWidget(tomovie);
navLayout->addWidget(gofirst); navLayout->addWidget(gofirst);
navLayout->addWidget(goprev); navLayout->addWidget(goprev);
navLayout->addWidget(goplay); navLayout->addWidget(goplay);
@ -178,6 +190,46 @@ void SlideShow::loadImage(int idx)
} while (idx >= 0); } while (idx >= 0);
} }
void SlideShow::movie()
{
QString fileName = QFileDialog::getSaveFileName(this, "Export to Movie File", ".",
"Movie Files (*.mpg *.mp4 *.mkv *.avi *.mpeg)");
if (fileName.isEmpty()) return;
QDir curdir(".");
QTemporaryFile concatfile;
concatfile.open();
for (auto image : imagefiles) {
concatfile.write("file '");
concatfile.write(curdir.absoluteFilePath(image).toLocal8Bit());
concatfile.write("'\n");
}
concatfile.close();
QStringList args;
args << "-y";
args << "-safe"
<< "0";
args << "-r"
<< "10";
args << "-f"
<< "concat";
args << "-i" << concatfile.fileName();
if (scaleFactor != 1.0) {
args << "-vf" << QString("scale=iw*%1:-1").arg(scaleFactor);
}
args << "-b:v"
<< "2000k";
args << "-r"
<< "24";
args << fileName;
auto *ffmpeg = new QProcess(this);
ffmpeg->start("ffmpeg", args);
ffmpeg->waitForFinished(-1);
delete ffmpeg;
}
void SlideShow::first() void SlideShow::first()
{ {
current = 0; current = 0;

View File

@ -32,6 +32,7 @@ public:
void clear(); void clear();
private slots: private slots:
void movie();
void first(); void first();
void last(); void last();
void next(); void next();