Commit 888df0c7 authored by Dmitry Kazakov's avatar Dmitry Kazakov

Implemented load/save of the Transformation Masks

Please also note that now we have KisDomUtils that simplify loading and
saving of variables into XML structure.
parent 503cb053
......@@ -135,6 +135,7 @@ set(kritaimage_LIB_SRCS
kis_transform_mask.cpp
kis_transform_mask_params_interface.cpp
kis_recalculate_transform_mask_job.cpp
kis_transform_mask_params_factory_registry.cpp
kis_gradient_painter.cc
kis_iterator_ng.cpp
kis_async_merger.cpp
......@@ -209,6 +210,7 @@ set(kritaimage_LIB_SRCS
kis_liquify_transform_worker.cpp
kis_green_coordinates_math.cpp
kis_algebra_2d.cpp
kis_dom_utils.cpp
kis_transparency_mask.cc
kis_undo_store.cpp
kis_undo_stores.cpp
......
......@@ -51,6 +51,7 @@ void KisImageSetResolutionCommand::redo()
#include "kis_external_layer_iface.h"
#include "kis_transparency_mask.h"
#include "kis_filter_mask.h"
#include "kis_transform_mask.h"
#include "kis_selection_mask.h"
#include "kis_selection.h"
......@@ -67,6 +68,7 @@ public:
void visit(KisGeneratorLayer *layer, KisUndoAdapter*) { layer->internalSelection()->updateProjection(); }
void visit(KisExternalLayer *layer, KisUndoAdapter*) { layer->resetCache(); }
void visit(KisFilterMask *mask, KisUndoAdapter*) { mask->selection()->updateProjection(); }
void visit(KisTransformMask *mask, KisUndoAdapter*) { KIS_ASSERT_RECOVER_NOOP(!mask->selection()); }
void visit(KisTransparencyMask *mask, KisUndoAdapter*) { mask->selection()->updateProjection(); }
void visit(KisSelectionMask *mask, KisUndoAdapter*) { mask->selection()->updateProjection(); }
};
......
......@@ -164,6 +164,9 @@ public:
bool visit(KisFilterMask*) {
return true;
}
bool visit(KisTransformMask*) {
return true;
}
bool visit(KisTransparencyMask*) {
return true;
}
......
......@@ -92,6 +92,9 @@ public:
bool visit(KisFilterMask*) {
return true;
}
bool visit(KisTransformMask*) {
return true;
}
bool visit(KisTransparencyMask*) {
return true;
}
......
......@@ -58,6 +58,9 @@ public:
bool visit(KisFilterMask*) {
return true;
}
bool visit(KisTransformMask*) {
return true;
}
bool visit(KisTransparencyMask*) {
return true;
}
......
......@@ -32,6 +32,7 @@
#include "kis_external_layer_iface.h"
#include "kis_clone_layer.h"
#include "kis_filter_mask.h"
#include "kis_transform_mask.h"
#include "kis_transparency_mask.h"
#include "kis_selection_mask.h"
#include "generator/kis_generator_layer.h"
......@@ -90,6 +91,9 @@ public:
return check(mask);
}
bool visit(KisTransformMask *mask) {
return check(mask);
}
bool visit(KisTransparencyMask *mask) {
return check(mask);
......
/*
* Copyright (c) 2014 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_dom_utils.h"
#include <QTransform>
#include <QDebug>
namespace KisDomUtils {
void saveValue(QDomElement *parent, const QString &tag, const QSize &size)
{
QDomDocument doc = parent->ownerDocument();
QDomElement e = doc.createElement(tag);
parent->appendChild(e);
e.setAttribute("type", "size");
e.setAttribute("w", size.width());
e.setAttribute("h", size.height());
}
void saveValue(QDomElement *parent, const QString &tag, const QRect &rc)
{
QDomDocument doc = parent->ownerDocument();
QDomElement e = doc.createElement(tag);
parent->appendChild(e);
e.setAttribute("type", "rect");
e.setAttribute("x", rc.x());
e.setAttribute("y", rc.y());
e.setAttribute("w", rc.width());
e.setAttribute("h", rc.height());
}
void saveValue(QDomElement *parent, const QString &tag, const QPointF &pt)
{
QDomDocument doc = parent->ownerDocument();
QDomElement e = doc.createElement(tag);
parent->appendChild(e);
e.setAttribute("type", "pointf");
e.setAttribute("x", pt.x());
e.setAttribute("y", pt.y());
}
void saveValue(QDomElement *parent, const QString &tag, const QVector3D &pt)
{
QDomDocument doc = parent->ownerDocument();
QDomElement e = doc.createElement(tag);
parent->appendChild(e);
e.setAttribute("type", "vector3d");
e.setAttribute("x", pt.x());
e.setAttribute("y", pt.y());
e.setAttribute("z", pt.z());
}
void saveValue(QDomElement *parent, const QString &tag, const QTransform &t)
{
QDomDocument doc = parent->ownerDocument();
QDomElement e = doc.createElement(tag);
parent->appendChild(e);
e.setAttribute("type", "transform");
e.setAttribute("m11", t.m11());
e.setAttribute("m12", t.m12());
e.setAttribute("m13", t.m13());
e.setAttribute("m21", t.m21());
e.setAttribute("m22", t.m22());
e.setAttribute("m23", t.m23());
e.setAttribute("m31", t.m31());
e.setAttribute("m32", t.m32());
e.setAttribute("m33", t.m33());
}
#include "kis_debug.h"
bool findOnlyElement(const QDomElement &parent, const QString &tag, QDomElement *el, QStringList *errorMessages)
{
QDomNodeList list = parent.elementsByTagName(tag);
if (list.size() != 1 || !list.at(0).isElement()) {
QString msg = i18n("Could not find \"%1\" XML tag in \"%2\"", tag, parent.tagName());
if (errorMessages) {
*errorMessages << msg;
} else {
qWarning() << msg;
}
return false;
}
*el = list.at(0).toElement();
return true;
}
bool checkType(const QDomElement &e, const QString &expectedType)
{
QString type = e.attribute("type", "unknown-type");
if (type != expectedType) {
qWarning() << i18n("Error: incorrect type (%2) for value %1. Expected %3", e.tagName(), type, expectedType);
return false;
}
return true;
}
bool loadValue(const QDomElement &parent, const QString &tag, QSize *size)
{
QDomElement e;
if (!findOnlyElement(parent, tag, &e)) return false;
if (!checkType(e, "size")) return false;
size->setWidth(e.attribute("w", "0").toInt());
size->setHeight(e.attribute("h", "0").toInt());
return true;
}
bool loadValue(const QDomElement &parent, const QString &tag, QRect *rc)
{
QDomElement e;
if (!findOnlyElement(parent, tag, &e)) return false;
if (!checkType(e, "rect")) return false;
rc->setX(e.attribute("x", "0").toInt());
rc->setY(e.attribute("y", "0").toInt());
rc->setWidth(e.attribute("w", "0").toInt());
rc->setHeight(e.attribute("h", "0").toInt());
return true;
}
bool loadValue(const QDomElement &parent, const QString &tag, QPointF *pt)
{
QDomElement e;
if (!findOnlyElement(parent, tag, &e)) return false;
if (!checkType(e, "pointf")) return false;
pt->setX(e.attribute("x", "0").toDouble());
pt->setY(e.attribute("y", "0").toDouble());
return true;
}
bool loadValue(const QDomElement &parent, const QString &tag, QVector3D *pt)
{
QDomElement e;
if (!findOnlyElement(parent, tag, &e)) return false;
if (!checkType(e, "vector3d")) return false;
pt->setX(e.attribute("x", "0").toDouble());
pt->setY(e.attribute("y", "0").toDouble());
pt->setZ(e.attribute("z", "0").toDouble());
return true;
}
bool loadValue(const QDomElement &parent, const QString &tag, QTransform *t)
{
QDomElement e;
if (!findOnlyElement(parent, tag, &e)) return false;
if (!checkType(e, "transform")) return false;
qreal m11 = e.attribute("m11", "1.0").toDouble();
qreal m12 = e.attribute("m12", "0.0").toDouble();
qreal m13 = e.attribute("m13", "0.0").toDouble();
qreal m21 = e.attribute("m21", "0.0").toDouble();
qreal m22 = e.attribute("m22", "1.0").toDouble();
qreal m23 = e.attribute("m23", "0.0").toDouble();
qreal m31 = e.attribute("m31", "0.0").toDouble();
qreal m32 = e.attribute("m32", "0.0").toDouble();
qreal m33 = e.attribute("m33", "1.0").toDouble();
t->setMatrix(
m11, m12, m13,
m21, m22, m23,
m31, m32, m33);
return true;
}
}
/*
* Copyright (c) 2014 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_DOM_UTILS_H
#define __KIS_DOM_UTILS_H
#include <QPointF>
#include <QVector3D>
#include <QVector>
#include <QDomElement>
#include "klocale.h"
#include "krita_export.h"
namespace KisDomUtils {
void KRITAIMAGE_EXPORT saveValue(QDomElement *parent, const QString &tag, const QRect &rc);
void KRITAIMAGE_EXPORT saveValue(QDomElement *parent, const QString &tag, const QSize &size);
void KRITAIMAGE_EXPORT saveValue(QDomElement *parent, const QString &tag, const QPointF &pt);
void KRITAIMAGE_EXPORT saveValue(QDomElement *parent, const QString &tag, const QVector3D &pt);
void KRITAIMAGE_EXPORT saveValue(QDomElement *parent, const QString &tag, const QTransform &t);
template <typename T>
void saveValue(QDomElement *parent, const QString &tag, T value)
{
QDomDocument doc = parent->ownerDocument();
QDomElement e = doc.createElement(tag);
parent->appendChild(e);
e.setAttribute("type", "value");
e.setAttribute("value", value);
}
template <typename T>
void saveValue(QDomElement *parent, const QString &tag, const QVector<T> &array)
{
QDomDocument doc = parent->ownerDocument();
QDomElement e = doc.createElement(tag);
parent->appendChild(e);
e.setAttribute("type", "array");
int i = 0;
foreach (const T &v, array) {
saveValue(&e, QString("item_%1").arg(i++), v);
}
}
bool KRITAIMAGE_EXPORT findOnlyElement(const QDomElement &parent, const QString &tag, QDomElement *el, QStringList *errorMessages = 0);
bool KRITAIMAGE_EXPORT loadValue(const QDomElement &parent, const QString &tag, QSize *size);
bool KRITAIMAGE_EXPORT loadValue(const QDomElement &parent, const QString &tag, QRect *rc);
bool KRITAIMAGE_EXPORT loadValue(const QDomElement &parent, const QString &tag, QPointF *pt);
bool KRITAIMAGE_EXPORT loadValue(const QDomElement &parent, const QString &tag, QVector3D *pt);
bool KRITAIMAGE_EXPORT loadValue(const QDomElement &parent, const QString &tag, QTransform *t);
bool KRITAIMAGE_EXPORT checkType(const QDomElement &e, const QString &expectedType);
template <typename T>
bool loadValue(const QDomElement &parent, const QString &tag, T *value)
{
QDomElement e;
if (!findOnlyElement(parent, tag, &e)) return false;
if (!checkType(e, "value")) return false;
QVariant v(e.attribute("value", "no-value"));
*value = v.value<T>();
return true;
}
template <typename T>
bool loadValue(const QDomElement &parent, const QString &tag, QVector<T> *array)
{
QDomElement e;
if (!findOnlyElement(parent, tag, &e)) return false;
if (!checkType(e, "array")) return false;
QDomElement child = e.firstChildElement();
while (!child.isNull()) {
T value;
if (!loadValue(e, child.tagName(), &value)) return false;
*array << value;
child = child.nextSiblingElement();
}
return true;
}
}
#endif /* __KIS_DOM_UTILS_H */
......@@ -25,6 +25,7 @@
#include "generator/kis_generator_layer.h"
#include "kis_clone_layer.h"
#include "kis_filter_mask.h"
#include "kis_transform_mask.h"
#include "kis_transparency_mask.h"
#include "kis_selection_mask.h"
......@@ -56,6 +57,7 @@ public:
virtual bool visit(KisGeneratorLayer* layer) { return process(layer); }
virtual bool visit(KisCloneLayer* layer) { return process(layer); }
virtual bool visit(KisFilterMask* mask) { return process(mask); }
virtual bool visit(KisTransformMask* mask) { return process(mask); }
virtual bool visit(KisTransparencyMask* mask) { return process(mask); }
virtual bool visit(KisSelectionMask* mask) { return process(mask); }
......
......@@ -19,6 +19,8 @@
#include "kis_liquify_transform_worker.h"
#include "kis_grid_interpolation_tools.h"
#include "kis_dom_utils.h"
struct KisLiquifyTransformWorker::Private
{
......@@ -81,6 +83,16 @@ KisLiquifyTransformWorker::~KisLiquifyTransformWorker()
{
}
bool KisLiquifyTransformWorker::operator==(const KisLiquifyTransformWorker &other) const
{
return
m_d->srcBounds == other.m_d->srcBounds &&
m_d->originalPoints == other.m_d->originalPoints &&
m_d->transformedPoints == other.m_d->transformedPoints &&
m_d->pixelPrecision == other.m_d->pixelPrecision &&
m_d->gridSize == other.m_d->gridSize;
}
int KisLiquifyTransformWorker::pointToIndex(const QPoint &cellPt)
{
return GridIterationTools::pointToIndex(cellPt, m_d->gridSize);
......@@ -458,3 +470,70 @@ QImage KisLiquifyTransformWorker::runOnQImage(const QImage &srcImage,
return dstImage;
}
void KisLiquifyTransformWorker::toXML(QDomElement *e) const
{
QDomDocument doc = e->ownerDocument();
QDomElement liqEl = doc.createElement("liquify_points");
e->appendChild(liqEl);
KisDomUtils::saveValue(&liqEl, "srcBounds", m_d->srcBounds);
KisDomUtils::saveValue(&liqEl, "originalPoints", m_d->originalPoints);
KisDomUtils::saveValue(&liqEl, "transformedPoints", m_d->transformedPoints);
KisDomUtils::saveValue(&liqEl, "pixelPrecision", m_d->pixelPrecision);
KisDomUtils::saveValue(&liqEl, "gridSize", m_d->gridSize);
}
KisLiquifyTransformWorker* KisLiquifyTransformWorker::fromXML(const QDomElement &e)
{
QDomElement liquifyEl;
QRect srcBounds;
QVector<QPointF> originalPoints;
QVector<QPointF> transformedPoints;
int pixelPrecision;
QSize gridSize;
bool result = false;
result =
KisDomUtils::findOnlyElement(e, "liquify_points", &liquifyEl) &&
KisDomUtils::loadValue(liquifyEl, "srcBounds", &srcBounds) &&
KisDomUtils::loadValue(liquifyEl, "originalPoints", &originalPoints) &&
KisDomUtils::loadValue(liquifyEl, "transformedPoints", &transformedPoints) &&
KisDomUtils::loadValue(liquifyEl, "pixelPrecision", &pixelPrecision) &&
KisDomUtils::loadValue(liquifyEl, "gridSize", &gridSize);
if (!result) {
qWarning() << "WARNING: Failed to load liquify worker from XML";
return new KisLiquifyTransformWorker(QRect(0,0,1024, 1024), 0, 8);
}
KisLiquifyTransformWorker *worker =
new KisLiquifyTransformWorker(srcBounds, 0, pixelPrecision);
const int numPoints = originalPoints.size();
if (numPoints != transformedPoints.size() ||
numPoints != worker->m_d->originalPoints.size() ||
gridSize != worker->m_d->gridSize) {
qWarning() << "WARNING: Inconsistent number of points!";
qWarning() << ppVar(originalPoints.size());
qWarning() << ppVar(transformedPoints.size());
qWarning() << ppVar(gridSize);
qWarning() << ppVar(worker->m_d->originalPoints.size());
qWarning() << ppVar(worker->m_d->transformedPoints.size());
qWarning() << ppVar(worker->m_d->gridSize);
return worker;
}
for (int i = 0; i < numPoints; i++) {
worker->m_d->originalPoints[i] = originalPoints[i];
worker->m_d->transformedPoints[i] = transformedPoints[i];
}
return worker;
}
......@@ -20,6 +20,8 @@
#define __KIS_LIQUIFY_TRANSFORM_WORKER_H
#include <QScopedPointer>
#include <boost/operators.hpp>
#include <krita_export.h>
#include <kis_types.h>
......@@ -27,9 +29,10 @@ class QImage;
class QRect;
class QSize;
class QTransform;
class QDomElement;
class KRITAIMAGE_EXPORT KisLiquifyTransformWorker
class KRITAIMAGE_EXPORT KisLiquifyTransformWorker : boost::equality_comparable<KisLiquifyTransformWorker>
{
public:
KisLiquifyTransformWorker(const QRect &srcBounds,
......@@ -40,6 +43,8 @@ public:
~KisLiquifyTransformWorker();
bool operator==(const KisLiquifyTransformWorker &other) const;
int pointToIndex(const QPoint &cellPt);
QSize gridSize() const;
......@@ -74,6 +79,9 @@ public:
const QTransform &imageToThumbTransform,
QPointF *newOffset);
void toXML(QDomElement *e) const;
static KisLiquifyTransformWorker* fromXML(const QDomElement &e);
private:
struct Private;
const QScopedPointer<Private> m_d;
......
......@@ -54,6 +54,8 @@ public:
virtual bool visit(KisFilterMask *mask) = 0;
virtual bool visit(KisTransformMask *mask) = 0;
virtual bool visit(KisTransparencyMask *mask) = 0;
virtual bool visit(KisSelectionMask *mask) = 0;
......
......@@ -34,6 +34,7 @@ class KisAdjustmentLayer;
class KisExternalLayer;
class KisCloneLayer;
class KisFilterMask;
class KisTransformMask;
class KisTransparencyMask;
class KisSelectionMask;
class KisGeneratorLayer;
......@@ -56,6 +57,7 @@ public:
virtual void visit(KisGeneratorLayer *layer, KisUndoAdapter *undoAdapter) = 0;
virtual void visit(KisCloneLayer *layer, KisUndoAdapter *undoAdapter) = 0;
virtual void visit(KisFilterMask *mask, KisUndoAdapter *undoAdapter) = 0;
virtual void visit(KisTransformMask *mask, KisUndoAdapter *undoAdapter) = 0;
virtual void visit(KisTransparencyMask *mask, KisUndoAdapter *undoAdapter) = 0;
virtual void visit(KisSelectionMask *mask, KisUndoAdapter *undoAdapter) = 0;
......
......@@ -16,13 +16,30 @@
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#include "kis_transform_params.h"
#include "kis_transform_mask_params_factory_registry.h"
#include <kglobal.h>
KisTransformParams::KisTransformParams()
KisTransformMaskParamsFactoryRegistry::KisTransformMaskParamsFactoryRegistry()
{
}
void KisTransformMaskParamsFactoryRegistry::addFactory(const QString &id, const KisTransformMaskParamsFactory &factory)
{
m_map.insert(id, factory);
}
KisTransformMaskParamsInterfaceSP
KisTransformMaskParamsFactoryRegistry::createParams(const QString &id, const QDomElement &e)
{
KisTransformMaskParamsFactoryMap::iterator it = m_map.find(id);
return it != m_map.end() ? (*it)(e) : KisTransformMaskParamsInterfaceSP(0);
}
KisTransformParams::~KisTransformParams()
KisTransformMaskParamsFactoryRegistry*
KisTransformMaskParamsFactoryRegistry::instance()
{
K_GLOBAL_STATIC(KisTransformMaskParamsFactoryRegistry, s_instance);
return s_instance;
}
/*
* Copyright (c) 2014 Dmitry Kazakov <dimula73@gmail.com>
*
* This program is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
*/
#ifndef __KIS_TRANSFORM_MASK_PARAMS_FACTORY_REGISTRY_H
#define __KIS_TRANSFORM_MASK_PARAMS_FACTORY_REGISTRY_H
#include <QMap>
#include <boost/function.hpp>
#include <boost/bind.hpp>
#include "kis_types.h"
#include "krita_export.h"
class QDomElement;
typedef boost::function<KisTransformMaskParamsInterfaceSP (const QDomElement &)> KisTransformMaskParamsFactory;
typedef QMap<QString, KisTransformMaskParamsFactory> KisTransformMaskParamsFactoryMap;
class KRITAIMAGE_EXPORT KisTransformMaskParamsFactoryRegistry