Commit f412fb8c authored by Wolthera van Hövell's avatar Wolthera van Hövell 🛍
Browse files

Update Ora support significantly.

The big problem is that destination in and destination out seem to be limited to the source layer.
parent 04115f1c
......@@ -76,18 +76,20 @@ KoCompositeOpRegistry::KoCompositeOpRegistry()
m_map.insert(m_categories[3], KoID(COMPOSITE_EXCLUSION , i18n("Exclusion")));
m_map.insert(m_categories[3], KoID(COMPOSITE_ARC_TANGENT , i18n("Arcus Tangent")));
m_map.insert(m_categories[4], KoID(COMPOSITE_OVER , i18n("Normal")));
m_map.insert(m_categories[4], KoID(COMPOSITE_BEHIND , i18n("Behind")));
m_map.insert(m_categories[4], KoID(COMPOSITE_GREATER , i18n("Greater")));
m_map.insert(m_categories[4], KoID(COMPOSITE_OVERLAY , i18n("Overlay")));
m_map.insert(m_categories[4], KoID(COMPOSITE_ERASE , i18n("Erase")));
m_map.insert(m_categories[4], KoID(COMPOSITE_ALPHA_DARKEN , i18n("Alpha Darken")));
m_map.insert(m_categories[4], KoID(COMPOSITE_HARD_MIX , i18n("Hard Mix")));
m_map.insert(m_categories[4], KoID(COMPOSITE_GRAIN_MERGE , i18n("Grain Merge")));
m_map.insert(m_categories[4], KoID(COMPOSITE_GRAIN_EXTRACT , i18n("Grain Extract")));
m_map.insert(m_categories[4], KoID(COMPOSITE_PARALLEL , i18n("Parallel")));
m_map.insert(m_categories[4], KoID(COMPOSITE_ALLANON , i18n("Allanon")));
m_map.insert(m_categories[4], KoID(COMPOSITE_GEOMETRIC_MEAN, i18n("Geometric Mean")));
m_map.insert(m_categories[4], KoID(COMPOSITE_OVER , i18n("Normal")));
m_map.insert(m_categories[4], KoID(COMPOSITE_BEHIND , i18n("Behind")));
m_map.insert(m_categories[4], KoID(COMPOSITE_GREATER , i18n("Greater")));
m_map.insert(m_categories[4], KoID(COMPOSITE_OVERLAY , i18n("Overlay")));
m_map.insert(m_categories[4], KoID(COMPOSITE_ERASE , i18n("Erase")));
m_map.insert(m_categories[4], KoID(COMPOSITE_ALPHA_DARKEN , i18n("Alpha Darken")));
m_map.insert(m_categories[4], KoID(COMPOSITE_HARD_MIX , i18n("Hard Mix")));
m_map.insert(m_categories[4], KoID(COMPOSITE_GRAIN_MERGE , i18n("Grain Merge")));
m_map.insert(m_categories[4], KoID(COMPOSITE_GRAIN_EXTRACT , i18n("Grain Extract")));
m_map.insert(m_categories[4], KoID(COMPOSITE_PARALLEL , i18n("Parallel")));
m_map.insert(m_categories[4], KoID(COMPOSITE_ALLANON , i18n("Allanon")));
m_map.insert(m_categories[4], KoID(COMPOSITE_GEOMETRIC_MEAN , i18n("Geometric Mean")));
m_map.insert(m_categories[4], KoID(COMPOSITE_DESTINATION_ATOP, i18n("Destination Atop")));
m_map.insert(m_categories[4], KoID(COMPOSITE_DESTINATION_IN , i18n("Destination In")));
m_map.insert(m_categories[5], KoID(COMPOSITE_BUMPMAP , i18n("Bumpmap")));
m_map.insert(m_categories[5], KoID(COMPOSITE_COMBINE_NORMAL, i18n("Combine Normal Map")));
......
......@@ -38,6 +38,8 @@ const QString COMPOSITE_ERASE = "erase";
const QString COMPOSITE_IN = "in";
const QString COMPOSITE_OUT = "out";
const QString COMPOSITE_ALPHA_DARKEN = "alphadarken";
const QString COMPOSITE_DESTINATION_IN = "destination-in";
const QString COMPOSITE_DESTINATION_ATOP = "destination-atop";
const QString COMPOSITE_XOR = "xor";
const QString COMPOSITE_PLUS = "plus";
......
/*
* Copyright (c) 2016 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
* Copyright (c) 2012 José Luis Vergara <pentalis@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _KOCOMPOSITEOPDESTINATIONATOP_H_
#define _KOCOMPOSITEOPDESTINATIONATOP_H_
#include "KoCompositeOpBase.h"
/**
* Generic implementation of the Destination-atop composite op, based off the behind composite op.
*/
template<class CS_Traits>
class KoCompositeOpDestinationAtop : public KoCompositeOpBase<CS_Traits, KoCompositeOpDestinationAtop<CS_Traits> >
{
typedef KoCompositeOpBase<CS_Traits, KoCompositeOpDestinationAtop<CS_Traits> > base_class;
typedef typename CS_Traits::channels_type channels_type;
static const qint8 channels_nb = CS_Traits::channels_nb;
static const qint8 alpha_pos = CS_Traits::alpha_pos;
public:
KoCompositeOpDestinationAtop(const KoColorSpace * cs)
: base_class(cs, COMPOSITE_DESTINATION_ATOP, i18n("Destination Atop"), KoCompositeOp::categoryMix()) { }
public:
template<bool alphaLocked, bool allChannelFlags>
inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha,
channels_type* dst, channels_type dstAlpha,
channels_type maskAlpha, channels_type opacity,
const QBitArray& channelFlags ) {
using namespace Arithmetic;
channels_type appliedAlpha = mul(maskAlpha, srcAlpha, opacity);
channels_type newDstAlpha = appliedAlpha;
if (dstAlpha != zeroValue<channels_type>() && srcAlpha != zeroValue<channels_type>()) {
// blend the color channels as if we were painting on the layer below
for (qint8 channel = 0; channel < channels_nb; ++channel)
if(channel != alpha_pos && (allChannelFlags || channelFlags.testBit(channel))) {
/*each color blended in proportion to their calculated opacity*/
channels_type srcMult= mul(src[channel], appliedAlpha);
channels_type blendedValue = lerp(srcMult,dst[channel],dstAlpha);
dst[channel] = KoColorSpaceMaths<channels_type>::multiply(blendedValue,newDstAlpha);
}
}
else if (srcAlpha != zeroValue<channels_type>()) {
// don't blend if the color of the destination is undefined (has zero opacity)
// copy the source channel instead
for (qint8 channel = 0; channel < channels_nb; ++channel)
if(channel != alpha_pos && (allChannelFlags || channelFlags.testBit(channel)))
dst[channel] = src[channel];
}
return newDstAlpha;
}
};
#endif // _KOCOMPOSITEOPDESTINATIONATOP_H_
/*
* Copyright (c) 2016 Wolthera van Hövell tot Westerflier <griffinvalley@gmail.com>
* Copyright (c) 2012 José Luis Vergara <pentalis@gmail.com>
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library 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
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this library; see the file COPYING.LIB. If not, write to
* the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
* Boston, MA 02110-1301, USA.
*/
#ifndef _KOCOMPOSITEOPDESTINATIONIN_H_
#define _KOCOMPOSITEOPDESTINATIONIN_H_
#include "KoCompositeOpBase.h"
/**
* Generic implementation of the Destination-in composite op, based off the behind composite op.
*/
template<class CS_Traits>
class KoCompositeOpDestinationIn : public KoCompositeOpBase<CS_Traits, KoCompositeOpDestinationIn<CS_Traits> >
{
typedef KoCompositeOpBase<CS_Traits, KoCompositeOpDestinationIn<CS_Traits> > base_class;
typedef typename CS_Traits::channels_type channels_type;
static const qint8 channels_nb = CS_Traits::channels_nb;
static const qint8 alpha_pos = CS_Traits::alpha_pos;
public:
KoCompositeOpDestinationIn(const KoColorSpace * cs)
: base_class(cs, COMPOSITE_DESTINATION_IN, i18n("Destination In"), KoCompositeOp::categoryMix()) { }
public:
template<bool alphaLocked, bool allChannelFlags>
inline static channels_type composeColorChannels(const channels_type* src, channels_type srcAlpha,
channels_type* dst, channels_type dstAlpha,
channels_type maskAlpha, channels_type opacity,
const QBitArray& channelFlags ) {
using namespace Arithmetic;
Q_UNUSED(src);
channels_type appliedAlpha = mul(maskAlpha, srcAlpha, opacity);
channels_type newDstAlpha = mul(dstAlpha, appliedAlpha);
if (newDstAlpha != zeroValue<channels_type>()) {
// blend the color channels as if we were painting on the layer below
for (qint8 channel = 0; channel < channels_nb; ++channel)
if(channel != alpha_pos && (allChannelFlags || channelFlags.testBit(channel))) {
/*each color blended in proportion to their calculated opacity*/
dst[channel] = KoColorSpaceMaths<channels_type>::multiply(dst[channel],newDstAlpha);
}
}
return newDstAlpha;
}
};
#endif // _KOCOMPOSITEOPDESTINATIONIN_H_
......@@ -35,6 +35,8 @@
#include "compositeops/KoCompositeOpCopy2.h"
#include "compositeops/KoCompositeOpDissolve.h"
#include "compositeops/KoCompositeOpBehind.h"
#include "compositeops/KoCompositeOpDestinationIn.h"
#include "compositeops/KoCompositeOpDestinationAtop.h"
#include "compositeops/KoCompositeOpGreater.h"
#include "KoOptimizedCompositeOpFactory.h"
......@@ -109,6 +111,8 @@ struct AddGeneralOps<Traits, true>
cs->addCompositeOp(new KoCompositeOpCopy2<Traits>(cs));
cs->addCompositeOp(new KoCompositeOpErase<Traits>(cs));
cs->addCompositeOp(new KoCompositeOpBehind<Traits>(cs));
cs->addCompositeOp(new KoCompositeOpDestinationIn<Traits>(cs));
cs->addCompositeOp(new KoCompositeOpDestinationAtop<Traits>(cs));
cs->addCompositeOp(new KoCompositeOpGreater<Traits>(cs));
add<&cfOverlay<Arg> >(cs, COMPOSITE_OVERLAY , i18n("Overlay") , KoCompositeOp::categoryMix());
......
......@@ -135,9 +135,22 @@ void KisOpenRasterStackLoadVisitor::loadLayerInfo(const QDomElement& elem, KisLa
QString compop = elem.attribute("composite-op");
if (compop.startsWith("svg:")) {
if (compop == "svg:clear") layer->setCompositeOpId(COMPOSITE_CLEAR);
//we don't have a 'composite op clear' despite the registery reserving a string for it, doesn't matter, ora doesn't use it.
//if (compop == "svg:clear") layer->setCompositeOpId(COMPOSITE_CLEAR);
if (compop == "svg:src-over") layer->setCompositeOpId(COMPOSITE_OVER);
if (compop == "svg:add") layer->setCompositeOpId(COMPOSITE_ADD);
//not part of the spec.
//if (compop == "svg:dst-over") layer->setCompositeOpId(COMPOSITE_BEHIND);
//dst-in "The source that overlaps the destination, replaces the destination."
if (compop == "svg:dst-in") layer->setCompositeOpId(COMPOSITE_DESTINATION_IN);
//dst-out "dst is placed, where it falls outside of the source."
if (compop == "svg:dst-out") layer->setCompositeOpId(COMPOSITE_ERASE);
//src-atop "Destination which overlaps the source replaces the source. Source is placed elsewhere."
//this is basically our alpha-inherit.
if (compop == "svg:src-atop") layer->disableAlphaChannel(true);
//dst-atop
if (compop == "svg:dst-atop") layer->setCompositeOpId(COMPOSITE_DESTINATION_ATOP);
//plus is svg standard's way of saying addtion... photoshop calls this linear dodge, btw, maybe make a similar alias?
if (compop == "svg:plus") layer->setCompositeOpId(COMPOSITE_ADD);
if (compop == "svg:multiply") layer->setCompositeOpId(COMPOSITE_MULT);
if (compop == "svg:screen") layer->setCompositeOpId(COMPOSITE_SCREEN);
if (compop == "svg:overlay") layer->setCompositeOpId(COMPOSITE_OVERLAY);
......@@ -152,7 +165,8 @@ void KisOpenRasterStackLoadVisitor::loadLayerInfo(const QDomElement& elem, KisLa
if (compop == "svg:luminosity") layer->setCompositeOpId(COMPOSITE_LUMINIZE);
if (compop == "svg:hue") layer->setCompositeOpId(COMPOSITE_HUE);
if (compop == "svg:saturation") layer->setCompositeOpId(COMPOSITE_SATURATION);
if (compop == "svg:exclusion") layer->setCompositeOpId(COMPOSITE_EXCLUSION);
//Exclusion isn't in the official list.
//if (compop == "svg:exclusion") layer->setCompositeOpId(COMPOSITE_EXCLUSION);
}
else if (compop.startsWith("krita:")) {
compop = compop.remove(0, 6);
......@@ -162,6 +176,7 @@ void KisOpenRasterStackLoadVisitor::loadLayerInfo(const QDomElement& elem, KisLa
// to fix old bugs in krita's ora export
if (compop == "color-dodge") layer->setCompositeOpId(COMPOSITE_DODGE);
if (compop == "difference") layer->setCompositeOpId(COMPOSITE_DIFF);
if (compop == "svg:add") layer->setCompositeOpId(COMPOSITE_ADD);
}
}
......@@ -191,6 +206,11 @@ void KisOpenRasterStackLoadVisitor::loadGroupLayer(const QDomElement& elem, KisG
opacity = KisDomUtils::toDouble(subelem.attribute("opacity", "1.0"));
}
KisGroupLayerSP layer = new KisGroupLayer(d->image, "", opacity * 255);
bool passThrough = true;
if (subelem.attribute("isolation")=="isolate") {
passThrough = false;
}
layer->setPassThroughMode(passThrough);
d->image->addNode(layer.data(), gL.data(), 0);
loadGroupLayer(subelem, layer);
} else if (node.nodeName() == "layer") {
......
......@@ -69,7 +69,9 @@ void KisOpenRasterStackSaveVisitor::saveLayerInfo(QDomElement& elt, KisLayer* la
QString compop = layer->compositeOpId();
if (layer->compositeOpId() == COMPOSITE_CLEAR) compop = "svg:clear";
else if (layer->compositeOpId() == COMPOSITE_OVER) compop = "svg:src-over";
else if (layer->compositeOpId() == COMPOSITE_ADD) compop = "svg:add";
else if (layer->compositeOpId() == COMPOSITE_ERASE) compop = "svg:dst-out";
else if (layer->alphaChannelDisabled()) compop = "svg:dst-atop";
else if (layer->compositeOpId() == COMPOSITE_ADD) compop = "svg:plus";
else if (layer->compositeOpId() == COMPOSITE_MULT) compop = "svg:multiply";
else if (layer->compositeOpId() == COMPOSITE_SCREEN) compop = "svg:screen";
else if (layer->compositeOpId() == COMPOSITE_OVERLAY) compop = "svg:overlay";
......@@ -84,7 +86,7 @@ void KisOpenRasterStackSaveVisitor::saveLayerInfo(QDomElement& elt, KisLayer* la
else if (layer->compositeOpId() == COMPOSITE_LUMINIZE) compop = "svg:luminosity";
else if (layer->compositeOpId() == COMPOSITE_HUE) compop = "svg:hue";
else if (layer->compositeOpId() == COMPOSITE_SATURATION) compop = "svg:saturation";
else if (layer->compositeOpId() == COMPOSITE_EXCLUSION) compop = "svg:exclusion";
//else if (layer->compositeOpId() == COMPOSITE_EXCLUSION) compop = "svg:exclusion";
else compop = "krita:" + layer->compositeOpId();
elt.setAttribute("composite-op", compop);
}
......@@ -106,7 +108,11 @@ bool KisOpenRasterStackSaveVisitor::visit(KisGroupLayer *layer)
QDomElement elt = d->layerStack.createElement("stack");
d->currentElement = &elt;
saveLayerInfo(elt, layer);
QString isolate = "isolate";
if (layer->passThroughMode()) {
isolate = "auto";
}
elt.setAttribute("isolation", isolate);
visitAll(layer);
if (previousElt) {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment