DlgAnimationRenderer.cpp 22.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
#include <QProcess>
27 28 29 30

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

31
#include <KoResourcePaths.h>
32 33 34 35 36
#include <kis_properties_configuration.h>
#include <kis_debug.h>
#include <KisMimeDatabase.h>
#include <KoJsonTrader.h>
#include <KisImportExportFilter.h>
37 38 39
#include <kis_image.h>
#include <kis_image_animation_interface.h>
#include <kis_time_range.h>
40
#include <KisImportExportManager.h>
41 42 43
#include <kis_config_widget.h>
#include <KisDocument.h>
#include <QHBoxLayout>
44 45
#include <kis_config.h>
#include <kis_file_name_requester.h>
46
#include <KoDialog.h>
47 48
#include "kis_slider_spin_box.h"
#include "kis_acyclic_signal_connector.h"
49 50 51 52
#include "video_saver.h"
#include "KisAnimationRenderingOptions.h"
#include "video_export_options_dialog.h"

53

54
DlgAnimationRenderer::DlgAnimationRenderer(KisDocument *doc, QWidget *parent)
55
    : KoDialog(parent)
56
    , m_image(doc->image())
57
    , m_doc(doc)
58
{
59
    KisConfig cfg(true);
60

61 62 63 64
    setCaption(i18n("Render Animation"));
    setButtons(Ok | Cancel);
    setDefaultButton(Ok);

Boudewijn Rempt's avatar
Boudewijn Rempt committed
65
    m_page = new WdgAnimationRenderer(this);
66
    m_page->layout()->setMargin(0);
67

68
    m_page->dirRequester->setMode(KoFileDialog::OpenDirectory);
69

70 71 72
    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());
73

74
    m_page->intEnd->setMinimum(doc->image()->animationInterface()->fullClipRange().start());
75 76
    // animators sometimes want to export after end frame
    //m_page->intEnd->setMaximum(doc->image()->animationInterface()->fullClipRange().end());
77
    m_page->intEnd->setValue(doc->image()->animationInterface()->playbackRange().end());
78

79 80 81 82 83 84 85 86 87 88 89 90 91 92 93
    m_page->intHeight->setMinimum(1);
    m_page->intHeight->setMaximum(10000);
    m_page->intHeight->setValue(doc->image()->height());

    m_page->intWidth->setMinimum(1);
    m_page->intWidth->setMaximum(10000);
    m_page->intWidth->setValue(doc->image()->width());

    // try to lock the width and height being updated
    KisAcyclicSignalConnector *constrainsConnector = new KisAcyclicSignalConnector(this);
    constrainsConnector->createCoordinatedConnector()->connectBackwardInt(m_page->intWidth, SIGNAL(valueChanged(int)), this, SLOT(slotLockAspectRatioDimensionsWidth(int)));
    constrainsConnector->createCoordinatedConnector()->connectForwardInt(m_page->intHeight, SIGNAL(valueChanged(int)), this, SLOT(slotLockAspectRatioDimensionsHeight(int)));

    m_page->intFramesPerSecond->setValue(doc->image()->animationInterface()->framerate());

94 95 96 97 98
    QFileInfo audioFileInfo(doc->image()->animationInterface()->audioChannelFileName());
    const bool hasAudio = audioFileInfo.exists();
    m_page->chkIncludeAudio->setEnabled(hasAudio);
    m_page->chkIncludeAudio->setChecked(hasAudio && !doc->image()->animationInterface()->isAudioMuted());

99
    QStringList mimes = KisImportExportManager::supportedMimeTypes(KisImportExportManager::Export);
100 101 102 103 104 105 106 107 108 109 110 111 112
    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);
        }

    }

113 114
    setMainWidget(m_page);

115 116 117 118 119
    QVector<QString> supportedMimeType;
    supportedMimeType << "video/x-matroska";
    supportedMimeType << "image/gif";
    supportedMimeType << "video/ogg";
    supportedMimeType << "video/mp4";
120

121 122 123 124
    Q_FOREACH (const QString &mime, supportedMimeType) {
        QString description = KisMimeDatabase::descriptionForMimeType(mime);
        if (description.isEmpty()) {
            description = mime;
125
        }
126
        m_page->cmbRenderType->addItem(description, mime);
127
    }
128

129 130
    m_page->videoFilename->setMode(KoFileDialog::SaveFile);

131
    connect(m_page->bnExportOptions, SIGNAL(clicked()), this, SLOT(sequenceMimeTypeOptionsClicked()));
132
    connect(m_page->bnRenderOptions, SIGNAL(clicked()), this, SLOT(selectRenderOptions()));
133

134
    m_page->ffmpegLocation->setMode(KoFileDialog::OpenFile);
135

136
    m_page->cmbRenderType->setCurrentIndex(cfg.readEntry<int>("AnimationRenderer/render_type", 0));
137

138 139 140 141
    connect(m_page->shouldExportOnlyImageSequence, SIGNAL(toggled(bool)), this, SLOT(slotExportTypeChanged()));
    connect(m_page->shouldExportOnlyVideo, SIGNAL(toggled(bool)), this, SLOT(slotExportTypeChanged()));
    connect(m_page->shouldExportAll, SIGNAL(toggled(bool)), this, SLOT(slotExportTypeChanged()));

142 143
    connect(m_page->intFramesPerSecond, SIGNAL(valueChanged(int)), SLOT(frameRateChanged(int)));

144
    // connect and cold init
145
    connect(m_page->cmbRenderType, SIGNAL(currentIndexChanged(int)), this, SLOT(selectRenderType(int)));
146
    selectRenderType(m_page->cmbRenderType->currentIndex());
147 148

    resize(m_page->sizeHint());
149

150
    connect(this, SIGNAL(accepted()), SLOT(slotDialogAccepted()));
151

152
    {
153
        KisPropertiesConfigurationSP settings = cfg.exportConfiguration("ANIMATION_EXPORT");
154

155 156
        KisAnimationRenderingOptions options;
        options.fromProperties(settings);
157

158
        loadAnimationOptions(options);
159 160
    }

161

162 163
}

164
DlgAnimationRenderer::~DlgAnimationRenderer()
165
{
166
    delete m_page;
167 168
}

169 170 171 172
void DlgAnimationRenderer::getDefaultVideoEncoderOptions(const QString &mimeType,
                                                         KisPropertiesConfigurationSP cfg,
                                                         QString *customFFMpegOptionsString,
                                                         bool *forceHDRVideo)
173
{
174 175 176 177 178 179 180 181 182 183 184 185 186
    const VideoExportOptionsDialog::ContainerType containerType =
        mimeType == "video/ogg" ?
        VideoExportOptionsDialog::OGV :
        VideoExportOptionsDialog::DEFAULT;

    QScopedPointer<VideoExportOptionsDialog> encoderConfigWidget(
        new VideoExportOptionsDialog(containerType, 0));

    // we always enable HDR, letting the user to force it
    encoderConfigWidget->setSupportsHDR(true);
    encoderConfigWidget->setConfiguration(cfg);
    *customFFMpegOptionsString = encoderConfigWidget->customUserOptionsString();
    *forceHDRVideo = encoderConfigWidget->forceHDRModeForFrames();
187 188
}

189
void DlgAnimationRenderer::loadAnimationOptions(const KisAnimationRenderingOptions &options)
190
{
191 192
    const QString documentPath = m_doc->localFilePath();

193 194 195
    m_page->txtBasename->setText(options.basename);

    if (!options.lastDocuemntPath.isEmpty() &&
196
            options.lastDocuemntPath == documentPath) {
197 198 199 200 201 202 203

        m_page->intStart->setValue(options.firstFrame);
        m_page->intEnd->setValue(options.lastFrame);
        m_page->sequenceStart->setValue(options.sequenceStart);
        m_page->intWidth->setValue(options.width);
        m_page->intHeight->setValue(options.height);
        m_page->intFramesPerSecond->setValue(options.frameRate);
204 205

        m_page->videoFilename->setStartDir(options.resolveAbsoluteDocumentFilePath(documentPath));
206
        m_page->videoFilename->setFileName(options.videoFileName);
207 208 209

        m_page->dirRequester->setStartDir(options.resolveAbsoluteDocumentFilePath(documentPath));
        m_page->dirRequester->setFileName(options.directory);
210 211 212 213 214 215 216
    } else {
        m_page->intStart->setValue(m_image->animationInterface()->playbackRange().start());
        m_page->intEnd->setValue(m_image->animationInterface()->playbackRange().end());
        m_page->sequenceStart->setValue(m_image->animationInterface()->playbackRange().start());
        m_page->intWidth->setValue(m_image->width());
        m_page->intHeight->setValue(m_image->height());
        m_page->intFramesPerSecond->setValue(m_image->animationInterface()->framerate());
217 218

        m_page->videoFilename->setStartDir(options.resolveAbsoluteDocumentFilePath(documentPath));
219
        m_page->videoFilename->setFileName(defaultVideoFileName(m_doc, options.videoMimeType));
220

221 222 223
        m_page->dirRequester->setStartDir(options.resolveAbsoluteDocumentFilePath(documentPath));
        m_page->dirRequester->setFileName(options.directory);
    }
224

225
    for (int i = 0; i < m_page->cmbMimetype->count(); ++i) {
226
        if (m_page->cmbMimetype->itemData(i).toString() == options.frameMimeType) {
227 228 229 230
            m_page->cmbMimetype->setCurrentIndex(i);
            break;
        }
    }
231

232 233 234 235 236
    for (int i = 0; i < m_page->cmbRenderType->count(); ++i) {
        if (m_page->cmbRenderType->itemData(i).toString() == options.videoMimeType) {
            m_page->cmbRenderType->setCurrentIndex(i);
            break;
        }
237
    }
238

239
    m_page->chkIncludeAudio->setChecked(options.includeAudio);
240

241 242 243 244 245 246 247 248 249
    if (options.shouldDeleteSequence) {
        KIS_SAFE_ASSERT_RECOVER_NOOP(options.shouldEncodeVideo);
        m_page->shouldExportOnlyVideo->setChecked(true);
    } else if (!options.shouldEncodeVideo) {
        KIS_SAFE_ASSERT_RECOVER_NOOP(!options.shouldDeleteSequence);
        m_page->shouldExportOnlyImageSequence->setChecked(true);
    } else {
        m_page->shouldExportAll->setChecked(true); // export to both
    }
250

251

252 253
    {
        KisConfig cfg(true);
254
        KisPropertiesConfigurationSP settings = cfg.exportConfiguration("VIDEO_ENCODER");
255

256 257 258
        getDefaultVideoEncoderOptions(options.videoMimeType, settings,
                                      &m_customFFMpegOptionsString,
                                      &m_forceHDRVideo);
259
    }
260

261
    m_page->ffmpegLocation->setStartDir(QFileInfo(m_doc->localFilePath()).path());
262
    m_page->ffmpegLocation->setFileName(findFFMpeg(options.ffmpegPath));
263 264
}

265
QString DlgAnimationRenderer::defaultVideoFileName(KisDocument *doc, const QString &mimeType)
266
{
267 268
    const QString docFileName = !doc->localFilePath().isEmpty() ?
        doc->localFilePath() : i18n("Untitled");
269

270 271 272 273
    return
        QString("%1.%2")
            .arg(QFileInfo(docFileName).completeBaseName())
            .arg(KisMimeDatabase::suffixesForMimeType(mimeType).first());
274 275
}

276 277
void DlgAnimationRenderer::selectRenderType(int index)
{
278
    const QString mimeType = m_page->cmbRenderType->itemData(index).toString();
279 280 281 282

    m_page->bnRenderOptions->setEnabled(mimeType != "image/gif");
    m_page->lblGifWarning->setVisible((mimeType == "image/gif" && m_page->intFramesPerSecond->value() > 50));

283
    QString videoFileName = defaultVideoFileName(m_doc, mimeType);
284

285 286 287 288
    if (!m_page->videoFilename->fileName().isEmpty()) {
        const QFileInfo info = QFileInfo(m_page->videoFilename->fileName());
        const QString baseName = info.completeBaseName();
        const QString path = info.path();
289

290 291 292 293 294 295
        videoFileName =
            QString("%1%2%3.%4").arg(path).arg(QDir::separator()).arg(baseName).arg(KisMimeDatabase::suffixesForMimeType(mimeType).first());

    }
    m_page->videoFilename->setMimeTypeFilters(QStringList() << mimeType, mimeType);
    m_page->videoFilename->setFileName(videoFileName);
296 297 298
}

void DlgAnimationRenderer::selectRenderOptions()
299
{
300 301
    const int index = m_page->cmbRenderType->currentIndex();
    const QString mimetype = m_page->cmbRenderType->itemData(index).toString();
302

303 304 305 306
    const VideoExportOptionsDialog::ContainerType containerType =
        mimetype == "video/ogg" ?
        VideoExportOptionsDialog::OGV :
        VideoExportOptionsDialog::DEFAULT;
307

308 309
    VideoExportOptionsDialog *encoderConfigWidget =
        new VideoExportOptionsDialog(containerType, this);
310

311 312
    // we always enable HDR, letting the user to force it
    encoderConfigWidget->setSupportsHDR(true);
313

314 315
    {
        KisConfig cfg(true);
316
        KisPropertiesConfigurationSP settings = cfg.exportConfiguration("VIDEO_ENCODER");
317
        encoderConfigWidget->setConfiguration(settings);
318
    }
319 320 321 322 323 324 325 326

    KoDialog dlg(this);
    dlg.setMainWidget(encoderConfigWidget);
    dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
    if (dlg.exec() == QDialog::Accepted) {
        KisConfig cfg(false);
        cfg.setExportConfiguration("VIDEO_ENCODER", encoderConfigWidget->configuration());
        m_customFFMpegOptionsString = encoderConfigWidget->customUserOptionsString();
327
        m_forceHDRVideo = encoderConfigWidget->forceHDRModeForFrames();
328
    }
329 330 331

    dlg.setMainWidget(0);
    encoderConfigWidget->deleteLater();
332 333
}

334
void DlgAnimationRenderer::sequenceMimeTypeOptionsClicked()
335
{
336 337
    int index = m_page->cmbMimetype->currentIndex();

338
    KisConfigWidget *frameExportConfigWidget = 0;
339

340
    QString mimetype = m_page->cmbMimetype->itemData(index).toString();
341
    QSharedPointer<KisImportExportFilter> filter(KisImportExportManager::filterForMimeType(mimetype, KisImportExportManager::Export));
342
    if (filter) {
343 344 345
        frameExportConfigWidget = filter->createConfigurationWidget(0, KisDocument::nativeFormatMimeType(), mimetype.toLatin1());

        if (frameExportConfigWidget) {
346 347 348 349 350
            KisPropertiesConfigurationSP config = filter->lastSavedConfiguration("", mimetype.toLatin1());
            if (config) {
                KisImportExportManager::fillStaticExportConfigurationProperties(config, m_image);
            }

351
            frameExportConfigWidget->setConfiguration(config);
352
            KoDialog dlg(this);
353
            dlg.setMainWidget(frameExportConfigWidget);
354
            dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
355 356 357
            if (dlg.exec() == QDialog::Accepted) {
                KisConfig cfg(false);
                cfg.setExportConfiguration(mimetype, frameExportConfigWidget->configuration());
358
            }
359 360

            frameExportConfigWidget->hide();
361
            dlg.setMainWidget(0);
362 363 364
            frameExportConfigWidget->setParent(0);
            frameExportConfigWidget->deleteLater();

365
        }
366 367
    }
}
368

369 370
inline int roundByTwo(int value) {
    return value + (value & 0x1);
371 372
}

373 374 375 376 377 378
KisAnimationRenderingOptions DlgAnimationRenderer::getEncoderOptions() const
{
    KisAnimationRenderingOptions options;

    options.lastDocuemntPath = m_doc->localFilePath();
    options.videoMimeType = m_page->cmbRenderType->currentData().toString();
379
    options.frameMimeType = m_page->cmbMimetype->currentData().toString();
380 381 382 383 384 385 386 387 388 389 390 391 392

    options.basename = m_page->txtBasename->text();
    options.directory = m_page->dirRequester->fileName();
    options.firstFrame = m_page->intStart->value();
    options.lastFrame = m_page->intEnd->value();
    options.sequenceStart = m_page->sequenceStart->value();

    options.shouldEncodeVideo = !m_page->shouldExportOnlyImageSequence->isChecked();
    options.shouldDeleteSequence = m_page->shouldExportOnlyVideo->isChecked();
    options.includeAudio = m_page->chkIncludeAudio->isChecked();

    options.ffmpegPath = m_page->ffmpegLocation->fileName();
    options.frameRate = m_page->intFramesPerSecond->value();
393 394 395 396 397

    if (options.frameRate > 50 && options.videoMimeType == "image/gif") {
        options.frameRate = 50;
    }

398 399 400 401 402 403
    options.width = roundByTwo(m_page->intWidth->value());
    options.height = roundByTwo(m_page->intHeight->value());
    options.videoFileName = m_page->videoFilename->fileName();

    options.customFFMpegOptions = m_customFFMpegOptionsString;

404 405 406 407 408 409 410 411
    {
        KisConfig config(true);

        KisPropertiesConfigurationSP cfg = config.exportConfiguration(options.frameMimeType);
        if (cfg) {
            KisImportExportManager::fillStaticExportConfigurationProperties(cfg, m_image);
        }

412 413
        const bool forceHDR = m_forceHDRVideo && !m_page->shouldExportOnlyImageSequence->isChecked();
        if (forceHDR) {
414
            KIS_SAFE_ASSERT_RECOVER_NOOP(options.frameMimeType == "image/png");
415 416 417 418
            cfg->setProperty("forceSRGB", false);
            cfg->setProperty("saveAsHDR", true);
        }
        options.frameExportConfig = cfg;
419
    }
420 421

    return options;
422 423
}

424 425
void DlgAnimationRenderer::slotButtonClicked(int button)
{
426
    if (button == KoDialog::Ok && !m_page->shouldExportOnlyImageSequence->isChecked()) {
427
        QString ffmpeg = m_page->ffmpegLocation->fileName();
428 429 430 431 432
        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()) {
433 434 435 436 437 438 439
            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."));
440
                return;
441 442 443 444 445 446
            }
        }
    }
    KoDialog::slotButtonClicked(button);
}

447 448 449 450 451 452 453 454
void DlgAnimationRenderer::slotDialogAccepted()
{
    KisConfig cfg(false);
    KisAnimationRenderingOptions options = getEncoderOptions();
    cfg.setExportConfiguration("ANIMATION_EXPORT", options.toProperties());
}

QString DlgAnimationRenderer::findFFMpeg(const QString &customLocation)
455 456 457 458 459
{
    QString result;

    QStringList proposedPaths;

460 461 462
    if (!customLocation.isEmpty()) {
        proposedPaths << customLocation;
        proposedPaths << customLocation + QDir::separator() + "ffmpeg";
463
    }
464

465 466 467
    proposedPaths << KoResourcePaths::getApplicationRoot() +
        QDir::separator() + "bin" + QDir::separator() + "ffmpeg";

468
#ifndef Q_OS_WIN
469 470 471
    proposedPaths << QDir::homePath() + "/bin/ffmpeg";
    proposedPaths << "/usr/bin/ffmpeg";
    proposedPaths << "/usr/local/bin/ffmpeg";
472
#endif
473

474
    Q_FOREACH (QString path, proposedPaths) {
475 476
        if (path.isEmpty()) continue;

477 478 479 480 481 482 483 484 485 486 487 488 489 490
#ifdef Q_OS_WIN
        path = QDir::toNativeSeparators(QDir::cleanPath(path));
        if (path.endsWith(QDir::separator())) {
            continue;
        }
        if (!path.endsWith(".exe")) {
            if (!QFile::exists(path)) {
                path += ".exe";
                if (!QFile::exists(path)) {
                    continue;
                }
            }
        }
#endif
491 492
        QProcess testProcess;
        testProcess.start(path, QStringList() << "-version");
493 494 495
        if (testProcess.waitForStarted(1000)) {
            testProcess.waitForFinished(1000);
        }
496 497 498 499 500 501 502 503 504 505 506 507 508 509

        const bool successfulStart =
            testProcess.state() == QProcess::NotRunning &&
            testProcess.error() == QProcess::UnknownError;

        if (successfulStart) {
            result = path;
            break;
        }
    }

    return result;
}

510 511
void DlgAnimationRenderer::slotExportTypeChanged()
{
512
    KisConfig cfg(false);
513

514 515
    bool willEncodeVideo =
        m_page->shouldExportAll->isChecked() || m_page->shouldExportOnlyVideo->isChecked();
516

517 518
    // if a video format needs to be outputted
    if (willEncodeVideo) {
519 520 521 522 523 524 525 526 527 528
         // videos always uses PNG for creating video, so disable the ability to change the format
         m_page->cmbMimetype->setEnabled(false);
         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;
             }
         }
    }

529 530 531 532 533 534 535
    m_page->intWidth->setVisible(willEncodeVideo);
    m_page->intHeight->setVisible(willEncodeVideo);
    m_page->intFramesPerSecond->setVisible(willEncodeVideo);
    m_page->fpsLabel->setVisible(willEncodeVideo);
    m_page->lblWidth->setVisible(willEncodeVideo);
    m_page->lblHeight->setVisible(willEncodeVideo);

536
    // if only exporting video
537
    if (m_page->shouldExportOnlyVideo->isChecked()) {
538 539 540 541 542 543 544 545 546 547 548 549 550
        m_page->cmbMimetype->setEnabled(false); // allow to change image format
        m_page->imageSequenceOptionsGroup->setVisible(false);
        m_page->videoOptionsGroup->setVisible(false); //shrinks the horizontal space temporarily to help resize() work
        m_page->videoOptionsGroup->setVisible(true);

        cfg.writeEntry<QString>("AnimationRenderer/export_type", "Video");
    }


    // if only an image sequence needs to be output
    if (m_page->shouldExportOnlyImageSequence->isChecked()) {
        m_page->cmbMimetype->setEnabled(true); // allow to change image format
        m_page->videoOptionsGroup->setVisible(false);
551
        m_page->imageSequenceOptionsGroup->setVisible(false);
552 553 554 555 556 557 558 559 560 561 562 563 564 565 566 567 568 569
        m_page->imageSequenceOptionsGroup->setVisible(true);

        cfg.writeEntry<QString>("AnimationRenderer/export_type", "ImageSequence");
    }

    // show all options
     if (m_page->shouldExportAll->isChecked() ) {
         m_page->imageSequenceOptionsGroup->setVisible(true);
         m_page->videoOptionsGroup->setVisible(true);

         cfg.writeEntry<QString>("AnimationRenderer/export_type", "VideoAndImageSequence");
     }


     // for the resize to work as expected, try to hide elements first before displaying other ones.
     // if the widget gets bigger at any point, the resize will use that, even if elements are hidden later to make it smaller
     resize(m_page->sizeHint());
}
570

571 572 573 574 575 576
void DlgAnimationRenderer::frameRateChanged(int framerate)
{
    const QString mimeType = m_page->cmbRenderType->itemData(m_page->cmbRenderType->currentIndex()).toString();
    m_page->lblGifWarning->setVisible((mimeType == "image/gif" && framerate > 50));
}

577 578 579 580 581 582 583 584 585 586 587 588 589 590 591 592 593 594 595 596 597 598 599 600
void DlgAnimationRenderer::slotLockAspectRatioDimensionsWidth(int width)
{
    Q_UNUSED(width);

    float aspectRatio = (float)m_image->width() / (float)m_image->height();

    // update height here
    float newHeight = m_page->intWidth->value() / aspectRatio  ;

    m_page->intHeight->setValue(newHeight);

}

void DlgAnimationRenderer::slotLockAspectRatioDimensionsHeight(int height)
{
    Q_UNUSED(height);

    float aspectRatio = (float)m_image->width() / (float)m_image->height();

    // update width here
     float newWidth = aspectRatio *  m_page->intHeight->value();

     m_page->intWidth->setValue(newWidth);
}