Krita Source Code Documentation
Loading...
Searching...
No Matches
KisDlgAnimationRenderer Class Reference

#include <KisDlgAnimationRenderer.h>

+ Inheritance diagram for KisDlgAnimationRenderer:

Public Member Functions

KisAnimationRenderingOptions getEncoderOptions () const
 
 KisDlgAnimationRenderer (KisDocument *doc, QWidget *parent=0)
 
 ~KisDlgAnimationRenderer () override
 
- Public Member Functions inherited from KoDialog
QPushButton * button (ButtonCode id) const
 
QIcon buttonIcon (ButtonCode id) const
 
QString buttonText (ButtonCode id) const
 
QString buttonToolTip (ButtonCode id) const
 
QString buttonWhatsThis (ButtonCode id) const
 
ButtonCode defaultButton () const
 
QString helpLinkText () const
 
void incrementInitialSize (const QSize &size)
 
bool isButtonEnabled (ButtonCode id) const
 
 KoDialog (QWidget *parent=0, Qt::WindowFlags f=Qt::WindowFlags())
 
QWidget * mainWidget ()
 
QSize minimumSizeHint () const override
 
void setButtonFocus (ButtonCode id)
 
void setButtonGuiItem (ButtonCode id, const KGuiItem &item)
 
void setButtonIcon (ButtonCode id, const QIcon &icon)
 
void setButtons (ButtonCodes buttonMask)
 
void setButtonsOrientation (Qt::Orientation orientation)
 
void setButtonText (ButtonCode id, const QString &text)
 
void setButtonToolTip (ButtonCode id, const QString &text)
 
void setButtonWhatsThis (ButtonCode id, const QString &text)
 
void setDefaultButton (ButtonCode id)
 
void setEscapeButton (ButtonCode id)
 
void setInitialSize (const QSize &size)
 
void setMainWidget (QWidget *widget)
 
void showButton (ButtonCode id, bool state)
 
void showButtonSeparator (bool state)
 
QSize sizeHint () const override
 
 ~KoDialog () override
 

Protected Slots

void slotButtonClicked (int button) override
 
void slotDialogAccepted ()
 
- Protected Slots inherited from KoDialog
virtual void slotButtonClicked (int button)
 

Private Types

enum  FFmpegValidationResult { VALID = 1 , INVALID = 0 , NOT_A_BINARY = -1 , COMPRESSED_FORMAT = -2 }
 

Private Slots

static bool getPngHdr (KisPropertiesConfigurationSP cfg, bool wantsRenderWithHdr)
 
void selectRenderOptions ()
 
void selectRenderType (int i)
 
void sequenceMimeTypeOptionsClicked ()
 sequenceMimeTypeSelected calls the dialog for the export widget.
 
void setFFmpegPath (const QString &path)
 
static void setPngHdr (KisPropertiesConfigurationSP cfg, bool enable=true)
 
void slotCheckWarnings ()
 
void slotExportTypeChanged ()
 
void slotLockAspectRatioDimensionsHeight (int height)
 
void slotLockAspectRatioDimensionsWidth (int width)
 
void slotRenderTypeChanged ()
 

Private Member Functions

QStringList filterMimeTypeListByAvailableEncoders (const QStringList &mimeTypes)
 
void initializeRenderSettings (const KisDocument &doc, const KisAnimationRenderingOptions &lastUsedOptions)
 
KisHDRMetadataOptions optionsFromImage ()
 
void updateWarnings ()
 
FFmpegValidationResult validateFFmpeg (const QString &ffmpegPath)
 
bool wantImageSequenceExport () const
 
bool wantVideoExport () const
 

Static Private Member Functions

static QString defaultVideoFileName (KisDocument *doc, const QString &mimeType)
 
static void filterSequenceMimeTypes (QStringList &mimeTypes)
 
static void getDefaultVideoEncoderOptions (const QString &mimeType, KisPropertiesConfigurationSP cfg, const QStringList &availableEncoders, QString *customFFMpegOptionsString, bool *forceHDRVideo)
 
static bool imageMimeSupportsHDR (QString &hdr)
 
static KisPropertiesConfigurationSP loadLastConfiguration (QString configurationID)
 
static bool looksLikeGif (const QString &videoType)
 
static QStringList makeVideoMimeTypesList ()
 
static void saveLastUsedConfiguration (QString configurationID, KisPropertiesConfigurationSP config)
 
static bool supportsAudio (const QString &videoType)
 

Private Attributes

QStringList ffmpegCodecs = QStringList()
 
QMap< QString, QStringListffmpegEncoderTypes
 
QString ffmpegVersion = "None"
 
QString m_customFFMpegOptionsString
 
KisDocumentm_doc
 
KisImageSP m_image
 
WdgAnimationRendererm_page {0}
 
bool m_wantsRenderWithHDR = false
 

Additional Inherited Members

- Public Types inherited from KoDialog
enum  ButtonCode {
  None = 0x00000000 , Help = 0x00000001 , Default = 0x00000002 , Ok = 0x00000004 ,
  Apply = 0x00000008 , Try = 0x00000010 , Cancel = 0x00000020 , Close = 0x00000040 ,
  No = 0x00000080 , Yes = 0x00000100 , Reset = 0x00000200 , Details = 0x00000400 ,
  User1 = 0x00001000 , User2 = 0x00002000 , User3 = 0x00004000 , NoDefault = 0x00008000
}
 
enum  ButtonPopupMode { InstantPopup = 0 , DelayedPopup = 1 }
 
enum  CaptionFlag { NoCaptionFlags = 0 , AppNameCaption = 1 , ModifiedCaption = 2 , HIGCompliantCaption = AppNameCaption }
 
- Public Slots inherited from KoDialog
void delayedDestruct ()
 
void enableButton (ButtonCode id, bool state)
 
void enableButtonApply (bool state)
 
void enableButtonCancel (bool state)
 
void enableButtonOk (bool state)
 
void enableLinkedHelp (bool state)
 
bool isDetailsWidgetVisible () const
 
virtual void setCaption (const QString &caption)
 
virtual void setCaption (const QString &caption, bool modified)
 
void setDetailsWidget (QWidget *detailsWidget)
 
void setDetailsWidgetVisible (bool visible)
 
void setHelp (const QString &anchor, const QString &appname=QString())
 
void setHelpLinkText (const QString &text)
 
virtual void setPlainCaption (const QString &caption)
 
- Signals inherited from KoDialog
void aboutToShowDetails ()
 
void applyClicked ()
 
void buttonClicked (KoDialog::ButtonCode button)
 
void cancelClicked ()
 
void closeClicked ()
 
void defaultClicked ()
 
void finished ()
 
void helpClicked ()
 
void hidden ()
 
void layoutHintChanged ()
 
void noClicked ()
 
void okClicked ()
 
void resetClicked ()
 
void tryClicked ()
 
void user1Clicked ()
 
void user2Clicked ()
 
void user3Clicked ()
 
void yesClicked ()
 
- Static Public Member Functions inherited from KoDialog
static int groupSpacingHint ()
 
static QString makeStandardCaption (const QString &userCaption, QWidget *window=0, CaptionFlags flags=HIGCompliantCaption)
 
static int marginHint ()
 
static void resizeLayout (QLayout *lay, int margin, int spacing)
 
static void resizeLayout (QWidget *widget, int margin, int spacing)
 
static int spacingHint ()
 
- Protected Member Functions inherited from KoDialog
void closeEvent (QCloseEvent *e) override
 
void hideEvent (QHideEvent *) override
 
void keyPressEvent (QKeyEvent *) override
 
void showEvent (QShowEvent *e) override
 

Detailed Description

Definition at line 43 of file KisDlgAnimationRenderer.h.

Member Enumeration Documentation

◆ FFmpegValidationResult

Enumerator
VALID 
INVALID 
NOT_A_BINARY 
COMPRESSED_FORMAT 

Definition at line 89 of file KisDlgAnimationRenderer.h.

Constructor & Destructor Documentation

◆ KisDlgAnimationRenderer()

KisDlgAnimationRenderer::KisDlgAnimationRenderer ( KisDocument * doc,
QWidget * parent = 0 )

Definition at line 58 of file KisDlgAnimationRenderer.cpp.

59 : KoDialog(parent)
60 , m_image(doc->image())
61 , m_doc(doc)
62{
63 KisConfig cfg(true);
64
65 setCaption(i18n("Render Animation"));
68
69 m_page = new WdgAnimationRenderer(this);
70 m_page->layout()->setContentsMargins(0, 0, 0, 0);
71
72 {
73 QIcon editIcon = KisIconUtils::loadIcon("document-edit");
74 m_page->bnExportOptions->setIcon(editIcon);
75 m_page->bnRenderOptions->setIcon(editIcon);
76 }
77
78 m_page->lblWarnings->hide();
79 m_page->lblWarnings->setPixmap(KisIconUtils::loadIcon(QStringLiteral("dialog-warning")).pixmap(32, 32));
80
81#ifdef Q_OS_ANDROID
82 m_exportButtonGroup = new QButtonGroup(this);
83 m_exportButtonGroup->addButton(m_page->bnExportImages);
84 m_exportButtonGroup->addButton(m_page->bnExportVideo);
85 m_page->shouldExportOnlyImageSequence->setChecked(false);
86 m_page->shouldExportOnlyVideo->setChecked(false);
87 m_page->shouldExportOnlyImageSequence->setCheckable(false);
88 m_page->shouldExportOnlyVideo->setCheckable(false);
89 m_page->pgImages->layout()->addWidget(m_page->shouldExportOnlyImageSequence);
90 m_page->pgVideo->layout()->addWidget(m_page->shouldExportOnlyVideo);
91 m_page->lblVideoFilenameTitle->hide();
92 m_page->videoFilename->hide();
93 m_page->lblDirRequester->hide();
94 m_page->dirRequester->hide();
95 m_page->lblFFMpegLocationTitle->hide();
96 m_page->ffmpegLocation->hide();
97 m_page->lblFFMpegVersionTitle->hide();
98 m_page->lblFFMpegVersion->hide();
99#else
100 m_page->wdgExportButtons->hide();
101 m_page->stkExport->hide();
102#endif
103
104 m_page->dirRequester->setMode(KoFileDialog::OpenDirectory);
105
106 m_page->intStart->setMinimum(0);
107 m_page->intStart->setMaximum(doc->image()->animationInterface()->documentPlaybackRange().end());
108 m_page->intEnd->setMinimum(doc->image()->animationInterface()->documentPlaybackRange().start());
109
110 m_page->intHeight->setMinimum(1);
111 m_page->intHeight->setMaximum(100000);
112
113 m_page->intWidth->setMinimum(1);
114 m_page->intWidth->setMaximum(100000);
115
116 // Setup audio...
117 QVector<QFileInfo> audioFiles = doc->getAudioTracks();
118 const bool hasAudio = audioFiles.count() > 0;
119 m_page->chkIncludeAudio->setEnabled(hasAudio);
120
121 // Setup image mimeTypes...
123 mimes.sort();
125 Q_FOREACH(const QString &mime, mimes) {
126 QString description = KisMimeDatabase::descriptionForMimeType(mime);
127 if (description.isEmpty()) {
128 description = mime;
129 }
130
131 m_page->cmbMimetype->addItem(description, mime);
132
133 if (mime == "image/png") {
134 m_page->cmbMimetype->setCurrentIndex(m_page->cmbMimetype->count() - 1);
135 }
136 }
137
138#ifdef Q_OS_ANDROID
139 // Set up video export formats on Android. No ffmpeg here.
140 m_videoFormatPreferences = loadVideoFormatPreferences();
142 for (KisMediaEncoderFormat *videoFormat : videoFormats) {
143 m_page->cmbRenderType->addItem(videoFormat->title(), QVariant(videoFormat->key()));
144 }
145#endif
146
147 m_page->cmbScaleFilter->addItem(i18nc("bicubic filtering", "bicubic"), "bicubic");
148 m_page->cmbScaleFilter->addItem(i18nc("bilinear filtering", "bilinear"), "bilinear");
149 m_page->cmbScaleFilter->addItem(i18nc("lanczos3 filtering", "lanczos3"), "lanczos");
150 m_page->cmbScaleFilter->addItem(i18nc("nearest neighbor filtering", "neighbor"), "neighbor");
151 m_page->cmbScaleFilter->addItem(i18nc("spline filtering", "spline"), "spline");
152
153#ifndef Q_OS_ANDROID
154 m_page->videoFilename->setMode(KoFileDialog::SaveFile);
155 m_page->ffmpegLocation->setMode(KoFileDialog::OpenFile);
156#endif
157
158 m_page->cmbRenderType->setPlaceholderText(i18nc("Not applicable. No render types without valid ffmpeg path.", "N/A"));
159
160 { // Establish connections...
161 connect(m_page->bnExportOptions, SIGNAL(clicked()), this, SLOT(sequenceMimeTypeOptionsClicked()));
162 connect(m_page->bnRenderOptions, SIGNAL(clicked()), this, SLOT(selectRenderOptions()));
163
164#ifdef Q_OS_ANDROID
165 connect(m_exportButtonGroup,
166 QOverload<QAbstractButton *>::of(&QButtonGroup::buttonClicked),
167 this,
169#else
170 connect(m_page->shouldExportOnlyImageSequence, SIGNAL(toggled(bool)), this, SLOT(slotExportTypeChanged()));
171 connect(m_page->shouldExportOnlyVideo, SIGNAL(toggled(bool)), this, SLOT(slotExportTypeChanged()));
172#endif
173 connect(m_page->cmbRenderType, SIGNAL(currentIndexChanged(int)), SLOT(slotRenderTypeChanged()));
174
175 connect(m_page->intFramesPerSecond, SIGNAL(valueChanged(int)), SLOT(slotCheckWarnings()));
176 connect(m_page->intWidth, SIGNAL(valueChanged(int)), SLOT(slotCheckWarnings()));
177 connect(m_page->intHeight, SIGNAL(valueChanged(int)), SLOT(slotCheckWarnings()));
178
179#ifndef Q_OS_ANDROID
180 connect(m_page->ffmpegLocation, SIGNAL(fileSelected(QString)), SLOT(setFFmpegPath(QString)));
181#endif
182
183 connect(this, SIGNAL(accepted()), SLOT(slotDialogAccepted()));
184 }
185
186
187 // try to lock the width and height being updated
188 KisAcyclicSignalConnector *constrainsConnector = new KisAcyclicSignalConnector(this);
189 constrainsConnector->createCoordinatedConnector()->connectBackwardInt(m_page->intWidth, SIGNAL(valueChanged(int)), this, SLOT(slotLockAspectRatioDimensionsWidth(int)));
190 constrainsConnector->createCoordinatedConnector()->connectForwardInt(m_page->intHeight, SIGNAL(valueChanged(int)), this, SLOT(slotLockAspectRatioDimensionsHeight(int)));
191
192 { // Initialize settings from last configuration...
193 KisPropertiesConfigurationSP animProperties = loadLastConfiguration("ANIMATION_EXPORT");
195 options.fromProperties(animProperties);
196
197 initializeRenderSettings(*doc, options);
198 }
199
202}
KisAcyclicSignalConnector * createCoordinatedConnector()
create a coordinated connector that can be used for extending the number of self-locking connection.
void connectBackwardInt(QObject *sender, const char *signal, QObject *receiver, const char *method)
void connectForwardInt(QObject *sender, const char *signal, QObject *receiver, const char *method)
void fromProperties(KisPropertiesConfigurationSP config)
void initializeRenderSettings(const KisDocument &doc, const KisAnimationRenderingOptions &lastUsedOptions)
void sequenceMimeTypeOptionsClicked()
sequenceMimeTypeSelected calls the dialog for the export widget.
void setFFmpegPath(const QString &path)
void slotLockAspectRatioDimensionsHeight(int height)
void slotLockAspectRatioDimensionsWidth(int width)
static KisPropertiesConfigurationSP loadLastConfiguration(QString configurationID)
WdgAnimationRenderer * m_page
static void filterSequenceMimeTypes(QStringList &mimeTypes)
KisImageSP image
QVector< QFileInfo > getAudioTracks() const
const KisTimeSpan & documentPlaybackRange() const
documentPlaybackRange
KisImageAnimationInterface * animationInterface() const
static QStringList supportedMimeTypes(Direction direction)
static const QVector< KisMediaEncoderFormat * > & getSupportedFormats()
static QString descriptionForMimeType(const QString &mimeType)
Find the user-readable description for the given mimetype.
int start() const
int end() const
void setMainWidget(QWidget *widget)
Definition KoDialog.cpp:345
virtual void setCaption(const QString &caption)
Definition KoDialog.cpp:489
void setButtons(ButtonCodes buttonMask)
Definition KoDialog.cpp:195
void setDefaultButton(ButtonCode id)
Definition KoDialog.cpp:293
@ Ok
Show Ok button. (this button accept()s the dialog; result set to QDialog::Accepted)
Definition KoDialog.h:127
@ Cancel
Show Cancel-button. (this button reject()s the dialog; result set to QDialog::Rejected)
Definition KoDialog.h:130
KoDialog(QWidget *parent=0, Qt::WindowFlags f=Qt::WindowFlags())
Definition KoDialog.cpp:176
QIcon loadIcon(const QString &name)

References KisImage::animationInterface(), KoDialog::Cancel, KisAcyclicSignalConnector::connectBackwardInt(), KisAcyclicSignalConnector::connectForwardInt(), KisAcyclicSignalConnector::createCoordinatedConnector(), KisMimeDatabase::descriptionForMimeType(), KisImageAnimationInterface::documentPlaybackRange(), KisTimeSpan::end(), KisImportExportManager::Export, filterSequenceMimeTypes(), KisAnimationRenderingOptions::fromProperties(), KisDocument::getAudioTracks(), KisMediaEncoderWrapper::getSupportedFormats(), KisDocument::image, initializeRenderSettings(), KisIconUtils::loadIcon(), loadLastConfiguration(), m_page, KoDialog::Ok, KoFileDialog::OpenDirectory, KoFileDialog::OpenFile, KoFileDialog::SaveFile, selectRenderOptions(), sequenceMimeTypeOptionsClicked(), KoDialog::setButtons(), KoDialog::setCaption(), KoDialog::setDefaultButton(), setFFmpegPath(), KoDialog::setMainWidget(), slotCheckWarnings(), slotDialogAccepted(), slotExportTypeChanged(), slotLockAspectRatioDimensionsHeight(), slotLockAspectRatioDimensionsWidth(), slotRenderTypeChanged(), KisTimeSpan::start(), and KisImportExportManager::supportedMimeTypes().

◆ ~KisDlgAnimationRenderer()

KisDlgAnimationRenderer::~KisDlgAnimationRenderer ( )
override

Definition at line 204 of file KisDlgAnimationRenderer.cpp.

205{
206 delete m_page;
207}

References m_page.

Member Function Documentation

◆ defaultVideoFileName()

QString KisDlgAnimationRenderer::defaultVideoFileName ( KisDocument * doc,
const QString & mimeType )
staticprivate

Definition at line 733 of file KisDlgAnimationRenderer.cpp.

734{
735 const QString docFileName = !doc->localFilePath().isEmpty() ? doc->localFilePath() : i18n("Untitled");
736
737 if (!mimeType.isEmpty()) {
738 return QString("%1.%2").arg(QFileInfo(docFileName).completeBaseName(),
739 KisMimeDatabase::suffixesForMimeType(mimeType).first());
740 } else {
741 return docFileName;
742 }
743}
QString localFilePath() const
static QStringList suffixesForMimeType(const QString &mimeType)

References KisDocument::localFilePath(), and KisMimeDatabase::suffixesForMimeType().

◆ filterMimeTypeListByAvailableEncoders()

QStringList KisDlgAnimationRenderer::filterMimeTypeListByAvailableEncoders ( const QStringList & mimeTypes)
private

Definition at line 453 of file KisDlgAnimationRenderer.cpp.

454{
455 QStringList retValue;
456
457 Q_FOREACH(const QString& mime, input) {
458 if ( mime == "video/x-matroska" ) {
459 if ( ffmpegCodecs.contains("h264") || ffmpegCodecs.contains("vp9") ) {
460 QList<QString> encodersPresent;
461 encodersPresent << ffmpegEncoderTypes["h264"] << ffmpegEncoderTypes["vp9"];
463 retValue << mime;
464 }
465 } else if (mime == "video/mp4") {
466 if ( ffmpegCodecs.contains("h264") || ffmpegCodecs.contains("vp9") ) {
467 QList<QString> encodersPresent;
468 encodersPresent << ffmpegEncoderTypes["h264"] << ffmpegEncoderTypes["vp9"];
470 retValue << mime;
471 }
472 } else if (mime == "video/webm") {
473 if ( ffmpegCodecs.contains("vp9") ) {
474 QList<QString> encodersPresent;
475 encodersPresent << ffmpegEncoderTypes["vp9"];
477 retValue << mime;
478 }
479 } else if (mime == "image/gif") {
480 if ( ffmpegCodecs.contains("gif") ) {
481 retValue << mime;
482 }
483 } else if (mime == "image/apng") {
484 if ( ffmpegCodecs.contains("apng") ) {
485 retValue << mime;
486 }
487 } else if (mime == "image/webp") {
488 if ( ffmpegCodecs.contains("webp") ) {
489 retValue << mime;
490 }
491 } else if (mime == "video/ogg") {
492 if ( ffmpegCodecs.contains("theora") ) {
493 retValue << mime;
494 }
495 }
496 }
497
498 return retValue;
499}
bool meetsEncoderRequirementsForContainer(KisVideoExportOptionsDialog::ContainerType encoderType, const QStringList &encodersPresent)
QMap< QString, QStringList > ffmpegEncoderTypes

References ffmpegCodecs, ffmpegEncoderTypes, meetsEncoderRequirementsForContainer(), KisVideoExportOptionsDialog::MKV, KisVideoExportOptionsDialog::MP4, and KisVideoExportOptionsDialog::WEBM.

◆ filterSequenceMimeTypes()

void KisDlgAnimationRenderer::filterSequenceMimeTypes ( QStringList & mimeTypes)
staticprivate

Definition at line 417 of file KisDlgAnimationRenderer.cpp.

418{
419 KritaUtils::filterContainer(mimeTypes, [](QString type) {
420 return (type.startsWith("image/")
421 || (type.startsWith("application/") &&
422 !type.startsWith("application/x-spriter")));
423 });
424}
auto filterContainer(C &container, KeepIfFunction keepIf) -> decltype(bool(keepIf(container[0])), void())

References KritaUtils::filterContainer().

◆ getDefaultVideoEncoderOptions()

void KisDlgAnimationRenderer::getDefaultVideoEncoderOptions ( const QString & mimeType,
KisPropertiesConfigurationSP cfg,
const QStringList & availableEncoders,
QString * customFFMpegOptionsString,
bool * forceHDRVideo )
staticprivate

Definition at line 397 of file KisDlgAnimationRenderer.cpp.

402{
405
406 QScopedPointer<KisVideoExportOptionsDialog> encoderConfigWidget(
407 new KisVideoExportOptionsDialog(containerType, availableEncoders, KisHDRMetadataOptions(), 0));
408
409 // we always enable HDR, letting the user to force it
410 encoderConfigWidget->setSupportsHDR(true);
411 encoderConfigWidget->setConfiguration(cfg);
412 *customFFMpegOptionsString = encoderConfigWidget->customUserOptionsString();
413 *renderHDR = encoderConfigWidget->videoConfiguredForHDR();
414}
static ContainerType mimeToContainer(const QString &mimeType)

References KisVideoExportOptionsDialog::mimeToContainer().

◆ getEncoderOptions()

KisAnimationRenderingOptions KisDlgAnimationRenderer::getEncoderOptions ( ) const

Definition at line 889 of file KisDlgAnimationRenderer.cpp.

890{
892
894 QString videoType = m_page->cmbRenderType->currentData().toString();
895
896#ifdef Q_OS_ANDROID
897 bool video = wantVideoExport();
898 options.shouldEncodeVideo = video;
899 options.includeAudio = video && supportsAudio(videoType) && m_page->chkIncludeAudio->isChecked();
900 options.wantsOnlyUniqueFrameSequence = !video && m_page->chkOnlyUniqueFrames->isChecked();
901
902 if (video) {
903 options.frameMimeType = QStringLiteral("image/png");
904 options.videoFileName = m_videoFileName;
905 options.videoFormatKey = videoType;
906 QVariantMap videoFormatPreferences = m_videoFormatPreferences.value(videoType).toMap();
907 if (!videoFormatPreferences.isEmpty()) {
908 options.videoFormatPreferencesJson =
909 QString::fromUtf8(QJsonDocument::fromVariant(videoFormatPreferences).toJson(QJsonDocument::Compact));
910 }
911 } else {
912 options.directory = m_imageDirectory;
913 options.frameMimeType = m_page->cmbMimetype->currentData().toString();
914 }
915#else
916 options.videoMimeType = videoType;
917 options.videoFileName = m_page->videoFilename->fileName();
918 options.ffmpegPath = m_page->ffmpegLocation->fileName();
920 options.directory = m_page->dirRequester->fileName();
923 options.includeAudio = supportsAudio(videoType) && m_page->chkIncludeAudio->isChecked();
924 options.wantsOnlyUniqueFrameSequence = m_page->chkOnlyUniqueFrames->isChecked();
925 options.frameMimeType = m_page->cmbMimetype->currentData().toString();
926#endif
927 options.scaleFilter = m_page->cmbScaleFilter->currentData().toString();
928
929 options.basename = m_page->txtBasename->text();
930 options.firstFrame = m_page->intStart->value();
931 options.lastFrame = m_page->intEnd->value();
932 options.sequenceStart = m_page->sequenceStart->value();
933
934 options.frameRate = m_page->intFramesPerSecond->value();
935 if (options.frameRate > 50 && looksLikeGif(videoType)) {
936 options.frameRate = 50;
937 }
938
939 options.width = m_page->intWidth->value();
940 options.height = m_page->intHeight->value();
941
942 {
944 if (cfg) {
946 }
947
948#ifndef Q_OS_ANDROID
949 const bool forceNecessaryHDRSettings = m_wantsRenderWithHDR && imageMimeSupportsHDR(options.frameMimeType);
950 if (forceNecessaryHDRSettings) {
951 KIS_SAFE_ASSERT_RECOVER_NOOP(options.frameMimeType == "image/png");
952 cfg->setProperty("forceSRGB", false);
953 setPngHdr(cfg);
954 }
955#endif
956
957 options.frameExportConfig = cfg;
958 }
959
960 return options;
961}
KisPropertiesConfigurationSP frameExportConfig
static bool looksLikeGif(const QString &videoType)
static bool supportsAudio(const QString &videoType)
static void setPngHdr(KisPropertiesConfigurationSP cfg, bool enable=true)
static bool imageMimeSupportsHDR(QString &hdr)
static void fillStaticExportConfigurationProperties(KisPropertiesConfigurationSP exportConfiguration, KisImageSP image)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130

References KisAnimationRenderingOptions::basename, KisAnimationRenderingOptions::customFFMpegOptions, KisAnimationRenderingOptions::directory, KisAnimationRenderingOptions::ffmpegPath, KisImportExportManager::fillStaticExportConfigurationProperties(), KisAnimationRenderingOptions::firstFrame, KisAnimationRenderingOptions::frameExportConfig, KisAnimationRenderingOptions::frameMimeType, KisAnimationRenderingOptions::frameRate, KisAnimationRenderingOptions::height, imageMimeSupportsHDR(), KisAnimationRenderingOptions::includeAudio, KIS_SAFE_ASSERT_RECOVER_NOOP, KisAnimationRenderingOptions::lastDocumentPath, KisAnimationRenderingOptions::lastFrame, loadLastConfiguration(), KisDocument::localFilePath(), looksLikeGif(), m_customFFMpegOptionsString, m_doc, m_image, m_page, m_wantsRenderWithHDR, KisAnimationRenderingOptions::scaleFilter, KisAnimationRenderingOptions::sequenceStart, setPngHdr(), KisAnimationRenderingOptions::shouldDeleteSequence, KisAnimationRenderingOptions::shouldEncodeVideo, supportsAudio(), KisAnimationRenderingOptions::videoFileName, KisAnimationRenderingOptions::videoMimeType, wantImageSequenceExport(), KisAnimationRenderingOptions::wantsOnlyUniqueFrameSequence, wantVideoExport(), and KisAnimationRenderingOptions::width.

◆ getPngHdr

bool KisDlgAnimationRenderer::getPngHdr ( KisPropertiesConfigurationSP cfg,
bool wantsRenderWithHdr )
staticprivateslot

Definition at line 1056 of file KisDlgAnimationRenderer.cpp.

1057{
1058 return cfg->getPropertyLazy("storeColorSpaceInfo", wantsRenderWithHdr)
1059 && cfg->getPropertyLazy("writeCicpIfPossible", wantsRenderWithHdr)
1060 && (cfg->getPropertyLazy("floatingPointConversionOption", wantsRenderWithHdr? "Rec2100PQ": "KeepSame") == "Rec2100PQ");
1061}

◆ imageMimeSupportsHDR()

bool KisDlgAnimationRenderer::imageMimeSupportsHDR ( QString & hdr)
staticprivate

Definition at line 502 of file KisDlgAnimationRenderer.cpp.

503{
504 return (mime == "image/png");
505}

◆ initializeRenderSettings()

void KisDlgAnimationRenderer::initializeRenderSettings ( const KisDocument & doc,
const KisAnimationRenderingOptions & lastUsedOptions )
private

Definition at line 209 of file KisDlgAnimationRenderer.cpp.

210{
211#ifndef Q_OS_ANDROID
212 // Initialize FFmpeg location... (!)
213 KisConfig cfg(false);
214 QString cfgFFmpegPath = cfg.ffmpegLocation();
215#ifdef Q_OS_MACOS
216 if (cfgFFmpegPath.isEmpty()) {
217 QJsonObject ffmpegInfo = KisFFMpegWrapper::findFFMpeg(cfgFFmpegPath);
218 cfgFFmpegPath = (ffmpegInfo["enabled"].toBool()) ? ffmpegInfo["path"].toString() : "";
219 }
220#endif
221
222 // Check known ffmpeg locations..
223 QString likelyFFmpegPath = [&]() {
224 // Check last used
225 if (!lastUsedOptions.ffmpegPath.isEmpty() && QFileInfo(lastUsedOptions.ffmpegPath).isExecutable()) {
226 return lastUsedOptions.ffmpegPath;
227 }
228
229 // Check krita config
230 if (!cfgFFmpegPath.isEmpty() && QFileInfo(cfgFFmpegPath).isExecutable()) {
231 return cfgFFmpegPath;
232 }
233
234 // Check standard paths
235 QString systemFFmpeg = QStandardPaths::findExecutable("ffmpeg");
236 if (!systemFFmpeg.isEmpty() && QFileInfo(systemFFmpeg).isExecutable()) {
237 return systemFFmpeg;
238 }
239
240 // Find ffmpeg elsewhere...
241 QJsonObject ffmpegJsonObj = KisFFMpegWrapper::findFFMpeg("");
242 return (ffmpegJsonObj["enabled"].toBool()) ? ffmpegJsonObj["path"].toString() : "";
243 }();
244
245 if (!likelyFFmpegPath.isEmpty() && QFileInfo(likelyFFmpegPath).isExecutable()) {
246 setFFmpegPath(likelyFFmpegPath);
247 }
248#endif
249
250 const QString documentPath = m_doc->localFilePath();
251
252 // Initialize these settings based on last used configuration when possible..
253 if (!lastUsedOptions.lastDocumentPath.isEmpty() &&
254 lastUsedOptions.lastDocumentPath == documentPath) {
255
256 // If the file is the same as last time, we use the last used basename.
257 m_page->txtBasename->setText(lastUsedOptions.basename);
258
259 m_page->sequenceStart->setValue(lastUsedOptions.sequenceStart);
260 m_page->intWidth->setValue(lastUsedOptions.width);
261 m_page->intHeight->setValue(lastUsedOptions.height);
262
263#ifdef Q_OS_ANDROID
264 m_page->dirRequester->setStartDir(documentPath);
265#else
266 m_page->videoFilename->setStartDir(lastUsedOptions.resolveAbsoluteDocumentFilePath(documentPath));
267 m_page->videoFilename->setFileName(lastUsedOptions.videoFileName);
268 m_page->dirRequester->setStartDir(lastUsedOptions.resolveAbsoluteDocumentFilePath(documentPath));
269#endif
270 m_page->dirRequester->setFileName(lastUsedOptions.directory);
271
272 } else {
273 m_page->sequenceStart->setValue(m_image->animationInterface()->activePlaybackRange().start());
274 m_page->intWidth->setValue(m_image->width());
275 m_page->intHeight->setValue(m_image->height());
276
277#ifdef Q_OS_ANDROID
278 m_page->dirRequester->setStartDir(documentPath);
279#else
280 m_page->videoFilename->setStartDir(lastUsedOptions.resolveAbsoluteDocumentFilePath(documentPath));
281 m_page->videoFilename->setFileName(defaultVideoFileName(m_doc, lastUsedOptions.videoMimeType));
282 m_page->dirRequester->setStartDir(lastUsedOptions.resolveAbsoluteDocumentFilePath(documentPath));
283#endif
284 m_page->dirRequester->setFileName(lastUsedOptions.directory);
285 }
286
287 // Initialize FRAME render format...
288 for (int i = 0; i < m_page->cmbMimetype->count(); ++i) {
289 if (m_page->cmbMimetype->itemData(i).toString() == lastUsedOptions.frameMimeType) {
290 m_page->cmbMimetype->setCurrentIndex(i);
291 break;
292 }
293 }
294
295 for (int i = 0; i < m_page->cmbScaleFilter->count(); ++i) {
296 if (m_page->cmbScaleFilter->itemData(i).toString() == lastUsedOptions.scaleFilter) {
297 m_page->cmbScaleFilter->setCurrentIndex(i);
298 break;
299 }
300 }
301
302 // Initialize VIDEO render format...
303#ifdef Q_OS_ANDROID
304 const QString &lastVideoType = lastUsedOptions.videoFormatKey;
305#else
306 const QString &lastVideoType = lastUsedOptions.videoMimeType;
307#endif
308 for (int i = 0; i < m_page->cmbRenderType->count(); ++i) {
309 if (m_page->cmbRenderType->itemData(i).toString() == lastVideoType) {
310 m_page->cmbRenderType->setCurrentIndex(i);
311 break;
312 }
313 }
314
315 m_page->chkOnlyUniqueFrames->setChecked(lastUsedOptions.wantsOnlyUniqueFrameSequence);
316#ifdef Q_OS_ANDROID
317 if (lastUsedOptions.shouldEncodeVideo) {
318 m_page->bnExportVideo->setChecked(true);
319 } else {
320 m_page->bnExportImages->setChecked(true);
321 }
322#else
323 m_page->shouldExportOnlyVideo->setChecked(lastUsedOptions.shouldEncodeVideo);
324 m_page->shouldExportOnlyImageSequence->setChecked(!lastUsedOptions.shouldDeleteSequence);
325#endif
326
328
329#ifndef Q_OS_ANDROID
330 {
331 KisPropertiesConfigurationSP settings = loadLastConfiguration("VIDEO_ENCODER");
332
333 QStringList encodersPresent;
334 Q_FOREACH(const QString& key, ffmpegEncoderTypes.keys()) {
335 encodersPresent << ffmpegEncoderTypes[key];
336 }
337
338 getDefaultVideoEncoderOptions(lastUsedOptions.videoMimeType, settings,
339 encodersPresent,
342 }
343
344 {
345 KisPropertiesConfigurationSP settings = loadLastConfiguration("img_sequence/" + lastUsedOptions.frameMimeType);
347 }
348
349 m_page->ffmpegLocation->setFileName(likelyFFmpegPath);
350 m_page->ffmpegLocation->setStartDir(QFileInfo(m_doc->localFilePath()).path());
351 m_page->ffmpegLocation->setReadOnlyText(true);
352#endif
353
354 // Initialize these settings based on the current document context..
355 m_page->intStart->setValue(doc.image()->animationInterface()->activePlaybackRange().start());
356 m_page->intEnd->setValue(doc.image()->animationInterface()->activePlaybackRange().end());
357 m_page->intFramesPerSecond->setValue(doc.image()->animationInterface()->framerate());
358
359 if (!doc.image()->animationInterface()->exportSequenceFilePath().isEmpty()
360 && QDir(doc.image()->animationInterface()->exportSequenceFilePath()).exists() ) {
361 m_page->dirRequester->setStartDir(doc.image()->animationInterface()->exportSequenceFilePath());
362 m_page->dirRequester->setFileName(doc.image()->animationInterface()->exportSequenceFilePath());
363 }
364
365 if (!doc.image()->animationInterface()->exportSequenceBaseName().isEmpty()) {
366 m_page->txtBasename->setText(doc.image()->animationInterface()->exportSequenceBaseName());
367 }
368
369 if (doc.image()->animationInterface()->exportInitialFrameNumber() != -1) {
370 m_page->sequenceStart->setValue(doc.image()->animationInterface()->exportInitialFrameNumber());
371 }
372
373 bool hasAudioLoaded = doc.getAudioTracks().count() > 0;
374 m_page->chkIncludeAudio->setChecked(hasAudioLoaded);
376}
QString resolveAbsoluteDocumentFilePath(const QString &documentPath) const
static void getDefaultVideoEncoderOptions(const QString &mimeType, KisPropertiesConfigurationSP cfg, const QStringList &availableEncoders, QString *customFFMpegOptionsString, bool *forceHDRVideo)
static QString defaultVideoFileName(KisDocument *doc, const QString &mimeType)
static bool getPngHdr(KisPropertiesConfigurationSP cfg, bool wantsRenderWithHdr)
static QJsonObject findFFMpeg(const QString &customLocation)
const KisTimeSpan & activePlaybackRange() const
activePlaybackRange
qint32 width() const
qint32 height() const
QString toString(const QString &value)

References KisImageAnimationInterface::activePlaybackRange(), KisImage::animationInterface(), KisAnimationRenderingOptions::basename, defaultVideoFileName(), KisAnimationRenderingOptions::directory, KisTimeSpan::end(), KisImageAnimationInterface::exportInitialFrameNumber(), KisImageAnimationInterface::exportSequenceBaseName(), KisImageAnimationInterface::exportSequenceFilePath(), ffmpegEncoderTypes, KisConfig::ffmpegLocation(), KisAnimationRenderingOptions::ffmpegPath, KisFFMpegWrapper::findFFMpeg(), KisAnimationRenderingOptions::frameMimeType, KisImageAnimationInterface::framerate(), KisDocument::getAudioTracks(), getDefaultVideoEncoderOptions(), getPngHdr(), KisImage::height(), KisAnimationRenderingOptions::height, KisDocument::image, KisAnimationRenderingOptions::lastDocumentPath, loadLastConfiguration(), KisDocument::localFilePath(), m_customFFMpegOptionsString, m_doc, m_image, m_page, m_wantsRenderWithHDR, KisAnimationRenderingOptions::resolveAbsoluteDocumentFilePath(), KisAnimationRenderingOptions::scaleFilter, KisAnimationRenderingOptions::sequenceStart, setFFmpegPath(), KisAnimationRenderingOptions::shouldDeleteSequence, KisAnimationRenderingOptions::shouldEncodeVideo, slotExportTypeChanged(), slotRenderTypeChanged(), KisTimeSpan::start(), KisAnimationRenderingOptions::videoFileName, KisAnimationRenderingOptions::videoMimeType, KisAnimationRenderingOptions::wantsOnlyUniqueFrameSequence, KisImage::width(), and KisAnimationRenderingOptions::width.

◆ loadLastConfiguration()

KisPropertiesConfigurationSP KisDlgAnimationRenderer::loadLastConfiguration ( QString configurationID)
staticprivate

Definition at line 530 of file KisDlgAnimationRenderer.cpp.

530 {
531 KisConfig globalConfig(true);
532 return globalConfig.exportConfiguration(configurationID);
533}

References KisConfig::exportConfiguration().

◆ looksLikeGif()

bool KisDlgAnimationRenderer::looksLikeGif ( const QString & videoType)
staticprivate

Definition at line 541 of file KisDlgAnimationRenderer.cpp.

542{
543#ifdef Q_OS_ANDROID
544 return videoType.contains(QStringLiteral(":gif"));
545#else
546 return videoType == QStringLiteral("image/gif");
547#endif
548}

◆ makeVideoMimeTypesList()

QStringList KisDlgAnimationRenderer::makeVideoMimeTypesList ( )
staticprivate

Definition at line 427 of file KisDlgAnimationRenderer.cpp.

428{
429 QStringList supportedMimeTypes = QStringList();
430 supportedMimeTypes << "video/x-matroska";
431 supportedMimeTypes << "video/mp4";
432 supportedMimeTypes << "video/webm";
433 supportedMimeTypes << "image/gif";
434 supportedMimeTypes << "image/apng";
435 supportedMimeTypes << "image/webp";
436 supportedMimeTypes << "video/ogg";
437
438 return supportedMimeTypes;
439}
QList< QString > QStringList

◆ optionsFromImage()

KisHDRMetadataOptions KisDlgAnimationRenderer::optionsFromImage ( )
private

Definition at line 560 of file KisDlgAnimationRenderer.cpp.

561{
562 KisHDRMetadataOptions hdrOptions;
565 }
567 hdrOptions.cvi = *m_image->colorVolumeInformation();
568 }
571 }
572 return hdrOptions;
573}
std::optional< KisRelativeContentLightLevelInformation > relativeContentLightLevelInformation() const
relativeContentLightLevelInformation This returns (optionally) a KisRelativeContentLightLevelInformat...
std::optional< double > hdrReferenceWhiteLightLevel() const
HDR Reference White livel.
std::optional< KisColorVolumeInformation > colorVolumeInformation() const
colorVolumeInformation
KisRelativeContentLightLevelInformation clli
KisColorVolumeInformation cvi

References KisHDRMetadataOptions::clli, KisImage::colorVolumeInformation(), KisHDRMetadataOptions::cvi, KisHDRMetadataOptions::hdrReferenceWhite, KisImage::hdrReferenceWhiteLightLevel(), m_image, and KisImage::relativeContentLightLevelInformation().

◆ saveLastUsedConfiguration()

void KisDlgAnimationRenderer::saveLastUsedConfiguration ( QString configurationID,
KisPropertiesConfigurationSP config )
staticprivate

Definition at line 535 of file KisDlgAnimationRenderer.cpp.

536{
537 KisConfig globalConfig(false);
538 globalConfig.setExportConfiguration(configurationID, config);
539}

References KisConfig::setExportConfiguration().

◆ selectRenderOptions

void KisDlgAnimationRenderer::selectRenderOptions ( )
privateslot

Definition at line 786 of file KisDlgAnimationRenderer.cpp.

787{
788#ifdef Q_OS_ANDROID
789 QString key = m_page->cmbRenderType->currentData().toString();
792
793 KisMediaEncoderPreferencesDialog dlg(format, m_videoFormatPreferences.value(key).toMap(), this);
794 if (dlg.exec() == QDialog::Accepted) {
795 m_videoFormatPreferences.insert(key, dlg.preferences());
796 saveVideoFormatPreferences(m_videoFormatPreferences);
797 }
798#else
799 const int index = m_page->cmbRenderType->currentIndex();
800 const QString mimetype = m_page->cmbRenderType->itemData(index).toString();
801
804
805 QStringList encodersPresent;
806 Q_FOREACH(const QString& key, ffmpegEncoderTypes.keys()) {
807 encodersPresent << ffmpegEncoderTypes[key];
808 }
809
811
812 KisVideoExportOptionsDialog *encoderConfigWidget =
813 new KisVideoExportOptionsDialog(containerType, encodersPresent, hdrOptions, this);
814
815 // we always enable HDR, letting the user to force it
816 encoderConfigWidget->setSupportsHDR(true);
817
818 {
819 KisPropertiesConfigurationSP settings = loadLastConfiguration("VIDEO_ENCODER");
820 encoderConfigWidget->setConfiguration(settings);
821 encoderConfigWidget->setHDRConfiguration(m_wantsRenderWithHDR);
822 }
823
824 KoDialog dlg(this);
825 dlg.setMainWidget(encoderConfigWidget);
826 dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
827 if (dlg.exec() == QDialog::Accepted) {
828 saveLastUsedConfiguration("VIDEO_ENCODER", encoderConfigWidget->configuration());
829#ifndef Q_OS_ANDROID
831 m_wantsRenderWithHDR = encoderConfigWidget->videoConfiguredForHDR();
832#endif
833 }
834
835 dlg.setMainWidget(0);
836 encoderConfigWidget->deleteLater();
837#endif
838}
KisHDRMetadataOptions optionsFromImage()
static void saveLastUsedConfiguration(QString configurationID, KisPropertiesConfigurationSP config)
static KisMediaEncoderFormat * getFormatByKey(const QString &key)
KisPropertiesConfigurationSP configuration() const override
void setConfiguration(const KisPropertiesConfigurationSP config) override
A dialog base class with standard buttons and predefined layouts.
Definition KoDialog.h:116
#define KIS_SAFE_ASSERT_RECOVER_RETURN(cond)
Definition kis_assert.h:128

References KoDialog::Cancel, KisVideoExportOptionsDialog::configuration(), KisVideoExportOptionsDialog::customUserOptionsString(), ffmpegEncoderTypes, KisMediaEncoderWrapper::getFormatByKey(), KIS_SAFE_ASSERT_RECOVER_RETURN, loadLastConfiguration(), m_customFFMpegOptionsString, m_page, m_wantsRenderWithHDR, KisVideoExportOptionsDialog::mimeToContainer(), KoDialog::Ok, optionsFromImage(), KisMediaEncoderPreferencesDialog::preferences(), saveLastUsedConfiguration(), KisVideoExportOptionsDialog::setConfiguration(), KisVideoExportOptionsDialog::setHDRConfiguration(), KisVideoExportOptionsDialog::setSupportsHDR(), and KisVideoExportOptionsDialog::videoConfiguredForHDR().

◆ selectRenderType

void KisDlgAnimationRenderer::selectRenderType ( int i)
privateslot

Definition at line 745 of file KisDlgAnimationRenderer.cpp.

746{
747 if (m_page->cmbRenderType->count() == 0) return;
748
749 const QString mimeType = m_page->cmbRenderType->itemData(index).toString();
750
752
753 QString videoFileName = defaultVideoFileName(m_doc, mimeType);
754
755 if (!m_page->videoFilename->fileName().isEmpty()) {
756 const QFileInfo info = QFileInfo(m_page->videoFilename->fileName());
757 const QString baseName = info.completeBaseName();
758 const QString path = info.path();
759
760 videoFileName = QString("%1%2%3.%4")
761 .arg(path, "/", baseName, KisMimeDatabase::suffixesForMimeType(mimeType).first());
762 }
763 m_page->videoFilename->setMimeTypeFilters(QStringList() << mimeType, mimeType);
764 m_page->videoFilename->setFileName(videoFileName);
765
766 m_wantsRenderWithHDR = (mimeType == "video/mp4") ? m_wantsRenderWithHDR : false;
767
768 { // We've got to reload the render settings to account for the user changing render type without configuration.
769 // If this is removed from the configuration, ogg vorbis can fail to render on first attempt. BUG:421658
770 // This should be revisited at some point, too much configuration juggling in this class makes it error-prone...
771
772 QStringList encodersPresent;
773 Q_FOREACH(const QString& key, ffmpegEncoderTypes.keys()) {
774 encodersPresent << ffmpegEncoderTypes[key];
775 }
776
777 KisPropertiesConfigurationSP settings = loadLastConfiguration("VIDEO_ENCODER");
778 getDefaultVideoEncoderOptions(mimeType, settings,
779 encodersPresent,
782 }
783}

References defaultVideoFileName(), ffmpegEncoderTypes, getDefaultVideoEncoderOptions(), loadLastConfiguration(), m_customFFMpegOptionsString, m_doc, m_page, m_wantsRenderWithHDR, slotCheckWarnings(), and KisMimeDatabase::suffixesForMimeType().

◆ sequenceMimeTypeOptionsClicked

void KisDlgAnimationRenderer::sequenceMimeTypeOptionsClicked ( )
privateslot

sequenceMimeTypeSelected calls the dialog for the export widget.

Definition at line 840 of file KisDlgAnimationRenderer.cpp.

841{
842 int index = m_page->cmbMimetype->currentIndex();
843
844 KisConfigWidget *frameExportConfigWidget = 0;
845
846 QString mimetype = m_page->cmbMimetype->itemData(index).toString();
848 if (filter) {
849 frameExportConfigWidget = filter->createConfigurationWidget(0, KisDocument::nativeFormatMimeType(), mimetype.toLatin1());
850
851 if (frameExportConfigWidget) {
852
853 KisPropertiesConfigurationSP exportConfig = loadLastConfiguration("img_sequence/" + mimetype);
854 if (exportConfig) {
856 }
857
858 //Important -- m_useHDR allows the synchronization of both the video and image render settings.
859#ifndef Q_OS_ANDROID
860 if(imageMimeSupportsHDR(mimetype)) {
861 setPngHdr(exportConfig, m_wantsRenderWithHDR);
863 exportConfig->setProperty("forceSRGB", false);
864 }
865 }
866#endif
867
868 frameExportConfigWidget->setConfiguration(exportConfig);
869 KoDialog dlg(this);
870 dlg.setMainWidget(frameExportConfigWidget);
871 dlg.setButtons(KoDialog::Ok | KoDialog::Cancel);
872 if (dlg.exec() == QDialog::Accepted) {
873#ifndef Q_OS_ANDROID
874 m_wantsRenderWithHDR = getPngHdr(frameExportConfigWidget->configuration(), false);
875#endif
876 saveLastUsedConfiguration("img_sequence/" + mimetype, frameExportConfigWidget->configuration());
877 }
878
879 frameExportConfigWidget->hide();
880 dlg.setMainWidget(0);
881 frameExportConfigWidget->setParent(0);
882 frameExportConfigWidget->deleteLater();
883
884 }
885 }
886}
virtual KisPropertiesConfigurationSP configuration() const =0
virtual void setConfiguration(const KisPropertiesConfigurationSP config)=0
static QByteArray nativeFormatMimeType()
static KisImportExportFilter * filterForMimeType(const QString &mimetype, Direction direction)
filterForMimeType loads the relevant import/export plugin and returns it. The caller is responsible f...

References KoDialog::Cancel, KisConfigWidget::configuration(), KisImportExportManager::Export, KisImportExportManager::fillStaticExportConfigurationProperties(), KisImportExportManager::filterForMimeType(), getPngHdr(), imageMimeSupportsHDR(), loadLastConfiguration(), m_image, m_page, m_wantsRenderWithHDR, KisDocument::nativeFormatMimeType(), KoDialog::Ok, saveLastUsedConfiguration(), KoDialog::setButtons(), KisConfigWidget::setConfiguration(), KoDialog::setMainWidget(), and setPngHdr().

◆ setFFmpegPath

void KisDlgAnimationRenderer::setFFmpegPath ( const QString & path)
privateslot

Definition at line 577 of file KisDlgAnimationRenderer.cpp.

577 {
578 // Let's START with the assumption that user-specified ffmpeg path is invalid
579 // and clear out all of the ffmpeg-specific fields to fill post-validation...
580 m_page->cmbRenderType->setDisabled(true);
581 m_page->bnRenderOptions->setDisabled(true);
582
583 QString previousMimeType = m_page->cmbRenderType->currentData().toString();
584
585 m_page->cmbRenderType->clear();
586 ffmpegEncoderTypes.clear();
587
588 // Validate FFmpeg binary and setup FFMpeg...
589 if (validateFFmpeg(path)) {
590 QJsonObject ffmpegJsonObj = KisFFMpegWrapper::findFFMpeg(path);
591 ffmpegVersion = ffmpegJsonObj["enabled"].toBool() ? ffmpegJsonObj["version"].toString() : i18n("No valid FFmpeg binary supplied...");
593
594 // Build map of encoding types to their specific encoder support (e.g. h264 => libopenh264, h264, h264_vaapi or whatever)
595 Q_FOREACH(const QString& codec, ffmpegCodecs) {
596 QJsonObject codecjson = ffmpegJsonObj["codecs"].toObject()[codec].toObject();
597 if ( codecjson["encoding"].toBool() ) {
598 QJsonArray codecEncoders = codecjson["encoders"].toArray();
599
600 // In the case where no specific codec "library" is specified but we do support
601 // encoding, we simply push the type onto the list regardless. This basically
602 // means that there's no "specific" requirements that we need to meet and
603 // encoding should be possible.
604 if (codecEncoders.size() == 0) {
605 codecEncoders.push_back(QJsonValue(codec));
606 }
607
608 Q_FOREACH(const QJsonValue& value, codecEncoders) {
609 if (ffmpegEncoderTypes.contains(codec)) {
610 ffmpegEncoderTypes[codec].push_back(value.toString());
611 } else {
612 ffmpegEncoderTypes.insert(codec, {value.toString()} );
613 }
614 }
615 }
616 }
617
618 KisConfig cfg(false);
619
620 { // Build list of supported container types and repopulate cmbRenderType.
621 KisSignalsBlocker(m_page->cmbRenderType);
622
623 QStringList supportedMimeTypes = makeVideoMimeTypesList();
624 supportedMimeTypes = filterMimeTypeListByAvailableEncoders(supportedMimeTypes);
625
626 int previousMimeTypeIndex = -1;
627 Q_FOREACH (const QString &mime, supportedMimeTypes) {
628 QString description = KisMimeDatabase::descriptionForMimeType(mime);
629 if (description.isEmpty()) {
630 description = mime;
631 }
632
633 m_page->cmbRenderType->addItem(description, mime);
634 if (mime == previousMimeType) {
635 previousMimeTypeIndex = m_page->cmbRenderType->count() - 1;
636 }
637 }
638
639 const int indexCount = m_page->cmbRenderType->count();
640 if (indexCount > 0) {
641 if (previousMimeTypeIndex >= 0) {
642 m_page->cmbRenderType->setCurrentIndex(previousMimeTypeIndex % indexCount);
643 } else {
644 m_page->cmbRenderType->setCurrentIndex(0);
645 }
646
647 selectRenderType(m_page->cmbRenderType->currentIndex());
648 m_page->cmbRenderType->setDisabled(false);
649 m_page->bnRenderOptions->setDisabled(false);
650 connect(m_page->cmbRenderType, SIGNAL(currentIndexChanged(int)), this, SLOT(selectRenderType(int)));
651 }
652 }
653
654 m_page->lblFFMpegVersion->setText(ffmpegVersion);
655
656 // Store configuration..
657 cfg.setFFMpegLocation(ffmpegJsonObj["path"].toString());
658
660 }
661}
float value(const T *src, size_t ch)
QStringList filterMimeTypeListByAvailableEncoders(const QStringList &mimeTypes)
FFmpegValidationResult validateFFmpeg(const QString &ffmpegPath)
static QStringList makeVideoMimeTypesList()
static QStringList getSupportedCodecs(const QJsonObject &ffmpegJsonProcessInput)

References KisMimeDatabase::descriptionForMimeType(), ffmpegCodecs, ffmpegEncoderTypes, ffmpegVersion, filterMimeTypeListByAvailableEncoders(), KisFFMpegWrapper::findFFMpeg(), KisFFMpegWrapper::getSupportedCodecs(), m_page, makeVideoMimeTypesList(), selectRenderType(), KisConfig::setFFMpegLocation(), slotCheckWarnings(), validateFFmpeg(), and value().

◆ setPngHdr

void KisDlgAnimationRenderer::setPngHdr ( KisPropertiesConfigurationSP cfg,
bool enable = true )
staticprivateslot

Definition at line 1046 of file KisDlgAnimationRenderer.cpp.

1047{
1048 cfg->setProperty("storeColorSpaceInfo", enable);
1049 cfg->setProperty("writeCicpIfPossible", enable);
1050 if (enable) {
1051 cfg->setProperty("storeExtraColorChunks", false);
1052 cfg->setProperty("floatingPointConversionOption", "Rec2100PQ");
1053 }
1054}

◆ slotButtonClicked

void KisDlgAnimationRenderer::slotButtonClicked ( int button)
overrideprotectedslot

Definition at line 985 of file KisDlgAnimationRenderer.cpp.

986{
987 if (button == KoDialog::Ok && !m_page->shouldExportOnlyImageSequence->isChecked()) {
988 QString fileName = m_page->videoFilename->fileName();
989
990 if (fileName.isEmpty()) {
991 QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("Please enter a file name to render to."));
992 return;
993 }
994 else {
995 switch (validateFFmpeg(m_page->ffmpegLocation->fileName())) {
997 QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("The FFmpeg that you've given us appears to be compressed. Please try to extract FFmpeg from the archive first."));
998 return;
1000 QMessageBox::warning(this, i18nc("@title:window", "Krita"), i18n("The FFmpeg that you've given us appears to be invalid. Please select the correct location of an FFmpeg executable on your system."));
1001 return;
1002 default:
1003 break;
1004 }
1005 }
1006 }
1008}
virtual void slotButtonClicked(int button)
Definition KoDialog.cpp:811
QPushButton * button(ButtonCode id) const
Definition KoDialog.cpp:582

References KoDialog::button(), COMPRESSED_FORMAT, m_page, NOT_A_BINARY, KoDialog::Ok, KoDialog::slotButtonClicked(), and validateFFmpeg().

◆ slotCheckWarnings

void KisDlgAnimationRenderer::slotCheckWarnings ( )
privateslot

Definition at line 664 of file KisDlgAnimationRenderer.cpp.

665{
666 setUpdatesEnabled(false);
668 m_page->adjustSize();
669 setUpdatesEnabled(true);
670}

References m_page, and updateWarnings().

◆ slotDialogAccepted

void KisDlgAnimationRenderer::slotDialogAccepted ( )
protectedslot

Definition at line 1011 of file KisDlgAnimationRenderer.cpp.

1012{
1013#ifdef Q_OS_ANDROID
1014 m_imageDirectory.clear();
1015 m_videoFileName.clear();
1016
1017 if (wantVideoExport()) {
1018 KisMediaEncoderFormat *format = KisMediaEncoderWrapper::getFormatByKey(m_page->cmbRenderType->currentData().toString());
1020 KoFileDialog dialog(this, KoFileDialog::SaveFile, QStringLiteral("ExportAnimation"));
1021 dialog.setMimeTypeFilters(QStringList(KisMimeDatabase::mimeTypeForSuffix(format->extension())));
1022 dialog.setDefaultDir(m_doc->localFilePath());
1023 m_videoFileName = dialog.filename();
1024 if (m_videoFileName.isEmpty()) {
1025 return;
1026 }
1027
1028 } else {
1029 KoFileDialog dialog(this, KoFileDialog::OpenDirectory, QStringLiteral("ExportAnimation"));
1030 m_imageDirectory = dialog.filename();
1031 if (m_imageDirectory.isEmpty()) {
1032 return;
1033 }
1034 }
1035#endif
1036
1037 KisConfig cfg(false);
1039 saveLastUsedConfiguration("ANIMATION_EXPORT", options.toProperties());
1040
1044}
KisPropertiesConfigurationSP toProperties() const
KisAnimationRenderingOptions getEncoderOptions() const
void setExportSequenceBaseName(const QString &baseName)
void setExportInitialFrameNumber(const int frameNum)
void setExportSequenceFilePath(const QString &filePath)
virtual QString extension() const =0
static QString mimeTypeForSuffix(const QString &suffix)
Find the mimetype for a given extension. The extension may have the form "*.xxx" or "xxx".

References KisImage::animationInterface(), KisAnimationRenderingOptions::basename, KisAnimationRenderingOptions::directory, KisMediaEncoderFormat::extension(), getEncoderOptions(), KisMediaEncoderWrapper::getFormatByKey(), KIS_SAFE_ASSERT_RECOVER_RETURN, KisDocument::localFilePath(), m_doc, m_image, m_page, KisMimeDatabase::mimeTypeForSuffix(), KoFileDialog::OpenDirectory, KoFileDialog::SaveFile, saveLastUsedConfiguration(), KisAnimationRenderingOptions::sequenceStart, KisImageAnimationInterface::setExportInitialFrameNumber(), KisImageAnimationInterface::setExportSequenceBaseName(), KisImageAnimationInterface::setExportSequenceFilePath(), KisAnimationRenderingOptions::toProperties(), and wantVideoExport().

◆ slotExportTypeChanged

void KisDlgAnimationRenderer::slotExportTypeChanged ( )
privateslot

A fallback fix for a case when both checkboxes are unchecked

Definition at line 1063 of file KisDlgAnimationRenderer.cpp.

1064{
1065 setUpdatesEnabled(false);
1066
1067#ifdef Q_OS_ANDROID
1068 if (wantVideoExport()) {
1069 m_page->stkExport->setCurrentWidget(m_page->pgVideo);
1070 } else {
1071 m_page->lblWarnings->hide();
1072 m_page->stkExport->setCurrentWidget(m_page->pgImages);
1073 }
1074#else
1075 // if a video format needs to be outputted
1076 if (m_page->shouldExportOnlyVideo->isChecked()) {
1077 // videos always uses PNG for creating video, so disable the ability to change the format
1078 m_page->cmbMimetype->setEnabled(false);
1079 m_page->cmbMimetype->setCurrentIndex(m_page->cmbMimetype->findData("image/png"));
1080 }
1081
1085 if (!m_page->shouldExportOnlyVideo->isChecked() &&
1086 !m_page->shouldExportOnlyImageSequence->isChecked()) {
1087
1088 KisSignalsBlocker b(m_page->shouldExportOnlyImageSequence);
1089 m_page->shouldExportOnlyImageSequence->setChecked(true);
1090 }
1091#endif
1092
1094 m_page->adjustSize();
1095 setUpdatesEnabled(true);
1096}

References m_page, updateWarnings(), and wantVideoExport().

◆ slotLockAspectRatioDimensionsHeight

void KisDlgAnimationRenderer::slotLockAspectRatioDimensionsHeight ( int height)
privateslot

Definition at line 1118 of file KisDlgAnimationRenderer.cpp.

1119{
1120 Q_UNUSED(height);
1121
1122 float aspectRatio = (float)m_image->width() / (float)m_image->height();
1123
1124 // update width here
1125 float newWidth = aspectRatio * m_page->intHeight->value();
1126
1127 m_page->intWidth->setValue(newWidth);
1128}

References KisImage::height(), m_image, m_page, and KisImage::width().

◆ slotLockAspectRatioDimensionsWidth

void KisDlgAnimationRenderer::slotLockAspectRatioDimensionsWidth ( int width)
privateslot

Definition at line 1105 of file KisDlgAnimationRenderer.cpp.

1106{
1107 Q_UNUSED(width);
1108
1109 float aspectRatio = (float)m_image->width() / (float)m_image->height();
1110
1111 // update height here
1112 float newHeight = m_page->intWidth->value() / aspectRatio ;
1113
1114 m_page->intHeight->setValue(newHeight);
1115
1116}

References KisImage::height(), m_image, m_page, and KisImage::width().

◆ slotRenderTypeChanged

void KisDlgAnimationRenderer::slotRenderTypeChanged ( )
privateslot

Definition at line 1098 of file KisDlgAnimationRenderer.cpp.

1099{
1100 m_page->chkIncludeAudio->setVisible(m_page->cmbRenderType->count() != 0
1101 && supportsAudio(m_page->cmbRenderType->currentData().toString()));
1102 m_page->adjustSize();
1103}

References m_page, and supportsAudio().

◆ supportsAudio()

bool KisDlgAnimationRenderer::supportsAudio ( const QString & videoType)
staticprivate

Definition at line 550 of file KisDlgAnimationRenderer.cpp.

551{
552#ifdef Q_OS_ANDROID
554 return format && format->supportsAudio();
555#else
556 return !videoType.startsWith(QStringLiteral("image/"));
557#endif
558}
virtual bool supportsAudio() const =0

References KisMediaEncoderWrapper::getFormatByKey(), and KisMediaEncoderFormat::supportsAudio().

◆ updateWarnings()

void KisDlgAnimationRenderer::updateWarnings ( )
private

Definition at line 672 of file KisDlgAnimationRenderer.cpp.

673{
674 QStringList warnings;
675 bool exportMayFail = false;
676
677 if (wantVideoExport()) {
678 QString videoType = m_page->cmbRenderType->itemData(m_page->cmbRenderType->currentIndex()).toString();
679 bool gif = looksLikeGif(videoType);
680
681#ifndef Q_OS_ANDROID
682 const QRegularExpression minVerFFMpegRX(R"(^n{0,1}(?:[0-3]|4\.[01])[\.\-])");
683 const QRegularExpressionMatch minVerFFMpegMatch = minVerFFMpegRX.match(ffmpegVersion);
684
685 if (gif && minVerFFMpegMatch.hasMatch()) {
686 warnings << i18nc("ffmpeg warning checks",
687 "FFmpeg must be at least version 4.2+ for GIF transparency to work");
688 }
689#endif
690
691 int fps = m_page->intFramesPerSecond->value();
692 if (gif && fps > 50) {
693 warnings << i18nc("ffmpeg warning checks",
694 "Animated GIF images cannot have a framerate higher than 50. The framerate will be "
695 "reduced to 50 frames per second");
696 }
697
698 if (fps > 30) {
699 exportMayFail = true;
700 warnings << i18nc("ffmpeg warning checks", "FPS beyond 30 are not widely supported.");
701 }
702
703 if (m_page->intWidth->value() > 1920 || m_page->intHeight->value() > 1920) {
704 exportMayFail = true;
705 warnings << i18nc("ffmpeg warnings checks", "Dimensions larger than 1920 pixels are not widely supported.");
706 }
707 }
708
709 if (warnings.isEmpty()) {
710 m_page->lblWarnings->hide();
711 } else {
712 QString text = QString("<p><b>%1</b>").arg(i18n("Warning(s):"));
713 text.append("<ul>");
714 Q_FOREACH (const QString &warning, warnings) {
715 text.append("<li>");
716 text.append(warning.toHtmlEscaped());
717 text.append("</li>");
718 }
719 text.append("</ul></p>");
720 if (exportMayFail) {
721 text.append(QStringLiteral("<p>"));
722 text.append(
723 i18nc("ffmpeg warning checks", "The export may fail and some devices may not be able to play it.")
724 .toHtmlEscaped());
725 text.append(QStringLiteral("</p>"));
726 }
727 m_page->lblWarnings->setText(text);
728 m_page->lblWarnings->show();
729 }
730}

References ffmpegVersion, looksLikeGif(), m_page, and wantVideoExport().

◆ validateFFmpeg()

KisDlgAnimationRenderer::FFmpegValidationResult KisDlgAnimationRenderer::validateFFmpeg ( const QString & ffmpegPath)
private

Definition at line 964 of file KisDlgAnimationRenderer.cpp.

965{
966 if (!ffmpegPath.isEmpty()) {
967 QFileInfo ffmpegBinary(ffmpegPath);
968 if (ffmpegBinary.exists() && ffmpegBinary.isExecutable()) {
969 QStringList commpressedFormats{"zip", "7z", "tar.bz2"};
970 Q_FOREACH(const QString& compressedFormat, commpressedFormats) {
971 if (ffmpegBinary.fileName().endsWith(compressedFormat)) {
973 }
974 }
976 } else if (ffmpegBinary.exists()) {
978 }
979 }
981}

References COMPRESSED_FORMAT, INVALID, NOT_A_BINARY, and VALID.

◆ wantImageSequenceExport()

bool KisDlgAnimationRenderer::wantImageSequenceExport ( ) const
private

Definition at line 378 of file KisDlgAnimationRenderer.cpp.

379{
380#ifdef Q_OS_ANDROID
381 return !wantVideoExport();
382#else
383 return m_page->shouldExportOnlyImageSequence->isChecked();
384#endif
385}

References m_page, and wantVideoExport().

◆ wantVideoExport()

bool KisDlgAnimationRenderer::wantVideoExport ( ) const
private

Definition at line 387 of file KisDlgAnimationRenderer.cpp.

388{
389#ifdef Q_OS_ANDROID
390 return m_page->bnExportVideo->isChecked();
391#else
392 return m_page->shouldExportOnlyVideo->isChecked();
393#endif
394}

References m_page.

Member Data Documentation

◆ ffmpegCodecs

QStringList KisDlgAnimationRenderer::ffmpegCodecs = QStringList()
private

Definition at line 150 of file KisDlgAnimationRenderer.h.

◆ ffmpegEncoderTypes

QMap<QString, QStringList> KisDlgAnimationRenderer::ffmpegEncoderTypes
private

Definition at line 151 of file KisDlgAnimationRenderer.h.

◆ ffmpegVersion

QString KisDlgAnimationRenderer::ffmpegVersion = "None"
private

Definition at line 148 of file KisDlgAnimationRenderer.h.

◆ m_customFFMpegOptionsString

QString KisDlgAnimationRenderer::m_customFFMpegOptionsString
private

Definition at line 147 of file KisDlgAnimationRenderer.h.

◆ m_doc

KisDocument* KisDlgAnimationRenderer::m_doc
private

Definition at line 139 of file KisDlgAnimationRenderer.h.

◆ m_image

KisImageSP KisDlgAnimationRenderer::m_image
private

Definition at line 138 of file KisDlgAnimationRenderer.h.

◆ m_page

WdgAnimationRenderer* KisDlgAnimationRenderer::m_page {0}
private

Definition at line 156 of file KisDlgAnimationRenderer.h.

156{0};

◆ m_wantsRenderWithHDR

bool KisDlgAnimationRenderer::m_wantsRenderWithHDR = false
private

Definition at line 153 of file KisDlgAnimationRenderer.h.


The documentation for this class was generated from the following files: