Krita Source Code Documentation
Loading...
Searching...
No Matches
kis_animation_importer.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2015 Jouni Pentikäinen <joupent@gmail.com>
3 *
4 * SPDX-License-Identifier: GPL-2.0-or-later
5 */
6
8
9#include <QStatusBar>
10
11#include "KoColorSpace.h"
12#include <KoUpdater.h>
13#include <QApplication>
14#include <QQueue>
15#include "KisPart.h"
16#include "KisDocument.h"
17#include "kis_image.h"
18#include "kis_undo_adapter.h"
19#include "kis_paint_layer.h"
20#include "kis_group_layer.h"
24#include <QRegularExpression>
25
33
35 : m_d(new Private())
36{
37 m_d->document = 0;
38 m_d->image = image;
39 m_d->stop = false;
40 m_d->updater = updater;
41}
42
44 : m_d(new Private())
45{
46 m_d->document= document;
47 m_d->image = document->image();
48 m_d->stop = false;
49}
50
53
54KisImportExportErrorCode KisAnimationImporter::import(QStringList files, int firstFrame, int step, bool autoAddHoldframes, bool startfrom0, int isAscending, bool assignDocumentProfile, QList<int> optionalKeyframeTimeList)
55{
56 //TODO: We should clean up this code --
57 // There are a lot of actions here that we should break into individual methods
58 // so that we can better control code flow, and I'd prefer to use multiple import
59 // calls to better handle all of these different options!
60 // Additionally, we might prefer to use flags for multiple booleans to improve
61 // legibility of calls.
62 Q_ASSERT(step > 0);
63
64 KisUndoAdapter *undo = m_d->image->undoAdapter();
65 undo->beginMacro(kundo2_i18n("Import animation"));
66
67 QScopedPointer<KisDocument> importDoc(KisPart::instance()->createDocument());
68 importDoc->setFileBatchMode(true);
69
70 const bool usingPredefinedTimes = !optionalKeyframeTimeList.isEmpty() && !autoAddHoldframes;
71 QQueue<int> predefinedFrameQueue;
72 predefinedFrameQueue.append(optionalKeyframeTimeList);
73
75 int frame = usingPredefinedTimes ? predefinedFrameQueue.dequeue() : firstFrame;
76 int filesProcessed = 0;
77
78 if (usingPredefinedTimes) {
79 KIS_ASSERT(files.count() == optionalKeyframeTimeList.count());
80 }
81
82 if (m_d->updater) {
83 m_d->updater->setRange(0, files.size());
84 }
85
86 QPair<KisPaintLayerSP, KisRasterKeyframeChannel*> layerRasterChannelPair;
87
88 const QRegularExpression rx(QLatin1String("(\\d+)")); //regex for extracting numbers
89 QStringList fileNumberRxList;
90
91 QRegularExpressionMatchIterator i = rx.globalMatch(files.at(0));
92 while (i.hasNext()) {
93 QRegularExpressionMatch match = i.next();
94 fileNumberRxList << match.captured(1);
95 }
96
97 int firstFrameNumber = 0;
98 bool ok;
99
100 if (!fileNumberRxList.isEmpty()) {
101 fileNumberRxList.last().toInt(&ok); // selects the last number of file name of the first frame (useful for descending order)
102 // Note to self -- ^^ uh.... This isn't doing anything?? Shouldn't this assign `firstFrameNumber`?
103 }
104
105 if (firstFrameNumber == 0){
106 startfrom0 = false; // if enabled, the zeroth frame will be places in -1 slot, leading to an error
107 }
108
109 fileNumberRxList.clear();
110 const int offset = (startfrom0 ? 1 : 0); //offset added to consider file numbering starts from 1 instead of 0
111 int autoframe = 0;
112
113 KisConfig cfg(true);
114
115 Q_FOREACH(QString file, files) {
116 bool successfullyLoaded = importDoc->openPath(file, KisDocument::DontAddToRecent);
118
119 if ( (!usingPredefinedTimes && frame == firstFrame)
120 || (usingPredefinedTimes && frame == optionalKeyframeTimeList.first()) ) {
121 layerRasterChannelPair = initializePaintLayer(importDoc, undo);
122 }
123
124 if (m_d->updater) {
125 if (m_d->updater->interrupted()) {
126 m_d->stop = true;
127 } else {
128 m_d->updater->setValue(filesProcessed + 1);
129
130 // the updater doesn't call that automatically,
131 // it is "threaded" by default
132 qApp->processEvents();
133 }
134 }
135
136 if (m_d->stop) {
138 break;
139 }
140
141 if (cfg.trimFramesImport()) {
142 importDoc->image()->projection()->crop(m_d->image->bounds());
143 }
144 importDoc->image()->projection()->purgeDefaultPixels();
145
147
148 if (!autoAddHoldframes) {
149 layerRasterChannelPair.second->importFrame(frame, importDoc->image()->projection(), NULL); // as first frame added will go to second slot i.e #1 instead of #0
150 } else {
151 QRegularExpressionMatchIterator i = rx.globalMatch(file);
152 while (i.hasNext()) {
153 QRegularExpressionMatch match = i.next();
154 fileNumberRxList << match.captured(1);
155 }
156
157 int filenum = fileNumberRxList.last().toInt(&ok);
158
159 if (isAscending == 0) {
160 autoframe = firstFrame + filenum - offset;
161 } else {
162 autoframe = firstFrame + (firstFrameNumber - filenum); //places the first frame #0 (or #1) slot, and later frames are added as per the difference
163 }
164
165 if (ok) {
166 layerRasterChannelPair.second->importFrame(autoframe , importDoc->image()->projection(), NULL);
167 } else {
168 // if it fails to extract a number, the next frame will simply be added to next slot
169 layerRasterChannelPair.second->importFrame(autoframe + 1, importDoc->image()->projection(), NULL);
170 }
171 fileNumberRxList.clear();
172 }
173
174 if (usingPredefinedTimes && predefinedFrameQueue.count()) {
175 frame = predefinedFrameQueue.dequeue();
176 } else {
177 frame += step;
178 }
179
180 filesProcessed++;
181 }
182
183 if (layerRasterChannelPair.first && assignDocumentProfile) {
184
185 if (layerRasterChannelPair.first->colorSpace()->colorModelId() == m_d->image->colorSpace()->colorModelId()) {
186
187 const KoColorSpace *srcColorSpace = layerRasterChannelPair.first->colorSpace();
189 srcColorSpace->colorModelId().id()
190 , srcColorSpace->colorDepthId().id()
191 , m_d->image->colorSpace()->profile());
192
193 KisAssignProfileProcessingVisitor *visitor = new KisAssignProfileProcessingVisitor(srcColorSpace, dstColorSpace);
194 visitor->visit(layerRasterChannelPair.first.data(), undo);
195 }
196 }
197
198 undo->endMacro();
199
200 return status;
201}
202
203QPair<KisPaintLayerSP, KisRasterKeyframeChannel*> KisAnimationImporter::initializePaintLayer(QScopedPointer<KisDocument>& doc, KisUndoAdapter *undoAdapter)
204{
205 const KoColorSpace *cs = doc->image()->colorSpace();
206 KisPaintLayerSP paintLayer = new KisPaintLayer(m_d->image, m_d->image->nextLayerName(), OPACITY_OPAQUE_U8, cs);
207 undoAdapter->addCommand(new KisImageLayerAddCommand(m_d->image, paintLayer, m_d->image->rootLayer(), m_d->image->rootLayer()->childCount()));
208
209 paintLayer->enableAnimation();
210 KisRasterKeyframeChannel* contentChannel = qobject_cast<KisRasterKeyframeChannel*>(paintLayer->getKeyframeChannel(KisKeyframeChannel::Raster.id(), true));
211 return QPair<KisPaintLayerSP, KisRasterKeyframeChannel*>(paintLayer, contentChannel);
212}
213
215{
216 m_d->stop = true;
217}
const quint8 OPACITY_OPAQUE_U8
QScopedPointer< Private > m_d
KisAnimationImporter(KisImageSP image, KoUpdaterPtr updater=0)
QPair< KisPaintLayerSP, class KisRasterKeyframeChannel * > initializePaintLayer(QScopedPointer< KisDocument > &doc, class KisUndoAdapter *undoAdapter)
KisImportExportErrorCode import(QStringList files, int firstFrame, int step, bool autoAddHoldframes=false, bool startfrom0=false, int isAscending=0, bool assignDocumentProfile=false, QList< int > optionalKeyframeTimeList={})
void visit(KisTransformMask *mask, KisUndoAdapter *undoAdapter) override
bool trimFramesImport(bool defaultValue=false) const
The command for adding a layer.
KisGroupLayerSP rootLayer() const
static const KoID Raster
static KisPart * instance()
Definition KisPart.cpp:131
The KisRasterKeyframeChannel is a concrete KisKeyframeChannel subclass that stores and manages KisRas...
virtual void addCommand(KUndo2Command *cmd)=0
virtual KoID colorModelId() const =0
virtual KoID colorDepthId() const =0
QString id() const
Definition KoID.cpp:63
#define KIS_SAFE_ASSERT_RECOVER_RETURN_VALUE(cond, val)
Definition kis_assert.h:129
#define KIS_ASSERT(cond)
Definition kis_assert.h:33
KisDocument * createDocument(QList< KisNodeSP > nodes, KisImageSP srcImage, const QRect &copiedBounds)
KUndo2MagicString kundo2_i18n(const char *text)
KisKeyframeChannel * getKeyframeChannel(const QString &id, bool create)
KisImageWSP image
void enableAnimation()
quint32 childCount() const
Definition kis_node.cpp:414
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()