56 bool isTemporaryFramesDirectory =
false;
57 QString framesDirectory;
68 }
else if (encoderOptions.
directory.isEmpty()) {
76 std::unique_ptr<QTemporaryDir> tempDir;
78 tempDir = std::make_unique<QTemporaryDir>();
80 framesDirectory = tempDir->path();
81 isTemporaryFramesDirectory =
true;
83 framesDirectory = encoderOptions.
directory;
91 const QString baseFileName = QString(
"%1/%2.%3").arg(framesDirectory, encoderOptions.
basename, extension);
94 QString videoType = encoderOptions.videoFormatKey;
100 encoderOptions.
width = encoderOptions.
width + (encoderOptions.
width & 0x1);
105 const QSize scaledSize = doc->
image()->
bounds().size().scaled(encoderOptions.
width, encoderOptions.
height, Qt::IgnoreAspectRatio);
109 QString type = looksLikeMp4(videoType) ?
"Mpeg4 (.mp4) " :
"Matroska (.mkv) ";
111 qWarning() << type <<
"requires width and height to be even, resize and try again!";
112 doc->
setErrorMessage(i18n(
"%1 requires width and height to be even numbers. Please resize or crop the image before exporting.", type));
113 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Could not render animation:\n%1", doc->
errorMessage()));
119 const bool batchMode =
false;
141 bool videoFileWriteAllowed =
true;
150 const QFileInfo videoOutputFile(videoOutputFilePath);
151 QDir outputDir(videoOutputFile.absolutePath());
153 if (!outputDir.exists()) {
154 outputDir.mkpath(videoOutputFile.absolutePath());
159 if (videoOutputFile.exists()) {
160 QMessageBox videoOverwritePrompt;
162 videoOverwritePrompt.setText(i18n(
"Overwrite existing video?"));
163 videoOverwritePrompt.setInformativeText(i18n(
"A file already exists at the path where you want to render your video [%1]... \n\
164 Are you sure you want to overwrite the existing file?", videoOutputFilePath));
165 videoOverwritePrompt.setStandardButtons(QMessageBox::Ok | QMessageBox::Abort);
167 videoFileWriteAllowed = videoOverwritePrompt.exec() == QMessageBox::Ok ? true :
false;
172 if (videoFileWriteAllowed) {
179 QFile videoFile(videoOutputFilePath);
180 if (!videoFile.open(QIODevice::WriteOnly)) {
181 qWarning() <<
"Could not open" << videoFile.fileName() <<
"for writing! Do you have permission to write to this file?";
188 if (exportResult.
isOk()) {
190 exportResult =
encoder->convert(doc,
198 if (!exportResult.
isOk()) {
199 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Krita"), i18n(
"Could not render animation:\n%1", exportResult.
errorMessage()));
201 delayReturnSuccess =
false;
207 if (!isTemporaryFramesDirectory) {
208 QDir d(framesDirectory);
211 bool shouldDeleteSequence =
false;
215 if (shouldDeleteSequence || !delayReturnSuccess) {
218 Q_FOREACH(
const QString &f, savedFiles) {
227 Q_FOREACH(
const QString &f, fileNames) {
228 if (!uniqueFrameNames.contains(f)) {
238 Q_FOREACH(
const QString &f, paletteFiles) {
244 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");
246 QMessageBox::critical(qApp->activeWindow(), i18nc(
"@title:window",
"Rendering error"), i18n(
"Failed to render animation frames! Output files are incomplete."));
249 return delayReturnSuccess;
KisViewManager * viewManager