Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAnimationRender Namespace Reference

Functions

bool hasEvenDimensions (int width, int height)
 
bool mustHaveEvenDimensions (const QString &mimeType, KisAnimationRenderingOptions::RenderMode renderMode)
 
KRITAUI_EXPORT bool render (KisDocument *doc, KisViewManager *viewManager, KisAnimationRenderingOptions encoderOptions)
 

Function Documentation

◆ hasEvenDimensions()

bool KisAnimationRender::hasEvenDimensions ( int width,
int height )

Definition at line 164 of file KisAnimationRender.cpp.

165{
166 return !((width & 0x1) || (height & 0x1));
167}

◆ mustHaveEvenDimensions()

bool KisAnimationRender::mustHaveEvenDimensions ( const QString & mimeType,
KisAnimationRenderingOptions::RenderMode renderMode )

Definition at line 159 of file KisAnimationRender.cpp.

160{
161 return (mimeType == "video/mp4" || mimeType == "video/x-matroska") && renderMode != KisAnimationRenderingOptions::RENDER_FRAMES_ONLY;
162}

References KisAnimationRenderingOptions::RENDER_FRAMES_ONLY.

◆ render()

bool KisAnimationRender::render ( KisDocument * doc,
KisViewManager * viewManager,
KisAnimationRenderingOptions encoderOptions )

Render an animation to file on disk. returns TRUE on success, FALSE on error or cancellation.

Definition at line 27 of file KisAnimationRender.cpp.

27 {
28 const QString frameMimeType = encoderOptions.frameMimeType;
29 const QString framesDirectory = encoderOptions.resolveAbsoluteFramesDirectory();
30 const QString extension = KisMimeDatabase::suffixesForMimeType(frameMimeType).first();
31 const QString baseFileName = QString("%1/%2.%3").arg(framesDirectory, encoderOptions.basename, extension);
32
33 if (mustHaveEvenDimensions(encoderOptions.videoMimeType, encoderOptions.renderMode())) {
34 if (hasEvenDimensions(encoderOptions.width, encoderOptions.height) != true) {
35 encoderOptions.width = encoderOptions.width + (encoderOptions.width & 0x1);
36 encoderOptions.height = encoderOptions.height + (encoderOptions.height & 0x1);
37 }
38 }
39
40 const QSize scaledSize = doc->image()->bounds().size().scaled(encoderOptions.width, encoderOptions.height, Qt::IgnoreAspectRatio);
41
42 if (mustHaveEvenDimensions(encoderOptions.videoMimeType, encoderOptions.renderMode())) {
43 if (hasEvenDimensions(scaledSize.width(), scaledSize.height()) != true) {
44 QString type = encoderOptions.videoMimeType == "video/mp4" ? "Mpeg4 (.mp4) " : "Matroska (.mkv) ";
45
46 qWarning() << type <<"requires width and height to be even, resize and try again!";
47 doc->setErrorMessage(i18n("%1 requires width and height to be even numbers. Please resize or crop the image before exporting.", type));
48 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"), i18n("Could not render animation:\n%1", doc->errorMessage()));
49
50 return false;
51 }
52 }
53
54 const bool batchMode = false; // TODO: fetch correctly!
57 encoderOptions.lastFrame),
58 baseFileName,
59 encoderOptions.sequenceStart,
60 encoderOptions.wantsOnlyUniqueFrameSequence && !encoderOptions.shouldEncodeVideo,
61 encoderOptions.frameExportConfig);
62 exporter.setBatchMode(batchMode);
63
65 exporter.regenerateRange(viewManager->mainWindow()->viewManager());
66
67 bool delayReturnSuccess = (result == KisAsyncAnimationFramesSaveDialog::RenderComplete);
68
69 // the folder could have been read-only or something else could happen
70 if ((encoderOptions.shouldEncodeVideo || encoderOptions.wantsOnlyUniqueFrameSequence) &&
72
73 const QString savedFilesMask = exporter.savedFilesMask();
74
75 if (encoderOptions.shouldEncodeVideo) {
76 const QString videoOutputFilePath = encoderOptions.resolveAbsoluteVideoFilePath();
77 KIS_SAFE_ASSERT_RECOVER_NOOP(QFileInfo(videoOutputFilePath).isAbsolute());
78
79 const QFileInfo videoOutputFile(videoOutputFilePath);
80 QDir outputDir(videoOutputFile.absolutePath());
81
82 if (!outputDir.exists()) {
83 outputDir.mkpath(videoOutputFile.absolutePath());
84 }
85 KIS_SAFE_ASSERT_RECOVER_NOOP(outputDir.exists());
86
87 // If file exists at output path, prompt user for overwrite..
88 bool videoFileWriteAllowed = true;
89 if (videoOutputFile.exists()) {
90 QMessageBox videoOverwritePrompt;
91
92 videoOverwritePrompt.setText(i18n("Overwrite existing video?"));
93 videoOverwritePrompt.setInformativeText(i18n("A file already exists at the path where you want to render your video [%1]... \n\
94 Are you sure you want to overwrite the existing file?", videoOutputFilePath));
95 videoOverwritePrompt.setStandardButtons(QMessageBox::Ok | QMessageBox::Abort);
96
97 videoFileWriteAllowed = videoOverwritePrompt.exec() == QMessageBox::Ok ? true : false;
98 }
99
100 // Write the video..
101 if (videoFileWriteAllowed) {
103
104 QFile videoOutputFile(videoOutputFilePath);
105 if (!videoOutputFile.open(QIODevice::WriteOnly)) {
106 qWarning() << "Could not open" << videoOutputFile.fileName() << "for writing! Do you have permission to write to this file?";
107 result = KisImportExportErrorCannotWrite(videoOutputFile.error());
108 } else {
109 videoOutputFile.close();
110 }
111
112 QScopedPointer<KisAnimationVideoSaver> encoder(new KisAnimationVideoSaver(doc, batchMode));
113 result = encoder->convert(doc, savedFilesMask, encoderOptions, batchMode);
114
115 if (!result.isOk()) {
116 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Krita"), i18n("Could not render animation:\n%1", result.errorMessage()));
117
118 delayReturnSuccess = false; // Delay return to clean up exported frames.
119 }
120 }
121 }
122
123 //File cleanup
124 QDir d(framesDirectory);
125
126 if (encoderOptions.shouldDeleteSequence || delayReturnSuccess == false) {
127 QStringList savedFiles = exporter.savedFiles();
128
129 Q_FOREACH(const QString &f, savedFiles) {
130 if (d.exists(f)) {
131 d.remove(f);
132 }
133 }
134 } else if(encoderOptions.wantsOnlyUniqueFrameSequence) {
135 const QStringList fileNames = exporter.savedFiles();
136 const QStringList uniqueFrameNames = exporter.savedUniqueFiles();
137
138 Q_FOREACH(const QString &f, fileNames) {
139 if (!uniqueFrameNames.contains(f)) {
140 d.remove(f);
141 }
142 }
143 }
144
145 QStringList paletteFiles = d.entryList(QStringList() << "KritaTempPalettegen_*.png", QDir::Files);
146
147 Q_FOREACH(const QString &f, paletteFiles) {
148 d.remove(f);
149 }
151 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Rendering error"), "Animation frame rendering has timed out. Output files are incomplete.\nTry to increase \"Frame Rendering Timeout\" or reduce \"Frame Rendering Clones Limit\" in Krita settings");
153 QMessageBox::critical(qApp->activeWindow(), i18nc("@title:window", "Rendering error"), i18n("Failed to render animation frames! Output files are incomplete."));
154 }
155
156 return delayReturnSuccess;
157}
QList< QString > QStringList
KisPropertiesConfigurationSP frameExportConfig
QString resolveAbsoluteVideoFilePath(const QString &documentPath) const
QString resolveAbsoluteFramesDirectory(const QString &documentPath) const
KisImageSP image
void setErrorMessage(const QString &errMsg)
QString errorMessage() const
QRect bounds() const override
KisViewManager * viewManager
static QStringList suffixesForMimeType(const QString &mimeType)
static KisTimeSpan fromTimeToTime(int start, int end)
KisMainWindow * mainWindow() const
Encoder * encoder(Imf::OutputFile &file, const ExrPaintLayerSaveInfo &info, int width)
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
bool mustHaveEvenDimensions(const QString &mimeType, KisAnimationRenderingOptions::RenderMode renderMode)
bool hasEvenDimensions(int width, int height)

References KisAnimationRenderingOptions::basename, KisImage::bounds(), encoder(), KisDocument::errorMessage(), KisImportExportErrorCode::errorMessage(), KisAnimationRenderingOptions::firstFrame, KisAnimationRenderingOptions::frameExportConfig, KisAnimationRenderingOptions::frameMimeType, KisTimeSpan::fromTimeToTime(), hasEvenDimensions(), KisAnimationRenderingOptions::height, KisDocument::image, KisImportExportErrorCode::isOk(), KIS_SAFE_ASSERT_RECOVER_NOOP, KisAnimationRenderingOptions::lastFrame, KisViewManager::mainWindow(), mustHaveEvenDimensions(), KisAsyncAnimationFramesSaveDialog::regenerateRange(), KisAsyncAnimationRenderDialogBase::RenderComplete, KisAsyncAnimationRenderDialogBase::RenderFailed, KisAnimationRenderingOptions::renderMode(), KisAsyncAnimationRenderDialogBase::RenderTimedOut, KisAnimationRenderingOptions::resolveAbsoluteFramesDirectory(), KisAnimationRenderingOptions::resolveAbsoluteVideoFilePath(), KisAsyncAnimationFramesSaveDialog::savedFiles(), KisAsyncAnimationFramesSaveDialog::savedFilesMask(), KisAsyncAnimationFramesSaveDialog::savedUniqueFiles(), KisAnimationRenderingOptions::sequenceStart, KisAsyncAnimationRenderDialogBase::setBatchMode(), KisDocument::setErrorMessage(), KisAnimationRenderingOptions::shouldDeleteSequence, KisAnimationRenderingOptions::shouldEncodeVideo, KisMimeDatabase::suffixesForMimeType(), KisAnimationRenderingOptions::videoMimeType, KisMainWindow::viewManager, KisAnimationRenderingOptions::wantsOnlyUniqueFrameSequence, and KisAnimationRenderingOptions::width.