File indexing completed on 2025-03-09 03:56:14

0001 /* ============================================================
0002  *
0003  * This file is a part of digiKam project
0004  * https://www.digikam.org
0005  *
0006  * Date        : 2017-05-25
0007  * Description : a tool to generate video slideshow frames from images.
0008  *
0009  * SPDX-FileCopyrightText: 2017-2024 by Gilles Caulier <caulier dot gilles at gmail dot com>
0010  *
0011  * SPDX-License-Identifier: GPL-2.0-or-later
0012  *
0013  * ============================================================ */
0014 
0015 #include "vidslidetask.h"
0016 
0017 // C++ includes
0018 
0019 #include <cmath>
0020 
0021 // Qt includes
0022 
0023 #include <QDir>
0024 #include <QString>
0025 #include <QStringList>
0026 #include <QImage>
0027 #include <QSize>
0028 #include <QPainter>
0029 #include <QFileInfo>
0030 #include <QFile>
0031 #include <QIODevice>
0032 #include <QDateTime>
0033 #include <QTextStream>
0034 
0035 // KDE includes
0036 
0037 #include <klocalizedstring.h>
0038 
0039 // Local includes
0040 
0041 #include "digikam_config.h"
0042 #include "digikam_debug.h"
0043 #include "digikam_globals.h"
0044 #include "frameutils.h"
0045 #include "frameosd.h"
0046 #include "dfileoperations.h"
0047 #include "transitionmngr.h"
0048 #include "effectmngr.h"
0049 
0050 namespace Digikam
0051 {
0052 
0053 VidSlideTask::VidSlideTask(VidSlideSettings* const settings)
0054     : ActionJob()
0055 {
0056     m_settings = settings;
0057 }
0058 
0059 VidSlideTask::~VidSlideTask()
0060 {
0061     cancel();
0062 }
0063 
0064 void VidSlideTask::run()
0065 {
0066     FrameOsd osd;
0067 
0068     int frameId           = 1;
0069     m_settings->filesList = m_settings->tempDir + QLatin1String("fileslist.txt");
0070     QFile fList(m_settings->filesList);
0071 
0072     if (!fList.open(QIODevice::WriteOnly | QIODevice::Text))
0073     {
0074         qCWarning(DIGIKAM_GENERAL_LOG) << "Cannot create files list:" << m_settings->filesList;
0075     }
0076 
0077     QTextStream out(&fList);
0078 
0079     // ---------------------------------------------
0080     // Setup output video file
0081 
0082     QUrl dest       = QUrl::fromLocalFile(m_settings->outputDir);
0083     dest            = dest.adjusted(QUrl::StripTrailingSlash);
0084     dest.setPath(dest.path() + QDir::separator() + QLatin1String("videoslideshow.") + m_settings->videoFormat());
0085     QString outFile = dest.toLocalFile();
0086     QFileInfo fi(outFile);
0087 
0088     if (fi.exists() && (m_settings->conflictRule != FileSaveConflictBox::OVERWRITE))
0089     {
0090         outFile = DFileOperations::getUniqueFileUrl(dest).toLocalFile();
0091     }
0092 
0093     QImage qiimg;
0094     QSize osize = m_settings->videoSize();
0095 
0096     // --------------------------------------------------------------
0097     // Loop to encode frames with images list as temporary JPEG files
0098 
0099     TransitionMngr transmngr;
0100     transmngr.setOutputSize(osize);
0101 
0102     EffectMngr effmngr;
0103     effmngr.setOutputSize(osize);
0104     effmngr.setFrames(m_settings->imgFrames);
0105 
0106     for (int i = 0 ; ((i < m_settings->inputImages.count() + 1) && !m_cancel) ; ++i)
0107     {
0108         if (i == 0)
0109         {
0110             qiimg = FrameUtils::makeFramedImage(QString(), osize);
0111         }
0112 
0113         QString ofile;
0114 
0115         if (i < m_settings->inputImages.count())
0116         {
0117             ofile = m_settings->inputImages[i].toLocalFile();
0118         }
0119 
0120         QImage qoimg = FrameUtils::makeFramedImage(ofile, osize);
0121 
0122         // -- Transition encoding ----------
0123 
0124         transmngr.setInImage(qiimg);
0125         transmngr.setOutImage(qoimg);
0126         transmngr.setTransition(m_settings->transition);
0127 
0128         int ttmout = 0;
0129         QImage frame;
0130         QString framePath;
0131 
0132         do
0133         {
0134             frame     = QImage(transmngr.currentFrame(ttmout));
0135             framePath = m_settings->tempDir + QString::fromLatin1("frame_%1").arg(frameId, 9, 10, QLatin1Char('0')) + QLatin1String(".jpg");
0136 
0137             if (!frame.save(framePath, "JPEG"))
0138             {
0139                 qCWarning(DIGIKAM_GENERAL_LOG) << "Cannot generate frame:" << framePath;
0140             }
0141             else
0142             {
0143                 qCDebug(DIGIKAM_GENERAL_LOG) << "Frame generated:" << framePath;
0144             }
0145 
0146             out << QString::fromUtf8("file '%1'").arg(QFileInfo(framePath).fileName()) << QT_ENDL;
0147             ++frameId;
0148         }
0149         while ((ttmout != -1) && !m_cancel);
0150 
0151         // -- Images encoding ----------
0152 
0153         if (i < m_settings->inputImages.count())
0154         {
0155             int count  = 0;
0156             int itmout = 0;
0157             effmngr.setImage(qoimg);
0158             effmngr.setEffect(m_settings->vEffect);
0159 
0160             do
0161             {
0162                 qiimg     = effmngr.currentFrame(itmout);
0163 
0164                 if ((osize.width() >= 1024) && (osize.height() >= 576))
0165                 {
0166                     osd.insertOsdToFrame(qiimg,
0167                                          QUrl::fromLocalFile(ofile),
0168                                          m_settings->osdSettings,
0169                                          m_settings->iface);
0170                 }
0171 
0172                 frame     = qiimg;
0173                 framePath = m_settings->tempDir + QString::fromLatin1("frame_%1").arg(frameId, 9, 10, QLatin1Char('0')) + QLatin1String(".jpg");
0174 
0175                 if (!frame.save(framePath, "JPEG"))
0176                 {
0177                     qCWarning(DIGIKAM_GENERAL_LOG) << "Cannot generate frame:" << framePath;
0178                 }
0179                 else
0180                 {
0181                     qCDebug(DIGIKAM_GENERAL_LOG) << "Frame generated:" << ":" << framePath;
0182                 }
0183 
0184                 out << QString::fromUtf8("file '%1'").arg(QFileInfo(framePath).fileName()) << QT_ENDL;
0185                 ++frameId;
0186                 ++count;
0187             }
0188             while ((count < m_settings->imgFrames) && !m_cancel);
0189         }
0190 
0191         qCDebug(DIGIKAM_GENERAL_LOG) << "Generating frames from image" << i << "done";
0192 
0193         if (!ofile.isEmpty())
0194         {
0195             Q_EMIT signalMessage(i18n("Generating frames from %1 Done", ofile), false);
0196         }
0197 
0198         Q_EMIT signalProgress(i);
0199     }
0200 
0201     fList.close();
0202 
0203     m_settings->outputFile = outFile;
0204 
0205     Q_EMIT signalDone(!m_cancel);
0206 }
0207 
0208 } // namespace Digikam