DlgAnimationRenderer.cpp 14.4 KB
Newer Older
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20
/*
 *  Copyright (c) 2016 Boudewijn Rempt <boud@valdyas.org>
 *
 *  This program is free software; you can redistribute it and/or modify
 *  it under the terms of the GNU General Public License as published by
 *  the Free Software Foundation; either version 2 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU General Public License for more details.
 *
 *  You should have received a copy of the GNU General Public License
 *  along with this program; if not, write to the Free Software
 *  Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
 */

#include "DlgAnimationRenderer.h"

21
#include <QStandardPaths>
22 23
#include <QPluginLoader>
#include <QJsonObject>
24
#include <QMessageBox>
25
#include <QStringList>
26 27 28 29 30 31 32 33 34

#include <klocalizedstring.h>
#include <kpluginfactory.h>

#include <kis_properties_configuration.h>
#include <kis_debug.h>
#include <KisMimeDatabase.h>
#include <KoJsonTrader.h>
#include <KisImportExportFilter.h>
35 36 37
#include <kis_image.h>
#include <kis_image_animation_interface.h>
#include <kis_time_range.h>
38
#include <KisImportExportManager.h>
39 40 41
#include <kis_config_widget.h>
#include <KisDocument.h>
#include <QHBoxLayout>
42
#include <KisImportExportFilter.h>
43 44
#include <kis_config.h>
#include <kis_file_name_requester.h>
45
#include <KisDocument.h>
46
#include <KoDialog.h>
47

48
DlgAnimationRenderer::DlgAnimationRenderer(KisDocument *doc, QWidget *parent)
49
    : KoDialog(parent)
50 51
    , m_image(doc->image())
    , m_defaultFileName(QFileInfo(doc->url().toLocalFile()).completeBaseName())
52
{
53 54
    KisConfig cfg;

55 56 57 58 59 60
    setCaption(i18n("Render Animation"));
    setButtons(Ok | Cancel);
    setDefaultButton(Ok);

    m_page = new WdgAnimaterionRenderer(this);
    m_page->layout()->setMargin(0);
61
    m_page->dirRequester->setMode(KoFileDialog::OpenDirectory);
62
    QString lastLocation = cfg.readEntry<QString>("AnimationRenderer/last_sequence_export_location", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
63
    m_page->dirRequester->setFileName(lastLocation);
64

65 66 67
    m_page->intStart->setMinimum(doc->image()->animationInterface()->fullClipRange().start());
    m_page->intStart->setMaximum(doc->image()->animationInterface()->fullClipRange().end());
    m_page->intStart->setValue(doc->image()->animationInterface()->playbackRange().start());
68

69 70 71
    m_page->intEnd->setMinimum(doc->image()->animationInterface()->fullClipRange().start());
    m_page->intEnd->setMaximum(doc->image()->animationInterface()->fullClipRange().end());
    m_page->intEnd->setValue(doc->image()->animationInterface()->playbackRange().end());
72

73 74 75 76 77 78 79 80 81 82 83 84 85 86
    QStringList mimes = KisImportExportManager::mimeFilter(KisImportExportManager::Export);
    mimes.sort();
    Q_FOREACH(const QString &mime, mimes) {
        QString description = KisMimeDatabase::descriptionForMimeType(mime);
        if (description.isEmpty()) {
            description = mime;
        }
        m_page->cmbMimetype->addItem(description, mime);
        if (mime == "image/png") {
            m_page->cmbMimetype->setCurrentIndex(m_page->cmbMimetype->count() - 1);
        }

    }

87 88 89 90 91 92 93
    setMainWidget(m_page);
    resize(m_page->sizeHint());

    KoJsonTrader trader;
    QList<QPluginLoader *>list = trader.query("Krita/AnimationExporter", "");
    Q_FOREACH(QPluginLoader *loader, list) {
        QJsonObject json = loader->metaData().value("MetaData").toObject();
94 95
        QStringList mimetypes = json.value("X-KDE-Export").toString().split(",");
        Q_FOREACH(const QString &mime, mimetypes) {
96 97 98 99 100 101 102

            KLibFactory *factory = qobject_cast<KLibFactory *>(loader->instance());
            if (!factory) {
                warnUI << loader->errorString();
                continue;
            }

103
            QObject* obj = factory->create<KisImportExportFilter>(0);
104 105 106 107 108
            if (!obj || !obj->inherits("KisImportExportFilter")) {
                delete obj;
                continue;
            }

109
            QSharedPointer<KisImportExportFilter>filter(static_cast<KisImportExportFilter*>(obj));
110 111 112 113 114
            if (!filter) {
                delete obj;
                continue;
            }

Boudewijn Rempt's avatar
Boudewijn Rempt committed
115
            m_renderFilters.append(filter);
116

117 118 119 120 121
            QString description = KisMimeDatabase::descriptionForMimeType(mime);
            if (description.isEmpty()) {
                description = mime;
            }
            m_page->cmbRenderType->addItem(description, mime);
122

123 124
        }
    }
125
    m_page->videoFilename->setMode(KoFileDialog::SaveFile);
126
    m_page->videoFilename->setStartDir(QStandardPaths::writableLocation(QStandardPaths::PicturesLocation));
127

128
    qDeleteAll(list);
129

130
    connect(m_page->grpRender, SIGNAL(toggled(bool)), this, SLOT(toggleSequenceType(bool)));
131 132
    connect(m_page->bnExportOptions, SIGNAL(clicked()), this, SLOT(sequenceMimeTypeSelected()));
    connect(m_page->bnRenderOptions, SIGNAL(clicked()), this, SLOT(selectRenderType()));
133

134
    QString ffmpeg = cfg.customFFMpegPath();
135
    m_page->ffmpegLocation->setFileName(ffmpeg);
136
    m_page->ffmpegLocation->setMode(KoFileDialog::OpenFile);
137
    connect(m_page->ffmpegLocation, SIGNAL(fileSelected(QString)), this, SLOT(ffmpegLocationChanged(QString)));
138

139 140 141
    m_page->grpRender->setChecked(cfg.readEntry<bool>("AnimationRenderer/render_animation", false));
    m_page->chkDeleteSequence->setChecked(cfg.readEntry<bool>("AnimationRenderer/delete_sequence", false));
    m_page->cmbRenderType->setCurrentIndex(cfg.readEntry<int>("AnimationRenderer/render_type", 0));
142 143


144 145
}

146
DlgAnimationRenderer::~DlgAnimationRenderer()
147
{
148
    KisConfig cfg;
149 150 151 152
    cfg.writeEntry<bool>("AnimationRenderer/render_animation", m_page->grpRender->isChecked());
    cfg.writeEntry<QString>("AnimationRenderer/last_sequence_export_location", m_page->dirRequester->fileName());
    cfg.writeEntry<int>("AnimationRenderer/render_type", m_page->cmbRenderType->currentIndex());
    cfg.writeEntry<bool>("AnimationRenderer/delete_sequence", m_page->chkDeleteSequence->isChecked());
153
    cfg.setCustomFFMpegPath(m_page->ffmpegLocation->fileName());
154 155 156 157 158 159 160 161 162

    if (m_encoderConfigWidget)  {
        m_encoderConfigWidget->setParent(0);
        m_encoderConfigWidget->deleteLater();
    }
    if (m_frameExportConfigWidget) {
        m_frameExportConfigWidget->setParent(0);
        m_frameExportConfigWidget->deleteLater();
    }
163

164
    delete m_page;
165

166 167
}

168
KisPropertiesConfigurationSP DlgAnimationRenderer::getSequenceConfiguration() const
169 170 171 172 173 174 175
{
    KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
    cfg->setProperty("basename", m_page->txtBasename->text());
    cfg->setProperty("directory", m_page->dirRequester->fileName());
    cfg->setProperty("first_frame", m_page->intStart->value());
    cfg->setProperty("last_frame", m_page->intEnd->value());
    cfg->setProperty("sequence_start", m_page->sequenceStart->value());
176
    cfg->setProperty("mimetype", m_page->cmbMimetype->currentData().toString());
177 178 179
    return cfg;
}

180
void DlgAnimationRenderer::setSequenceConfiguration(KisPropertiesConfigurationSP cfg)
181 182 183 184 185 186
{
    m_page->txtBasename->setText(cfg->getString("basename", "frame"));
    m_page->dirRequester->setFileName(cfg->getString("directory", QStandardPaths::writableLocation(QStandardPaths::PicturesLocation)));
    m_page->intStart->setValue(cfg->getInt("first_frame", m_image->animationInterface()->playbackRange().start()));
    m_page->intEnd->setValue(cfg->getInt("last_frame", m_image->animationInterface()->playbackRange().end()));
    m_page->sequenceStart->setValue(cfg->getInt("sequence_start", m_image->animationInterface()->playbackRange().start()));
187 188 189 190 191 192 193
    QString mimetype = cfg->getString("mimetype");
    for (int i = 0; i < m_page->cmbMimetype->count(); ++i) {
        if (m_page->cmbMimetype->itemData(i).toString() == mimetype) {
            m_page->cmbMimetype->setCurrentIndex(i);
            break;
        }
    }
194 195
}

196
KisPropertiesConfigurationSP DlgAnimationRenderer::getFrameExportConfiguration() const
197
{
198
    if (m_frameExportConfigWidget) {
199 200 201 202 203 204 205
        KisPropertiesConfigurationSP cfg = m_frameExportConfigWidget->configuration();
        cfg->setProperty("basename", m_page->txtBasename->text());
        cfg->setProperty("directory", m_page->dirRequester->fileName());
        cfg->setProperty("first_frame", m_page->intStart->value());
        cfg->setProperty("last_frame", m_page->intEnd->value());
        cfg->setProperty("sequence_start", m_page->sequenceStart->value());

206
        return m_frameExportConfigWidget->configuration();
207 208 209 210
    }
    return 0;
}

211
bool DlgAnimationRenderer::renderToVideo() const
212 213 214 215
{
    return m_page->grpRender->isChecked();
}

216
KisPropertiesConfigurationSP DlgAnimationRenderer::getVideoConfiguration() const
217
{
218
    if (!m_page->grpRender->isChecked()) {
219 220 221 222 223 224 225 226
        return 0;
    }
    KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
    cfg->setProperty("filename", m_page->videoFilename->fileName());
    cfg->setProperty("delete_sequence", m_page->chkDeleteSequence->isChecked());
    return cfg;
}

227
void DlgAnimationRenderer::setVideoConfiguration(KisPropertiesConfigurationSP /*cfg*/)
228 229 230
{
}

231
KisPropertiesConfigurationSP DlgAnimationRenderer::getEncoderConfiguration() const
232
{
233
    if (!m_page->grpRender->isChecked()) {
234 235 236
        return 0;
    }
    KisPropertiesConfigurationSP cfg = new KisPropertiesConfiguration();
237 238 239
    if (m_encoderConfigWidget) {
        cfg = m_encoderConfigWidget->configuration();
    }
240
    cfg->setProperty("mimetype", m_page->cmbRenderType->currentData().toString());
241 242 243 244 245
    cfg->setProperty("directory", m_page->dirRequester->fileName());
    cfg->setProperty("first_frame", m_page->intStart->value());
    cfg->setProperty("last_frame", m_page->intEnd->value());
    cfg->setProperty("sequence_start", m_page->sequenceStart->value());

246 247 248
    return cfg;
}

249
void DlgAnimationRenderer::setEncoderConfiguration(KisPropertiesConfigurationSP /*cfg*/)
250 251 252 253
{

}

254 255 256 257 258
QSharedPointer<KisImportExportFilter> DlgAnimationRenderer::encoderFilter() const
{
    if (m_page->cmbRenderType->currentIndex() < m_renderFilters.size()) {
        return m_renderFilters[m_page->cmbRenderType->currentIndex()];
    }
Boudewijn Rempt's avatar
Boudewijn Rempt committed
259
    return QSharedPointer<KisImportExportFilter>(0);
260 261
}

262
void DlgAnimationRenderer::selectRenderType()
263
{
264 265
    int index = m_page->cmbRenderType->currentIndex();

266 267 268 269 270 271 272 273
    if (m_encoderConfigWidget) {
        m_encoderConfigWidget->deleteLater();
        m_encoderConfigWidget = 0;
    }

    if (index >= m_renderFilters.size()) return;

    QSharedPointer<KisImportExportFilter> filter = m_renderFilters[index];
274
    QString mimetype = m_page->cmbRenderType->itemData(index).toString();
275 276 277 278

    if (!m_page->videoFilename->fileName().isEmpty() && QFileInfo(m_page->videoFilename->fileName()).completeBaseName() != m_defaultFileName) {
        m_defaultFileName = QFileInfo(m_page->videoFilename->fileName()).completeBaseName();
    }
Boudewijn Rempt's avatar
Boudewijn Rempt committed
279
    m_page->videoFilename->setMimeTypeFilters(QStringList() << mimetype, mimetype);
280
    m_page->videoFilename->setFileName(m_defaultFileName + "." + KisMimeDatabase::suffixesForMimeType(mimetype).first());
281 282

    if (filter) {
283
        m_encoderConfigWidget = filter->createConfigurationWidget(0, KisDocument::nativeFormatMimeType(), mimetype.toLatin1());
284
        if (m_encoderConfigWidget) {
285 286
            m_encoderConfigWidget->setConfiguration(filter->lastSavedConfiguration("", mimetype.toLatin1()));
            KoDialog dlg(this);
287 288 289 290 291 292 293 294
            dlg.setMainWidget(m_encoderConfigWidget);
            dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
            if (!dlg.exec()) {
                m_encoderConfigWidget->setConfiguration(filter->lastSavedConfiguration());
            }
            dlg.setMainWidget(0);
            m_encoderConfigWidget->hide();
            m_encoderConfigWidget->setParent(0);
295 296
        }
    }
297 298 299
    else {
        m_encoderConfigWidget = 0;
    }
300
}
301

302
void DlgAnimationRenderer::toggleSequenceType(bool toggle)
303 304 305 306 307 308 309 310 311
{
    m_page->cmbMimetype->setEnabled(!toggle);
    for (int i = 0; i < m_page->cmbMimetype->count(); ++i) {
        if (m_page->cmbMimetype->itemData(i).toString() == "image/png") {
            m_page->cmbMimetype->setCurrentIndex(i);
            break;
        }
    }
}
312

313
void DlgAnimationRenderer::sequenceMimeTypeSelected()
314
{
315 316
    int index = m_page->cmbMimetype->currentIndex();

317 318 319
    if (m_frameExportConfigWidget) {
        m_frameExportConfigWidget->deleteLater();
        m_frameExportConfigWidget = 0;
320
    }
321

322
    QString mimetype = m_page->cmbMimetype->itemData(index).toString();
323 324
    KisImportExportFilter *filter = KisImportExportManager::filterForMimeType(mimetype, KisImportExportManager::Export);
    if (filter) {
325
        m_frameExportConfigWidget = filter->createConfigurationWidget(0, KisDocument::nativeFormatMimeType(), mimetype.toLatin1());
326
        if (m_frameExportConfigWidget) {
327 328
            m_frameExportConfigWidget->setConfiguration(filter->lastSavedConfiguration("", mimetype.toLatin1()));
            KoDialog dlg(this);
329 330 331 332 333 334 335 336
            dlg.setMainWidget(m_frameExportConfigWidget);
            dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
            if (!dlg.exec()) {
                m_frameExportConfigWidget->setConfiguration(filter->lastSavedConfiguration());
            }
            m_frameExportConfigWidget->hide();
            m_frameExportConfigWidget->setParent(0);
            dlg.setMainWidget(0);
337
        }
338
        delete filter;
339 340
    }
}
341

342 343 344
void DlgAnimationRenderer::ffmpegLocationChanged(const QString &s)
{
    KisConfig cfg;
345
    cfg.setCustomFFMpegPath(s);
346 347 348 349 350 351
}

void DlgAnimationRenderer::slotButtonClicked(int button)
{
    if (button == KoDialog::Ok && m_page->grpRender->isChecked()) {
        QString ffmpeg = m_page->ffmpegLocation->fileName();
352 353 354 355 356
        if (m_page->videoFilename->fileName().isEmpty()) {
            QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("Please enter a file name to render to."));
            return;
        }
        else if (ffmpeg.isEmpty()) {
357 358 359 360 361 362 363
            QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("The location of FFmpeg is unknown. Please install FFmpeg first: Krita cannot render animations without FFmpeg. (<a href=\"https://www.ffmpeg.org\">www.ffmpeg.org</a>)"));
            return;
        }
        else {
            QFileInfo fi(ffmpeg);
            if (!fi.exists()) {
                QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("The location of FFmpeg is invalid. Please select the correct location of the FFmpeg executable on your system."));
364
                return;
365 366 367 368 369 370
            }
        }
    }
    KoDialog::slotButtonClicked(button);
}