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);
539void Object::importPaletteGPL(
QFile& file)
546 in.readLineInto(&line);
549 in.readLineInto(&line);
554 in.readLineInto(&line);
559 in.readLineInto(&line);
578#if QT_VERSION >= QT_VERSION_CHECK(5, 14, 0)
590 green = snip.toInt();
605 if (countInLine < 2)
green = prevColor.green();
606 if (countInLine < 3)
blue = prevColor.blue();
613 QColor color(red, green, blue);
616 mPalette.append(
ColorRef(color, name));
619 }
while (in.readLineInto(&line));
622void Object::importPalettePencil(
QFile& file)
645void Object::openPalette(
const QString& filePath)
653 importPalette(filePath);
659bool Object::importPalette(
const QString& filePath)
661 QFile file(filePath);
670 importPaletteGPL(file);
672 importPalettePencil(file);
678void Object::loadDefaultPalette()
699 addColor(
ColorRef(
QColor(255, 227, 187), tr(
"Pale Orange Yellow")));
700 addColor(
ColorRef(
QColor(221, 196, 161), tr(
"Pale Grayish Orange Yellow")));
702 addColor(
ColorRef(
QColor(207, 174, 127), tr(
"Grayish Orange Yellow")));
703 addColor(
ColorRef(
QColor(255, 198, 116), tr(
"Light Orange Yellow")));
704 addColor(
ColorRef(
QColor(227, 177, 105), tr(
"Light Grayish Orange Yellow")));
707void Object::paintImage(
QPainter& painter,
int frameNumber,
709 bool antialiasing)
const
711 updateActiveFrames(frameNumber);
727 for (
Layer* layer : mLayers)
729 if (!layer->visible())
736 if (layer->type() == Layer::BITMAP)
740 BitmapImage* bitmap = layerBitmap->getLastBitmapImageAtFrame(frameNumber);
744 bitmap->paintImage(painter);
749 if (layer->type() == Layer::VECTOR)
752 VectorImage* vec = layerVector->getLastVectorImageAtFrame(frameNumber, 0);
756 vec->
paintImage(painter, *
this,
false,
false, antialiasing);
766 qDebug() <<
"[Object] sound file doesn't exist: " << strFilePath;
770 QString sNewFileName =
"sound_";
784 qDebug() <<
"[Object] couldn't copy sound file to data folder: " << strFilePath;
791bool Object::exportFrames(
int frameStart,
int frameEnd,
797 bool exportKeyframesOnly,
801 int progressMax = 50)
const
803 Q_ASSERT(cameraLayer);
807 if (formatStr ==
"PNG" || formatStr ==
"png")
812 if (formatStr ==
"JPG" || formatStr ==
"jpg" || formatStr ==
"JPEG" || formatStr ==
"jpeg")
816 transparency =
false;
818 if (formatStr ==
"TIFF" || formatStr ==
"tiff" || formatStr ==
"TIF" || formatStr ==
"tif")
823 if (formatStr ==
"BMP" || formatStr ==
"bmp")
827 transparency =
false;
829 if (formatStr ==
"WEBP" || formatStr ==
"webp") {
838 qDebug() <<
"Exporting frames from "
839 << frameStart <<
"to"
841 <<
"at size " << exportSize;
843 for (
int currentFrame = frameStart; currentFrame <= frameEnd; currentFrame++)
845 if (progress !=
nullptr)
847 int totalFramesToExport = (frameEnd - frameStart) + 1;
848 if (totalFramesToExport != 0)
850 progress->setValue((currentFrame - frameStart + 1) * progressMax / totalFramesToExport);
854 if (progress->wasCanceled())
860 QTransform view = cameraLayer->getViewAtFrame(currentFrame);
861 QSize camSize = cameraLayer->getViewSize();
864 while (frameNumberString.
length() < 4)
866 frameNumberString.
prepend(
"0");
868 QString sFileName = filePath + frameNumberString + extension;
869 Layer* layer = findLayerByName(layerName);
870 if (exportKeyframesOnly)
872 if (layer->keyExists(currentFrame))
873 exportIm(currentFrame, view, camSize, exportSize, sFileName, format, antialiasing, transparency);
877 exportIm(currentFrame, view, camSize, exportSize, sFileName, format, antialiasing, transparency);
884bool Object::exportIm(
int frame,
const QTransform& view,
QSize cameraSize,
QSize exportSize,
const QString& filePath,
const QString& format,
bool antialiasing,
bool transparency)
const
891 imageToExport.fill(bgColor);
900 paintImage(painter, frame,
false, antialiasing);
902 return imageToExport.save(filePath, format.
toStdString().c_str());
905int Object::getLayerCount()
const
907 return mLayers.size();
915int Object::totalKeyFrameCount()
const
918 for (
const Layer* layer : mLayers)
920 sum += layer->keyFrameCount();
925void Object::updateActiveFrames(
int frame)
const
927 const int beginFrame = std::max(frame - 3, 1);
928 const int endFrame = frame + 4;
930 const int minFrameCount = getLayerCount() * (endFrame - beginFrame);
931 mActiveFramePool->setMinFrameCount(minFrameCount);
933 for (
Layer* layer : mLayers)
935 if (layer->visible())
937 for (
int k = beginFrame; k < endFrame; ++k)
939 KeyFrame* key = layer->getKeyFrameAt(k);
940 mActiveFramePool->put(key);
946void Object::setActiveFramePoolSize(
int sizeInMB)
949 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
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