Krita Source Code Documentation
Loading...
Searching...
No Matches
KisAsyncAnimationFramesSaveDialog.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2017 Dmitry Kazakov <dimula73@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <kis_image.h>
10#include <kis_time_span.h>
11
14
15#include "KisMimeDatabase.h"
16
17#include <QFileInfo>
18#include <QDir>
19#include <QMessageBox>
20#include <QApplication>
21
24 const KisTimeSpan &_range,
25 const QString &baseFilename,
26 int _sequenceNumberingOffset,
27 bool _onlyNeedsUniqueFrames,
28 KisPropertiesConfigurationSP _exportConfiguration)
29 : originalImage(_image),
30 range(_range),
31 onlyNeedsUniqueFrames(_onlyNeedsUniqueFrames),
32 sequenceNumberingOffset(_sequenceNumberingOffset),
33 exportConfiguration(_exportConfiguration)
34 {
35 int baseLength = baseFilename.lastIndexOf(".");
36 if (baseLength > -1) {
37 filenamePrefix = baseFilename.left(baseLength);
38 filenameSuffix = baseFilename.right(baseFilename.length() - baseLength);
39 } else {
40 filenamePrefix = baseFilename;
41 }
42
43 outputMimeType = KisMimeDatabase::mimeTypeForFile(baseFilename, false).toLatin1();
44 }
45
48
51 QByteArray outputMimeType;
53
56};
57
59 const KisTimeSpan &range,
60 const QString &baseFilename,
61 int startNumberingAt,
62 bool onlyNeedsUniqueFrames,
63 KisPropertiesConfigurationSP exportConfiguration)
64 : KisAsyncAnimationRenderDialogBase(i18n("Saving frames..."), originalImage, 0),
65 m_d(new Private(originalImage, range, baseFilename, qMax(startNumberingAt - range.start(), range.start() * -1), onlyNeedsUniqueFrames, exportConfiguration))
66{
67
68
69}
70
74
76{
77 QFileInfo fileInfo(savedFilesMaskWildcard());
78 QDir dir(fileInfo.absolutePath());
79
80 if (!dir.exists()) {
81 dir.mkpath(fileInfo.absolutePath());
82 }
83 KIS_SAFE_ASSERT_RECOVER_NOOP(dir.exists());
84
85 // Check for overwrite. (Batch mode always overwrites.)
86 QStringList preexistingFileNames = dir.entryList({ fileInfo.fileName() });
87 if (!preexistingFileNames.isEmpty() && !batchMode()) {
88 QStringList truncatedList = preexistingFileNames;
89
90 while (truncatedList.size() > 3) {
91 truncatedList.takeLast();
92 }
93
94 QString exampleFiles = truncatedList.join(", ");
95 if (truncatedList.size() != preexistingFileNames.size()) {
96 exampleFiles += QString(", ...");
97 }
98
99 QMessageBox::StandardButton result =
100 QMessageBox::warning(qApp->activeWindow(),
101 i18n("Delete old frames?"),
102 i18n("Frames with the same naming "
103 "scheme exist in the destination "
104 "directory. They are going to be "
105 "deleted, continue?\n\n"
106 "Directory: %1\n"
107 "Files: %2",
108 fileInfo.absolutePath(), exampleFiles),
109 QMessageBox::Yes | QMessageBox::No,
110 QMessageBox::No);
111
112 if (result == QMessageBox::No) {
113 return RenderCancelled;
114 }
115 }
116
117 // Remove any preexisting files.
118 Q_FOREACH (const QString &file, preexistingFileNames) {
119 if (!dir.remove(file)) {
120 if (!batchMode()) {
121 QMessageBox::critical(qApp->activeWindow(),
122 i18n("Failed to delete"),
123 i18n("Failed to delete an old frame file:\n\n"
124 "%1\n\n"
125 "Rendering cancelled.", dir.absoluteFilePath(file)));
126 }
127
128 qWarning() << "WARNING: KisAsyncAnimFramesSaveDialog: Failed to delete old frame file(s):" << dir.absoluteFilePath(file);
129 return RenderFailed;
130 }
131 }
132
133 // Save new frame files.
135
136 // If we cancel rendering or fail rendering process,
137 // lets clean up any files that may have been created
138 // to keep the next render from having artifacts.
139 preexistingFileNames = savedFiles();
140 if (renderingResult != RenderComplete) {
141 Q_FOREACH (const QString &file, preexistingFileNames) {
142 if (dir.exists(file)) {
143 (void)dir.remove(file);
144 }
145 }
146 }
147
148 return renderingResult;
149}
150
152{
153 QList<int> result;
154 for (int frame = m_d->range.start(); frame <= m_d->range.end(); frame++) {
155 KisTimeSpan heldFrameTimeRange = KisTimeSpan::calculateIdenticalFramesRecursive(m_d->originalImage->root(), frame);
156
157 if (!m_d->onlyNeedsUniqueFrames) {
158 // Clamp holds that begin before the rendered range onto it
159 heldFrameTimeRange &= m_d->range;
160 }
161
162 KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(heldFrameTimeRange.isValid(), result);
163
164 result.append(heldFrameTimeRange.start());
165
166 if (heldFrameTimeRange.isInfinite()) {
167 break;
168 } else {
169 frame = heldFrameTimeRange.end();
170 }
171 }
172 return result;
173}
174
176{
178 m_d->filenamePrefix,
179 m_d->filenameSuffix,
180 m_d->outputMimeType,
181 m_d->range,
182 m_d->sequenceNumberingOffset,
183 m_d->onlyNeedsUniqueFrames,
184 m_d->exportConfiguration);
185}
186
188{
189 Q_UNUSED(renderer);
190 Q_UNUSED(image);
191 Q_UNUSED(frame);
192}
193
195{
196 return m_d->filenamePrefix + "%04d" + m_d->filenameSuffix;
197}
198
200{
201 return m_d->filenamePrefix + "????" + m_d->filenameSuffix;
202}
203
205{
206 QStringList files;
207
208 for (int i = m_d->range.start(); i <= m_d->range.end(); i++) {
209 const int num = m_d->sequenceNumberingOffset + i;
210 QString name = QString("%1").arg(num, 4, 10, QChar('0'));
211 name = m_d->filenamePrefix + name + m_d->filenameSuffix;
212 files.append(QFileInfo(name).fileName());
213 }
214
215 return files;
216}
217
219{
220 QStringList files;
221
222 const QList<int> frames = calcDirtyFrames();
223
224 Q_FOREACH (int frame, frames) {
225 const int num = m_d->sequenceNumberingOffset + frame;
226 QString name = QString("%1").arg(num, 4, 10, QChar('0'));
227 name = m_d->filenamePrefix + name + m_d->filenameSuffix;
228 files.append(QFileInfo(name).fileName());
229 }
230
231 return files;
232}
233
QList< int > calcDirtyFrames() const override
returns a list of frames that should be regenerated by the dialog
KisAsyncAnimationRendererBase * createRenderer(KisImageSP image) override
create a renderer object linked to image
void initializeRendererForFrame(KisAsyncAnimationRendererBase *renderer, KisImageSP image, int frame) override
Result regenerateRange(KisViewManager *viewManager) override
start generation of frames and (if not in batch mode) show the dialog
KisAsyncAnimationFramesSaveDialog(KisImageSP image, const KisTimeSpan &range, const QString &baseFilename, int startNumberingAt, bool onlyNeedsUniqueFrames, KisPropertiesConfigurationSP exportConfiguration)
KisAsyncAnimationRenderDialogBase is a special class for rendering multiple frames of the image and p...
virtual Result regenerateRange(KisViewManager *viewManager)
start generation of frames and (if not in batch mode) show the dialog
static QString mimeTypeForFile(const QString &file, bool checkExistingFiles=true)
Find the mimetype for the given filename. The filename must include a suffix.
int start() const
bool isInfinite() const
static KisTimeSpan calculateIdenticalFramesRecursive(const KisNode *node, int time)
int end() const
bool isValid() const
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
typedef void(QOPENGLF_APIENTRYP PFNGLINVALIDATEBUFFERDATAPROC)(GLuint buffer)
Private(KisImageSP _image, const KisTimeSpan &_range, const QString &baseFilename, int _sequenceNumberingOffset, bool _onlyNeedsUniqueFrames, KisPropertiesConfigurationSP _exportConfiguration)