12#include <ImfAttribute.h>
13#include <ImfChannelList.h>
14#include <ImfFrameBuffer.h>
16#include <ImfInputFile.h>
17#include <ImfOutputFile.h>
19#include <ImfStringAttribute.h>
22#include <QApplication>
24#include <QDomDocument>
56#define HDR_LAYER "HDR Layer"
141 template <
class WrapperType>
144 template<
typename _T_>
147 template<
typename _T_>
163 d->showNotifications = showNotifications;
166 Imf::setGlobalThreadCount(QThread::idealThreadCount());
167 dbgFile <<
"EXR Threadcount was set to: " << QThread::idealThreadCount();
178 case Imf::NUM_PIXELTYPES:
185 qFatal(
"Out of bound enum");
193 QString colorDepthID =
"UNKNOWN";
212 const QString profileName =
215 defaultProfileForColorSpace;
224 return static_cast<T
>(HALF_EPSILON);
230 return static_cast<T
>(0.01);
235 return std::abs(
p1 -
p2) < float(HALF_EPSILON);
240 return std::abs(h) < float(HALF_EPSILON);
256 return !(std::abs(
pixel.
a) <= alphaEpsilon<T>() &&
265 return alpha >= alphaNoiseThreshold<T>() ||
272 const T absoluteAlpha = std::abs(newAlpha);
274 pixel.
r = mult.
r / absoluteAlpha;
275 pixel.
g = mult.
g / absoluteAlpha;
276 pixel.
b = mult.
b / absoluteAlpha;
296 return !(std::abs(
pixel.
alpha) <= alphaEpsilon<T>() &&
303 return alpha >= alphaNoiseThreshold<T>() ||
308 const T absoluteAlpha = std::abs(newAlpha);
317template <
class WrapperType>
320 typedef typename WrapperType::pixel_type pixel_type;
321 typedef typename WrapperType::channel_type channel_type;
323 WrapperType srcPixel(*pixel);
325 if (!srcPixel.checkMultipliedColorsConsistent()) {
327 channel_type newAlpha = srcPixel.alpha();
329 pixel_type __dstPixelData;
330 WrapperType dstPixel(__dstPixelData);
337 dstPixel.setUnmultiplied(srcPixel.pixel, newAlpha);
339 if (dstPixel.checkUnmultipliedColorsConsistent(srcPixel.pixel)) {
343 newAlpha += alphaEpsilon<channel_type>();
347 *pixel = dstPixel.pixel;
350 }
else if (srcPixel.alpha() > 0.0) {
351 srcPixel.setUnmultiplied(srcPixel.pixel, srcPixel.alpha());
355template <
typename T,
typename Pixel,
int size,
int alphaPos>
359 T alpha = pixel->data[alphaPos];
361 if (alpha > alphaEpsilon<T>()) {
362 for (
int i = 0; i < size; ++i) {
364 pixel->data[i] *= alpha;
368 pixel->data[alphaPos] = alpha;
370 for (
int i = 0; i < size; ++i) {
377template<
typename _T_>
384 bool hasAlpha = info.
channelMap.contains(
"A");
386 Imf::FrameBuffer frameBuffer;
387 Rgba* frameBufferData = (pixels.data()) - xstart - ystart * width;
388 frameBuffer.insert(info.
channelMap[
"R"].toLatin1().constData(),
389 Imf::Slice(ptype, (
char *) &frameBufferData->
r,
391 sizeof(
Rgba) * width));
392 frameBuffer.insert(info.
channelMap[
"G"].toLatin1().constData(),
393 Imf::Slice(ptype, (
char *) &frameBufferData->
g,
395 sizeof(
Rgba) * width));
396 frameBuffer.insert(info.
channelMap[
"B"].toLatin1().constData(),
397 Imf::Slice(ptype, (
char *) &frameBufferData->
b,
399 sizeof(
Rgba) * width));
401 frameBuffer.insert(info.
channelMap[
"A"].toLatin1().constData(),
402 Imf::Slice(ptype, (
char *) &frameBufferData->
a,
404 sizeof(
Rgba) * width));
407 file.setFrameBuffer(frameBuffer);
408 file.readPixels(ystart, height + ystart - 1);
411 QRect paintRegion(xstart, ystart, width, height);
415 unmultiplyAlpha<RgbPixelWrapper<_T_> >(
rgba);
433template<
typename _T_>
447 bool hasAlpha = info.
channelMap.contains(
"A");
448 dbgFile <<
"Has Alpha:" << hasAlpha;
451 Imf::FrameBuffer frameBuffer;
452 pixel_type* frameBufferData = (pixels.data()) - xstart - ystart * width;
455 Imf::Slice(ptype, (
char *)&frameBufferData->gray,
sizeof(pixel_type) * 1,
sizeof(pixel_type) * width));
458 frameBuffer.insert(info.
channelMap[
"A"].toLatin1().constData(),
459 Imf::Slice(ptype, (
char *) &frameBufferData->alpha,
460 sizeof(pixel_type) * 1,
461 sizeof(pixel_type) * width));
464 file.setFrameBuffer(frameBuffer);
465 file.readPixels(ystart, height + ystart - 1);
467 pixel_type *srcPtr = pixels.data();
469 QRect paintRegion(xstart, ystart, width, height);
473 unmultiplyAlpha<GrayPixelWrapper<_T_> >(srcPtr);
476 pixel_type* dstPtr =
reinterpret_cast<pixel_type*
>(it.
rawData());
478 dstPtr->gray = srcPtr->gray;
479 dstPtr->alpha = hasAlpha ? srcPtr->alpha : channel_type(1.0);
487 if (idx1 > idx2)
return true;
488 if (group.
name == list[idx2]) {
500 for (
int i = 0; i < groups->size(); ++i) {
502 return &(*groups)[i];
507 info.
name = list.at(idx2);
509 groups->append(info);
510 return &groups->last();
515 const Imf::StringAttribute *layersInfoAttribute =
518 if (!layersInfoAttribute)
return QDomDocument();
520 QString layersInfoString = QString::fromUtf8(layersInfoAttribute->value().c_str());
523 doc.setContent(layersInfoString);
530 std::set<std::string> extraInfoLayers;
532 QDomElement root = doc.documentElement();
536 QDomElement el = root.firstChildElement();
538 while(!el.isNull()) {
540 QString layerName = el.attribute(
EXR_NAME).toUtf8();
542 extraInfoLayers.insert(el.attribute(
EXR_NAME).toUtf8().constData());
544 el = el.nextSiblingElement();
547 bool result = (extraInfoLayers == exrLayerNames);
550 dbgKrita <<
"WARNING: Krita EXR extra layers info is inconsistent!";
553 std::set<std::string>::const_iterator it1 = extraInfoLayers.begin();
554 std::set<std::string>::const_iterator it2 = exrLayerNames.begin();
556 std::set<std::string>::const_iterator end1 = extraInfoLayers.end();
558 for (; it1 != end1; ++it1, ++it2) {
559 dbgKrita << it1->c_str() << it2->c_str();
570 Imf::InputFile file(filename.toUtf8());
572 Imath::Box2i dw = file.header().dataWindow();
573 Imath::Box2i displayWindow = file.header().displayWindow();
575 int width = dw.max.x - dw.min.x + 1;
576 int height = dw.max.y - dw.min.y + 1;
581 for (Imf::Header::ConstIterator it = file.header().begin();
582 it != file.header().end(); ++it) {
583 dbgFile <<
"Attribute: " << it.name() <<
" type: " << it.attribute().typeName();
587 QDomDocument extraLayersInfo =
d->loadExtraLayersInfo(file.header());
596 const Imf::ChannelList &channels = file.header().channels();
597 std::set<std::string> layerNames;
598 channels.layers(layerNames);
600 if (!extraLayersInfo.isNull() &&
601 !
d->checkExtraLayersInfoConsistent(extraLayersInfo, layerNames)) {
604 extraLayersInfo = QDomDocument();
609 dbgFile <<
"Checking for ARGB channels, they can occur in single-layer _or_ multi-layer images:";
611 bool topLevelRGBFound =
false;
644 for (Imf::ChannelList::ConstIterator i = channels.begin(); i != channels.end(); ++i) {
645 const Imf::Channel &channel = i.channel();
646 dbgFile <<
"Channel name = " << i.name() <<
" type = " << channel.type;
648 QString qname = i.name();
649 if (topLevelChannelNames.contains(qname)) {
650 topLevelRGBFound =
true;
651 dbgFile <<
"Found top-level channel" << qname;
658 else if (!qname.contains(
'.')
659 || !qname.mid(1).contains(
'.')
660 || !qname.left(qname.size() - 1).contains(
'.')) {
661 warnFile <<
"Found a top-level channel that is not part of the rendered image" << qname <<
". Krita will not load this channel.";
664 if (topLevelRGBFound) {
665 dbgFile <<
"Toplevel layer" << info.
name <<
":Image type:" << imageType <<
"Layer type" << info.
imageType;
666 informationObjects.push_back(info);
670 dbgFile <<
"Extra layers:" << layerNames.size();
672 for (std::set<std::string>::const_iterator i = layerNames.begin();i != layerNames.end(); ++i) {
676 dbgFile <<
"layer name = " << i->c_str();
677 info.
name = i->c_str();
678 Imf::ChannelList::ConstIterator layerBegin, layerEnd;
679 channels.channelsInLayer(*i, layerBegin, layerEnd);
680 for (Imf::ChannelList::ConstIterator j = layerBegin;
681 j != layerEnd; ++j) {
682 const Imf::Channel &channel = j.channel();
686 QString qname = j.name();
688 QString layersuffix = list.last();
690 dbgFile <<
"\tchannel " << j.name() <<
"suffix" << layersuffix <<
" type = " << channel.type;
694 if (topLevelChannelNames.contains(
"." + layersuffix)) {
695 layersuffix = layersuffix.at(0).toUpper();
697 dbgFile <<
"\t\tsuffix" << layersuffix;
700 if (list.size() > 1) {
701 info.
name = list[list.size()-2];
709 informationObjects.push_back(info);
716 dbgFile <<
"File has" << informationObjects.size() <<
"layer(s)";
719 for (
int i = 0; i < informationObjects.size(); ++i) {
728 QString channel = info.
channelMap.begin().value();
736 QMap<QString,QString>::const_iterator it = info.
channelMap.constBegin();
737 QMap<QString,QString>::const_iterator end = info.
channelMap.constEnd();
739 QString failingChannelKey;
741 for (; it != end; ++it) {
743 if (it.key() !=
"A") {
744 failingChannelKey = it.key();
751 QString failingChannelValue = info.
channelMap[failingChannelKey];
762 QMap<QString, QString> newChannelMap;
780 QMap<QString, QString> newChannelMap;
781 QMap<QString, QString>::iterator it = info.
channelMap.begin();
782 newChannelMap[
"R"] = it.value();
785 newChannelMap[
"G"] = it.value();
788 newChannelMap[
"B"] = it.value();
792 newChannelMap[
"A"] = it.value();
800 dbgFile << info.
name <<
"has" << info.
channelMap.size() <<
"channels, and we don't know what to do.";
802 if (!modelId.isEmpty()) {
808 dbgFile <<
"Image type = " << imageType;
815 for (
int i = 0; i < groups.size(); ++i) {
823 int displayWidth = displayWindow.max.x - displayWindow.min.x + 1;
824 int displayHeight = displayWindow.max.y - displayWindow.min.y + 1;
825 d->image =
new KisImage(
d->doc->createUndoStore(), displayWidth, displayHeight, colorSpace,
"");
842 for (
int i = 0; i < groups.size(); ++i) {
847 d->image->addNode(info.
groupLayer, groupLayerParent);
851 for (
int i = informationObjects.size() - 1; i >= 0; --i) {
869 d->decodeData1<half>(file, info, layer, width, dx, dy, height, Imf::HALF);
872 d->decodeData1<
float>(file, info, layer, width, dx, dy, height, Imf::FLOAT);
876 qFatal(
"Impossible error");
884 d->decodeData4<half>(file, info, layer, width, dx, dy, height, Imf::HALF);
887 d->decodeData4<
float>(file, info, layer, width, dx, dy, height, Imf::FLOAT);
891 qFatal(
"Impossible error");
895 qFatal(
"Invalid number of channels: %i", info.
channelMap.size());
901 QMap<QString, KisMetaData::Value> map;
910 d->image->addNode(layer, groupLayerParent);
912 dbgFile <<
"No decoding " << info.
name <<
" with " << info.
channelMap.size() <<
" channels, and lack of a color space";
917 if (
d->alphaWasModified) {
920 "The image contains pixels with zero alpha channel and non-zero "
921 "color channels. Krita has modified those pixels to have "
922 "at least some alpha. The initial values will <i>not</i> "
923 "be reverted on saving the image back."
925 "This will hardly make any visual difference just keep it in mind.");
926 if (
d->showNotifications) {
927 QMessageBox::information(qApp->activeWindow(), i18nc(
"@title:window",
"EXR image has been modified"), msg);
933 if (!extraLayersInfo.isNull()) {
939 }
catch (std::exception &e) {
940 dbgFile <<
"Error while reading from the exr file: " << e.what();
968 return d->errorMessage;
971template<
typename _T_,
int size>
985template<
typename _T_,
int size,
int alphaPos>
991 void prepareFrameBuffer(Imf::FrameBuffer*,
int line)
override;
1001template<
typename _T_,
int size,
int alphaPos>
1006 ExrPixel* frameBufferData = (pixels.data()) - xstart - (ystart + line) * m_width;
1007 for (
int k = 0; k < size; ++k) {
1008 frameBuffer->insert(info->channels[k].toUtf8(),
1009 Imf::Slice(info->pixelType, (
char *) &frameBufferData->
data[k],
1015template<
typename _T_,
int size,
int alphaPos>
1021 const _T_* dst =
reinterpret_cast < const _T_*
>(it->
oldRawData());
1023 for (
int i = 0; i < size; ++i) {
1024 rgba->data[i] = dst[i];
1027 if (alphaPos != -1) {
1028 multiplyAlpha<_T_, ExrPixel, size, alphaPos>(
rgba);
1042 return new EncoderImpl < half, 1, -1 > (&file, &info, width);
1045 return new EncoderImpl < float, 1, -1 > (&file, &info, width);
1070 qFatal(
"Impossible error");
1079 encoders.push_back(
encoder(file, info, width));
1082 for (
int y = 0; y < height; ++y) {
1083 Imf::FrameBuffer frameBuffer;
1087 file.setFrameBuffer(frameBuffer);
1091 file.writePixels(1);
1093 qDeleteAll(encoders);
1108 targetBestEffortProfile = cs->
profile();
1115 targetBestEffortProfile);
1142 Imf::Header header(width, height);
1147 Imf::PixelType pixelType = Imf::NUM_PIXELTYPES;
1149 pixelType = Imf::HALF;
1152 pixelType = Imf::FLOAT;
1158 header.channels().insert(
"R", Imf::Channel(pixelType));
1159 header.channels().insert(
"G", Imf::Channel(pixelType));
1160 header.channels().insert(
"B", Imf::Channel(pixelType));
1161 header.channels().insert(
"A", Imf::Channel(pixelType));
1168 header.channels().insert(
"Y", Imf::Channel(pixelType));
1169 header.channels().insert(
"A", Imf::Channel(pixelType));
1174 header.channels().insert(
"X", Imf::Channel(pixelType));
1175 header.channels().insert(
"Y", Imf::Channel(pixelType));
1176 header.channels().insert(
"Z", Imf::Channel(pixelType));
1177 header.channels().insert(
"A", Imf::Channel(pixelType));
1187 Imf::OutputFile file(filename.toUtf8(), header);
1190 informationObjects.push_back(info);
1191 encodeData(file, informationObjects, width, height);
1194 }
catch(std::exception &e) {
1195 dbgFile <<
"Exception while writing to exr file: " << e.what();
1204QString
remap(
const QMap<QString, QString>& current2original,
const QString& current)
1206 if (current2original.contains(current)) {
1207 return current2original[current];
1214 typedef QMultiMap<QString, QList<ExrPaintLayerSaveInfo>::iterator> NamesMap;
1221 for (; it != end; ++it) {
1222 namesMap.insert(it->name, it);
1226 Q_FOREACH (
const QString &key, namesMap.keys()) {
1227 if (namesMap.count(key) > 1) {
1229 QString strippedName = key.left(key.size() - 1);
1230 int nameCounter = 0;
1232 NamesMap::iterator it = namesMap.find(key);
1233 NamesMap::iterator end = namesMap.end();
1235 for (; it != end; ++it) {
1239 .arg(nameCounter++);
1241 it.value()->name = newName;
1246 for (; channelsIt != channelsEnd; ++channelsIt) {
1247 channelsIt->replace(key, newName);
1257 QSet<KisNodeSP> layersNotSaved;
1259 for (
uint i = 0; i < parent->childCount(); ++i) {
1263 QMap<QString, QString> current2original;
1271 QMap<QString, KisMetaData::Value> map =
value.asStructure();
1272 if (map.contains(
"original") && map.contains(
"current")) {
1273 current2original[map[
"current"].toString()] = map[
"original"].toString();
1280 info.
name = name + paintLayer->name() +
'.';
1281 info.
layer = paintLayer;
1319 if (info.
pixelType < Imf::NUM_PIXELTYPES) {
1321 informationObjects.push_back(info);
1325 layersNotSaved << node;
1330 recBuildPaintLayerSaveInfo(informationObjects, name + groupLayer->name() +
'.', groupLayer);
1337 layersNotSaved.insert(node);
1341 if (!layersNotSaved.isEmpty()) {
1342 reportLayersNotSaved(layersNotSaved);
1349 QTextStream textStream(&layersList);
1352 Q_FOREACH (
KisNodeSP node, layersNotSaved) {
1353 textStream <<
"<li>" << i18nc(
"@item:unsupported-node-message",
"%1 (type: \"%2\")", node->
name(), node->metaObject()->className()) <<
"</li>";
1358 "<p>The following layers have a type that is not supported by EXR format:</p>"
1359 "<r><ul>%1</ul></p>"
1360 "<p><warning>these layers have <b>not</b> been saved to the final EXR file</warning></p>", layersList);
1369 if (informationObjects.size() == 1 && informationObjects[0].name == QString(
HDR_LAYER) +
".") {
1373 QDomDocument doc(
"krita-extra-layers-info");
1374 doc.appendChild(doc.createElement(
"root"));
1375 QDomElement rootElement = doc.documentElement();
1377 for (
int i = 0; i < informationObjects.size(); i++) {
1388 QString strippedName = info.
name.left(info.
name.size() - 1);
1390 el.setAttribute(
EXR_NAME, strippedName);
1392 rootElement.appendChild(el);
1395 return doc.toString();
1407 Imf::Header header(width, height);
1416 d->recBuildPaintLayerSaveInfo(informationObjects,
"", layer);
1418 if(informationObjects.isEmpty()) {
1421 d->makeLayerNamesUnique(informationObjects);
1423 QByteArray extraLayersInfo =
d->fetchExtraLayersInfo(informationObjects).toUtf8();
1424 if (!extraLayersInfo.isNull()) {
1425 header.insert(
EXR_KRITA_LAYERS, Imf::StringAttribute(extraLayersInfo.constData()));
1427 dbgFile << informationObjects.size() <<
" layers to save";
1429 if (info.
pixelType < Imf::NUM_PIXELTYPES) {
1430 Q_FOREACH (
const QString& channel, info.
channels) {
1432 header.channels().insert(channel.toUtf8().data(), Imf::Channel(info.
pixelType));
1439 Imf::OutputFile file(filename.toUtf8(), header);
1440 encodeData(file, informationObjects, width, height);
1442 }
catch(std::exception &e) {
1443 dbgFile <<
"Exception while writing to exr file: " << e.what();
1455 warnKrita <<
"WARNING: Cancelling of an EXR loading is not supported!";
float value(const T *src, size_t ch)
QList< QString > QStringList
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID XYZAColorModelID("XYZA", ki18n("XYZ/Alpha"))
const KoID Float16BitsColorDepthID("F16", ki18n("16-bit float/channel"))
const KoID RGBAColorModelID("RGBA", ki18n("RGB/Alpha"))
const quint8 OPACITY_OPAQUE_U8
const QString COMPOSITE_OVER
KisImportExportErrorCode buildFile(const QString &filename, KisPaintLayerSP layer)
QString errorMessage() const
KisImportExportErrorCode buildImage(const QString &filename)
const QScopedPointer< Private > d
KisImportExportErrorCode decode(const QString &filename)
EXRConverter(KisDocument *doc, bool showNotifications)
void encodeData(int line) override
void prepareFrameBuffer(Imf::FrameBuffer *, int line) override
ExrPixel_< _T_, size > ExrPixel
QVector< ExrPixel > pixels
const ExrPaintLayerSaveInfo * info
EncoderImpl(Imf::OutputFile *_file, const ExrPaintLayerSaveInfo *_info, int width)
virtual void encodeData(int line)=0
virtual void prepareFrameBuffer(Imf::FrameBuffer *, int line)=0
virtual const quint8 * oldRawData() const =0
virtual bool nextPixel()=0
T readEntry(const QString &name, const T &defaultValue=T())
KisPaintDeviceSP projection() const
static bool doesFileExist(QString filepath)
static bool isFileWritable(QString filepath)
static bool isFileReadable(QString filepath)
const KisMetaData::Value & value() const
const KoColorSpace * colorSpace() const
void convertTo(const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent=KoColorConversionTransformation::internalRenderingIntent(), KoColorConversionTransformation::ConversionFlags conversionFlags=KoColorConversionTransformation::internalConversionFlags(), KUndo2Command *parentCommand=nullptr, KoUpdater *progressUpdater=nullptr)
QDomElement savePaintLayerAttributes(KisPaintLayer *layer, QDomDocument &doc, bool saveLayerOffset)
ALWAYS_INLINE quint8 * rawData()
virtual KoID colorModelId() const =0
virtual quint32 channelCount() const =0
virtual KoID colorDepthId() const =0
virtual const KoColorProfile * profile() const =0
static bool qFuzzyCompare(half p1, half p2)
static T alphaNoiseThreshold()
static bool qFuzzyIsNull(half h)
bool recCheckGroup(const ExrGroupLayerInfo &group, QStringList list, int idx1, int idx2)
QString remap(const QMap< QString, QString > ¤t2original, const QString ¤t)
const KoColorSpace * kisTypeToColorSpace(QString colorModelID, ImageType imageType)
void multiplyAlpha(Pixel *pixel)
ExrGroupLayerInfo * searchGroup(QList< ExrGroupLayerInfo > *groups, QStringList list, int idx1, int idx2)
Encoder * encoder(Imf::OutputFile &file, const ExrPaintLayerSaveInfo &info, int width)
KisPaintDeviceSP wrapLayerDevice(KisPaintDeviceSP device)
ImageType imfTypeToKisType(Imf::PixelType type)
void encodeData(Imf::OutputFile &file, const QList< ExrPaintLayerSaveInfo > &informationObjects, int width, int height)
#define KIS_ASSERT_RECOVER_RETURN_VALUE(cond, val)
#define KIS_ASSERT_RECOVER(cond)
#define KIS_ASSERT_RECOVER_RETURN(cond)
#define KIS_ASSERT_RECOVER_NOOP(cond)
@ FormatColorSpaceUnsupported
void setUtf8OnStream(QTextStream &stream)
void recBuildPaintLayerSaveInfo(QList< ExrPaintLayerSaveInfo > &informationObjects, const QString &name, KisGroupLayerSP parent)
QDomDocument loadExtraLayersInfo(const Imf::Header &header)
void makeLayerNamesUnique(QList< ExrPaintLayerSaveInfo > &informationObjects)
void unmultiplyAlpha(typename WrapperType::pixel_type *pixel)
QString fetchExtraLayersInfo(QList< ExrPaintLayerSaveInfo > &informationObjects)
void reportLayersNotSaved(const QSet< KisNodeSP > &layersNotSaved)
void decodeData4(Imf::InputFile &file, ExrPaintLayerInfo &info, KisPaintLayerSP layer, int width, int xstart, int ystart, int height, Imf::PixelType ptype)
bool checkExtraLayersInfoConsistent(const QDomDocument &doc, std::set< std::string > exrLayerNames)
void decodeData1(Imf::InputFile &file, ExrPaintLayerInfo &info, KisPaintLayerSP layer, int width, int xstart, int ystart, int height, Imf::PixelType ptype)
KisGroupLayerSP groupLayer
const KoColorSpace * colorSpace
const ExrGroupLayerInfo * parent
Remap(const QString &_original, const QString &_current)
QMap< QString, QString > channelMap
first is either R, G, B or A second is the EXR channel name
void updateImageType(ImageType channelType)
QList< Remap > remappedChannels
this is used to store in the metadata the mapping between exr channel name, and channels used in Krit...
QList< QString > channels
QString name
name of the layer with a "." at the end (ie "group1.group2.layer1.")
KisPaintDeviceSP layerDevice
void setUnmultiplied(const pixel_type &mult, T newAlpha)
bool checkUnmultipliedColorsConsistent(const pixel_type &mult) const
GrayPixelWrapper(pixel_type &_pixel)
KoGrayTraits< T >::Pixel pixel_type
bool checkMultipliedColorsConsistent() const
void setCompositeOpId(const QString &compositeOpId)
KisMetaData::Store * metaData()
KisPaintDeviceSP paintDevice
QString colorSpaceId(const QString &colorModelId, const QString &colorDepthId) const
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
static KoColorSpaceRegistry * instance()
QString defaultProfileForColorSpace(const QString &colorSpaceId) const
bool checkMultipliedColorsConsistent() const
void setUnmultiplied(const Rgba< T > &mult, T newAlpha)
RgbPixelWrapper(Rgba< T > &_pixel)
bool checkUnmultipliedColorsConsistent(const Rgba< T > &mult) const