19#include <QDomDocument>
21#include <QProgressDialog>
22#include <QApplication>
28#include <QRegularExpression>
31#include "layerbitmap.h"
32#include "layervector.h"
33#include "layersound.h"
34#include "layercamera.h"
37#include "bitmapimage.h"
38#include "vectorimage.h"
39#include "fileformat.h"
40#include "activeframepool.h"
50 mActiveFramePool->clear();
52 for (
Layer* layer : mLayers)
71 for (
Layer* layer : mLayers)
73 QDomElement layerTag = layer->createDomElement(doc);
79bool Object::loadXML(
const QDomElement& docElem, ProgressCallback progressForward)
86 const QString dataDirPath = mDataDirPath;
91 if (element.
tagName() !=
"layer")
106 newLayer =
new LayerSound(getUniqueLayerID());
114 mLayers.append(newLayer);
115 newLayer->loadDomElement(element, dataDirPath, progressForward);
123 mLayers.append(layerBitmap);
133 mLayers.append(layerVector);
143 mLayers.append(layerSound);
153 mLayers.append(layerCamera);
160void Object::createWorkingDir()
165 projectName =
"Default";
170 projectName = fileInfo.completeBaseName();
179 PFF_TMP_DECOMPRESS_EXT,
182 while(dir.exists(strWorkingDir));
184 dir.mkpath(strWorkingDir);
185 mWorkingDirPath = strWorkingDir;
187 QDir dataDir(strWorkingDir + PFF_DATA_DIR);
190 mDataDirPath = dataDir.absolutePath();
193void Object::deleteWorkingDir()
const
195 if (!mWorkingDirPath.
isEmpty())
197 QDir dir(mWorkingDirPath);
198 bool ok = dir.removeRecursively();
203void Object::setWorkingDir(
const QString& path)
206 Q_ASSERT(dir.exists());
207 mWorkingDirPath = path;
210int Object::getMaxLayerID()
213 for (
Layer* iLayer : mLayers)
215 if (iLayer->id() > maxId)
217 maxId = iLayer->id();
223int Object::getUniqueLayerID()
225 return 1 + getMaxLayerID();
228Layer* Object::getLayer(
int i)
const
230 if (i < 0 || i >= getLayerCount())
235 return mLayers.at(i);
238Layer* Object::getLayerBelow(
int i, Layer::LAYER_TYPE type)
const
242 Layer* layerCheck = getLayer(i);
243 Q_ASSERT(layerCheck);
244 if (layerCheck->type() == type)
253Layer* Object::findLayerById(
int layerId)
const
255 for(
Layer* layer : mLayers)
257 if (layer->id() == layerId)
265Layer* Object::findLayerByName(
const QString& strName, Layer::LAYER_TYPE type)
const
267 bool bCheckType = (type != Layer::UNDEFINED);
268 for (
Layer* layer : mLayers)
270 bool isTypeMatch = (bCheckType) ? (type == layer->type()) :
true;
271 if (isTypeMatch && layer->name() == strName)
279Layer* Object::takeLayer(
int layerId)
284 for (
int i = 0; i< mLayers.length(); ++i)
286 Layer* layer = mLayers[i];
287 if (layer->id() == layerId)
294 if (index == -1) {
return nullptr; }
296 Layer* layer = mLayers.takeAt(index);
300bool Object::swapLayers(
int i,
int j)
303 if (!canSwap) {
return false; }
307#if QT_VERSION >= QT_VERSION_CHECK(5, 13, 0)
308 mLayers.swapItemsAt(i, j);
318 if (layerIndexLeft < 0 || layerIndexLeft >= mLayers.size())
323 if (layerIndexRight < 0 || layerIndexRight >= mLayers.size())
328 Layer* firstLayer = mLayers.first();
329 Layer* leftLayer = mLayers.at(layerIndexLeft);
330 Layer* rightLayer = mLayers.at(layerIndexRight);
333 if ((leftLayer->type() == Layer::CAMERA ||
334 rightLayer->type() == Layer::CAMERA) &&
335 (firstLayer == leftLayer || firstLayer == rightLayer)) {
348 if (mLayers.at(index) ==
nullptr)
356void Object::deleteLayer(
int i)
358 if (i > -1 && i < mLayers.size())
360 delete mLayers.takeAt(i);
364void Object::deleteLayer(
Layer* layer)
366 auto it = std::find(mLayers.begin(), mLayers.end(), layer);
368 if (it != mLayers.end())
375bool Object::addLayer(
Layer* layer)
377 if (layer ==
nullptr || mLayers.contains(layer))
381 layer->setId(getUniqueLayerID());
382 mLayers.append(layer);
386ColorRef Object::getColor(
int index)
const
389 if (index > -1 && index < mPalette.
size())
391 result = mPalette.
at(index);
396void Object::setColor(
int index,
const QColor& newColor)
398 Q_ASSERT(index >= 0);
400 mPalette[index].color = newColor;
403void Object::setColorRef(
int index,
const ColorRef& newColorRef)
405 mPalette[index] = newColorRef;
408void Object::movePaletteColor(
int start,
int end)
410 mPalette.
move(start, end);
413void Object::moveVectorColor(
int start,
int end)
415 for (
Layer* layer : mLayers)
417 if (layer->type() == Layer::VECTOR)
419 static_cast<LayerVector*
>(layer)->moveColor(start, end);
424void Object::addColorAtIndex(
int index,
const ColorRef& newColor)
426 mPalette.
insert(index, newColor);
429bool Object::isColorInUse(
int index)
const
431 for (
Layer* layer : mLayers)
433 if (layer->type() == Layer::VECTOR)
437 if (layerVector->usesColor(index))
446void Object::removeColor(
int index)
448 for (
Layer* layer : mLayers)
450 if (layer->type() == Layer::VECTOR)
453 layerVector->removeColor(index);
462void Object::renameColor(
int i,
const QString& text)
464 mPalette[i].name = text;
470 bool ok = exportPalette(fullPath);
476void Object::exportPaletteGPL(
QFile& file)
const
481 out <<
"GIMP Palette" <<
"\n";
482 out <<
"Name: " << fileName <<
"\n";
485 for (
const ColorRef& ref : mPalette)
489 out <<
" " << ref.name <<
"\n";
493void Object::exportPalettePencil(
QFile& file)
const
500 for (
const ColorRef& ref : mPalette)
511 doc.
save(out, indentSize);
514bool Object::exportPalette(
const QString& filePath)
const
516 QFile file(filePath);
519 qDebug(
"Error: cannot export palette");
524 exportPaletteGPL(file);
526 exportPalettePencil(file);
540void Object::importPaletteGPL(
QFile& file)
547 in.readLineInto(&line);
550 in.readLineInto(&line);
555 in.readLineInto(&line);
560 in.readLineInto(&line);
579#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
591 green = snip.toInt();
606 if (countInLine < 2)
green = prevColor.green();
607 if (countInLine < 3)
blue = prevColor.blue();
614 QColor color(red, green, blue);
617 mPalette.append(
ColorRef(color, name));
620 }
while (in.readLineInto(&line));
623void Object::importPalettePencil(
QFile& file)
646void Object::openPalette(
const QString& filePath)
654 importPalette(filePath);
660bool Object::importPalette(
const QString& filePath)
662 QFile file(filePath);
671 importPaletteGPL(file);
673 importPalettePencil(file);
680void Object::loadDefaultPalette()
701 addColor(
ColorRef(
QColor(255, 227, 187), tr(
"Pale Orange Yellow")));
702 addColor(
ColorRef(
QColor(221, 196, 161), tr(
"Pale Grayish Orange Yellow")));
704 addColor(
ColorRef(
QColor(207, 174, 127), tr(
"Grayish Orange Yellow")));
705 addColor(
ColorRef(
QColor(255, 198, 116), tr(
"Light Orange Yellow")));
706 addColor(
ColorRef(
QColor(227, 177, 105), tr(
"Light Grayish Orange Yellow")));
709void Object::paintImage(
QPainter& painter,
int frameNumber,
711 bool antialiasing)
const
713 updateActiveFrames(frameNumber);
729 for (
Layer* layer : mLayers)
731 if (!layer->visible())
738 if (layer->type() == Layer::BITMAP)
742 BitmapImage* bitmap = layerBitmap->getLastBitmapImageAtFrame(frameNumber);
746 bitmap->paintImage(painter);
751 if (layer->type() == Layer::VECTOR)
754 VectorImage* vec = layerVector->getLastVectorImageAtFrame(frameNumber, 0);
758 vec->
paintImage(painter, *
this,
false,
false, antialiasing);
768 qDebug() <<
"[Object] sound file doesn't exist: " << strFilePath;
772 QString sNewFileName =
"sound_";
786 qDebug() <<
"[Object] couldn't copy sound file to data folder: " << strFilePath;
793bool Object::exportFrames(
int frameStart,
int frameEnd,
799 bool exportKeyframesOnly,
803 int progressMax = 50)
const
805 Q_ASSERT(cameraLayer);
809 if (formatStr ==
"PNG" || formatStr ==
"png")
814 if (formatStr ==
"JPG" || formatStr ==
"jpg" || formatStr ==
"JPEG" || formatStr ==
"jpeg")
818 transparency =
false;
820 if (formatStr ==
"TIFF" || formatStr ==
"tiff" || formatStr ==
"TIF" || formatStr ==
"tif")
825 if (formatStr ==
"BMP" || formatStr ==
"bmp")
829 transparency =
false;
831 if (formatStr ==
"WEBP" || formatStr ==
"webp") {
840 qDebug() <<
"Exporting frames from "
841 << frameStart <<
"to"
843 <<
"at size " << exportSize;
845 for (
int currentFrame = frameStart; currentFrame <= frameEnd; currentFrame++)
847 if (progress !=
nullptr)
849 int totalFramesToExport = (frameEnd - frameStart) + 1;
850 if (totalFramesToExport != 0)
852 progress->setValue((currentFrame - frameStart + 1) * progressMax / totalFramesToExport);
856 if (progress->wasCanceled())
862 QTransform view = cameraLayer->getViewAtFrame(currentFrame);
863 QSize camSize = cameraLayer->getViewSize();
866 while (frameNumberString.
length() < 4)
868 frameNumberString.
prepend(
"0");
870 QString sFileName = filePath + frameNumberString + extension;
871 Layer* layer = findLayerByName(layerName);
872 if (exportKeyframesOnly)
874 if (layer->keyExists(currentFrame))
875 exportIm(currentFrame, view, camSize, exportSize, sFileName, format, antialiasing, transparency);
879 exportIm(currentFrame, view, camSize, exportSize, sFileName, format, antialiasing, transparency);
886bool Object::exportIm(
int frame,
const QTransform& view,
QSize cameraSize,
QSize exportSize,
const QString& filePath,
const QString& format,
bool antialiasing,
bool transparency)
const
893 imageToExport.fill(bgColor);
902 paintImage(painter, frame,
false, antialiasing);
904 return imageToExport.save(filePath, format.
toStdString().c_str());
907int Object::getLayerCount()
const
909 return mLayers.size();
917int Object::totalKeyFrameCount()
const
920 for (
const Layer* layer : mLayers)
922 sum += layer->keyFrameCount();
927void Object::updateActiveFrames(
int frame)
const
929 const int beginFrame = std::max(frame - 3, 1);
930 const int endFrame = frame + 4;
932 const int minFrameCount = getLayerCount() * (endFrame - beginFrame);
933 mActiveFramePool->setMinFrameCount(minFrameCount);
935 for (
Layer* layer : mLayers)
937 if (layer->visible())
939 for (
int k = beginFrame; k < endFrame; ++k)
941 KeyFrame* key = layer->getKeyFrameAt(k);
942 mActiveFramePool->put(key);
948void Object::setActiveFramePoolSize(
int sizeInMB)
951 mActiveFramePool->resize(qint64(sizeInMB) * 1024 * 1024);
ActiveFramePool implemented a LRU cache to keep tracking the most recent accessed key frames A key fr...
bool addNewKeyFrameAt(int position)
Creates a new keyframe at the given position, unless one already exists.
bool canDeleteLayer(int index) const
Allows you to check whether the layer at the given index can be deleted.
bool canSwapLayers(int layerIndexLeft, int layerIndexRight) const
Allows you to check whether two layers can be swappped, before doing the actual operation.
void paintImage(QPainter &painter, const Object &object, bool simplified, bool showThinCurves, bool antialiasing)
VectorImage::paintImage.
QColor toRgb() const const
void processEvents(QEventLoop::ProcessEventsFlags flags)
QDateTime currentDateTime()
QString toString(Qt::DateFormat format) const const
QString filePath(const QString &fileName) const const
QDomElement createElement(const QString &tagName)
QDomElement documentElement() const const
bool setContent(const QByteArray &data, bool namespaceProcessing, QString *errorMsg, int *errorLine, int *errorColumn)
QString attribute(const QString &name, const QString &defValue) const const
void setAttribute(const QString &name, const QString &value)
QString tagName() const const
QDomNode appendChild(const QDomNode &newChild)
QDomNode firstChild() const const
bool isNull() const const
QDomNode nextSibling() const const
void save(QTextStream &stream, int indent, QDomNode::EncodingPolicy encodingPolicy) const const
QDomElement toElement() const const
bool copy(const QString &newName)
bool exists() const const
virtual QString fileName() const const override
virtual bool open(QIODevice::OpenMode mode) override
virtual void close() override
QString baseName() const const
QString suffix() const const
const T & at(int i) const const
void insert(int i, const T &value)
void move(int from, int to)
CompositionMode_SourceOver
QPaintDevice * device() const const
void drawRect(const QRectF &rectangle)
void setBrush(const QBrush &brush)
void setCompositionMode(QPainter::CompositionMode mode)
void setOpacity(qreal opacity)
void setPen(const QColor &color)
void setRenderHint(QPainter::RenderHint hint, bool on)
void setWindow(const QRect &rectangle)
void setWorldMatrixEnabled(bool enable)
QStringList split(const QString &sep, QString::SplitBehavior behavior, Qt::CaseSensitivity cs) const const
QString arg(qlonglong a, int fieldWidth, int base, QChar fillChar) const const
bool endsWith(const QString &s, Qt::CaseSensitivity cs) const const
bool isEmpty() const const
QString number(int n, int base)
QString & prepend(QChar ch)
bool startsWith(const QString &s, Qt::CaseSensitivity cs) const const
int toInt(bool *ok, int base) const const
std::string toStdString() const const
QString trimmed() const const