summaryrefslogtreecommitdiffstats
path: root/chalk/chalkcolor
diff options
context:
space:
mode:
Diffstat (limited to 'chalk/chalkcolor')
-rw-r--r--chalk/chalkcolor/Makefile.am45
-rw-r--r--chalk/chalkcolor/README4
-rw-r--r--chalk/chalkcolor/TODO11
-rw-r--r--chalk/chalkcolor/chalk_colorspace.desktop38
-rw-r--r--chalk/chalkcolor/colorspaces/Makefile.am20
-rw-r--r--chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc296
-rw-r--r--chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h93
-rw-r--r--chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc571
-rw-r--r--chalk/chalkcolor/colorspaces/kis_lab_colorspace.h153
-rw-r--r--chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc624
-rw-r--r--chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h112
-rw-r--r--chalk/chalkcolor/kis_abstract_colorspace.cc762
-rw-r--r--chalk/chalkcolor/kis_abstract_colorspace.h312
-rw-r--r--chalk/chalkcolor/kis_basic_histogram_producers.cc484
-rw-r--r--chalk/chalkcolor/kis_basic_histogram_producers.h197
-rw-r--r--chalk/chalkcolor/kis_channelinfo.h115
-rw-r--r--chalk/chalkcolor/kis_color.cc185
-rw-r--r--chalk/chalkcolor/kis_color.h90
-rw-r--r--chalk/chalkcolor/kis_color_conversions.cc427
-rw-r--r--chalk/chalkcolor/kis_color_conversions.h49
-rw-r--r--chalk/chalkcolor/kis_colorspace.cc39
-rw-r--r--chalk/chalkcolor/kis_colorspace.h450
-rw-r--r--chalk/chalkcolor/kis_colorspace_factory_registry.cc222
-rw-r--r--chalk/chalkcolor/kis_colorspace_factory_registry.h121
-rw-r--r--chalk/chalkcolor/kis_colorspace_iface.cc39
-rw-r--r--chalk/chalkcolor/kis_colorspace_iface.h43
-rw-r--r--chalk/chalkcolor/kis_composite_op.cc138
-rw-r--r--chalk/chalkcolor/kis_composite_op.h103
-rw-r--r--chalk/chalkcolor/kis_f16half_base_colorspace.cc125
-rw-r--r--chalk/chalkcolor/kis_f16half_base_colorspace.h107
-rw-r--r--chalk/chalkcolor/kis_f32_base_colorspace.cc125
-rw-r--r--chalk/chalkcolor/kis_f32_base_colorspace.h83
-rw-r--r--chalk/chalkcolor/kis_histogram_producer.cc67
-rw-r--r--chalk/chalkcolor/kis_histogram_producer.h129
-rw-r--r--chalk/chalkcolor/kis_profile.cc208
-rw-r--r--chalk/chalkcolor/kis_profile.h98
-rw-r--r--chalk/chalkcolor/kis_u16_base_colorspace.cc148
-rw-r--r--chalk/chalkcolor/kis_u16_base_colorspace.h80
-rw-r--r--chalk/chalkcolor/kis_u8_base_colorspace.cc118
-rw-r--r--chalk/chalkcolor/kis_u8_base_colorspace.h77
-rw-r--r--chalk/chalkcolor/tests/Makefile.am16
-rw-r--r--chalk/chalkcolor/tests/kis_color_conversions_tester.cpp227
-rw-r--r--chalk/chalkcolor/tests/kis_color_conversions_tester.h44
43 files changed, 7395 insertions, 0 deletions
diff --git a/chalk/chalkcolor/Makefile.am b/chalk/chalkcolor/Makefile.am
new file mode 100644
index 00000000..9ec16a40
--- /dev/null
+++ b/chalk/chalkcolor/Makefile.am
@@ -0,0 +1,45 @@
+# all_includes must remain last!
+INCLUDES = $(KOFFICE_INCLUDES) \
+ -I$(srcdir) \
+ -I$(srcdir)/../sdk \
+ -I$(srcdir)/colorspaces \
+ $(OPENEXR_CFLAGS) \
+ $(all_includes)
+
+lib_LTLIBRARIES = libchalkcolor.la
+
+if have_openexr
+OPENEXR_SOURCES=kis_f16half_base_colorspace.cc
+endif
+
+libchalkcolor_la_SOURCES = kis_color.cc kis_colorspace.cc \
+ kis_colorspace_iface.cc kis_colorspace_iface.skel kis_composite_op.cc kis_profile.cc \
+ kis_histogram_producer.cc kis_basic_histogram_producers.cc kis_abstract_colorspace.cc \
+ kis_colorspace_factory_registry.cc kis_color_conversions.cc kis_u8_base_colorspace.cc \
+ kis_u16_base_colorspace.cc kis_f32_base_colorspace.cc $(OPENEXR_SOURCES)
+
+libchalkcolor_la_LDFLAGS = -version-info 1:0:0 -no-undefined $(all_libraries)
+libchalkcolor_la_LIBADD = colorspaces/libchalkcolorspaces.la $(LCMS_LIBS) $(LIB_KPARTS) $(LIB_KDECORE) $(LIB_QT) $(OPENEXR_LIBS)
+
+include_HEADERS = \
+ kis_channelinfo.h \
+ kis_color.h \
+ kis_colorspace.h \
+ kis_composite_op.h \
+ kis_profile.h \
+ kis_histogram_producer.h \
+ kis_basic_histogram_producers.h kis_u8_base_colorspace.h kis_u16_base_colorspace.h kis_f16half_base_colorspace.h kis_f32_base_colorspace.h \
+ kis_colorspace_factory_registry.h kis_abstract_colorspace.h
+
+
+if include_kunittest_tests
+TESTSDIR = tests
+endif
+
+SUBDIRS = colorspaces . $(TESTSDIR)
+
+kde_servicetypes_DATA = chalk_colorspace.desktop
+
+METASOURCES = AUTO
+
+
diff --git a/chalk/chalkcolor/README b/chalk/chalkcolor/README
new file mode 100644
index 00000000..f80e0520
--- /dev/null
+++ b/chalk/chalkcolor/README
@@ -0,0 +1,4 @@
+The color library is a wrapper around lcms and provides colorspaces
+that can do things to arrays of bytes that represent pixels. The
+number of colorspaces is extensible with plugins. The colorspace
+registry is responsible for loading the colorspace plugins.
diff --git a/chalk/chalkcolor/TODO b/chalk/chalkcolor/TODO
new file mode 100644
index 00000000..81bc56c1
--- /dev/null
+++ b/chalk/chalkcolor/TODO
@@ -0,0 +1,11 @@
+This library is still dependent upon chalk/sdk for some headers. This
+should be changed. The headers concerned are:
+
+kis_id.h
+kis_global.h
+kis_annotation.h
+kis_integer_maths.h
+
+Additionally, there is a problem with the histogram producers: those are
+tied to the individual base colorspaces, but also need iterators, so they
+are in core for the moment.
diff --git a/chalk/chalkcolor/chalk_colorspace.desktop b/chalk/chalkcolor/chalk_colorspace.desktop
new file mode 100644
index 00000000..7379a273
--- /dev/null
+++ b/chalk/chalkcolor/chalk_colorspace.desktop
@@ -0,0 +1,38 @@
+[Desktop Entry]
+Type=ServiceType
+X-KDE-ServiceType=Chalk/ColorSpace
+Comment=A module implementing a complete colorspace for use with libchalkcolor
+Comment[bg]=Модул, реализиращ пълна цветова гама за употреба с libchalkcolor
+Comment[ca]=Un mòdul que implementa un complet espai de colors per a usar-lo amb libchalkcolor
+Comment[cy]=Modiwl sy'n gweithredoli gofod lliw cyflawn i'w ddefnyddio efo libchalkcolor
+Comment[da]=Et modul som implementerer et fuldstændigt farverum til brug med libchalkcolor
+Comment[de]=Ein Modul, das einen kompletten Farbraum zur Benutzung mit libchalkcolor implementiert
+Comment[el]=Ένα άρθρωμα που υλοποιεί έναν πλήρη χρωματικό χώρο για χρήση με το libchalkcolor
+Comment[en_GB]=A module implementing a complete colourspace for use with libchalkcolor
+Comment[es]=Un módulo que implementa un espacio de color completo para usar con libchalkcolor
+Comment[et]=Täielikku värviruumi teostav moodul (teegile libchalkcolor)
+Comment[fa]=پیمانه‌ای که فضای رنگ کاملی برای استفاده با libchalkcolor پیاده می‌کند
+Comment[fr]=Un module implantant un espace de couleurs complet à utiliser avec libchalkcolor
+Comment[fy]=In module dy in folslein kleurgebiet ymplementearret dat brûkt wurde kin mei libchalkcolor
+Comment[gl]=Un módulo que implemente un espazo de cor completo para usar con libchalkcolor
+Comment[hu]=Teljes színteret megvalósító modul a libchalkcolor programkönyvtárhoz
+Comment[is]=Eining með fullu litasvæði til notkunar með libchalkcolor
+Comment[it]=Un modulo che implementa uno spazio dei colori completo per usarlo con libchalkcolor
+Comment[km]=ម៉ូឌុល​ដែល​អនុវត្ត​ប្រភេទ​ពណ៌​ពេញលេញ ដើម្បី​ប្រើ​ជាមួយ libchalkcolor
+Comment[nb]=En modul som implementerer et komplett fargerom til bruk med libchalkcolor
+Comment[nds]=En Moduul, dat en helen Klörenruum för den Bruuk mit libchalkcolor inbuut
+Comment[ne]=लिबक्रितारङसँग प्रयोग गर्नका लागि सम्पूर्ण रङ खालीस्थानलाई मोड्युललाई औजार बनाइदै
+Comment[nl]=Een module die een volledig kleurgebied implementeert dat gebruikt kan worden met libchalkcolor
+Comment[pl]=Moduł implementujący kompletną przestrzeń barw do użytku z libchalkcolor
+Comment[pt]=Um módulo que implementa um espaço de cores completo para usar com a 'libchalkcolor'
+Comment[pt_BR]=Um módulo que implementa um espaço de cores completo para usar com a 'libchalkcolor'
+Comment[ru]=Полная поддержка цветовых пространств в libchalkcolor
+Comment[sk]=Modul ktorý poskytuje úplný farebný priestor pre použitie s libchalkcolor
+Comment[sl]=Modul, v katerem je izveden celoten barvni prostor za uporabo z libchalkcolor
+Comment[sr]=Модул који имплементира потпун простор боја за употребу са libchalkcolor
+Comment[sr@Latn]=Modul koji implementira potpun prostor boja za upotrebu sa libchalkcolor
+Comment[sv]=En modul som implementerar en fullständig färgrymd för användning med libchalkcolor
+Comment[uk]=Модуль впровадження повного простору кольорів для вжитку з libchalkcolor
+Comment[zh_TW]=實作完整色彩空間以使用 libchalkcolor 的模組
+[PropertyDef::X-Chalk-Version]
+Type=int
diff --git a/chalk/chalkcolor/colorspaces/Makefile.am b/chalk/chalkcolor/colorspaces/Makefile.am
new file mode 100644
index 00000000..90f75d29
--- /dev/null
+++ b/chalk/chalkcolor/colorspaces/Makefile.am
@@ -0,0 +1,20 @@
+INCLUDES = -I$(srcdir)/.. \
+ -I$(srcdir)/../../sdk \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+noinst_LTLIBRARIES = libchalkcolorspaces.la
+
+libchalkcolorspaces_la_SOURCES = \
+ kis_alpha_colorspace.cc \
+ kis_lab_colorspace.cc
+
+noinst_HEADERS = \
+ kis_alpha_colorspace.h \
+ kis_lab_colorspace.h
+
+libchalkcolorspaces_la_LIBADD = $(OPENEXR_LIBS)
+
+libchalkcolorspaces_la_METASOURCES = AUTO
+
+
diff --git a/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc
new file mode 100644
index 00000000..4b54556f
--- /dev/null
+++ b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.cc
@@ -0,0 +1,296 @@
+/*
+ * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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 <limits.h>
+#include <stdlib.h>
+
+#include <tqimage.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <config.h>
+
+#include LCMS_HEADER
+
+#include "kis_alpha_colorspace.h"
+#include "kis_u8_base_colorspace.h"
+#include "kis_channelinfo.h"
+#include "kis_id.h"
+#include "kis_integer_maths.h"
+
+namespace {
+ const TQ_UINT8 PIXEL_MASK = 0;
+}
+
+KisAlphaColorSpace::KisAlphaColorSpace(KisColorSpaceFactoryRegistry * tqparent,
+ KisProfile *p) :
+ KisU8BaseColorSpace(KisID("ALPHA", i18n("Alpha tqmask")), TYPE_GRAY_8, icSigGrayData, tqparent, p)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 0, KisChannelInfo::ALPHA, KisChannelInfo::UINT8));
+ m_alphaPos = 0;
+}
+
+KisAlphaColorSpace::~KisAlphaColorSpace()
+{
+}
+
+void KisAlphaColorSpace::fromTQColor(const TQColor& /*c*/, TQ_UINT8 *dst, KisProfile * /*profile*/)
+{
+ dst[PIXEL_MASK] = OPACITY_OPAQUE;
+}
+
+void KisAlphaColorSpace::fromTQColor(const TQColor& /*c*/, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * /*profile*/)
+{
+ dst[PIXEL_MASK] = opacity;
+}
+
+void KisAlphaColorSpace::getAlpha(const TQ_UINT8 *pixel, TQ_UINT8 *alpha) const
+{
+ *alpha = *pixel;
+}
+
+void KisAlphaColorSpace::toTQColor(const TQ_UINT8 */*src*/, TQColor *c, KisProfile * /*profile*/)
+{
+ c->setRgb(255, 255, 255);
+}
+
+void KisAlphaColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * /*profile*/)
+{
+ c->setRgb(255, 255, 255);
+ *opacity = src[PIXEL_MASK];
+}
+
+TQ_UINT8 KisAlphaColorSpace::difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2)
+{
+ // Arithmetic operands smaller than int are converted to int automatically
+ return TQABS(src2[PIXEL_MASK] - src1[PIXEL_MASK]);
+}
+
+void KisAlphaColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const
+{
+ if (nColors > 0) {
+ TQ_UINT32 total = 0;
+
+ while(nColors)
+ {
+ nColors--;
+ total += *colors[nColors] * weights[nColors];
+ }
+ *dst = total / 255;
+ }
+}
+
+TQValueVector<KisChannelInfo *> KisAlphaColorSpace::channels() const
+{
+ return m_channels;
+}
+
+bool KisAlphaColorSpace::convertPixelsTo(const TQ_UINT8 *src,
+ TQ_UINT8 *dst, KisAbstractColorSpace * dstColorSpace,
+ TQ_UINT32 numPixels,
+ TQ_INT32 /*renderingIntent*/)
+{
+ // No lcms trickery here, we are only a opacity channel
+ TQ_INT32 size = dstColorSpace->pixelSize();
+
+ TQ_UINT32 j = 0;
+ TQ_UINT32 i = 0;
+
+ while ( i < numPixels ) {
+
+ dstColorSpace->fromTQColor(TQt::red, OPACITY_OPAQUE - *(src + i), (dst + j));
+
+ i += 1;
+ j += size;
+
+ }
+ return true;
+
+}
+
+
+//XXX bitblt of ColorSpaceAlpha does not take tqmask into consideration as this is probably not
+// used ever
+void KisAlphaColorSpace::bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dststride,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op)
+{
+
+ TQ_UINT8 *d;
+ const TQ_UINT8 *s;
+ TQ_INT32 i;
+ TQ_INT32 linesize;
+
+ if (rows <= 0 || cols <= 0)
+ return;
+ switch (op.op()) {
+ case COMPOSITE_COPY:
+ compositeCopy(dst, dststride, src, srcRowStride, srcAlphaMask, tqmaskRowStride, rows, cols, opacity);
+ return;
+ case COMPOSITE_CLEAR:
+ linesize = sizeof(TQ_UINT8) * cols;
+ d = dst;
+ while (rows-- > 0) {
+ memset(d, OPACITY_TRANSPARENT, linesize);
+ d += dststride;
+ }
+ return;
+ case COMPOSITE_ERASE:
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+
+ for (i = cols; i > 0; i--, d ++, s ++) {
+ if (d[PIXEL_MASK] < s[PIXEL_MASK]) {
+ continue;
+ }
+ else {
+ d[PIXEL_MASK] = s[PIXEL_MASK];
+ }
+
+ }
+
+ dst += dststride;
+ src += srcRowStride;
+ }
+ return;
+ case COMPOSITE_SUBTRACT:
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+
+ for (i = cols; i > 0; i--, d++, s++) {
+ if (d[PIXEL_MASK] <= s[PIXEL_MASK]) {
+ d[PIXEL_MASK] = MIN_SELECTED;
+ } else {
+ d[PIXEL_MASK] -= s[PIXEL_MASK];
+ }
+ }
+
+ dst += dststride;
+ src += srcRowStride;
+ }
+ return;
+ case COMPOSITE_ALPHA_DARKEN:
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d++, s++) {
+ if (s[PIXEL_MASK] == OPACITY_TRANSPARENT)
+ continue;
+ int srcAlpha = (s[PIXEL_MASK] * opacity + UINT8_MAX / 2) / UINT8_MAX;
+ if (srcAlpha > d[PIXEL_MASK])
+ d[PIXEL_MASK] = srcAlpha;
+ }
+ dst += dststride;
+ src += srcRowStride;
+ }
+ return;
+ case COMPOSITE_OVER:
+ default:
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+ if (opacity != OPACITY_OPAQUE) {
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d++, s++) {
+ if (s[PIXEL_MASK] == OPACITY_TRANSPARENT)
+ continue;
+ int srcAlpha = (s[PIXEL_MASK] * opacity + UINT8_MAX / 2) / UINT8_MAX;
+ d[PIXEL_MASK] = (d[PIXEL_MASK] * (UINT8_MAX - srcAlpha) + srcAlpha * UINT8_MAX + UINT8_MAX / 2) / UINT8_MAX;
+ }
+ dst += dststride;
+ src += srcRowStride;
+ }
+ }
+ else {
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d++, s++) {
+ if (s[PIXEL_MASK] == OPACITY_TRANSPARENT)
+ continue;
+ if (d[PIXEL_MASK] == OPACITY_TRANSPARENT || s[PIXEL_MASK] == OPACITY_OPAQUE) {
+ memcpy(d, s, 1);
+ continue;
+ }
+ int srcAlpha = s[PIXEL_MASK];
+ d[PIXEL_MASK] = (d[PIXEL_MASK] * (UINT8_MAX - srcAlpha) + srcAlpha * UINT8_MAX + UINT8_MAX / 2) / UINT8_MAX;
+ }
+ dst += dststride;
+ src += srcRowStride;
+ }
+ }
+
+ }
+}
+
+KisCompositeOpList KisAlphaColorSpace::userVisiblecompositeOps() const
+{
+ KisCompositeOpList list;
+
+ list.append(KisCompositeOp(COMPOSITE_OVER));
+
+ return list;
+}
+
+TQString KisAlphaColorSpace::channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < nChannels());
+ TQ_UINT32 channelPosition = m_channels[channelIndex]->pos();
+
+ return TQString().setNum(pixel[channelPosition]);
+}
+
+TQString KisAlphaColorSpace::normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < nChannels());
+ TQ_UINT32 channelPosition = m_channels[channelIndex]->pos();
+
+ return TQString().setNum(static_cast<float>(pixel[channelPosition]) / UINT8_MAX);
+}
+
+
+void KisAlphaColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const
+{
+ TQ_INT32 totalAlpha = 0;
+
+ while (nColors--)
+ {
+ TQ_INT32 weight = *kernelValues;
+
+ if (weight != 0) {
+ totalAlpha += (*colors)[PIXEL_MASK] * weight;
+ }
+ colors++;
+ kernelValues++;
+ }
+
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ dst[PIXEL_MASK] = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT8_MAX);
+ }
+}
diff --git a/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h
new file mode 100644
index 00000000..dd4f3916
--- /dev/null
+++ b/chalk/chalkcolor/colorspaces/kis_alpha_colorspace.h
@@ -0,0 +1,93 @@
+/*
+ * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_COLORSPACE_ALPHA_H_
+#define KIS_COLORSPACE_ALPHA_H_
+
+#include <tqcolor.h>
+
+#include "kis_global.h"
+#include "kis_u8_base_colorspace.h"
+
+/**
+ * The alpha tqmask is a special color strategy that treats all pixels as
+ * alpha value with a colour common to the tqmask. The default color is white.
+ */
+class KisAlphaColorSpace : public KisU8BaseColorSpace {
+public:
+ KisAlphaColorSpace(KisColorSpaceFactoryRegistry * tqparent,
+ KisProfile *p);
+ virtual ~KisAlphaColorSpace();
+
+public:
+ virtual bool willDegrade(ColorSpaceIndependence)
+ {
+ return false;
+ };
+
+ virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0);
+ virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0);
+
+ virtual void getAlpha(const TQ_UINT8 *pixel, TQ_UINT8 *alpha) const;
+
+ virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0);
+ virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0);
+
+ virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2);
+ virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const;
+
+ virtual TQValueVector<KisChannelInfo *> channels() const;
+ virtual TQ_UINT32 nChannels() const { return 1; };
+ virtual TQ_UINT32 nColorChannels() const { return 0; };
+ virtual TQ_UINT32 pixelSize() const { return 1; };
+
+ virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+ virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+
+ virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const;
+
+protected:
+
+ /**
+ * Convert a byte array of srcLen pixels *src to the specified color space
+ * and put the converted bytes into the prepared byte array *dst.
+ *
+ * Returns false if the conversion failed, true if it succeeded
+ */
+ virtual bool convertPixelsTo(const TQ_UINT8 *src,
+ TQ_UINT8 *dst, KisAbstractColorSpace * dstColorSpace,
+ TQ_UINT32 numPixels,
+ TQ_INT32 renderingIntent = INTENT_PERCEPTUAL);
+
+
+
+ virtual void bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dststride,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op);
+
+ KisCompositeOpList userVisiblecompositeOps() const;
+
+};
+
+#endif // KIS_COLORSPACE_ALPHA_H_
diff --git a/chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc
new file mode 100644
index 00000000..829b4f27
--- /dev/null
+++ b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.cc
@@ -0,0 +1,571 @@
+ /*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.com>
+ * Copyright (c) 2005 Casper Boemann <cbr@boemann.dk>
+ *
+ * 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 <config.h>
+#include <limits.h>
+#include <stdlib.h>
+#include LCMS_HEADER
+
+#include <tqimage.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "kis_lab_colorspace.h"
+#include "kis_color_conversions.h"
+#include "kis_integer_maths.h"
+
+KisLabColorSpace::KisLabColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p)
+ : KisU16BaseColorSpace(KisID("LABA", i18n("L*a*b* (16-bit integer/channel)")),
+ COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1),
+ icSigLabData, tqparent, p)
+
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Lightness"), i18n("L"), CHANNEL_L * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(100,100,100)));
+ m_channels.push_back(new KisChannelInfo(i18n("a*"), i18n("a"), CHANNEL_A * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(150,150,150)));
+ m_channels.push_back(new KisChannelInfo(i18n("b*"), i18n("b"), CHANNEL_B * sizeof(TQ_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(TQ_UINT16), TQColor(200,200,200)));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), CHANNEL_ALPHA * sizeof(TQ_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(TQ_UINT16)));
+
+ m_alphaPos = CHANNEL_ALPHA * sizeof(TQ_UINT16);
+
+ init();
+}
+
+KisLabColorSpace::~KisLabColorSpace()
+{
+}
+
+TQ_UINT8 * KisLabColorSpace::toLabA16(const TQ_UINT8 * data, const TQ_UINT32 nPixels) const
+{
+ TQ_UINT8 * pixels = new TQ_UINT8[nPixels * pixelSize()];
+ memcpy( pixels, data, nPixels * pixelSize() );
+ return pixels;
+}
+
+TQ_UINT8 * KisLabColorSpace::fromLabA16(const TQ_UINT8 * labData, const TQ_UINT32 nPixels) const
+{
+ TQ_UINT8 * pixels = new TQ_UINT8[nPixels * pixelSize()];
+ memcpy( pixels, labData, nPixels * pixelSize() );
+ return pixels;
+}
+
+TQ_UINT8 KisLabColorSpace::difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2)
+{
+ cmsCIELab labF1, labF2;
+
+ if (getAlpha(src1) == OPACITY_TRANSPARENT || getAlpha(src2) == OPACITY_TRANSPARENT)
+ return (getAlpha(src1) == getAlpha(src2) ? 0 : 255);
+
+ cmsLabEncoded2Float(&labF1, (WORD *)src1);
+ cmsLabEncoded2Float(&labF2, (WORD *)src2);
+ double diff = cmsDeltaE(&labF1, &labF2);
+ if(diff>255)
+ return 255;
+ else
+ return TQ_INT8(diff);
+}
+
+void KisLabColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const
+{
+ TQ_UINT32 totalLightness = 0, totalAlpha = 0;
+ TQ_UINT32 totala = 0, totalb = 0;
+
+ while (nColors--)
+ {
+ const Pixel *color = reinterpret_cast<const Pixel *>( *colors );
+ TQ_UINT32 alphaTimesWeight = UINT8_MULT(color->alpha, *weights);
+
+ totalLightness += color->lightness * alphaTimesWeight;
+ totala += color->a * alphaTimesWeight;
+ totalb += color->b * alphaTimesWeight;
+ totalAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ if (totalAlpha > UINT16_MAX) {
+ totalAlpha = UINT16_MAX;
+ }
+
+ ((Pixel *)dst)->alpha = totalAlpha;
+
+ if (totalAlpha > 0) {
+ totalLightness /= totalAlpha;
+ totala /= totalAlpha;
+ totalb /= totalAlpha;
+ } // else the values are already 0 too
+
+ if (totalLightness > MAX_CHANNEL_L) {
+ totalLightness = MAX_CHANNEL_L;
+ }
+
+ ((Pixel *)dst)->lightness = totalLightness;
+
+ if (totala > MAX_CHANNEL_AB) {
+ totala = MAX_CHANNEL_AB;
+ }
+
+ ((Pixel *)dst)->a = totala;
+
+ if (totalb > MAX_CHANNEL_AB) {
+ totalb = MAX_CHANNEL_AB;
+ }
+
+ ((Pixel *)dst)->b = totalb;
+}
+
+void KisLabColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels)
+{
+ TQ_UINT32 psize = pixelSize();
+
+ while (nPixels--)
+ {
+ Pixel * s = reinterpret_cast<Pixel *>( src );
+
+ s->lightness = MAX_CHANNEL_L - s->lightness;
+ s->a = MAX_CHANNEL_AB - s->a;
+ s->b = MAX_CHANNEL_AB - s->b;
+
+ src += psize;
+ }
+}
+
+void KisLabColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags,
+ TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const
+{
+ TQ_INT32 totalL = 0, totalA = 0, totalB = 0, totalAlpha = 0;
+
+ while ( nColors -- )
+ {
+ const Pixel * pixel = reinterpret_cast<const Pixel *>( *colors );
+ TQ_INT32 weight = *kernelValues;
+ if ( weight != 0 ) {
+ totalL += pixel->lightness * weight;
+ totalA += pixel->a * weight;
+ totalB += pixel->b * weight;
+ totalAlpha += pixel->alpha * weight;
+ }
+ colors++;
+ kernelValues++;
+ }
+
+
+ Pixel * p = reinterpret_cast< Pixel *>( dst );
+
+ if (channelFlags & KisChannelInfo::FLAG_COLOR) {
+ p->lightness = CLAMP( ( totalL / factor) + offset, 0, TQ_UINT16_MAX);
+ p->a = CLAMP( ( totalA / factor) + offset, 0, TQ_UINT16_MAX);
+ p->b = CLAMP( ( totalB / factor) + offset, 0, TQ_UINT16_MAX);
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT16_MAX);
+ }
+
+}
+
+void KisLabColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const
+{
+ // XXX: Is the 255 right for u16 colorspaces?
+ TQ_UINT32 pSize = pixelSize();
+ while ( nPixels-- ) {
+ const Pixel * s = reinterpret_cast<const Pixel*>( src );
+ Pixel * d = reinterpret_cast<Pixel*>( dst );
+
+ if ( compensate ) {
+ d->lightness = static_cast<TQ_UINT16>( ( s->lightness * shade ) / ( compensation * 255 ) );
+ }
+ else {
+ d->lightness = static_cast<TQ_UINT16>( s->lightness * shade / 255 );
+ }
+ d->a = s->a;
+ d->b = s->b;
+ d->alpha = s->alpha;
+
+ src += pSize;
+ dst += pSize;
+ }
+}
+
+
+TQValueVector<KisChannelInfo *> KisLabColorSpace::channels() const
+{
+ return m_channels;
+}
+
+TQ_UINT32 KisLabColorSpace::nChannels() const
+{
+ return NUM_CHANNELS;
+}
+
+TQ_UINT32 KisLabColorSpace::nColorChannels() const
+{
+ return NUM_COLOR_CHANNELS;
+}
+
+TQ_UINT32 KisLabColorSpace::pixelSize() const
+{
+ return sizeof(Pixel);
+}
+
+void KisLabColorSpace::getSingleChannelPixel(TQ_UINT8 *dst, const TQ_UINT8 *src, TQ_UINT32 channelIndex)
+{
+ if (channelIndex < NUM_CHANNELS) {
+
+ const Pixel *srcPixel = reinterpret_cast<const Pixel *>(src);
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ switch (channelIndex) {
+ case CHANNEL_L:
+ dstPixel->lightness = srcPixel->lightness;
+ dstPixel->a = CHANNEL_AB_ZERO_OFFSET;
+ dstPixel->b = CHANNEL_AB_ZERO_OFFSET;
+ dstPixel->alpha = U16_OPACITY_TRANSPARENT;
+ break;
+ case CHANNEL_A:
+ dstPixel->lightness = MAX_CHANNEL_L / 2;
+ dstPixel->a = srcPixel->a;
+ dstPixel->b = CHANNEL_AB_ZERO_OFFSET;
+ dstPixel->alpha = U16_OPACITY_TRANSPARENT;
+ break;
+ case CHANNEL_B:
+ dstPixel->lightness = MAX_CHANNEL_L / 2;
+ dstPixel->a = CHANNEL_AB_ZERO_OFFSET;
+ dstPixel->b = srcPixel->b;
+ dstPixel->alpha = U16_OPACITY_TRANSPARENT;
+ break;
+ case CHANNEL_ALPHA:
+ dstPixel->lightness = MAX_CHANNEL_L / 2;
+ dstPixel->a = CHANNEL_AB_ZERO_OFFSET;
+ dstPixel->b = CHANNEL_AB_ZERO_OFFSET;
+ dstPixel->alpha = srcPixel->alpha;
+ break;
+ }
+ }
+}
+
+void KisLabColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity)
+{
+ while (rows > 0) {
+ const Pixel *src = reinterpret_cast<const Pixel *>(srcRowStart);
+ Pixel *dst = reinterpret_cast<Pixel *>(dstRowStart);
+ const TQ_UINT8 *tqmask = tqmaskRowStart;
+ TQ_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ TQ_UINT16 srcAlpha = src->alpha;
+
+ // apply the alphatqmask
+ if (tqmask != 0) {
+ if (*tqmask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, *tqmask);
+ }
+ tqmask++;
+ }
+
+ if (srcAlpha != U16_OPACITY_TRANSPARENT) {
+
+ if (opacity != U16_OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, opacity);
+ }
+
+ if (srcAlpha == U16_OPACITY_OPAQUE) {
+ memcpy(dst, src, sizeof(Pixel));
+ } else {
+ TQ_UINT16 dstAlpha = dst->alpha;
+
+ TQ_UINT16 srcBlend;
+
+ if (dstAlpha == U16_OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst->alpha = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ if (srcBlend == U16_OPACITY_OPAQUE) {
+ memcpy(dst, src, sizeof(Pixel));
+ } else {
+/*printf("blend is %d\n", srcBlend);
+printf("%d %d %d\n", src->lightness, src->a, src->b);
+printf("%d %d %d\n", dst->lightness, dst->a, dst->b);
+*/
+ dst->lightness = UINT16_BLEND(src->lightness, dst->lightness, srcBlend);
+ dst->a = UINT16_BLEND(src->a, dst->a, srcBlend);
+ dst->b = UINT16_BLEND(src->b, dst->b, srcBlend);
+//printf("%d %d %d\n", dst->lightness, dst->a, dst->b);
+ }
+ }
+ }
+
+ columns--;
+ src++;
+ dst++;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(tqmaskRowStart) {
+ tqmaskRowStart += tqmaskRowStride;
+ }
+ }
+}
+
+void KisLabColorSpace::compositeErase(TQ_UINT8 *dst,
+ TQ_INT32 dstRowSize,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowSize,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ TQ_UINT16 /*opacity*/)
+{
+ while (rows-- > 0)
+ {
+ const Pixel *s = reinterpret_cast<const Pixel *>(src);
+ Pixel *d = reinterpret_cast<Pixel *>(dst);
+ const TQ_UINT8 *tqmask = srcAlphaMask;
+
+ for (TQ_INT32 i = cols; i > 0; i--, s++, d++)
+ {
+ TQ_UINT16 srcAlpha = s->alpha;
+
+ // apply the alphatqmask
+ if (tqmask != 0) {
+ TQ_UINT8 U8_tqmask = *tqmask;
+
+ if (U8_tqmask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_tqmask));
+ }
+ tqmask++;
+ }
+ d->alpha = UINT16_MULT(srcAlpha, d->alpha);
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ if(srcAlphaMask) {
+ srcAlphaMask += tqmaskRowStride;
+ }
+ }
+}
+
+void KisLabColorSpace::bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dstRowStride,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *tqmask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 U8_opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op)
+{
+ TQ_UINT16 opacity = UINT8_TO_UINT16(U8_opacity);
+
+ switch (op.op()) {
+ case COMPOSITE_UNDEF:
+ // Undefined == no composition
+ break;
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_IN:
+ //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_OUT:
+ //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ATOP:
+ //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_XOR:
+ //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_PLUS:
+ //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_MINUS:
+ //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ADD:
+ //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SUBTRACT:
+ //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIFF:
+ //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_MULT:
+ //compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIVIDE:
+ //compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BUMPMAP:
+ //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY:
+ compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, U8_opacity);
+ break;
+ case COMPOSITE_COPY_RED:
+ //compositeCopyRed(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY_GREEN:
+ //compositeCopyGreen(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY_BLUE:
+ //compositeCopyBlue(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY_OPACITY:
+ //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_CLEAR:
+ //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DISSOLVE:
+ //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DISPLACE:
+ //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+#if 0
+ case COMPOSITE_MODULATE:
+ compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_THRESHOLD:
+ compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+#endif
+ case COMPOSITE_NO:
+ // No composition.
+ break;
+ case COMPOSITE_DARKEN:
+ //compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LIGHTEN:
+ //compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_HUE:
+ //compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SATURATION:
+ //compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_VALUE:
+ //compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COLOR:
+ //compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COLORIZE:
+ //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LUMINIZE:
+ //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SCREEN:
+ //compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_OVERLAY:
+ //compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DODGE:
+ //compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BURN:
+ //compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ALPHA_DARKEN:
+ abstractCompositeAlphaDarken<TQ_UINT16, U16Mult, Uint8ToU16, U16OpacityTest,
+ CHANNEL_ALPHA, NUM_COLOR_CHANNELS, NUM_CHANNELS>(
+ dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride,
+ rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest());
+ break;
+ default:
+ break;
+ }
+}
+
+KisCompositeOpList KisLabColorSpace::userVisiblecompositeOps() const
+{
+ KisCompositeOpList list;
+
+ list.append(KisCompositeOp(COMPOSITE_OVER));
+ list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN));
+
+ return list;
+}
+
+TQString KisLabColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
+{
+ const Pixel *pix = reinterpret_cast<const Pixel *>(U8_pixel);
+ Q_ASSERT(channelIndex < nChannels());
+ switch(channelIndex)
+ {
+ case CHANNEL_L:
+ return TQString().setNum(pix->lightness);
+ case CHANNEL_A:
+ return TQString().setNum(pix->a);
+ case CHANNEL_B:
+ return TQString().setNum(pix->b);
+ case CHANNEL_ALPHA:
+ return TQString().setNum(pix->alpha);
+ default:
+ return TQString("Error");
+ }
+}
+
+TQString KisLabColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
+{
+ const Pixel *pix = reinterpret_cast<const Pixel *>(U8_pixel);
+ Q_ASSERT(channelIndex < nChannels());
+
+ // These convert from lcms encoded format to standard ranges.
+
+ switch(channelIndex)
+ {
+ case CHANNEL_L:
+ return TQString().setNum(100.0 * static_cast<float>(pix->lightness) / MAX_CHANNEL_L);
+ case CHANNEL_A:
+ return TQString().setNum(100.0 * ((static_cast<float>(pix->a) - CHANNEL_AB_ZERO_OFFSET) / MAX_CHANNEL_AB));
+ case CHANNEL_B:
+ return TQString().setNum(100.0 * ((static_cast<float>(pix->b) - CHANNEL_AB_ZERO_OFFSET) / MAX_CHANNEL_AB));
+ case CHANNEL_ALPHA:
+ return TQString().setNum(100.0 * static_cast<float>(pix->alpha) / UINT16_MAX);
+ default:
+ return TQString("Error");
+ }
+}
+
diff --git a/chalk/chalkcolor/colorspaces/kis_lab_colorspace.h b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.h
new file mode 100644
index 00000000..eeab55cf
--- /dev/null
+++ b/chalk/chalkcolor/colorspaces/kis_lab_colorspace.h
@@ -0,0 +1,153 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.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_STRATEGY_COLORSPACE_LAB_H_
+#define KIS_STRATEGY_COLORSPACE_LAB_H_
+
+#include <tqcolor.h>
+
+#include <klocale.h>
+
+#include "kis_global.h"
+#include "kis_integer_maths.h"
+#include "kis_u16_base_colorspace.h"
+
+class KisLabColorSpace : public KisU16BaseColorSpace {
+public:
+ KisLabColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p);
+ virtual ~KisLabColorSpace();
+
+public:
+
+ /**
+ * Return a COPY of the provided data. This method is provided to provide consistency,
+ * but you really don't want to be calling it.
+ */
+ virtual TQ_UINT8 * toLabA16(const TQ_UINT8 * data, const TQ_UINT32 nPixels) const;
+
+ /**
+ * Return a COPY of the provided data. This method is provided for consistency,
+ * but you really don't want to call it.
+ */
+ virtual TQ_UINT8 * fromLabA16(const TQ_UINT8 * labData, const TQ_UINT32 nPixels) const;
+
+
+
+ virtual bool willDegrade(ColorSpaceIndependence independence)
+ {
+ if (independence == TO_RGBA8)
+ return true;
+ else
+ return false;
+ };
+
+ virtual TQValueVector<KisChannelInfo *> channels() const;
+ virtual TQ_UINT32 nChannels() const;
+ virtual TQ_UINT32 nColorChannels() const;
+ virtual TQ_UINT32 pixelSize() const;
+
+ virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+ virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+ virtual void getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex);
+
+ virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2);
+ virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const;
+ virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels);
+ virtual void convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const;
+
+ virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const;
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+protected:
+
+ virtual void bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dstRowStride,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op);
+
+ void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+/*
+ void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeHue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeSaturation(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeValue(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeColor(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+*/
+ void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+
+private:
+ struct Pixel {
+ TQ_UINT16 lightness;
+ TQ_UINT16 a;
+ TQ_UINT16 b;
+ TQ_UINT16 alpha;
+ };
+ static const TQ_UINT16 U16_OPACITY_OPAQUE = UINT16_MAX;
+ static const TQ_UINT16 U16_OPACITY_TRANSPARENT = UINT16_MIN;
+
+ static const TQ_UINT32 NUM_CHANNELS = 4;
+ static const TQ_UINT32 NUM_COLOR_CHANNELS = 3;
+
+ static const TQ_UINT32 CHANNEL_L = 0;
+ static const TQ_UINT32 CHANNEL_A = 1;
+ static const TQ_UINT32 CHANNEL_B = 2;
+ static const TQ_UINT32 CHANNEL_ALPHA = 3;
+
+ static const TQ_UINT32 MAX_CHANNEL_L = 0xff00;
+ static const TQ_UINT32 MAX_CHANNEL_AB = 0xffff;
+ static const TQ_UINT32 CHANNEL_AB_ZERO_OFFSET = 0x8000;
+
+ friend class KisLabColorSpaceTester;
+};
+
+class KisLabColorSpaceFactory : public KisColorSpaceFactory
+{
+public:
+ /**
+ * Chalk definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("LABA", i18n("L*a*b* (16-bit integer/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual TQ_UINT32 colorSpaceType() { return (COLORSPACE_SH(PT_Lab)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)); };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icSigLabData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *p) { return new KisLabColorSpace(tqparent, p); };
+
+ virtual TQString defaultProfile() { return "Lab built-in - (lcms internal)"; };
+};
+
+#endif // KIS_STRATEGY_COLORSPACE_LAB_H_
diff --git a/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc
new file mode 100644
index 00000000..98ccead0
--- /dev/null
+++ b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.cc
@@ -0,0 +1,624 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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 <limits.h>
+#include <stdlib.h>
+
+#include <config.h>
+#include LCMS_HEADER
+
+#include <tqimage.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kis_abstract_colorspace.h"
+#include "kis_u16_base_colorspace.h"
+#include "kis_xyz_colorspace.h"
+#include "kis_integer_maths.h"
+
+#define downscale(quantum) (quantum) //((unsigned char) ((quantum)/257UL))
+#define upscale(value) (value) // ((TQ_UINT8) (257UL*(value)))
+
+// XXX: Maybe use TYPE_XYZ_DBL for an extra stimulating performance hit? People shouldn't depend
+// on this fallback...
+
+KisXyzColorSpace::KisXyzColorSpace(KisColorSpaceFactoryRegistry * tqparent,
+ KisProfile *p) :
+ KisU16BaseColorSpace(KisID("XYZA", i18n("XYZ/Alpha")), (COLORSPACE_SH(PT_XYZ)|CHANNELS_SH(3)|BYTES_SH(2)|EXTRA_SH(1)), icSigCmykData, tqparent, p)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("X"), i18n("X"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
+ m_channels.push_back(new KisChannelInfo(i18n("Y"), i18n("Y"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
+ m_channels.push_back(new KisChannelInfo(i18n("Z"), i18n("Z"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 4, KisChannelInfo::ALPHA, KisChannelInfo::UINT8));
+
+ m_alphaPos = PIXEL_ALPHA * sizeof(TQ_UINT16);
+
+ init();
+}
+
+
+KisXyzColorSpace::~KisXyzColorSpace()
+{
+}
+
+
+TQValueVector<KisChannelInfo *> KisXyzColorSpace::channels() const
+{
+ return m_channels;
+}
+
+TQ_UINT32 KisXyzColorSpace::nChannels() const
+{
+ return xyz::MAX_CHANNEL_XYZA;
+}
+
+TQ_UINT32 KisXyzColorSpace::nColorChannels() const
+{
+ return xyz::MAX_CHANNEL_XYZ;
+}
+
+TQ_UINT32 KisXyzColorSpace::pixelSize() const
+{
+ return xyz::MAX_CHANNEL_XYZA * sizeof(TQ_UINT16);
+}
+
+KisColorAdjustment * KisXyzColorSpace::createBrightnessContrastAdjustment(TQ_UINT16 *transferValues)
+{
+ return 0;
+}
+
+void KisXyzColorSpace::applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels)
+{
+}
+
+void KisXyzColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels)
+{
+ TQ_INT32 pSize = pixelSize();
+
+ while (nPixels--)
+ {
+ TQ_UINT16 * p = reinterpret_cast<TQ_UINT16 *>(src);
+ p[PIXEL_X] = UINT16_MAX - p[PIXEL_X];
+ p[PIXEL_Y] = UINT16_MAX - p[PIXEL_Y];
+ p[PIXEL_Z] = UINT16_MAX - p[PIXEL_Z];
+ src += pSize;
+ }
+}
+
+void KisXyzColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const
+{
+}
+
+void KisXyzColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nPixels) const
+{
+}
+
+void KisXyzColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const
+{
+}
+
+TQ_UINT8 KisXyzColorSpace::intensity8(const TQ_UINT8 * src) const
+{
+ return 0;
+}
+
+void KisXyzColorSpace::compositeOver(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity)
+{
+ while (rows > 0) {
+
+ const TQ_UINT16 *src = reinterpret_cast<const TQ_UINT16 *>(srcRowStart);
+ TQ_UINT16 *dst = reinterpret_cast<TQ_UINT16 *>(dstRowStart);
+ const TQ_UINT8 *tqmask = tqmaskRowStart;
+ TQ_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ TQ_UINT16 srcAlpha = src[PIXEL_ALPHA];
+
+ // apply the alphatqmask
+ if (tqmask != 0) {
+ TQ_UINT8 U8_tqmask = *tqmask;
+
+ if (U8_tqmask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask));
+ }
+ tqmask++;
+ }
+
+ if (srcAlpha != U16_OPACITY_TRANSPARENT) {
+
+ if (opacity != U16_OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, opacity);
+ }
+
+ if (srcAlpha == U16_OPACITY_OPAQUE) {
+ memcpy(dst, src, xyz::MAX_CHANNEL_XYZA * sizeof(TQ_UINT16));
+ } else {
+ TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA];
+
+ TQ_UINT16 srcBlend;
+
+ if (dstAlpha == U16_OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ if (srcBlend == U16_OPACITY_OPAQUE) {
+ memcpy(dst, src, xyz::MAX_CHANNEL_XYZ * sizeof(TQ_UINT16));
+ } else {
+ dst[PIXEL_X] = UINT16_BLEND(src[PIXEL_X], dst[PIXEL_X], srcBlend);
+ dst[PIXEL_Y] = UINT16_BLEND(src[PIXEL_Y], dst[PIXEL_Y], srcBlend);
+ dst[PIXEL_Z] = UINT16_BLEND(src[PIXEL_Z], dst[PIXEL_Z], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += xyz::MAX_CHANNEL_XYZA;
+ dst += xyz::MAX_CHANNEL_XYZA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(tqmaskRowStart) {
+ tqmaskRowStart += tqmaskRowStride;
+ }
+ }
+}
+
+#define COMMON_COMPOSITE_OP_PROLOG() \
+ while (rows > 0) { \
+ \
+ const TQ_UINT16 *src = reinterpret_cast<const TQ_UINT16 *>(srcRowStart); \
+ TQ_UINT16 *dst = reinterpret_cast<TQ_UINT16 *>(dstRowStart); \
+ TQ_INT32 columns = numColumns; \
+ const TQ_UINT8 *tqmask = tqmaskRowStart; \
+ \
+ while (columns > 0) { \
+ \
+ TQ_UINT16 srcAlpha = src[PIXEL_ALPHA]; \
+ TQ_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \
+ \
+ srcAlpha = TQMIN(srcAlpha, dstAlpha); \
+ \
+ if (tqmask != 0) { \
+ TQ_UINT8 U8_tqmask = *tqmask; \
+ \
+ if (U8_tqmask != OPACITY_OPAQUE) { \
+ srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_tqmask)); \
+ } \
+ tqmask++; \
+ } \
+ \
+ if (srcAlpha != U16_OPACITY_TRANSPARENT) { \
+ \
+ if (opacity != U16_OPACITY_OPAQUE) { \
+ srcAlpha = UINT16_MULT(srcAlpha, opacity); \
+ } \
+ \
+ TQ_UINT16 srcBlend; \
+ \
+ if (dstAlpha == U16_OPACITY_OPAQUE) { \
+ srcBlend = srcAlpha; \
+ } else { \
+ TQ_UINT16 newAlpha = dstAlpha + UINT16_MULT(U16_OPACITY_OPAQUE - dstAlpha, srcAlpha); \
+ dst[PIXEL_ALPHA] = newAlpha; \
+ \
+ if (newAlpha != 0) { \
+ srcBlend = UINT16_DIVIDE(srcAlpha, newAlpha); \
+ } else { \
+ srcBlend = srcAlpha; \
+ } \
+ }
+
+#define COMMON_COMPOSITE_OP_EPILOG() \
+ } \
+ \
+ columns--; \
+ src += xyz::MAX_CHANNEL_XYZA; \
+ dst += xyz::MAX_CHANNEL_XYZA; \
+ } \
+ \
+ rows--; \
+ srcRowStart += srcRowStride; \
+ dstRowStart += dstRowStride; \
+ if(tqmaskRowStart) { \
+ tqmaskRowStart += tqmaskRowStride; \
+ } \
+ }
+
+void KisXyzColorSpace::compositeMultiply(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+
+ for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) {
+ TQ_UINT16 srcColor = src[channel];
+ TQ_UINT16 dstColor = dst[channel];
+
+ srcColor = UINT16_MULT(srcColor, dstColor);
+
+ dst[channel] = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisXyzColorSpace::compositeDivide(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) {
+
+ TQ_UINT16 srcColor = src[channel];
+ TQ_UINT16 dstColor = dst[channel];
+
+ srcColor = TQMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX);
+
+ TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisXyzColorSpace::compositeScreen(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) {
+
+ TQ_UINT16 srcColor = src[channel];
+ TQ_UINT16 dstColor = dst[channel];
+
+ srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor);
+
+ TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisXyzColorSpace::compositeOverlay(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) {
+
+ TQ_UINT16 srcColor = src[channel];
+ TQ_UINT16 dstColor = dst[channel];
+
+ srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor));
+
+ TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisXyzColorSpace::compositeDodge(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) {
+
+ TQ_UINT16 srcColor = src[channel];
+ TQ_UINT16 dstColor = dst[channel];
+
+ srcColor = TQMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX);
+
+ TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisXyzColorSpace::compositeBurn(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) {
+
+ TQ_UINT16 srcColor = src[channel];
+ TQ_UINT16 dstColor = dst[channel];
+
+ srcColor = TQMIN(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX);
+ srcColor = CLAMP(UINT16_MAX - srcColor, 0u, UINT16_MAX);
+
+ TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisXyzColorSpace::compositeDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) {
+
+ TQ_UINT16 srcColor = src[channel];
+ TQ_UINT16 dstColor = dst[channel];
+
+ srcColor = TQMIN(srcColor, dstColor);
+
+ TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisXyzColorSpace::compositeLighten(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < xyz::MAX_CHANNEL_XYZ; channel++) {
+
+ TQ_UINT16 srcColor = src[channel];
+ TQ_UINT16 dstColor = dst[channel];
+
+ srcColor = TQMAX(srcColor, dstColor);
+
+ TQ_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+
+
+void KisXyzColorSpace::compositeErase(TQ_UINT8 *dst,
+ TQ_INT32 dstRowSize,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowSize,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ TQ_UINT16 /*opacity*/)
+{
+ while (rows-- > 0)
+ {
+ const Pixel *s = reinterpret_cast<const Pixel *>(src);
+ Pixel *d = reinterpret_cast<Pixel *>(dst);
+ const TQ_UINT8 *tqmask = srcAlphaMask;
+
+ for (TQ_INT32 i = cols; i > 0; i--, s++, d++)
+ {
+ TQ_UINT16 srcAlpha = s -> alpha;
+
+ // apply the alphatqmask
+ if (tqmask != 0) {
+ TQ_UINT8 U8_tqmask = *tqmask;
+
+ if (U8_tqmask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_tqmask));
+ }
+ tqmask++;
+ }
+ d -> alpha = UINT16_MULT(srcAlpha, d -> alpha);
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ if(srcAlphaMask) {
+ srcAlphaMask += tqmaskRowStride;
+ }
+ }
+}
+
+void KisXyzColorSpace::bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dstRowStride,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *tqmask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 U8_opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op)
+{
+ TQ_UINT16 opacity = UINT8_TO_UINT16(U8_opacity);
+
+ switch (op.op()) {
+ case COMPOSITE_UNDEF:
+ // Undefined == no composition
+ break;
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_IN:
+ //compositeIn(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ case COMPOSITE_OUT:
+ //compositeOut(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ATOP:
+ //compositeAtop(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_XOR:
+ //compositeXor(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_PLUS:
+ //compositePlus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_MINUS:
+ //compositeMinus(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ADD:
+ //compositeAdd(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SUBTRACT:
+ //compositeSubtract(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIFF:
+ //compositeDiff(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_MULT:
+ compositeMultiply(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIVIDE:
+ compositeDivide(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BUMPMAP:
+ //compositeBumpmap(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY:
+ compositeCopy(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, U8_opacity);
+ break;
+ case COMPOSITE_COPY_RED:
+ //compositeCopyRed(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY_GREEN:
+ //compositeCopyGreen(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY_BLUE:
+ //compositeCopyBlue(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY_OPACITY:
+ //compositeCopyOpacity(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_CLEAR:
+ //compositeClear(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DISSOLVE:
+ //compositeDissolve(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DISPLACE:
+ //compositeDisplace(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+#if 0
+ case COMPOSITE_MODULATE:
+ compositeModulate(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_THRESHOLD:
+ compositeThreshold(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+#endif
+ case COMPOSITE_NO:
+ // No composition.
+ break;
+ case COMPOSITE_DARKEN:
+ compositeDarken(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LIGHTEN:
+ compositeLighten(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_HUE:
+ //compositeHue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SATURATION:
+ //compositeSaturation(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_VALUE:
+ //compositeValue(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COLOR:
+ //compositeColor(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COLORIZE:
+ //compositeColorize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LUMINIZE:
+ //compositeLuminize(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SCREEN:
+ compositeScreen(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_OVERLAY:
+ compositeOverlay(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DODGE:
+ compositeDodge(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BURN:
+ compositeBurn(dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ALPHA_DARKEN:
+ abstractCompositeAlphaDarken<TQ_UINT16, U16Mult, Uint8ToU16, U16OpacityTest,
+ PIXEL_ALPHA, xyz::MAX_CHANNEL_XYZ, xyz::MAX_CHANNEL_XYZA>(
+ dst, dstRowStride, src, srcRowStride, tqmask, tqmaskRowStride,
+ rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest());
+ break;
+ default:
+ break;
+ }
+}
+
+KisCompositeOpList KisXyzColorSpace::userVisiblecompositeOps() const
+{
+ KisCompositeOpList list;
+
+ list.append(KisCompositeOp(COMPOSITE_OVER));
+ list.append(KisCompositeOp(COMPOSITE_ALPHA_DARKEN));
+ list.append(KisCompositeOp(COMPOSITE_MULT));
+ list.append(KisCompositeOp(COMPOSITE_BURN));
+ list.append(KisCompositeOp(COMPOSITE_DODGE));
+ list.append(KisCompositeOp(COMPOSITE_DIVIDE));
+ list.append(KisCompositeOp(COMPOSITE_SCREEN));
+ list.append(KisCompositeOp(COMPOSITE_OVERLAY));
+ list.append(KisCompositeOp(COMPOSITE_DARKEN));
+ list.append(KisCompositeOp(COMPOSITE_LIGHTEN));
+
+ return list;
+}
+
+
diff --git a/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h
new file mode 100644
index 00000000..2f7c3efd
--- /dev/null
+++ b/chalk/chalkcolor/colorspaces/kis_xyz_colorspace.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt (boud@valdyas.org)
+ *
+ * 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__COLORSPACE_XYZ_H_
+#define KIS__COLORSPACE_XYZ_H_
+
+#include <tqcolor.h>
+
+#include "kis_global.h"
+#include "kis_integer_maths.h"
+#include "kis_u16_base_colorspace.h"
+
+namespace xyz {
+ const TQ_INT32 MAX_CHANNEL_XYZ = 3;
+ const TQ_INT32 MAX_CHANNEL_XYZA = 4;
+}
+
+
+
+class KisXyzColorSpace : public KisU16BaseColorSpace {
+
+public:
+
+ struct Pixel {
+ TQ_UINT16 X;
+ TQ_UINT16 Y;
+ TQ_UINT16 Z;
+ TQ_UINT16 alpha;
+ };
+
+public:
+ KisXyzColorSpace(KisColorSpaceFactoryRegistry * tqparent,
+ KisProfile *p);
+ virtual ~KisXyzColorSpace();
+
+ virtual bool willDegrade(ColorSpaceIndependence independence)
+ {
+ if (independence == TO_RGBA8)
+ return true;
+ else
+ return false;
+ };
+public:
+ // Pixel manipulation
+ virtual KisColorAdjustment *createBrightnessContrastAdjustment(TQ_UINT16 *transferValues);
+ virtual void applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels);
+ virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels);
+ virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const;
+ virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nPixels) const;
+ virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const;
+ virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const;
+
+ // Information about the colorstrategy
+ virtual TQValueVector<KisChannelInfo *> channels() const;
+ virtual TQ_UINT32 nChannels() const;
+ virtual TQ_UINT32 nColorChannels() const;
+ virtual TQ_UINT32 pixelSize() const;
+
+
+ // Composition
+
+ virtual void bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dststride,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op);
+
+ KisCompositeOpList userVisiblecompositeOps() const;
+
+protected:
+ void compositeOver(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeMultiply(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeDivide(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeScreen(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeOverlay(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeDodge(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeBurn(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeDarken(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeLighten(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+ void compositeErase(TQ_UINT8 *dst, TQ_INT32 dstRowStride, const TQ_UINT8 *src, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmask, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 columns, TQ_UINT16 opacity);
+
+private:
+
+ static const TQ_UINT8 PIXEL_X = 0;
+ static const TQ_UINT8 PIXEL_Y = 1;
+ static const TQ_UINT8 PIXEL_Z = 2;
+ static const TQ_UINT8 PIXEL_ALPHA = 3;
+
+ TQ_UINT8 * m_qcolordata; // A small buffer for conversion from and to qcolor.
+
+};
+
+#endif // KIS__COLORSPACE_XYZ_H_
diff --git a/chalk/chalkcolor/kis_abstract_colorspace.cc b/chalk/chalkcolor/kis_abstract_colorspace.cc
new file mode 100644
index 00000000..a19b9d69
--- /dev/null
+++ b/chalk/chalkcolor/kis_abstract_colorspace.cc
@@ -0,0 +1,762 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ * Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
+ *
+ * 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 <tqimage.h>
+
+#include <kdebug.h>
+#include <kconfig.h>
+
+#include "kis_abstract_colorspace.h"
+#include "kis_global.h"
+#include "kis_profile.h"
+#include "kis_id.h"
+#include "kis_integer_maths.h"
+#include "kis_color_conversions.h"
+#include "kis_colorspace_factory_registry.h"
+#include "kis_channelinfo.h"
+
+class KisColorAdjustmentImpl : public KisColorAdjustment
+{
+ public:
+
+ KisColorAdjustmentImpl() : KisColorAdjustment()
+ {
+ csProfile = 0;
+ transform = 0;
+ profiles[0] = 0;
+ profiles[1] = 0;
+ profiles[2] = 0;
+ };
+
+ ~KisColorAdjustmentImpl() {
+
+ if (transform)
+ cmsDeleteTransform(transform);
+ if (profiles[0] && profiles[0] != csProfile)
+ cmsCloseProfile(profiles[0]);
+ if(profiles[1] && profiles[1] != csProfile)
+ cmsCloseProfile(profiles[1]);
+ if(profiles[2] && profiles[2] != csProfile)
+ cmsCloseProfile(profiles[2]);
+ }
+
+ cmsHPROFILE csProfile;
+ cmsHPROFILE profiles[3];
+ cmsHTRANSFORM transform;
+};
+
+KisAbstractColorSpace::KisAbstractColorSpace(const KisID& id,
+ DWORD cmType,
+ icColorSpaceSignature colorSpaceSignature,
+ KisColorSpaceFactoryRegistry * tqparent,
+ KisProfile *p)
+ : m_parent( tqparent )
+ , m_profile( p )
+ , m_id( id )
+ , m_cmType( cmType )
+ , m_colorSpaceSignature( colorSpaceSignature )
+{
+ m_alphaPos = -1;
+ m_alphaSize = -1;
+ m_qcolordata = 0;
+ m_lastUsedDstColorSpace = 0;
+ m_lastUsedTransform = 0;
+ m_lastRGBProfile = 0;
+ m_lastToRGB = 0;
+ m_lastFromRGB = 0;
+ m_defaultFromRGB = 0;
+ m_defaultToRGB = 0;
+ m_defaultFromLab = 0;
+ m_defaultToLab = 0;
+}
+
+void KisAbstractColorSpace::init()
+{
+ // Default pixel buffer for TQColor conversion
+ m_qcolordata = new TQ_UINT8[3];
+ Q_CHECK_PTR(m_qcolordata);
+
+ if (m_profile == 0) return;
+
+ // For conversions from default rgb
+ m_lastFromRGB = cmsCreate_sRGBProfile();
+
+ m_defaultFromRGB = cmsCreateTransform(m_lastFromRGB, TYPE_BGR_8,
+ m_profile->profile(), m_cmType,
+ INTENT_PERCEPTUAL, 0);
+
+ m_defaultToRGB = cmsCreateTransform(m_profile->profile(), m_cmType,
+ m_lastFromRGB, TYPE_BGR_8,
+ INTENT_PERCEPTUAL, 0);
+
+ cmsHPROFILE hLab = cmsCreateLabProfile(NULL);
+
+ m_defaultFromLab = cmsCreateTransform(hLab, TYPE_Lab_16, m_profile->profile(), m_cmType,
+ INTENT_PERCEPTUAL, 0);
+
+ m_defaultToLab = cmsCreateTransform(m_profile->profile(), m_cmType, hLab, TYPE_Lab_16,
+ INTENT_PERCEPTUAL, 0);
+}
+
+KisAbstractColorSpace::~KisAbstractColorSpace()
+{
+}
+
+
+
+void KisAbstractColorSpace::fromTQColor(const TQColor& color, TQ_UINT8 *dst, KisProfile * profile)
+{
+ m_qcolordata[2] = color.red();
+ m_qcolordata[1] = color.green();
+ m_qcolordata[0] = color.blue();
+
+
+ if (profile == 0) {
+ // Default sRGB
+ if (!m_defaultFromRGB) return;
+
+ cmsDoTransform(m_defaultFromRGB, m_qcolordata, dst, 1);
+ }
+ else {
+ if (m_lastFromRGB == 0 || (m_lastFromRGB != 0 && m_lastRGBProfile != profile->profile())) {
+ m_lastFromRGB = cmsCreateTransform(profile->profile(), TYPE_BGR_8,
+ m_profile->profile(), m_cmType,
+ INTENT_PERCEPTUAL, 0);
+ m_lastRGBProfile = profile->profile();
+
+ }
+ cmsDoTransform(m_lastFromRGB, m_qcolordata, dst, 1);
+ }
+
+ setAlpha(dst, OPACITY_OPAQUE, 1);
+}
+
+void KisAbstractColorSpace::fromTQColor(const TQColor& color, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile)
+{
+ fromTQColor(color, dst, profile);
+ setAlpha(dst, opacity, 1);
+}
+
+void KisAbstractColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile)
+{
+ if (profile == 0) {
+ // Default sRGB transform
+ if (!m_defaultToRGB) return;
+ cmsDoTransform(m_defaultToRGB, const_cast <TQ_UINT8 *>(src), m_qcolordata, 1);
+ }
+ else {
+ if (m_lastToRGB == 0 || (m_lastToRGB != 0 && m_lastRGBProfile != profile->profile())) {
+ m_lastToRGB = cmsCreateTransform(m_profile->profile(), m_cmType,
+ profile->profile(), TYPE_BGR_8,
+ INTENT_PERCEPTUAL, 0);
+ m_lastRGBProfile = profile->profile();
+ }
+ cmsDoTransform(m_lastToRGB, const_cast <TQ_UINT8 *>(src), m_qcolordata, 1);
+ }
+ c->setRgb(m_qcolordata[2], m_qcolordata[1], m_qcolordata[0]);
+}
+
+void KisAbstractColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile)
+{
+ toTQColor(src, c, profile);
+ *opacity = getAlpha(src);
+}
+
+void KisAbstractColorSpace::toLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const
+{
+ if ( m_defaultToLab == 0 ) return;
+
+ cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8 *>( src ), dst, nPixels );
+}
+
+void KisAbstractColorSpace::fromLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const
+{
+ if ( m_defaultFromLab == 0 ) return;
+
+ cmsDoTransform( m_defaultFromLab, const_cast<TQ_UINT8 *>( src ), dst, nPixels );
+}
+
+
+void KisAbstractColorSpace::getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex)
+{
+ if (channelIndex < m_channels.count()) {
+
+ fromTQColor(TQt::black, OPACITY_TRANSPARENT, dstPixel);
+
+ const KisChannelInfo *channelInfo = m_channels[channelIndex];
+ memcpy(dstPixel + channelInfo->pos(), srcPixel + channelInfo->pos(), channelInfo->size());
+ }
+}
+
+bool KisAbstractColorSpace::convertPixelsTo(const TQ_UINT8 * src,
+ TQ_UINT8 * dst,
+ KisColorSpace * dstColorSpace,
+ TQ_UINT32 numPixels,
+ TQ_INT32 renderingIntent)
+{
+ if (dstColorSpace->colorSpaceType() == colorSpaceType()
+ && dstColorSpace->getProfile() == getProfile())
+ {
+ if (src!= dst)
+ memcpy (dst, src, numPixels * pixelSize());
+
+ return true;
+ }
+
+ cmsHTRANSFORM tf = 0;
+
+ TQ_INT32 srcPixelSize = pixelSize();
+ TQ_INT32 dstPixelSize = dstColorSpace->pixelSize();
+
+ if (m_lastUsedTransform != 0 && m_lastUsedDstColorSpace != 0) {
+ if (dstColorSpace->colorSpaceType() == m_lastUsedDstColorSpace->colorSpaceType() &&
+ dstColorSpace->getProfile() == m_lastUsedDstColorSpace->getProfile()) {
+ tf = m_lastUsedTransform;
+ }
+ }
+
+ if (!tf && m_profile && dstColorSpace->getProfile()) {
+
+ if (!m_transforms.tqcontains(dstColorSpace)) {
+ tf = createTransform(dstColorSpace,
+ m_profile,
+ dstColorSpace->getProfile(),
+ renderingIntent);
+ if (tf) {
+ // XXX: Should we clear the transform cache if it gets too big?
+ m_transforms[dstColorSpace] = tf;
+ }
+ }
+ else {
+ tf = m_transforms[dstColorSpace];
+ }
+
+ if ( tf ) {
+ m_lastUsedTransform = tf;
+ m_lastUsedDstColorSpace = dstColorSpace;
+ }
+ }
+
+ if (tf) {
+
+ cmsDoTransform(tf, const_cast<TQ_UINT8 *>(src), dst, numPixels);
+
+ // Lcms does nothing to the destination alpha channel so we must convert that manually.
+ while (numPixels > 0) {
+ TQ_UINT8 alpha = getAlpha(src);
+ dstColorSpace->setAlpha(dst, alpha, 1);
+
+ src += srcPixelSize;
+ dst += dstPixelSize;
+ numPixels--;
+ }
+
+ return true;
+ }
+
+ // Last resort fallback. This will be removed when this class is renamed KisLCMSColorSpace after 1.5.
+ while (numPixels > 0) {
+ TQColor color;
+ TQ_UINT8 opacity;
+
+ toTQColor(src, &color, &opacity);
+ dstColorSpace->fromTQColor(color, opacity, dst);
+
+ src += srcPixelSize;
+ dst += dstPixelSize;
+ numPixels--;
+ }
+
+ return true;
+}
+
+
+KisColorAdjustment *KisAbstractColorSpace::createBrightnessContrastAdjustment(TQ_UINT16 *transferValues)
+{
+ if (!m_profile) return 0;
+
+ LPGAMMATABLE transferFunctions[3];
+ transferFunctions[0] = cmsBuildGamma(256, 1.0);
+ transferFunctions[1] = cmsBuildGamma(256, 1.0);
+ transferFunctions[2] = cmsBuildGamma(256, 1.0);
+
+ for(int i =0; i < 256; i++)
+ transferFunctions[0]->GammaTable[i] = transferValues[i];
+
+ KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
+ adj->profiles[1] = cmsCreateLinearizationDeviceLink(icSigLabData, transferFunctions);
+ cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass);
+
+ adj->profiles[0] = m_profile->profile();
+ adj->profiles[2] = m_profile->profile();
+ adj->transform = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0);
+ adj->csProfile = m_profile->profile();
+ return adj;
+}
+
+typedef struct {
+ double Saturation;
+
+} BCHSWADJUSTS, *LPBCHSWADJUSTS;
+
+
+static int desaturateSampler(register WORD In[], register WORD Out[], register LPVOID /*Cargo*/)
+{
+ cmsCIELab LabIn, LabOut;
+ cmsCIELCh LChIn, LChOut;
+ //LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo;
+
+ cmsLabEncoded2Float(&LabIn, In);
+
+ cmsLab2LCh(&LChIn, &LabIn);
+
+ // Do some adjusts on LCh
+ LChOut.L = LChIn.L;
+ LChOut.C = 0;//LChIn.C + bchsw->Saturation;
+ LChOut.h = LChIn.h;
+
+ cmsLCh2Lab(&LabOut, &LChOut);
+
+ // Back to encoded
+ cmsFloat2LabEncoded(Out, &LabOut);
+
+ return TRUE;
+}
+
+KisColorAdjustment *KisAbstractColorSpace::createDesaturateAdjustment()
+{
+ if (!m_profile) return 0;
+
+ KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
+
+ adj->profiles[0] = m_profile->profile();
+ adj->profiles[2] = m_profile->profile();
+ adj->csProfile = m_profile->profile();
+
+ LPLUT Lut;
+ BCHSWADJUSTS bchsw;
+
+ bchsw.Saturation = -25;
+
+ adj->profiles[1] = _cmsCreateProfilePlaceholder();
+ if (!adj->profiles[1]) // can't allocate
+ return NULL;
+
+ cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass);
+ cmsSetColorSpace(adj->profiles[1], icSigLabData);
+ cmsSetPCS(adj->profiles[1], icSigLabData);
+
+ cmsSetRenderingIntent(adj->profiles[1], INTENT_PERCEPTUAL);
+
+ // Creates a LUT with 3D grid only
+ Lut = cmsAllocLUT();
+
+ cmsAlloc3DGrid(Lut, 32, 3, 3);
+
+ if (!cmsSample3DGrid(Lut, desaturateSampler, static_cast<LPVOID>(&bchsw), 0)) {
+ // Shouldn't reach here
+ cmsFreeLUT(Lut);
+ cmsCloseProfile(adj->profiles[1]);
+ return NULL;
+ }
+
+ // Create tags
+
+ cmsAddTag(adj->profiles[1], icSigDeviceMfgDescTag, (LPVOID) "(chalk internal)");
+ cmsAddTag(adj->profiles[1], icSigProfileDescriptionTag, (LPVOID) "chalk saturation abstract profile");
+ cmsAddTag(adj->profiles[1], icSigDeviceModelDescTag, (LPVOID) "saturation built-in");
+
+ cmsAddTag(adj->profiles[1], icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ());
+
+ cmsAddTag(adj->profiles[1], icSigAToB0Tag, (LPVOID) Lut);
+
+ // LUT is already on virtual profile
+ cmsFreeLUT(Lut);
+
+ adj->transform = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0);
+
+ return adj;
+}
+
+KisColorAdjustment *KisAbstractColorSpace::createPerChannelAdjustment(TQ_UINT16 **transferValues)
+{
+ if (!m_profile) return 0;
+
+ LPGAMMATABLE *transferFunctions = new LPGAMMATABLE[nColorChannels()+1];
+
+ for(uint ch=0; ch < nColorChannels(); ch++) {
+ transferFunctions[ch] = cmsBuildGamma(256, 1.0);
+ for(uint i =0; i < 256; i++) {
+ transferFunctions[ch]->GammaTable[i] = transferValues[ch][i];
+ }
+ }
+
+ KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
+ adj->profiles[0] = cmsCreateLinearizationDeviceLink(colorSpaceSignature(), transferFunctions);
+ adj->profiles[1] = NULL;
+ adj->profiles[2] = NULL;
+ adj->csProfile = m_profile->profile();
+ adj->transform = cmsCreateTransform(adj->profiles[0], m_cmType, NULL, m_cmType, INTENT_PERCEPTUAL, 0);
+
+ delete [] transferFunctions;
+
+ return adj;
+}
+
+
+void KisAbstractColorSpace::applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *adjustment, TQ_INT32 nPixels)
+{
+ KisColorAdjustmentImpl * adj = dynamic_cast<KisColorAdjustmentImpl*>(adjustment);
+ if (adj)
+ cmsDoTransform(adj->transform, const_cast<TQ_UINT8 *>(src), dst, nPixels);
+}
+
+
+void KisAbstractColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels)
+{
+ TQColor c;
+ TQ_UINT8 opacity;
+ TQ_UINT32 psize = pixelSize();
+
+ while (nPixels--)
+ {
+ toTQColor(src, &c, &opacity);
+ c.setRgb(TQ_UINT8_MAX - c.red(), TQ_UINT8_MAX - c.green(), TQ_UINT8_MAX - c.blue());
+ fromTQColor( c, opacity, src);
+
+ src += psize;
+ }
+}
+
+TQ_UINT8 KisAbstractColorSpace::difference(const TQ_UINT8* src1, const TQ_UINT8* src2)
+{
+ if (m_defaultToLab) {
+
+ TQ_UINT8 lab1[8], lab2[8];
+ cmsCIELab labF1, labF2;
+
+ if (getAlpha(src1) == OPACITY_TRANSPARENT || getAlpha(src2) == OPACITY_TRANSPARENT)
+ return (getAlpha(src1) == getAlpha(src2) ? 0 : 255);
+
+ cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8*>( src1 ), lab1, 1);
+ cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8*>( src2 ), lab2, 1);
+ cmsLabEncoded2Float(&labF1, (WORD *)lab1);
+ cmsLabEncoded2Float(&labF2, (WORD *)lab2);
+ double diff = cmsDeltaE(&labF1, &labF2);
+ if(diff>255)
+ return 255;
+ else
+ return TQ_INT8(diff);
+ }
+ else {
+ TQColor c1;
+ TQ_UINT8 opacity1;
+ toTQColor(src1, &c1, &opacity1);
+
+ TQColor c2;
+ TQ_UINT8 opacity2;
+ toTQColor(src2, &c2, &opacity2);
+
+ TQ_UINT8 red = abs(c1.red() - c2.red());
+ TQ_UINT8 green = abs(c1.green() - c2.green());
+ TQ_UINT8 blue = abs(c1.blue() - c2.blue());
+ return TQMAX(red, TQMAX(green, blue));
+ }
+}
+
+void KisAbstractColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const
+{
+ TQ_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0;
+
+ TQColor c;
+ TQ_UINT8 opacity;
+
+ while (nColors--)
+ {
+ // Ugly hack to get around the current constness mess of the colour strategy...
+ const_cast<KisAbstractColorSpace *>(this)->toTQColor(*colors, &c, &opacity);
+
+ TQ_UINT32 alphaTimesWeight = UINT8_MULT(opacity, *weights);
+
+ totalRed += c.red() * alphaTimesWeight;
+ totalGreen += c.green() * alphaTimesWeight;
+ totalBlue += c.blue() * alphaTimesWeight;
+ newAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ Q_ASSERT(newAlpha <= 255);
+
+ if (newAlpha > 0) {
+ totalRed = UINT8_DIVIDE(totalRed, newAlpha);
+ totalGreen = UINT8_DIVIDE(totalGreen, newAlpha);
+ totalBlue = UINT8_DIVIDE(totalBlue, newAlpha);
+ }
+
+ // Divide by 255.
+ totalRed += 0x80;
+
+ TQ_UINT32 dstRed = ((totalRed >> 8) + totalRed) >> 8;
+ Q_ASSERT(dstRed <= 255);
+
+ totalGreen += 0x80;
+ TQ_UINT32 dstGreen = ((totalGreen >> 8) + totalGreen) >> 8;
+ Q_ASSERT(dstGreen <= 255);
+
+ totalBlue += 0x80;
+ TQ_UINT32 dstBlue = ((totalBlue >> 8) + totalBlue) >> 8;
+ Q_ASSERT(dstBlue <= 255);
+
+ const_cast<KisAbstractColorSpace *>(this)->fromTQColor(TQColor(dstRed, dstGreen, dstBlue), newAlpha, dst);
+}
+
+void KisAbstractColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags,
+ TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const
+{
+ TQ_INT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0;
+
+ TQColor dstColor;
+ TQ_UINT8 dstOpacity;
+
+ const_cast<KisAbstractColorSpace *>(this)->toTQColor(dst, &dstColor, &dstOpacity);
+
+ while (nColors--)
+ {
+ TQ_INT32 weight = *kernelValues;
+
+ if (weight != 0) {
+ TQColor c;
+ TQ_UINT8 opacity;
+ const_cast<KisAbstractColorSpace *>(this)->toTQColor( *colors, &c, &opacity );
+ totalRed += c.red() * weight;
+ totalGreen += c.green() * weight;
+ totalBlue += c.blue() * weight;
+ totalAlpha += opacity * weight;
+ }
+ colors++;
+ kernelValues++;
+ }
+
+
+ if (channelFlags & KisChannelInfo::FLAG_COLOR) {
+ const_cast<KisAbstractColorSpace *>(this)->fromTQColor(TQColor(CLAMP((totalRed / factor) + offset, 0, TQ_UINT8_MAX),
+ CLAMP((totalGreen / factor) + offset, 0, TQ_UINT8_MAX),
+ CLAMP((totalBlue / factor) + offset, 0, TQ_UINT8_MAX)),
+ dstOpacity,
+ dst);
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ const_cast<KisAbstractColorSpace *>(this)->fromTQColor(dstColor, CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT8_MAX), dst);
+ }
+
+}
+
+void KisAbstractColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const
+{
+ if (m_defaultToLab) {
+ TQ_UINT16 * labcache = new TQ_UINT16[nPixels * 4];
+ cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8*>( src ), reinterpret_cast<TQ_UINT8*>( labcache ), nPixels );
+ for ( int i = 0; i < nPixels * 4; ++i ) {
+ if ( compensate ) {
+ labcache[i] = static_cast<TQ_UINT16>( ( labcache[i] * shade ) / ( compensation * 255 ) );
+ }
+ else {
+ labcache[i] = static_cast<TQ_UINT16>( labcache[i] * shade / 255 );
+ }
+ }
+ cmsDoTransform( m_defaultFromLab, reinterpret_cast<TQ_UINT8*>( labcache ), dst, nPixels );
+
+ // Copy alpha
+ for ( int i = 0; i < nPixels; ++i ) {
+ TQ_UINT8 alpha = getAlpha( src );
+ setAlpha( dst, alpha, 1 );
+ }
+ delete [] labcache;
+ }
+ else {
+
+ TQColor c;
+ TQ_INT32 psize = pixelSize();
+
+ for (int i = 0; i < nPixels; ++i) {
+
+ const_cast<KisAbstractColorSpace *>(this)->toTQColor(src + (i * psize), &c);
+ TQ_INT32 r, g, b;
+
+ if (compensate) {
+ r = static_cast<TQ_INT32>( TQMIN(255, (c.red() * shade) / (compensation * 255)));
+ g = static_cast<TQ_INT32>( TQMIN(255, (c.green() * shade) / (compensation * 255)));
+ b = static_cast<TQ_INT32>( TQMIN(255, (c.blue() * shade) / (compensation * 255)));
+ }
+ else {
+ r = static_cast<TQ_INT32>( TQMIN(255, (c.red() * shade / 255)));
+ g = static_cast<TQ_INT32>( TQMIN(255, (c.green() * shade / 255)));
+ b = static_cast<TQ_INT32>( TQMIN(255, (c.blue() * shade / 255)));
+ }
+ c.setRgb(r, g, b);
+
+ const_cast<KisAbstractColorSpace *>(this)->fromTQColor( c, dst + (i * psize));
+ }
+ }
+}
+
+TQ_UINT8 KisAbstractColorSpace::intensity8(const TQ_UINT8 * src) const
+{
+ TQColor c;
+ TQ_UINT8 opacity;
+ const_cast<KisAbstractColorSpace *>(this)->toTQColor(src, &c, &opacity);
+ return static_cast<TQ_UINT8>((c.red() * 0.30 + c.green() * 0.59 + c.blue() * 0.11) + 0.5);
+
+}
+
+
+KisID KisAbstractColorSpace::mathToolboxID() const
+{
+ return KisID("Basic");
+}
+
+void KisAbstractColorSpace::bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dststride,
+ KisColorSpace * srcSpace,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op)
+{
+ if (rows <= 0 || cols <= 0)
+ return;
+
+ if (this != srcSpace) {
+ TQ_UINT32 len = pixelSize() * rows * cols;
+
+ // If our conversion cache is too small, extend it.
+ if (!m_conversionCache.resize( len, TQGArray::SpeedOptim )) {
+ kdWarning() << "Could not allocate enough memory for the conversion!\n";
+ // XXX: We should do a slow, pixel by pixel bitblt here...
+ abort();
+ }
+
+ for (TQ_INT32 row = 0; row < rows; row++) {
+ srcSpace->convertPixelsTo(src + row * srcRowStride,
+ m_conversionCache.data() + row * cols * pixelSize(), this,
+ cols);
+ }
+
+ // The old srcRowStride is no longer valid because we converted to the current cs
+ srcRowStride = cols * pixelSize();
+
+ bitBlt(dst,
+ dststride,
+ m_conversionCache.data(),
+ srcRowStride,
+ srcAlphaMask,
+ tqmaskRowStride,
+ opacity,
+ rows,
+ cols,
+ op);
+
+ }
+ else {
+ bitBlt(dst,
+ dststride,
+ src,
+ srcRowStride,
+ srcAlphaMask,
+ tqmaskRowStride,
+ opacity,
+ rows,
+ cols,
+ op);
+ }
+}
+
+TQImage KisAbstractColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height,
+ KisProfile *dstProfile,
+ TQ_INT32 renderingIntent, float /*exposure*/)
+
+{
+ TQImage img = TQImage(width, height, 32, 0, TQImage::LittleEndian);
+ img.setAlphaBuffer( true );
+
+ KisColorSpace * dstCS;
+
+ if (dstProfile)
+ dstCS = m_parent->getColorSpace(KisID("RGBA",""),dstProfile->productName());
+ else
+ dstCS = m_parent->getRGB8();
+
+ if (data)
+ convertPixelsTo(const_cast<TQ_UINT8 *>(data), img.bits(), dstCS, width * height, renderingIntent);
+
+ return img;
+}
+
+
+cmsHTRANSFORM KisAbstractColorSpace::createTransform(KisColorSpace * dstColorSpace,
+ KisProfile * srcProfile,
+ KisProfile * dstProfile,
+ TQ_INT32 renderingIntent)
+{
+ KConfig * cfg = KGlobal::config();
+ bool bpCompensation = cfg->readBoolEntry("useBlackPointCompensation", false);
+
+ int flags = 0;
+
+ if (bpCompensation) {
+ flags = cmsFLAGS_BLACKPOINTCOMPENSATION;
+ }
+
+ if (dstColorSpace && dstProfile && srcProfile ) {
+ cmsHTRANSFORM tf = cmsCreateTransform(srcProfile->profile(),
+ colorSpaceType(),
+ dstProfile->profile(),
+ dstColorSpace->colorSpaceType(),
+ renderingIntent,
+ flags);
+
+ return tf;
+ }
+ return 0;
+}
+
+void KisAbstractColorSpace::compositeCopy(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 * /*tqmaskRowStart*/, TQ_INT32 /*tqmaskRowStride*/, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity)
+{
+ TQ_UINT8 *dst = dstRowStart;
+ const TQ_UINT8 *src = srcRowStart;
+ TQ_INT32 bytesPerPixel = pixelSize();
+
+ while (rows > 0) {
+ memcpy(dst, src, numColumns * bytesPerPixel);
+
+ if (opacity != OPACITY_OPAQUE) {
+ multiplyAlpha(dst, opacity, numColumns);
+ }
+
+ dst += dstRowStride;
+ src += srcRowStride;
+ --rows;
+ }
+}
+
diff --git a/chalk/chalkcolor/kis_abstract_colorspace.h b/chalk/chalkcolor/kis_abstract_colorspace.h
new file mode 100644
index 00000000..75dfd1ef
--- /dev/null
+++ b/chalk/chalkcolor/kis_abstract_colorspace.h
@@ -0,0 +1,312 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
+ * Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
+ *
+ * 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_ABSTRACT_COLORSPACE_H_
+#define KIS_ABSTRACT_COLORSPACE_H_
+
+#include <strings.h>
+
+#include <tqmap.h>
+#include <tqcolor.h>
+#include <tqstringlist.h>
+#include <tqpair.h>
+
+#include "kis_global.h"
+#include "kis_channelinfo.h"
+#include "kis_profile.h"
+#include "kis_id.h"
+#include "kis_composite_op.h"
+#include "kis_colorspace.h"
+#include "koffice_export.h"
+
+
+class TQPainter;
+class KisPixelRO;
+class KisColorSpaceFactoryRegistry;
+
+
+/**
+ * A colorspace strategy is the definition of a certain color model
+ * in Chalk.
+ */
+class KRITA_EXPORT KisAbstractColorSpace : public KisColorSpace {
+
+
+public:
+
+ /**
+ * @param id The unique human and machine readable identifiation of this colorspace
+ * @param cmType the lcms type indentification for this colorspace, may be 0
+ * @param colorSpaceSignature the icc identification for this colorspace, may be 0
+ * @param tqparent the registry that owns this instance
+ * @param profile the profile this colorspace uses for transforms
+ */
+ KisAbstractColorSpace(const KisID & id,
+ DWORD cmType,
+ icColorSpaceSignature colorSpaceSignature,
+ KisColorSpaceFactoryRegistry * tqparent,
+ KisProfile *profile);
+
+ void init();
+
+ virtual ~KisAbstractColorSpace();
+
+ virtual bool operator==(const KisAbstractColorSpace& rhs) const {
+ return (m_id == rhs.m_id && m_profile == rhs.m_profile);
+ }
+
+
+//================== Information about this color strategy ========================//
+
+public:
+
+
+ //========== Channels =====================================================//
+
+ // Return a vector describing all the channels this color model has.
+ virtual TQValueVector<KisChannelInfo *> channels() const = 0;
+
+ virtual TQ_UINT32 nChannels() const = 0;
+
+ virtual TQ_UINT32 nColorChannels() const = 0;
+
+ virtual TQ_UINT32 nSubstanceChannels() const { return 0; };
+
+ virtual TQ_UINT32 pixelSize() const = 0;
+
+ virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const = 0;
+
+ virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const = 0;
+
+ virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) = 0;
+
+ virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) = 0;
+
+ virtual void getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex);
+
+ //========== Identification ===============================================//
+
+ virtual KisID id() const { return m_id; }
+
+ void setColorSpaceType(TQ_UINT32 type) { m_cmType = type; }
+ TQ_UINT32 colorSpaceType() { return m_cmType; }
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return m_colorSpaceSignature; }
+
+ //========== Capabilities =================================================//
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const = 0;
+
+ /**
+ * Returns true if the colorspace supports channel values outside the
+ * (normalised) range 0 to 1.
+ */
+ virtual bool hasHighDynamicRange() const { return false; }
+
+ //========== Display profiles =============================================//
+
+ virtual KisProfile * getProfile() const { return m_profile; };
+
+
+//================= Conversion functions ==================================//
+
+
+ virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0);
+ virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0);
+
+ virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0);
+ virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0);
+
+
+ virtual void toLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const;
+ virtual void fromLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const;
+
+ virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height,
+ KisProfile * dstProfile,
+ TQ_INT32 renderingIntent = INTENT_PERCEPTUAL,
+ float exposure = 0.0f);
+
+ virtual bool convertPixelsTo(const TQ_UINT8 * src,
+ TQ_UINT8 * dst, KisColorSpace * dstColorSpace,
+ TQ_UINT32 numPixels,
+ TQ_INT32 renderingIntent = INTENT_PERCEPTUAL);
+
+//============================== Manipulation fucntions ==========================//
+
+
+//
+// The manipulation functions have default implementations that _convert_ the pixel
+// to a TQColor and back. Reimplement these methods in your color strategy!
+//
+ virtual KisColorAdjustment *createBrightnessContrastAdjustment(TQ_UINT16 *transferValues);
+
+ virtual KisColorAdjustment *createDesaturateAdjustment();
+
+ virtual KisColorAdjustment *createPerChannelAdjustment(TQ_UINT16 **transferValues);
+
+ virtual void applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels);
+
+ virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels);
+
+ virtual TQ_UINT8 difference(const TQ_UINT8* src1, const TQ_UINT8* src2);
+
+ virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const;
+
+ virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nPixels) const;
+
+ virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const;
+
+ virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const;
+
+ virtual KisID mathToolboxID() const;
+
+ virtual void bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dststride,
+ KisColorSpace * srcSpace,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op);
+
+//========================== END of Public API ========================================//
+
+protected:
+
+
+ /**
+ * Compose two byte arrays containing pixels in the same color
+ * model together.
+ */
+ virtual void bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dstRowSize,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op) = 0;
+
+ virtual cmsHTRANSFORM createTransform(KisColorSpace * dstColorSpace,
+ KisProfile * srcProfile,
+ KisProfile * dstProfile,
+ TQ_INT32 renderingIntent);
+
+ virtual void compositeCopy(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity);
+
+
+ // So I don't need to re-implement it everywhere.
+ template <typename ColorType,
+ typename NativeMult, typename Uint8ToNative, typename NativeOpacityTest,
+ int AlphaPos, int NonAlphaSize, int TotalSize>
+ void abstractCompositeAlphaDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride,
+ const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride,
+ const TQ_UINT8 *tqmaskRowStart, TQ_INT32 tqmaskRowStride,
+ TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity,
+ NativeMult nativeMult, Uint8ToNative uint8ToNative,
+ NativeOpacityTest nativeOpacityTest) {
+ while (rows > 0) {
+
+ const ColorType *src = reinterpret_cast<const ColorType*>(srcRowStart);
+ ColorType *dst = reinterpret_cast<ColorType*>(dstRowStart);
+ const TQ_UINT8 *tqmask = tqmaskRowStart;
+ TQ_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ ColorType srcAlpha = src[AlphaPos];
+ ColorType dstAlpha = dst[AlphaPos];
+
+ // apply the alphatqmask
+ if(tqmask != 0)
+ {
+ if(*tqmask != OPACITY_OPAQUE)
+ srcAlpha = nativeMult(srcAlpha, uint8ToNative(*tqmask));
+ tqmask++;
+ }
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = nativeMult(srcAlpha, uint8ToNative(opacity));
+ }
+
+ // not transparent
+ if (nativeOpacityTest(srcAlpha) && srcAlpha >= dstAlpha) {
+ dst[AlphaPos] = srcAlpha;
+ memcpy(dst, src, NonAlphaSize * sizeof(ColorType));
+ }
+
+ columns--;
+ src += TotalSize;
+ dst += TotalSize;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(tqmaskRowStart)
+ tqmaskRowStart += tqmaskRowStride;
+ }
+ }
+
+protected:
+
+ TQStringList m_profileFilenames;
+ TQ_UINT8 * m_qcolordata; // A small buffer for conversion from and to qcolor.
+ TQ_INT32 m_alphaPos; // The position in _bytes_ of the alpha channel
+ TQ_INT32 m_alphaSize; // The width in _bytes_ of the alpha channel
+
+ TQValueVector<KisChannelInfo *> m_channels;
+
+ KisColorSpaceFactoryRegistry * m_parent;
+
+private:
+
+ cmsHTRANSFORM m_defaultToRGB; // Default transform to 8 bit sRGB
+ cmsHTRANSFORM m_defaultFromRGB; // Default transform from 8 bit sRGB
+
+ cmsHPROFILE m_lastRGBProfile; // Last used profile to transform to/from RGB
+ cmsHTRANSFORM m_lastToRGB; // Last used transform to transform to RGB
+ cmsHTRANSFORM m_lastFromRGB; // Last used transform to transform from RGB
+
+ cmsHTRANSFORM m_defaultToLab;
+ cmsHTRANSFORM m_defaultFromLab;
+
+ KisProfile * m_profile;
+ KisColorSpace *m_lastUsedDstColorSpace;
+ cmsHTRANSFORM m_lastUsedTransform;
+
+ KisID m_id;
+ DWORD m_cmType; // The colorspace type as defined by littlecms
+ icColorSpaceSignature m_colorSpaceSignature; // The colorspace signature as defined in icm/icc files
+
+ // cmsHTRANSFORM is a void *, so this should work.
+ typedef TQMap<KisColorSpace *, cmsHTRANSFORM> TransformMap;
+ TransformMap m_transforms; // Cache for existing transforms
+
+ KisAbstractColorSpace(const KisAbstractColorSpace&);
+ KisAbstractColorSpace& operator=(const KisAbstractColorSpace&);
+
+ TQMemArray<TQ_UINT8> m_conversionCache; // XXX: This will be a bad problem when we have threading.
+};
+
+#endif // KIS_STRATEGY_COLORSPACE_H_
diff --git a/chalk/chalkcolor/kis_basic_histogram_producers.cc b/chalk/chalkcolor/kis_basic_histogram_producers.cc
new file mode 100644
index 00000000..b769a3d3
--- /dev/null
+++ b/chalk/chalkcolor/kis_basic_histogram_producers.cc
@@ -0,0 +1,484 @@
+/*
+ * Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be>
+ *
+ * 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 <tqstring.h>
+#include <klocale.h>
+
+#include "config.h"
+
+#ifdef HAVE_OPENEXR
+#include <half.h>
+#endif
+
+#include "kis_global.h"
+#include "kis_basic_histogram_producers.h"
+#include "kis_integer_maths.h"
+#include "kis_channelinfo.h"
+#include "kis_colorspace.h"
+#include "kis_lab_colorspace.h"
+
+KisLabColorSpace* KisGenericLabHistogramProducer::m_labCs = 0;
+
+
+KisBasicHistogramProducer::KisBasicHistogramProducer(const KisID& id, int channels, int nrOfBins, KisColorSpace *cs)
+ : m_channels(channels),
+ m_nrOfBins(nrOfBins),
+ m_colorSpace(cs),
+ m_id(id)
+{
+ m_bins.resize(m_channels);
+ for (int i = 0; i < m_channels; i++)
+ m_bins.at(i).resize(m_nrOfBins);
+ m_outLeft.resize(m_channels);
+ m_outRight.resize(m_channels);
+ m_count = 0;
+ m_from = 0.0;
+ m_width = 1.0;
+}
+
+void KisBasicHistogramProducer::clear() {
+ m_count = 0;
+ for (int i = 0; i < m_channels; i++) {
+ for (int j = 0; j < m_nrOfBins; j++) {
+ m_bins.at(i).at(j) = 0;
+ }
+ m_outRight.at(i) = 0;
+ m_outLeft.at(i) = 0;
+ }
+}
+
+void KisBasicHistogramProducer::makeExternalToInternal() {
+ // This function assumes that the pixel is has no 'gaps'. That is to say: if we start
+ // at byte 0, we can get to the end of the pixel by adding consecutive size()s of
+ // the channels
+ TQValueVector<KisChannelInfo *> c = channels();
+ uint count = c.count();
+ int currentPos = 0;
+
+ for (uint i = 0; i < count; i++) {
+ for (uint j = 0; j < count; j++) {
+ if (c.at(j)->pos() == currentPos) {
+ m_external.append(j);
+ break;
+ }
+ }
+ currentPos += c.at(m_external.at(m_external.count() - 1))->size();
+ }
+}
+
+// ------------ U8 ---------------------
+
+KisBasicU8HistogramProducer::KisBasicU8HistogramProducer(const KisID& id, KisColorSpace *cs)
+ : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
+{
+}
+
+TQString KisBasicU8HistogramProducer::positionToString(double pos) const {
+ return TQString("%1").tqarg(static_cast<TQ_UINT8>(pos * UINT8_MAX));
+}
+
+void KisBasicU8HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs)
+{
+ if (!pixels) return;
+ if (!cs) return;
+ if (nPixels == 0) return;
+
+ TQ_INT32 pSize = cs->pixelSize();
+
+ if ( selectionMask ) {
+ while (nPixels > 0) {
+ if ( ! (m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) {
+
+ for (int i = 0; i < m_channels; i++) {
+ m_bins.at(i).at(pixels[i])++;
+ }
+ m_count++;
+
+ }
+
+ pixels += pSize;
+ selectionMask++;
+ nPixels--;
+ }
+ }
+ else {
+ while (nPixels > 0) {
+ if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT) ) {
+
+ for (int i = 0; i < m_channels; i++) {
+ m_bins.at(i).at(pixels[i])++;
+ }
+ m_count++;
+
+ }
+
+ pixels += pSize;
+ nPixels--;
+ }
+ }
+}
+
+// ------------ U16 ---------------------
+
+KisBasicU16HistogramProducer::KisBasicU16HistogramProducer(const KisID& id, KisColorSpace *cs)
+ : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
+{
+}
+
+TQString KisBasicU16HistogramProducer::positionToString(double pos) const
+{
+ return TQString("%1").tqarg(static_cast<TQ_UINT8>(pos * UINT8_MAX));
+}
+
+double KisBasicU16HistogramProducer::maximalZoom() const
+{
+ return 1.0 / 255.0;
+}
+
+void KisBasicU16HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs)
+{
+ // The view
+ TQ_UINT16 from = static_cast<TQ_UINT16>(m_from * UINT16_MAX);
+ TQ_UINT16 width = static_cast<TQ_UINT16>(m_width * UINT16_MAX + 0.5); // We include the end
+ TQ_UINT16 to = from + width;
+ double factor = 255.0 / width;
+
+ TQ_INT32 pSize = cs->pixelSize();
+
+ if ( selectionMask ) {
+ TQ_UINT16* pixel = reinterpret_cast<TQ_UINT16*>(pixels);
+ while (nPixels > 0) {
+ if ( ! ((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
+ for (int i = 0; i < m_channels; i++) {
+ TQ_UINT16 value = pixel[i];
+ if (value > to)
+ m_outRight.at(i)++;
+ else if (value < from)
+ m_outLeft.at(i)++;
+ else
+ m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
+ }
+ m_count++;
+ }
+ pixels += pSize;
+ selectionMask++;
+ nPixels--;
+ }
+ }
+ else {
+ while (nPixels > 0) {
+ TQ_UINT16* pixel = reinterpret_cast<TQ_UINT16*>(pixels);
+
+ if ( ! (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
+ for (int i = 0; i < m_channels; i++) {
+ TQ_UINT16 value = pixel[i];
+ if (value > to)
+ m_outRight.at(i)++;
+ else if (value < from)
+ m_outLeft.at(i)++;
+ else
+ m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
+ }
+ m_count++;
+ }
+ pixels += pSize;
+ nPixels--;
+
+ }
+ }
+}
+
+// ------------ Float32 ---------------------
+KisBasicF32HistogramProducer::KisBasicF32HistogramProducer(const KisID& id, KisColorSpace *cs)
+ : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs)
+{
+}
+
+TQString KisBasicF32HistogramProducer::positionToString(double pos) const {
+ return TQString("%1").tqarg(static_cast<float>(pos)); // XXX I doubt this is correct!
+}
+
+double KisBasicF32HistogramProducer::maximalZoom() const {
+ // XXX What _is_ the maximal zoom here? I don't think there is one with floats, so this seems a fine compromis for the moment
+ return 1.0 / 255.0;
+}
+
+void KisBasicF32HistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) {
+ // The view
+ float from = static_cast<float>(m_from);
+ float width = static_cast<float>(m_width);
+ float to = from + width;
+ float factor = 255.0 / width;
+
+ TQ_INT32 pSize = cs->pixelSize();
+
+ if ( selectionMask ) {
+ while (nPixels > 0) {
+
+ float* pixel = reinterpret_cast<float*>(pixels);
+ if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
+ for (int i = 0; i < m_channels; i++) {
+ float value = pixel[i];
+ if (value > to)
+ m_outRight.at(i)++;
+ else if (value < from)
+ m_outLeft.at(i)++;
+ else
+ m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
+ }
+ m_count++;
+ }
+
+ pixels += pSize;
+ selectionMask++;
+ nPixels--;
+
+ }
+ }
+ else {
+ while (nPixels > 0) {
+
+ float* pixel = reinterpret_cast<float*>(pixels);
+ if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
+ for (int i = 0; i < m_channels; i++) {
+ float value = pixel[i];
+ if (value > to)
+ m_outRight.at(i)++;
+ else if (value < from)
+ m_outLeft.at(i)++;
+ else
+ m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
+ }
+ m_count++;
+ }
+
+ pixels += pSize;
+ nPixels--;
+
+ }
+ }
+}
+
+#ifdef HAVE_OPENEXR
+// ------------ Float16 Half ---------------------
+KisBasicF16HalfHistogramProducer::KisBasicF16HalfHistogramProducer(const KisID& id,
+ KisColorSpace *cs)
+ : KisBasicHistogramProducer(id, cs->nChannels(), 256, cs) {
+}
+
+TQString KisBasicF16HalfHistogramProducer::positionToString(double pos) const {
+ return TQString("%1").tqarg(static_cast<float>(pos)); // XXX I doubt this is correct!
+}
+
+double KisBasicF16HalfHistogramProducer::maximalZoom() const {
+ // XXX What _is_ the maximal zoom here? I don't think there is one with floats, so this seems a fine compromis for the moment
+ return 1.0 / 255.0;
+}
+
+void KisBasicF16HalfHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs) {
+ // The view
+ float from = static_cast<float>(m_from);
+ float width = static_cast<float>(m_width);
+ float to = from + width;
+ float factor = 255.0 / width;
+
+ TQ_INT32 pSize = cs->pixelSize();
+ if ( selectionMask ) {
+ while (nPixels > 0) {
+ half* pixel = reinterpret_cast<half*>(pixels);
+ if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
+ for (int i = 0; i < m_channels; i++) {
+ float value = pixel[i];
+ if (value > to)
+ m_outRight.at(i)++;
+ else if (value < from)
+ m_outLeft.at(i)++;
+ else
+ m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
+ }
+ m_count++;
+ }
+ pixels += pSize;
+ selectionMask++;
+ nPixels--;
+ }
+ }
+ else {
+ while (nPixels > 0) {
+ half* pixel = reinterpret_cast<half*>(pixels);
+ if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
+ for (int i = 0; i < m_channels; i++) {
+ float value = pixel[i];
+ if (value > to)
+ m_outRight.at(i)++;
+ else if (value < from)
+ m_outLeft.at(i)++;
+ else
+ m_bins.at(i).at(static_cast<TQ_UINT8>((value - from) * factor))++;
+ }
+ m_count++;
+ }
+ pixels += pSize;
+ nPixels--;
+ }
+ }
+}
+#endif
+
+// ------------ Generic RGB ---------------------
+KisGenericRGBHistogramProducer::KisGenericRGBHistogramProducer()
+ : KisBasicHistogramProducer(KisID("GENRGBHISTO", i18n("Generic RGB Histogram")),
+ 3, 256, 0) {
+ /* we set 0 as colorspece, because we are not based on a specific colorspace. This
+ is no problem for the superclass since we override channels() */
+ m_channelsList.append(new KisChannelInfo(i18n("R"), i18n("R"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(255,0,0)));
+ m_channelsList.append(new KisChannelInfo(i18n("G"), i18n("G"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(0,255,0)));
+ m_channelsList.append(new KisChannelInfo(i18n("B"), i18n("B"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, TQColor(0,0,255)));
+}
+
+TQValueVector<KisChannelInfo *> KisGenericRGBHistogramProducer::channels() {
+ return m_channelsList;
+}
+
+TQString KisGenericRGBHistogramProducer::positionToString(double pos) const {
+ return TQString("%1").tqarg(static_cast<TQ_UINT8>(pos * UINT8_MAX));
+}
+
+double KisGenericRGBHistogramProducer::maximalZoom() const {
+ return 1.0;
+}
+
+
+void KisGenericRGBHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs)
+{
+ for (int i = 0; i < m_channels; i++) {
+ m_outRight.at(i) = 0;
+ m_outLeft.at(i) = 0;
+ }
+
+ TQColor c;
+ TQ_INT32 pSize = cs->pixelSize();
+ if (selectionMask) {
+ while (nPixels > 0) {
+ if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
+ cs->toTQColor(pixels, &c);
+ m_bins.at(0).at(c.red())++;
+ m_bins.at(1).at(c.green())++;
+ m_bins.at(2).at(c.blue())++;
+
+ m_count++;
+ }
+ pixels += pSize;
+ selectionMask++;
+ nPixels--;
+ }
+
+ }
+ else {
+ while (nPixels > 0) {
+
+ if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
+ cs->toTQColor(pixels, &c);
+ m_bins.at(0).at(c.red())++;
+ m_bins.at(1).at(c.green())++;
+ m_bins.at(2).at(c.blue())++;
+
+ m_count++;
+ }
+ pixels += pSize;
+ nPixels--;
+ }
+ }
+}
+
+// ------------ Generic L*a*b* ---------------------
+KisGenericLabHistogramProducer::KisGenericLabHistogramProducer()
+ : KisBasicHistogramProducer(KisID("GENLABHISTO", i18n("L*a*b* Histogram")), 3, 256, 0) {
+ /* we set 0 as colorspace, because we are not based on a specific colorspace. This
+ is no problem for the superclass since we override channels() */
+ m_channelsList.append(new KisChannelInfo(i18n("L*"), i18n("L"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
+ m_channelsList.append(new KisChannelInfo(i18n("a*"), i18n("a"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
+ m_channelsList.append(new KisChannelInfo(i18n("b*"), i18n("b"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
+
+ if (!m_labCs) {
+ KisProfile *labProfile = new KisProfile(cmsCreateLabProfile(NULL));
+ m_labCs = new KisLabColorSpace(0, labProfile);
+ }
+ m_colorSpace = m_labCs;
+}
+KisGenericLabHistogramProducer::~KisGenericLabHistogramProducer()
+{
+ delete m_channelsList[0];
+ delete m_channelsList[1];
+ delete m_channelsList[2];
+}
+
+TQValueVector<KisChannelInfo *> KisGenericLabHistogramProducer::channels() {
+ return m_channelsList;
+}
+
+TQString KisGenericLabHistogramProducer::positionToString(double pos) const {
+ return TQString("%1").tqarg(static_cast<TQ_UINT16>(pos * UINT16_MAX));
+}
+
+double KisGenericLabHistogramProducer::maximalZoom() const {
+ return 1.0;
+}
+
+
+void KisGenericLabHistogramProducer::addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *cs)
+{
+ for (int i = 0; i < m_channels; i++) {
+ m_outRight.at(i) = 0;
+ m_outLeft.at(i) = 0;
+ }
+
+ TQ_UINT8 dst[8];
+ TQ_INT32 pSize = cs->pixelSize();
+
+ if (selectionMask) {
+ while (nPixels > 0) {
+ if ( !((m_skipUnselected && *selectionMask == 0) || (m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) ) {
+/*
+ cs->toTQColor(pixels, &c);
+ m_bins.at(0).at(c.red())++;
+*/
+ m_count++;
+ }
+ pixels += pSize;
+ selectionMask++;
+ nPixels--;
+ }
+ }
+ else {
+ while (nPixels > 0) {
+ if ( !(m_skipTransparent && cs->getAlpha(pixels) == OPACITY_TRANSPARENT)) {
+
+ cs->convertPixelsTo(pixels, dst, m_colorSpace, 1);
+ m_bins.at(0).at(m_colorSpace->scaleToU8(dst, 0))++;
+ m_bins.at(1).at(m_colorSpace->scaleToU8(dst, 1))++;
+ m_bins.at(2).at(m_colorSpace->scaleToU8(dst, 2))++;
+
+ m_count++;
+ }
+ pixels += pSize;
+ nPixels--;
+ }
+ }
+}
+
diff --git a/chalk/chalkcolor/kis_basic_histogram_producers.h b/chalk/chalkcolor/kis_basic_histogram_producers.h
new file mode 100644
index 00000000..8b913ece
--- /dev/null
+++ b/chalk/chalkcolor/kis_basic_histogram_producers.h
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be>
+ *
+ * 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_BASIC_HISTOGRAM_PRODUCERS_
+#define _KIS_BASIC_HISTOGRAM_PRODUCERS_
+
+#include <tqvaluevector.h>
+#include <klocale.h>
+
+#include "config.h"
+
+#include "kis_histogram_producer.h"
+#include "kis_colorspace.h"
+#include "kis_id.h"
+
+class KisLabColorSpace;
+
+class KisBasicHistogramProducer : public KisHistogramProducer {
+public:
+ KisBasicHistogramProducer(const KisID& id, int channels, int nrOfBins, KisColorSpace *colorSpace);
+ virtual ~KisBasicHistogramProducer() {}
+
+ virtual void clear();
+
+ virtual void setView(double from, double size) { m_from = from; m_width = size; }
+
+ virtual const KisID& id() const { return m_id; }
+ virtual TQValueVector<KisChannelInfo *> channels() { return m_colorSpace->channels(); }
+ virtual TQ_INT32 numberOfBins() { return m_nrOfBins; }
+ virtual double viewFrom() const { return m_from; }
+ virtual double viewWidth() const { return m_width; }
+
+ virtual TQ_INT32 count() { return m_count; }
+
+ virtual TQ_INT32 getBinAt(int channel, int position)
+ { return m_bins.at(externalToInternal(channel)).at(position); }
+
+ virtual TQ_INT32 outOfViewLeft(int channel)
+ { return m_outLeft.at(externalToInternal(channel)); }
+
+ virtual TQ_INT32 outOfViewRight(int channel)
+ { return m_outRight.at(externalToInternal(channel)); }
+
+protected:
+ /**
+ * The order in which channels() returns is not the same as the internal representation,
+ * that of the pixel internally. This method converts external usage to internal usage.
+ * This method uses some basic assumtpions about the tqlayout of the pixel, so _extremely_
+ * exotic spaces might want to override this (see makeExternalToInternal source for
+ * those assumptions)
+ **/
+ virtual int externalToInternal(int ext) {
+ if (channels().count() > 0 && m_external.count() == 0) // Set up the translation table
+ makeExternalToInternal();
+ return m_external.at(ext);
+ }
+ // not virtual since that is useless: we call it from constructor
+ void makeExternalToInternal();
+ typedef TQValueVector<TQ_UINT32> vBins;
+ TQValueVector<vBins> m_bins;
+ vBins m_outLeft, m_outRight;
+ double m_from, m_width;
+ TQ_INT32 m_count;
+ int m_channels, m_nrOfBins;
+ KisColorSpace *m_colorSpace;
+ KisID m_id;
+ TQValueVector<TQ_INT32> m_external;
+};
+
+class KisBasicU8HistogramProducer : public KisBasicHistogramProducer {
+public:
+ KisBasicU8HistogramProducer(const KisID& id, KisColorSpace *colorSpace);
+ virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace);
+ virtual TQString positionToString(double pos) const;
+ virtual double maximalZoom() const { return 1.0; }
+};
+
+class KisBasicU16HistogramProducer : public KisBasicHistogramProducer {
+public:
+ KisBasicU16HistogramProducer(const KisID& id, KisColorSpace *colorSpace);
+ virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace);
+ virtual TQString positionToString(double pos) const;
+ virtual double maximalZoom() const;
+};
+
+class KisBasicF32HistogramProducer : public KisBasicHistogramProducer {
+public:
+ KisBasicF32HistogramProducer(const KisID& id, KisColorSpace *colorSpace);
+ virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace);
+ virtual TQString positionToString(double pos) const;
+ virtual double maximalZoom() const;
+};
+
+#ifdef HAVE_OPENEXR
+class KisBasicF16HalfHistogramProducer : public KisBasicHistogramProducer {
+public:
+ KisBasicF16HalfHistogramProducer(const KisID& id, KisColorSpace *colorSpace);
+ virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace);
+ virtual TQString positionToString(double pos) const;
+ virtual double maximalZoom() const;
+};
+#endif
+
+/**
+ * Parametrized on a specific KisHistogramProducer. Its generated producers
+ * will have the same KisID as the factory's. This is acceptable because we can't mix
+ * Factories with Producers in the code because they are incompatible types, and
+ * in the GUI we actually only need a producer's name, not a factory's.
+ */
+template<class T> class KisBasicHistogramProducerFactory : public KisHistogramProducerFactory {
+public:
+ KisBasicHistogramProducerFactory(const KisID& id, KisColorSpace *colorSpace)
+ : KisHistogramProducerFactory(id), m_cs(colorSpace) {}
+ virtual ~KisBasicHistogramProducerFactory() {}
+ virtual KisHistogramProducerSP generate() { return new T(id(), m_cs); }
+ virtual bool isCompatibleWith(KisColorSpace* colorSpace) const { return colorSpace->id() == m_cs->id(); }
+ virtual float preferrednessLevelWith(KisColorSpace* /*colorSpace*/) const { return 1.0; }
+protected:
+ KisColorSpace *m_cs;
+};
+
+/**
+ * This is a Producer (with associated factory) that converts the pixels of the colorspace
+ * to RGB8 with toTQColor, and then does its counting on RGB. This is NOT registered with the
+ * Registry, because it isCompatibleWith all colorspaces, and should only be used in extreme
+ * cases (like no other producer being available
+ **/
+class KisGenericRGBHistogramProducer : public KisBasicHistogramProducer {
+public:
+ KisGenericRGBHistogramProducer();
+ virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace);
+ virtual TQString positionToString(double pos) const;
+ virtual double maximalZoom() const;
+ virtual TQValueVector<KisChannelInfo *> channels();
+protected:
+ TQValueVector<KisChannelInfo *> m_channelsList;
+};
+
+/** KisGenericRGBHistogramProducer his special Factory that isCompatibleWith everything. */
+class KisGenericRGBHistogramProducerFactory : public KisHistogramProducerFactory {
+public:
+ KisGenericRGBHistogramProducerFactory()
+ : KisHistogramProducerFactory(KisID("GENRGBHISTO", i18n("Generic RGB"))) {}
+ virtual ~KisGenericRGBHistogramProducerFactory() {}
+ virtual KisHistogramProducerSP generate() { return new KisGenericRGBHistogramProducer(); }
+ virtual bool isCompatibleWith(KisColorSpace*) const { return true; }
+ virtual float preferrednessLevelWith(KisColorSpace*) const { return 0.0; }
+};
+
+
+/**
+ * This is a Producer (with associated factory) that converts the pixels of the colorspace
+ * to L*a*b*, and then does its counting.
+ * It isCompatibleWith all colorspaces
+ **/
+class KisGenericLabHistogramProducer : public KisBasicHistogramProducer {
+ public:
+ KisGenericLabHistogramProducer();
+ virtual ~KisGenericLabHistogramProducer();
+ virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace *colorSpace);
+ virtual TQString positionToString(double pos) const;
+ virtual double maximalZoom() const;
+ virtual TQValueVector<KisChannelInfo *> channels();
+ protected:
+ TQValueVector<KisChannelInfo *> m_channelsList;
+ private:
+ static KisLabColorSpace* m_labCs;
+};
+
+/** KisGenericLabHistogramProducer his special Factory that isCompatibleWith everything. */
+class KisGenericLabHistogramProducerFactory : public KisHistogramProducerFactory {
+ public:
+ KisGenericLabHistogramProducerFactory()
+ : KisHistogramProducerFactory(KisID("GENLABHISTO", i18n("Generic L*a*b*"))) {}
+ virtual ~KisGenericLabHistogramProducerFactory() {}
+ virtual KisHistogramProducerSP generate() { return new KisGenericLabHistogramProducer(); }
+ virtual bool isCompatibleWith(KisColorSpace*) const { return true; }
+ virtual float preferrednessLevelWith(KisColorSpace*) const { return 0.0; }
+};
+
+
+#endif // _KIS_BASIC_HISTOGRAM_PRODUCERS_
diff --git a/chalk/chalkcolor/kis_channelinfo.h b/chalk/chalkcolor/kis_channelinfo.h
new file mode 100644
index 00000000..f8ec8301
--- /dev/null
+++ b/chalk/chalkcolor/kis_channelinfo.h
@@ -0,0 +1,115 @@
+/*
+ * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_CHANNELINFO_H_
+#define KIS_CHANNELINFO_H_
+
+#include <tqcolor.h>
+#include "tqstring.h"
+#include "ksharedptr.h"
+
+/**
+ * This class gives some basic information about a channel,
+ * that is, one of the components that makes up a particular
+ * pixel.
+ */
+class KisChannelInfo : public KShared {
+public:
+ enum enumChannelType {
+ COLOR, // The channel represents a color
+ ALPHA, // The channel represents the opacity of a pixel
+ SUBSTANCE, // The channel represents a real-world substance like pigments or medium
+ SUBSTRATE // The channel represents a real-world painting substrate like a canvas
+ };
+
+ enum enumChannelValueType {
+ UINT8,
+ UINT16,
+ FLOAT16,
+ FLOAT32,
+ INT8,
+ INT16,
+ OTHER // Use this if the channel is neither an integer or a float
+ };
+ enum enumChannelFlags {
+ FLAG_COLOR = 1,
+ FLAG_ALPHA = (1 << 1),
+ FLAG_SUBSTANCE = (1 << 2),
+ FLAG_SUBSTRATE = (1 << 3),
+ FLAG_COLOR_AND_ALPHA = FLAG_ALPHA | FLAG_COLOR // HACK to be able to use convolution of color and alpha at the same time
+ };
+
+public:
+ KisChannelInfo() { };
+ /**
+ * @param name The i18n'ed name of this channel ("Red")
+ * @param abbrev A one or two letter abbreviation of the name of this channel ("R")
+ * @param npos the position of the first byte of this channel value in the pixel
+ * @param channelType the type of this channel (color, alpha, etc)
+ * @param channelValueType the datatype of this channel
+ * @param size the size in bytes of this channel
+ * @param color a color to visually represent this channel by in the gui
+ */
+ KisChannelInfo( const TQString & name, const TQString & abbrev, TQ_INT32 npos, enumChannelType channelType, enumChannelValueType channelValueType, TQ_INT32 size = 1, TQColor color = TQColor(0,0,0))
+ : m_name (name), m_abbrev(abbrev), m_pos (npos), m_channelType(channelType), m_channelValueType(channelValueType), m_size(size), m_color(color) { };
+public:
+ /**
+ * User-friendly name for this channel for presentation purposes in the gui
+ */
+ inline TQString name() const { return m_name; };
+
+ /**
+ * Return the single-letter abbreviation for this channel
+ */
+ inline TQString abbrev() const { return m_abbrev; };
+ /**
+ * returns the position of the first byte of the channel in the pixel
+ */
+ inline TQ_INT32 pos() const { return m_pos; };
+
+ /**
+ * returns the number of bytes this channel takes
+ */
+ inline TQ_INT32 size() const { return m_size; };
+
+ /**
+ * returns the type of the channel
+ */
+ inline enumChannelType channelType() const { return m_channelType; };
+ /**
+ * return the type of the value of the channel (float, uint8 or uint16)
+ */
+ inline enumChannelValueType channelValueType() const { return m_channelValueType; };
+ /**
+ * This is a color that can be used to represent this channel in histograms and so.
+ * By default this is black, so keep in mind that many channels might look the same
+ */
+ inline TQColor color() const { return m_color; }
+
+private:
+
+ TQString m_name;
+ TQString m_abbrev;
+ TQ_INT32 m_pos;
+ enumChannelType m_channelType;
+ enumChannelValueType m_channelValueType;
+ TQ_INT32 m_size;
+ TQColor m_color;
+
+};
+
+#endif // KIS_CHANNELINFO_H_
diff --git a/chalk/chalkcolor/kis_color.cc b/chalk/chalkcolor/kis_color.cc
new file mode 100644
index 00000000..7d6acb89
--- /dev/null
+++ b/chalk/chalkcolor/kis_color.cc
@@ -0,0 +1,185 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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 <tqcolor.h>
+
+#include "kdebug.h"
+#include "kis_debug_areas.h"
+#include "kis_color.h"
+#include "kis_profile.h"
+#include "kis_colorspace.h"
+#include "kis_colorspace_factory_registry.h"
+
+KisColor::KisColor()
+{
+ m_data = 0;
+ m_colorSpace = 0;
+}
+
+KisColor::~KisColor()
+{
+ delete [] m_data;
+}
+
+KisColor::KisColor(const TQColor & color, KisColorSpace * colorSpace)
+ : m_colorSpace(colorSpace)
+{
+ Q_ASSERT(color.isValid());
+ Q_ASSERT(colorSpace);
+
+ m_data = new TQ_UINT8[colorSpace->pixelSize()];
+ memset(m_data, 0, m_colorSpace->pixelSize());
+
+ m_colorSpace->fromTQColor(color, OPACITY_OPAQUE, m_data);
+}
+
+
+KisColor::KisColor(const TQColor & color, TQ_UINT8 alpha, KisColorSpace * colorSpace)
+ : m_colorSpace(colorSpace)
+{
+ Q_ASSERT(color.isValid());
+ Q_ASSERT(colorSpace);
+ m_data = new TQ_UINT8[colorSpace->pixelSize()];
+ memset(m_data, 0, m_colorSpace->pixelSize());
+
+ m_colorSpace->fromTQColor(color, alpha, m_data);
+}
+
+KisColor::KisColor(const TQ_UINT8 * data, KisColorSpace * colorSpace)
+ : m_colorSpace(colorSpace)
+{
+
+ m_data = new TQ_UINT8[colorSpace->pixelSize()];
+ memset(m_data, 0, m_colorSpace->pixelSize());
+ memmove(m_data, data, colorSpace->pixelSize());
+}
+
+
+KisColor::KisColor(const KisColor &src, KisColorSpace * colorSpace)
+ : m_colorSpace(colorSpace)
+{
+ m_data = new TQ_UINT8[colorSpace->pixelSize()];
+ memset(m_data, 0, m_colorSpace->pixelSize());
+
+ src.colorSpace()->convertPixelsTo(src.data(), m_data, colorSpace, 1);
+}
+
+KisColor::KisColor(const KisColor & rhs)
+{
+ if (this == &rhs) return;
+
+ m_colorSpace = rhs.colorSpace();
+ m_data = new TQ_UINT8[m_colorSpace->pixelSize()];
+ memset(m_data, 0, m_colorSpace->pixelSize());
+ memcpy(m_data, rhs.data(), m_colorSpace->pixelSize());
+}
+
+KisColor & KisColor::operator=(const KisColor & rhs)
+{
+ delete [] m_data;
+ m_data = 0;
+ m_colorSpace = rhs.colorSpace();
+
+ if (rhs.m_colorSpace && rhs.m_data) {
+ m_data = new TQ_UINT8[m_colorSpace->pixelSize()];
+ memcpy(m_data, rhs.m_data, m_colorSpace->pixelSize());
+ }
+ return * this;
+}
+
+void KisColor::convertTo(KisColorSpace * cs)
+{
+ //kdDebug(DBG_AREA_CMS) << "Our colormodel: " << m_colorSpace->id().name()
+ // << ", new colormodel: " << cs->id().name() << "\n";
+
+ if (m_colorSpace == cs)
+ return;
+
+ TQ_UINT8 * m_data2 = new TQ_UINT8[cs->pixelSize()];
+ memset(m_data2, 0, cs->pixelSize());
+
+ m_colorSpace->convertPixelsTo(m_data, m_data2, cs, 1);
+
+ delete [] m_data;
+ m_data = m_data2;
+ m_colorSpace = cs;
+}
+
+
+void KisColor::setColor(TQ_UINT8 * data, KisColorSpace * colorSpace)
+{
+ delete [] m_data;
+ m_data = new TQ_UINT8[colorSpace->pixelSize()];
+ memcpy(m_data, data, colorSpace->pixelSize());
+ m_colorSpace = colorSpace;
+}
+
+// To save the user the trouble of doing color->colorSpace()->toTQColor(color->data(), &c, &a, profile
+void KisColor::toTQColor(TQColor *c) const
+{
+ if (m_colorSpace && m_data) {
+ // XXX (bsar): There must be a better way, but I'm getting hopelessly confused about constness by now
+ KisColorSpace * cs(const_cast<KisColorSpace*>(m_colorSpace));
+
+ cs->toTQColor(m_data, c);
+ }
+}
+
+void KisColor::toTQColor(TQColor *c, TQ_UINT8 *opacity) const
+{
+ if (m_colorSpace && m_data) {
+ // XXX (bsar): There must be a better way, but I'm getting hopelessly confused about constness by now
+ KisColorSpace * cs(const_cast<KisColorSpace*>(m_colorSpace));
+ cs->toTQColor(m_data, c, opacity);
+ }
+}
+
+TQColor KisColor::toTQColor() const
+{
+ TQColor c;
+ toTQColor(&c);
+ return c;
+}
+
+void KisColor::dump() const
+{
+
+ //kdDebug(DBG_AREA_CMS) << "KisColor (" << this << "), " << m_colorSpace->id().name() << "\n";
+ TQValueVector<KisChannelInfo *> channels = m_colorSpace->channels();
+
+ TQValueVector<KisChannelInfo *>::const_iterator begin = channels.begin();
+ TQValueVector<KisChannelInfo *>::const_iterator end = channels.end();
+
+ for (TQValueVector<KisChannelInfo *>::const_iterator it = begin; it != end; ++it)
+ {
+ KisChannelInfo * ch = (*it);
+ // XXX: setNum always takes a byte.
+ if (ch->size() == sizeof(TQ_UINT8)) {
+ // Byte
+ //kdDebug(DBG_AREA_CMS) << "Channel (byte): " << ch->name() << ": " << TQString().setNum(m_data[ch->pos()]) << "\n";
+ }
+ else if (ch->size() == sizeof(TQ_UINT16)) {
+ // Short (may also by an nvidia half)
+ //kdDebug(DBG_AREA_CMS) << "Channel (short): " << ch->name() << ": " << TQString().setNum(*((const TQ_UINT16 *)(m_data+ch->pos()))) << "\n";
+ }
+ else if (ch->size() == sizeof(TQ_UINT32)) {
+ // Integer (may also be float... Find out how to distinguish these!)
+ //kdDebug(DBG_AREA_CMS) << "Channel (int): " << ch->name() << ": " << TQString().setNum(*((const TQ_UINT32 *)(m_data+ch->pos()))) << "\n";
+ }
+ }
+
+}
diff --git a/chalk/chalkcolor/kis_color.h b/chalk/chalkcolor/kis_color.h
new file mode 100644
index 00000000..b7646586
--- /dev/null
+++ b/chalk/chalkcolor/kis_color.h
@@ -0,0 +1,90 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_COLOR_H_
+#define _KIS_COLOR_H_
+
+#include <tqcolor.h>
+#include "ksharedptr.h"
+
+#include "kis_global.h"
+#include "kis_profile.h"
+#include "kis_colorspace.h"
+
+
+/**
+ * A KisColor describes a color in a certain colorspace.
+ *
+ */
+class KisColor {
+
+public:
+ /// Create an empty KisColor. It will be valid, but also black and transparent
+ KisColor();
+
+ virtual ~KisColor();
+
+ /// Create a KisColor from a TQColor. The TQColor is immediately converted to native. The TQColor
+ /// is assumed to have the current monitor profile.
+ KisColor(const TQColor & color, KisColorSpace * colorSpace);
+
+ /// Create a KisColor from a TQColor. The TQColor is immediately converted to native. The TQColor
+ /// is assumed to have the current monitor profile.
+ KisColor(const TQColor & color, TQ_UINT8 alpha, KisColorSpace * colorSpace);
+
+ /// Create a KisColor using a native color strategy. The data is copied.
+ KisColor(const TQ_UINT8 * data, KisColorSpace * colorSpace);
+
+ /// Create a KisColor by converting src into another colorspace
+ KisColor(const KisColor &src, KisColorSpace * colorSpace);
+
+ /// Copy constructor -- deep copies the colors.
+ KisColor(const KisColor & rhs);
+
+ /// Effective C++, item 11
+ KisColor &operator=(const KisColor &);
+
+ /// For easy memcpy'ing etc.
+ TQ_UINT8 * data() const { return m_data; }
+
+ KisColorSpace * colorSpace() const { return m_colorSpace; }
+
+ KisProfile * profile() const { return m_colorSpace->getProfile(); }
+
+ /// Convert this KisColor to the specified colorspace. If the specified colorspace is the
+ /// same as the original colorspace, do nothing. Returns the converted KisColor.
+ void convertTo(KisColorSpace * cs);
+
+ /// Replace the existing color data, and colorspace with the specified data.
+ void setColor(TQ_UINT8 * data, KisColorSpace * colorSpace = 0);
+
+ /// To save the user the trouble of doing color->colorSpace()->toTQColor(color->data(), &c, &a
+ void toTQColor(TQColor *c) const;
+ void toTQColor(TQColor *c, TQ_UINT8 *opacity) const;
+
+ TQColor toTQColor() const;
+
+ void dump() const;
+
+private:
+
+ TQ_UINT8 * m_data;
+
+ KisColorSpace * m_colorSpace;
+};
+
+#endif
diff --git a/chalk/chalkcolor/kis_color_conversions.cc b/chalk/chalkcolor/kis_color_conversions.cc
new file mode 100644
index 00000000..e517c9f7
--- /dev/null
+++ b/chalk/chalkcolor/kis_color_conversions.cc
@@ -0,0 +1,427 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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 <cmath>
+
+#include <tqglobal.h>
+
+#include "kis_color_conversions.h"
+
+/**
+ * A number of often-used conversions between color models
+ */
+
+void rgb_to_hsv(int R, int G, int B, int *H, int *S, int *V)
+{
+ unsigned int max = R;
+ unsigned int min = R;
+ unsigned char maxValue = 0; // r = 0, g = 1, b = 2
+
+ // find maximum and minimum RGB values
+ if(static_cast<unsigned int>(G) > max) {
+ max = G;
+ maxValue = 1;
+ }
+
+ if (static_cast<unsigned int>(B) > max)
+ {
+ max = B;
+ maxValue = 2;
+ }
+
+ if(static_cast<unsigned int>(G) < min)
+ min = G;
+
+ if(static_cast<unsigned int>(B) < min )
+ min = B;
+
+ int delta = max - min;
+
+ // To prevent division by zero later on.
+ if (delta == 0) delta = 1;
+
+ *V = max; // value
+ *S = max ? (510 * delta + max) / ( 2 * max) : 0; // saturation
+
+ // calc hue
+ if(*S == 0)
+ *H = -1; // undefined hue
+ else
+ {
+ switch(maxValue)
+ {
+ case 0: // red
+ if(G >= B)
+ *H = (120 * (G - B) + delta) / (2 * delta);
+ else
+ *H = (120 * (G - B + delta) + delta) / (2 * delta) + 300;
+ break;
+ case 1: // green
+ if(B > R)
+ *H = 120 + (120 * (B - R) + delta) / (2 * delta);
+ else
+ *H = 60 + (120 * (B - R + delta) + delta) / (2 * delta);
+ break;
+ case 2: // blue
+ if(R > G)
+ *H = 240 + (120 * (R - G) + delta) / (2 * delta);
+ else
+ *H = 180 + (120 * (R - G + delta) + delta) / (2 * delta);
+ break;
+ }
+ }
+}
+
+void hsv_to_rgb(int H, int S, int V, int *R, int *G, int *B)
+{
+ *R = *G = *B = V;
+
+ if (S != 0 && H != -1) { // chromatic
+
+ if (H >= 360) {
+ // angle > 360
+ H %= 360;
+ }
+
+ unsigned int f = H % 60;
+ H /= 60;
+ unsigned int p = static_cast<unsigned int>(2*V*(255-S)+255)/510;
+ unsigned int q, t;
+
+ if (H & 1) {
+ q = static_cast<unsigned int>(2 * V * (15300 - S * f) + 15300) / 30600;
+ switch (H) {
+ case 1:
+ *R = static_cast<int>(q);
+ *G = static_cast<int>(V);
+ *B = static_cast<int>(p);
+ break;
+ case 3:
+ *R = static_cast<int>(p);
+ *G = static_cast<int>(q);
+ *B = static_cast<int>(V);
+ break;
+ case 5:
+ *R = static_cast<int>(V);
+ *G = static_cast<int>(p);
+ *B = static_cast<int>(q);
+ break;
+ }
+ } else {
+ t = static_cast<unsigned int>(2 * V * (15300 - (S * (60 - f))) + 15300) / 30600;
+ switch (H) {
+ case 0:
+ *R = static_cast<int>(V);
+ *G = static_cast<int>(t);
+ *B = static_cast<int>(p);
+ break;
+ case 2:
+ *R = static_cast<int>(p);
+ *G = static_cast<int>(V);
+ *B = static_cast<int>(t);
+ break;
+ case 4:
+ *R = static_cast<int>(t);
+ *G = static_cast<int>(p);
+ *B = static_cast<int>(V);
+ break;
+ }
+ }
+ }
+}
+
+#define EPSILON 1e-6
+#define UNDEFINED_HUE -1
+
+void RGBToHSV(float r, float g, float b, float *h, float *s, float *v)
+{
+ float max = TQMAX(r, TQMAX(g, b));
+ float min = TQMIN(r, TQMIN(g, b));
+
+ *v = max;
+
+ if (max > EPSILON) {
+ *s = (max - min) / max;
+ } else {
+ *s = 0;
+ }
+
+ if (*s < EPSILON) {
+ *h = UNDEFINED_HUE;
+ } else {
+ float delta = max - min;
+
+ if (r == max) {
+ *h = (g - b) / delta;
+ } else if (g == max) {
+ *h = 2 + (b - r) / delta;
+ } else {
+ *h = 4 + (r - g) / delta;
+ }
+
+ *h *= 60;
+ if (*h < 0) {
+ *h += 360;
+ }
+ }
+}
+
+void HSVToRGB(float h, float s, float v, float *r, float *g, float *b)
+{
+ if (s < EPSILON || h == UNDEFINED_HUE) {
+ // Achromatic case
+
+ *r = v;
+ *g = v;
+ *b = v;
+ } else {
+ float f, p, q, t;
+ int i;
+
+ if (h > 360 - EPSILON) {
+ h -= 360;
+ }
+
+ h /= 60;
+ i = static_cast<int>(floor(h));
+ f = h - i;
+ p = v * (1 - s);
+ q = v * (1 - (s * f));
+ t = v * (1 - (s * (1 - f)));
+
+ switch (i) {
+ case 0:
+ *r = v;
+ *g = t;
+ *b = p;
+ break;
+ case 1:
+ *r = q;
+ *g = v;
+ *b = p;
+ break;
+ case 2:
+ *r = p;
+ *g = v;
+ *b = t;
+ break;
+ case 3:
+ *r = p;
+ *g = q;
+ *b = v;
+ break;
+ case 4:
+ *r = t;
+ *g = p;
+ *b = v;
+ break;
+ case 5:
+ *r = v;
+ *g = p;
+ *b = q;
+ break;
+ }
+ }
+}
+
+void rgb_to_hls(TQ_UINT8 red, TQ_UINT8 green, TQ_UINT8 blue, float * hue, float * lightness, float * saturation)
+{
+ float r = red / 255.0;
+ float g = green / 255.0;
+ float b = blue / 255.0;
+ float h = 0;
+ float l = 0;
+ float s = 0;
+
+ float max, min, delta;
+
+ max = TQMAX(r, g);
+ max = TQMAX(max, b);
+
+ min = TQMIN(r, g);
+ min = TQMIN(min, b);
+
+ delta = max - min;
+
+ l = (max + min) / 2;
+
+ if (delta == 0) {
+ // This is a gray, no chroma...
+ h = 0;
+ s = 0;
+ }
+ else {
+ if ( l < 0.5)
+ s = delta / ( max + min );
+ else
+ s = delta / ( 2 - max - min );
+
+ float delta_r, delta_g, delta_b;
+
+ delta_r = (( max - r ) / 6 ) / delta;
+ delta_g = (( max - g ) / 6 ) / delta;
+ delta_b = (( max - b ) / 6 ) / delta;
+
+ if ( r == max )
+ h = delta_b - delta_g;
+ else if ( g == max)
+ h = ( 1.0 / 3 ) + delta_r - delta_b;
+ else if ( b == max)
+ h = ( 2.0 / 3 ) + delta_g - delta_r;
+
+ if (h < 0) h += 1;
+ if (h > 1) h += 1;
+
+ }
+
+ *hue = h * 360;
+ *saturation = s;
+ *lightness = l;
+}
+
+float hue_value(float n1, float n2, float hue)
+{
+ if (hue > 360 )
+ hue = hue -360;
+ else if (hue < 0 )
+ hue = hue +360;
+ if (hue < 60 )
+ return n1 + (((n2 - n1) * hue) / 60);
+ else if (hue < 180 )
+ return n2;
+ else if (hue < 240 )
+ return n1 + (((n2 - n1) * (240 - hue)) / 60);
+ else return n1;
+}
+
+
+void hls_to_rgb(float h, float l, float s, TQ_UINT8 * r, TQ_UINT8 * g, TQ_UINT8 * b)
+{
+ float m1, m2;
+
+ if (l <= 0.5 )
+ m2 = l * ( 1 + s );
+ else
+ m2 = l + s - l * s;
+
+ m1 = 2 * l - m2;
+
+ *r = (TQ_UINT8)(hue_value(m1, m2, h + 120) * 255 + 0.5);
+ *g = (TQ_UINT8)(hue_value(m1, m2, h) * 255 + 0.5);
+ *b = (TQ_UINT8)(hue_value(m1, m2, h - 120) * 255 + 0.5);
+
+}
+
+void rgb_to_hls(TQ_UINT8 r, TQ_UINT8 g, TQ_UINT8 b, int * h, int * l, int * s)
+{
+ float hue, saturation, lightness;
+
+ rgb_to_hls(r, g, b, &hue, &lightness, &saturation);
+ *h = (int)(hue + 0.5);
+ *l = (int)(lightness * 255 + 0.5);
+ *s = (int)(saturation * 255 + 0.5);
+}
+
+void hls_to_rgb(int h, int l, int s, TQ_UINT8 * r, TQ_UINT8 * g, TQ_UINT8 * b)
+{
+ float hue = h;
+ float lightness = l / 255.0;
+ float saturation = s / 255.0;
+
+ hls_to_rgb(hue, lightness, saturation, r, g, b);
+}
+
+/*
+A Fast HSL-to-RGB Transform
+by Ken Fishkin
+from "Graphics Gems", Academic Press, 1990
+*/
+
+void RGBToHSL(float r, float g, float b, float *h, float *s, float *l)
+{
+ float v;
+ float m;
+ float vm;
+ float r2, g2, b2;
+
+ v = TQMAX(r,g);
+ v = TQMAX(v,b);
+ m = TQMIN(r,g);
+ m = TQMIN(m,b);
+
+ if ((*l = (m + v) / 2.0) <= 0.0) {
+ *h = UNDEFINED_HUE;
+ *s = 0;
+ return;
+ }
+ if ((*s = vm = v - m) > 0.0) {
+ *s /= (*l <= 0.5) ? (v + m ) :
+ (2.0 - v - m) ;
+ } else {
+ *h = UNDEFINED_HUE;
+ return;
+ }
+
+
+ r2 = (v - r) / vm;
+ g2 = (v - g) / vm;
+ b2 = (v - b) / vm;
+
+ if (r == v)
+ *h = (g == m ? 5.0 + b2 : 1.0 - g2);
+ else if (g == v)
+ *h = (b == m ? 1.0 + r2 : 3.0 - b2);
+ else
+ *h = (r == m ? 3.0 + g2 : 5.0 - r2);
+
+ *h *= 60;
+}
+
+void HSLToRGB(float h, float sl, float l, float *r, float *g, float *b)
+
+{
+ float v;
+
+ v = (l <= 0.5) ? (l * (1.0 + sl)) : (l + sl - l * sl);
+ if (v <= 0) {
+ *r = *g = *b = 0.0;
+ } else {
+ float m;
+ float sv;
+ int sextant;
+ float fract, vsf, mid1, mid2;
+
+ m = l + l - v;
+ sv = (v - m ) / v;
+ h /= 60.0;
+ sextant = static_cast<int>(h);
+ fract = h - sextant;
+ vsf = v * sv * fract;
+ mid1 = m + vsf;
+ mid2 = v - vsf;
+ switch (sextant) {
+ case 0: *r = v; *g = mid1; *b = m; break;
+ case 1: *r = mid2; *g = v; *b = m; break;
+ case 2: *r = m; *g = v; *b = mid1; break;
+ case 3: *r = m; *g = mid2; *b = v; break;
+ case 4: *r = mid1; *g = m; *b = v; break;
+ case 5: *r = v; *g = m; *b = mid2; break;
+ }
+ }
+}
+
diff --git a/chalk/chalkcolor/kis_color_conversions.h b/chalk/chalkcolor/kis_color_conversions.h
new file mode 100644
index 00000000..53a476e0
--- /dev/null
+++ b/chalk/chalkcolor/kis_color_conversions.h
@@ -0,0 +1,49 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_CONVERSIONS_H_
+#define _KIS_CONVERSIONS_H_
+
+#include <tqglobal.h>
+
+/**
+ * A number of often-used conversions between color models
+ */
+
+// 8-bit integer versions. RGBSL are 0-255, H is 0-360.
+ void rgb_to_hsv(int R, int G, int B, int *H, int *S, int *V);
+ void hsv_to_rgb(int H, int S, int V, int *R, int *G, int *B);
+
+// Floating point versions. RGBSL are 0-1, H is 0-360.
+ void RGBToHSV(float r, float g, float b, float *h, float *s, float *v);
+ void HSVToRGB(float h, float s, float v, float *r, float *g, float *b);
+
+ void RGBToHSL(float r, float g, float b, float *h, float *s, float *l);
+ void HSLToRGB(float h, float sl, float l, float *r, float *g, float *b);
+
+ void rgb_to_hls(TQ_UINT8 r, TQ_UINT8 g, TQ_UINT8 b, float * h, float * l, float * s);
+
+ float hue_value(float n1, float n2, float hue);
+
+ void hls_to_rgb(float h, float l, float s, TQ_UINT8 * r, TQ_UINT8 * g, TQ_UINT8 * b);
+
+ void rgb_to_hls(TQ_UINT8 r, TQ_UINT8 g, TQ_UINT8 b, int * h, int * l, int * s);
+ void hls_to_rgb(int h, int l, int s, TQ_UINT8 * r, TQ_UINT8 * g, TQ_UINT8 * b);
+
+#endif // _KIS_CONVERSIONS_H_
+
diff --git a/chalk/chalkcolor/kis_colorspace.cc b/chalk/chalkcolor/kis_colorspace.cc
new file mode 100644
index 00000000..de0c44cf
--- /dev/null
+++ b/chalk/chalkcolor/kis_colorspace.cc
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_colorspace.h"
+#include "kis_colorspace_iface.h"
+
+KisColorSpace::KisColorSpace()
+{
+ m_dcop = 0;
+}
+
+KisColorSpace::~KisColorSpace()
+{
+ delete m_dcop;
+}
+
+DCOPObject * KisColorSpace::dcopObject()
+{
+ if (!m_dcop) {
+ m_dcop = new KisColorSpaceIface(this);
+ Q_CHECK_PTR(m_dcop);
+ }
+ return m_dcop;
+}
diff --git a/chalk/chalkcolor/kis_colorspace.h b/chalk/chalkcolor/kis_colorspace.h
new file mode 100644
index 00000000..6071909c
--- /dev/null
+++ b/chalk/chalkcolor/kis_colorspace.h
@@ -0,0 +1,450 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_COLORSPACE_H_
+#define KIS_COLORSPACE_H_
+
+#include <config.h>
+#include LCMS_HEADER
+
+#include <tqvaluevector.h>
+#include <tqvaluelist.h>
+
+#include "kis_composite_op.h"
+#include "kis_channelinfo.h"
+
+class DCOPObject;
+
+class KisProfile;
+class KisColorSpaceFactoryRegistry;
+class KisMathToolbox;
+class KisFilter;
+
+class KisColorAdjustment
+{
+public:
+
+ KisColorAdjustment() {};
+ virtual ~KisColorAdjustment() {};
+};
+
+
+enum ColorSpaceIndependence {
+ FULLY_INDEPENDENT,
+ TO_LAB16,
+ TO_RGBA8,
+ TO_RGBA16
+};
+
+/**
+ * A colorspace is the definition of a certain color model
+ * in Chalk. This is the definition of the public API for
+ * colormodels.
+ */
+class KisColorSpace {
+
+
+public:
+
+ KisColorSpace();
+ virtual ~KisColorSpace();
+
+ virtual DCOPObject * dcopObject();
+
+ virtual bool operator==(const KisColorSpace& rhs) const {
+ return id().id() == rhs.id().id();
+ }
+
+
+public:
+
+ //========== Channels =====================================================//
+
+ /// Return a vector describing all the channels this color model has.
+ virtual TQValueVector<KisChannelInfo *> channels() const = 0;
+
+ /**
+ * The total number of channels for a single pixel in this color model
+ */
+ virtual TQ_UINT32 nChannels() const = 0;
+
+ /**
+ * The total number of color channels (excludes alpha and substance) for a single
+ * pixel in this color model.
+ */
+ virtual TQ_UINT32 nColorChannels() const = 0;
+
+ /**
+ * The total number of substance channels for a single pixel
+ * in this color model
+ */
+ virtual TQ_UINT32 nSubstanceChannels() const { return 0; };
+
+ /**
+ * The size in bytes of a single pixel in this color model
+ */
+ virtual TQ_UINT32 pixelSize() const = 0;
+
+ /**
+ * Return a string with the channel's value suitable for display in the gui.
+ */
+ virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const = 0;
+
+ /**
+ * Return a string with the channel's value with integer
+ * channels normalised to the floating point range 0 to 1, if appropriate.
+ */
+ virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const = 0;
+
+ /**
+ * Convert the value of the channel at the specified position into
+ * an 8-bit value. The position is not the number of bytes, but
+ * the position of the channel as defined in the channel info list.
+ */
+ virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) = 0;
+
+ /**
+ * Convert the value of the channel at the specified position into
+ * a 16-bit value. This may be upscaling or downscaling, depending
+ * on the defined value of the channel
+ */
+ virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) = 0;
+
+ /**
+ * Set dstPixel to the pixel containing only the given channel of srcPixel. The remaining channels
+ * should be set to whatever makes sense for 'empty' channels of this colour space,
+ * with the intent being that the pixel should look like it only has the given channel.
+ */
+ virtual void getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex) = 0;
+
+ //========== Identification ===============================================//
+
+ /**
+ * Chalk definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const = 0;
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual TQ_UINT32 colorSpaceType() = 0;
+
+ virtual icColorSpaceSignature colorSpaceSignature() = 0;
+
+ /**
+ * If false, images in this colorspace will degrade considerably by
+ * functions, tools and filters that have the given measure of colorspace
+ * independence.
+ *
+ * @param independence the measure to which this colorspace will suffer
+ * from the manipulations of the tool or filter asking
+ * @return false if no degradation will take place, true if degradation will
+ * take place
+ */
+ virtual bool willDegrade(ColorSpaceIndependence independence) = 0;
+
+ //========== Capabilities =================================================//
+
+ /**
+ * Returns the list of user-visible composite ops supported by this colourspace. Internal
+ * ops such as COPY, CLEAR, and ERASE, are not included as these make no sense
+ * for layers in the full image model.
+ */
+ virtual KisCompositeOpList userVisiblecompositeOps() const = 0;
+
+ /**
+ * Returns true if the colorspace supports channel values outside the
+ * (normalised) range 0 to 1.
+ */
+ virtual bool hasHighDynamicRange() const = 0;
+
+
+ //========== Display profiles =============================================//
+
+ /**
+ * Return the profile of this color space. This may be 0
+ */
+ virtual KisProfile * getProfile() const = 0;
+
+//================= Conversion functions ==================================//
+
+
+ /**
+ * The fromTQColor methods take a given color defined as an RGB TQColor
+ * and fills a byte array with the corresponding color in the
+ * the colorspace managed by this strategy.
+ *
+ * @param c the TQColor that will be used to fill dst
+ * @param dst a pointer to a pixel
+ * @param profile the optional profile that describes the color values of TQColor
+ */
+ virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0) = 0;
+
+ /**
+ * The fromTQColor methods take a given color defined as an RGB TQColor
+ * and fills a byte array with the corresponding color in the
+ * the colorspace managed by this strategy.
+ *
+ * @param c the TQColor that will be used to fill dst
+ * @param opacity the opacity of the color
+ * @param dst a pointer to a pixel
+ * @param profile the optional profile that describes the color values of TQColor
+ */
+ virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0) = 0;
+
+
+ /**
+ * The toTQColor methods take a byte array that is at least pixelSize() long
+ * and converts the contents to a TQColor, using the given profile as a source
+ * profile and the optional profile as a destination profile.
+ *
+ * @param src a pointer to the source pixel
+ * @param c the TQColor that will be filled with the color at src
+ * @param profile the optional profile that describes the color in c, for instance the monitor profile
+ */
+ virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0) = 0;
+
+ /**
+ * The toTQColor methods take a byte array that is at least pixelSize() long
+ * and converts the contents to a TQColor, using the given profile as a source
+ * profile and the option profile as a destination profile.
+ *
+ * @param src a pointer to the source pixel
+ * @param c the TQColor that will be filled with the color at src
+ * @param opacity a pointer to a byte that will be filled with the opacity a src
+ * @param profile the optional profile that describes the color in c, for instance the monitor profile
+ */
+ virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0) = 0;
+
+ /**
+ * Convert the pixels in data to (8-bit BGRA) TQImage using the specified profiles.
+ * The pixels are supposed to be encoded in this color model. The default implementation
+ * will convert the pixels using either the profiles or the default profiles for the
+ * current colorstrategy and the RGBA colorstrategy. If that is not what you want,
+ * or if you think you can do better than lcms, reimplement this methods.
+ *
+ * @param data A pointer to a contiguous memory region containing width * height pixels
+ * @param width in pixels
+ * @param height in pixels
+ * @param dstProfile destination profile
+ * @param renderingIntent the rendering intent
+ * @param exposure The exposure setting for rendering a preview of a high dynamic range image.
+ */
+ virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height,
+ KisProfile * dstProfile, TQ_INT32 renderingIntent = INTENT_PERCEPTUAL,
+ float exposure = 0.0f) = 0;
+
+
+ /**
+ * Convert the specified data to Lab. All colorspaces are guaranteed to support this
+ *
+ * @param src the source data
+ * @param dst the destination data
+ * @param nPixels the number of source pixels
+ */
+ virtual void toLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const = 0;
+
+ /**
+ * Convert the specified data from Lab. to this colorspace. All colorspaces are
+ * guaranteed to support this.
+ *
+ * @param src the pixels in 16 bit lab format
+ * @param dst the destination data
+ * @param nPixels the number of pixels in the array
+ */
+ virtual void fromLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const = 0;
+
+ /**
+ * Convert a byte array of srcLen pixels *src to the specified color space
+ * and put the converted bytes into the prepared byte array *dst.
+ *
+ * Returns false if the conversion failed, true if it succeeded
+ */
+ virtual bool convertPixelsTo(const TQ_UINT8 * src,
+ TQ_UINT8 * dst, KisColorSpace * dstColorSpace,
+ TQ_UINT32 numPixels,
+ TQ_INT32 renderingIntent = INTENT_PERCEPTUAL) = 0;
+
+//============================== Manipulation functions ==========================//
+
+
+//
+// The manipulation functions have default implementations that _convert_ the pixel
+// to a TQColor and back. Reimplement these methods in your color strategy!
+//
+
+ /**
+ * Get the alpha value of the given pixel, downscaled to an 8-bit value.
+ */
+ virtual TQ_UINT8 getAlpha(const TQ_UINT8 * pixel) const = 0;
+
+ /**
+ * Set the alpha channel of the given run of pixels to the given value.
+ *
+ * pixels -- a pointer to the pixels that will have their alpha set to this value
+ * alpha -- a downscaled 8-bit value for opacity
+ * nPixels -- the number of pixels
+ *
+ */
+ virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const = 0;
+
+ /**
+ * Multiply the alpha channel of the given run of pixels by the given value.
+ *
+ * pixels -- a pointer to the pixels that will have their alpha set to this value
+ * alpha -- a downscaled 8-bit value for opacity
+ * nPixels -- the number of pixels
+ *
+ */
+ virtual void multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) = 0;
+
+ /**
+ * Applies the specified 8-bit alpha tqmask to the pixels. We assume that there are just
+ * as many alpha values as pixels but we do not check this; the alpha values
+ * are assumed to be 8-bits.
+ */
+ virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels) = 0;
+
+ /**
+ * Applies the inverted 8-bit alpha tqmask to the pixels. We assume that there are just
+ * as many alpha values as pixels but we do not check this; the alpha values
+ * are assumed to be 8-bits.
+ */
+ virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels) = 0;
+
+ /**
+ * Create an adjustment object for adjusting the brightness and contrast
+ * transferValues is a 256 bins array with values from 0 to 0xFFFF
+ */
+ virtual KisColorAdjustment *createBrightnessContrastAdjustment(TQ_UINT16 *transferValues) = 0;
+
+ /**
+ * Create an adjustment object for desaturating
+ */
+ virtual KisColorAdjustment *createDesaturateAdjustment() = 0;
+
+ /**
+ * Create an adjustment object for adjusting individual channels
+ * transferValues is an array of nColorChannels number of 256 bins array with values from 0 to 0xFFFF
+ */
+ virtual KisColorAdjustment *createPerChannelAdjustment(TQ_UINT16 **transferValues) = 0;
+
+ /**
+ * Apply the adjustment created with onr of the other functions
+ */
+ virtual void applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels) = 0;
+
+ /**
+ * Invert color channels of the given pixels
+ */
+ virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels) = 0;
+
+ // XXX: What with alpha channels? YYY: Add an overloaded function that takes alpha into account?
+ /**
+ * Get the difference between 2 colors, normalized in the range (0,255)
+ */
+ virtual TQ_UINT8 difference(const TQ_UINT8* src1, const TQ_UINT8* src2) = 0;
+
+
+ /**
+ * Mix the colors given their weights and return in dst
+ * The sum of weights is assumed 255 */
+ virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const = 0;
+
+ /**
+ * Convolve the given array of pointers to pixels and return the result
+ * in dst. The kernel values are clamped between -128 and 128
+ */
+ virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nPixels) const = 0;
+
+ /**
+ * Darken all color channels with the given amount. If compensate is true,
+ * the compensation factor will be used to limit the darkening.
+ *
+ * (See the bumpmap filter)
+ */
+ virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const = 0;
+
+ /**
+ * Calculate the intensity of the given pixel, scaled down to the range 0-255. XXX: Maybe this should be more flexible
+ */
+ virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const = 0;
+
+ /**
+ * Create a mathematical toolbox compatible with this colorspace
+ */
+ virtual KisID mathToolboxID() const =0;
+
+ /**
+ * Compose two arrays of pixels together. If source and target
+ * are not the same colour model, the source pixels will be
+ * converted to the target model.
+ */
+ virtual void bitBlt(TQ_UINT8 *dst,
+ TQ_INT32 dststride,
+ KisColorSpace * srcSpace,
+ const TQ_UINT8 *src,
+ TQ_INT32 srcRowStride,
+ const TQ_UINT8 *srcAlphaMask,
+ TQ_INT32 tqmaskRowStride,
+ TQ_UINT8 opacity,
+ TQ_INT32 rows,
+ TQ_INT32 cols,
+ const KisCompositeOp& op) = 0;
+
+ /**
+ * The backgroundfilters will be run periodically on the newly
+ * created paint device. XXX: Currently this uses times and not
+ * threads.
+ */
+ virtual TQValueList<KisFilter*> createBackgroundFilters()
+ { return TQValueList<KisFilter*>(); };
+
+private:
+
+ DCOPObject * m_dcop;
+
+};
+
+class KisColorSpaceFactory {
+public:
+ /**
+ * Chalk definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const = 0;
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual TQ_UINT32 colorSpaceType() = 0;
+
+ virtual icColorSpaceSignature colorSpaceSignature() = 0;
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * tqparent, KisProfile *) = 0;
+
+ /**
+ * Returns the default icc profile for use with this colorspace. This may be ""
+ *
+ & @return the default icc profile name
+ */
+ virtual TQString defaultProfile() = 0;
+
+};
+
+#endif // KIS_COLORSPACE_H_
diff --git a/chalk/chalkcolor/kis_colorspace_factory_registry.cc b/chalk/chalkcolor/kis_colorspace_factory_registry.cc
new file mode 100644
index 00000000..6758f7d5
--- /dev/null
+++ b/chalk/chalkcolor/kis_colorspace_factory_registry.cc
@@ -0,0 +1,222 @@
+/*
+ * Copyright (c) 2003 Patrick Julien <freak@codepimps.org>
+ * Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
+ *
+ * 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 "kdebug.h"
+#include <kparts/plugin.h>
+#include <kservice.h>
+#include <ktrader.h>
+#include <kparts/componentfactory.h>
+#include <kmessagebox.h>
+#include <klocale.h>
+#include "kis_debug_areas.h"
+#include "kis_colorspace.h"
+#include "kis_profile.h"
+#include "kis_colorspace_factory_registry.h"
+#include "kis_alpha_colorspace.h"
+#include "kis_lab_colorspace.h"
+
+
+KisColorSpaceFactoryRegistry::KisColorSpaceFactoryRegistry(TQStringList profileFilenames)
+{
+ // Create the built-in colorspaces
+
+ m_alphaCs = new KisAlphaColorSpace(this, 0);
+
+ // Load the profiles
+ if (!profileFilenames.empty()) {
+ KisProfile * profile = 0;
+ for ( TQStringList::Iterator it = profileFilenames.begin(); it != profileFilenames.end(); ++it ) {
+ profile = new KisProfile(*it);
+ Q_CHECK_PTR(profile);
+
+ profile->load();
+ if (profile->valid()) {
+ m_profileMap[profile->productName()] = profile;
+ }
+ }
+ }
+
+ KisProfile *labProfile = new KisProfile(cmsCreateLabProfile(NULL));
+ addProfile(labProfile);
+ add(new KisLabColorSpaceFactory());
+/* XXX where to put this
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicU16HistogramProducer>
+ (KisID("LABAHISTO", i18n("L*a*b* Histogram")), new KisLabColorSpace(this, 0);) );
+*/
+
+ // Load all colorspace modules
+ KTrader::OfferList offers = KTrader::self()->query(TQString::tqfromLatin1("Chalk/ColorSpace"),
+ TQString::tqfromLatin1("(Type == 'Service') and "
+ "([X-Chalk-Version] == 2)"));
+
+ if (offers.empty()) {
+ KMessageBox::sorry(0, i18n("Cannot start Chalk: no colorspaces available."));
+ abort();
+ }
+
+ KTrader::OfferList::ConstIterator iter;
+ for(iter = offers.begin(); iter != offers.end(); ++iter)
+ {
+ KService::Ptr service = *iter;
+ int errCode = 0;
+ KParts::Plugin* plugin =
+ KParts::ComponentFactory::createInstanceFromService<KParts::Plugin> ( service, this, 0, TQStringList(), &errCode);
+ if ( plugin )
+ kdDebug(DBG_AREA_PLUGINS) << "found colorspace " << service->property("Name").toString() << "\n";
+ else {
+ kdDebug(41006) << "found plugin " << service->property("Name").toString() << ", " << errCode << "\n";
+ if( errCode == KParts::ComponentFactory::ErrNoLibrary)
+ {
+ kdWarning(41006) << " Error loading plugin was : ErrNoLibrary " << KLibLoader::self()->lastErrorMessage() << endl;
+ }
+ }
+ }
+}
+
+KisColorSpaceFactoryRegistry::KisColorSpaceFactoryRegistry()
+{
+}
+
+KisColorSpaceFactoryRegistry::~KisColorSpaceFactoryRegistry()
+{
+}
+
+KisProfile * KisColorSpaceFactoryRegistry::getProfileByName(const TQString & name)
+{
+ if (m_profileMap.tqfind(name) == m_profileMap.end()) {
+ return 0;
+ }
+
+ return m_profileMap[name];
+}
+
+TQValueVector<KisProfile *> KisColorSpaceFactoryRegistry::profilesFor(KisID id)
+{
+ return profilesFor(get(id));
+}
+
+TQValueVector<KisProfile *> KisColorSpaceFactoryRegistry::profilesFor(KisColorSpaceFactory * csf)
+{
+
+ TQValueVector<KisProfile *> profiles;
+
+ TQMap<TQString, KisProfile * >::Iterator it;
+ for (it = m_profileMap.begin(); it != m_profileMap.end(); ++it) {
+ KisProfile * profile = it.data();
+ if (profile->colorSpaceSignature() == csf->colorSpaceSignature()) {
+ profiles.push_back(profile);
+ }
+ }
+ return profiles;
+}
+
+void KisColorSpaceFactoryRegistry::addProfile(KisProfile *p)
+{
+ if (p->valid()) {
+ m_profileMap[p->productName()] = p;
+ }
+}
+
+void KisColorSpaceFactoryRegistry::addPaintDeviceAction(KisColorSpace* cs,
+ KisPaintDeviceAction* action) {
+ m_paintDevActionMap[cs->id()].append(action);
+}
+
+TQValueVector<KisPaintDeviceAction *>
+KisColorSpaceFactoryRegistry::paintDeviceActionsFor(KisColorSpace* cs) {
+ return m_paintDevActionMap[cs->id()];
+}
+
+KisColorSpace * KisColorSpaceFactoryRegistry::getColorSpace(const KisID & csID, const TQString & pName)
+{
+ TQString profileName = pName;
+
+ if(profileName.isEmpty())
+ {
+ KisColorSpaceFactory *csf = get(csID);
+
+ if(!csf)
+ return 0;
+
+ profileName = csf->defaultProfile();
+ }
+
+ TQString name = csID.id() + "<comb>" + profileName;
+
+ if (m_csMap.tqfind(name) == m_csMap.end()) {
+ KisColorSpaceFactory *csf = get(csID);
+ if(!csf)
+ return 0;
+
+ KisProfile *p = getProfileByName(profileName);
+ if(!p && profileName != "")
+ return 0;
+ KisColorSpace *cs = csf->createColorSpace(this, p);
+ if(!cs)
+ return 0;
+
+ m_csMap[name] = cs;
+ }
+
+ if(m_csMap.tqcontains(name))
+ return m_csMap[name];
+ else
+ return 0;
+}
+
+
+KisColorSpace * KisColorSpaceFactoryRegistry::getColorSpace(const KisID & csID, const KisProfile * profile)
+{
+ if( profile )
+ {
+ KisColorSpace *cs = getColorSpace( csID, profile->productName());
+
+ if(!cs)
+ {
+ // The profile was not stored and thus not the combination either
+ KisColorSpaceFactory *csf = get(csID);
+ if(!csf)
+ return 0;
+
+ cs = csf->createColorSpace(this, const_cast<KisProfile *>(profile));
+ if(!cs )
+ return 0;
+
+ TQString name = csID.id() + "<comb>" + profile->productName();
+ m_csMap[name] = cs;
+ }
+
+ return cs;
+ } else {
+ return getColorSpace( csID, "");
+ }
+}
+
+KisColorSpace * KisColorSpaceFactoryRegistry::getAlpha8()
+{
+ return m_alphaCs;
+}
+
+KisColorSpace * KisColorSpaceFactoryRegistry::getRGB8()
+{
+ return getColorSpace(KisID("RGBA", ""), "");
+}
+
+#include "kis_colorspace_factory_registry.moc"
diff --git a/chalk/chalkcolor/kis_colorspace_factory_registry.h b/chalk/chalkcolor/kis_colorspace_factory_registry.h
new file mode 100644
index 00000000..104c99aa
--- /dev/null
+++ b/chalk/chalkcolor/kis_colorspace_factory_registry.h
@@ -0,0 +1,121 @@
+/*
+ * Copyright (c) 2003 Patrick Julien <freak@codepimps.org>
+ * Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
+ *
+ * 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_COLORSPACE_FACTORY_REGISTRY_H_
+#define KIS_COLORSPACE_FACTORY_REGISTRY_H_
+#include "tqobject.h"
+#include "kis_generic_registry.h"
+#include "kis_colorspace.h"
+
+class TQStringList;
+class KisPaintDeviceAction;
+
+/**
+ * This class tqcontains:
+ * - a registry of colorspace instantiated with specific profiles.
+ * - a registry of singleton colorspace factories.
+ * - a registry of icc profiles
+ */
+class KisColorSpaceFactoryRegistry : public TQObject, public KisGenericRegistry<KisColorSpaceFactory *> {
+
+
+ Q_OBJECT
+ TQ_OBJECT
+
+public:
+
+ /**
+ * Create a new colorspacefactory registry. The registry will
+ * load all colorspace modules that have the right version and
+ * all profiles given in the list. It is always possible
+ * to add more profiles with addProfile()
+ *
+ * @param profileFileNames a list of all filenames of all profiles that need to be loaded initially
+ */
+ KisColorSpaceFactoryRegistry(TQStringList profileFileNames);
+
+ virtual ~KisColorSpaceFactoryRegistry();
+
+ /**
+ * Add the profile to the list.
+ */
+ void addProfile(KisProfile * p);
+
+ /**
+ * Return the profile associated with the given product name,
+ * or 0.
+ */
+ KisProfile * getProfileByName(const TQString & name);
+
+ /**
+ * Return the vector of profiles for this colorspacefactory
+ */
+ TQValueVector<KisProfile *> profilesFor(KisColorSpaceFactory * cs);
+
+ TQValueVector<KisProfile *> profilesFor(KisID id);
+
+ /**
+ * Return the colorspace + profile as named, or NULL if impossible combination.
+ */
+ KisColorSpace * getColorSpace(const KisID & csID, const TQString & profileName);
+
+ /**
+ * Return the colorspace + profile -- where the profile is matched on the name of the specified profile
+ */
+ KisColorSpace * getColorSpace(const KisID & csID, const KisProfile * profile);
+
+ /**
+ * Convenience method to get the often used alpha colorspace
+ */
+ KisColorSpace * getAlpha8();
+
+ /**
+ * Convenience method to get an RGB colorspace with the default lcms profile
+ */
+ KisColorSpace * getRGB8();
+
+ /**
+ * add a KisConstructPaintDeviceAction to the registry for a colorspace
+ *
+ * These actions are exectued when an image is created on the first layer
+ * in the image, on the image width and height rect.
+ */
+ void addPaintDeviceAction(KisColorSpace* cs, KisPaintDeviceAction* action);
+
+ /**
+ * Get a list of KisConstructPaintDeviceAction for a colorspace
+ */
+ TQValueVector<KisPaintDeviceAction *> paintDeviceActionsFor(KisColorSpace* cs);
+
+private:
+ KisColorSpaceFactoryRegistry();
+ KisColorSpaceFactoryRegistry(const KisColorSpaceFactoryRegistry&);
+ KisColorSpaceFactoryRegistry operator=(const KisColorSpaceFactoryRegistry&);
+
+private:
+
+ TQMap<TQString, KisProfile * > m_profileMap;
+ TQMap<TQString, KisColorSpace * > m_csMap;
+ typedef TQValueVector<KisPaintDeviceAction *> PaintActionVector;
+ TQMap<KisID, PaintActionVector> m_paintDevActionMap;
+ KisColorSpace *m_alphaCs;
+};
+
+#endif // KIS_COLORSPACE_FACTORY_REGISTRY_H_
+
diff --git a/chalk/chalkcolor/kis_colorspace_iface.cc b/chalk/chalkcolor/kis_colorspace_iface.cc
new file mode 100644
index 00000000..6e6b3cb8
--- /dev/null
+++ b/chalk/chalkcolor/kis_colorspace_iface.cc
@@ -0,0 +1,39 @@
+/*
+ * This file is part of the KDE project
+ *
+ * Copyright (C) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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 <kapplication.h>
+
+#include "kis_colorspace_iface.h"
+#include "kis_colorspace.h"
+
+#include <dcopclient.h>
+
+KisColorSpaceIface::KisColorSpaceIface( KisColorSpace * tqparent )
+ : DCOPObject(tqparent->id().id().latin1())
+{
+ m_parent = tqparent;
+}
+
+TQByteArray KisColorSpaceIface::invertColor(TQByteArray src, TQ_INT32 nPixels)
+{
+ m_parent->invertColor((TQ_UINT8*)src.data(), nPixels);
+ return src;
+
+}
+
diff --git a/chalk/chalkcolor/kis_colorspace_iface.h b/chalk/chalkcolor/kis_colorspace_iface.h
new file mode 100644
index 00000000..ce52e846
--- /dev/null
+++ b/chalk/chalkcolor/kis_colorspace_iface.h
@@ -0,0 +1,43 @@
+/* This file is part of the KDE project
+ * Copyright (C) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_COLORSPACE_IFACE_H
+#define _KIS_COLORSPACE_IFACE_H
+
+#include <dcopref.h>
+#include <dcopobject.h>
+
+#include <tqstring.h>
+
+class KisColorSpace;
+
+class KisColorSpaceIface : public DCOPObject
+{
+ K_DCOP
+public:
+ KisColorSpaceIface( KisColorSpace * tqparent );
+k_dcop:
+
+ TQByteArray invertColor(TQByteArray src, TQ_INT32 nPixels);
+
+private:
+
+ KisColorSpace *m_parent;
+};
+
+#endif
diff --git a/chalk/chalkcolor/kis_composite_op.cc b/chalk/chalkcolor/kis_composite_op.cc
new file mode 100644
index 00000000..ddce271b
--- /dev/null
+++ b/chalk/chalkcolor/kis_composite_op.cc
@@ -0,0 +1,138 @@
+/*
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.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 <klocale.h>
+
+#include "kis_composite_op.h"
+
+//KisIDCompositeOpMap
+std::map<KisID, CompositeOp> KisCompositeOp::s_idOpMap;
+
+KisCompositeOp::KisCompositeOp()
+{
+ m_valid = false;
+}
+
+KisCompositeOp::KisCompositeOp(const TQString& id)
+{
+ if (s_idOpMap.empty()) {
+ fillMap();
+ }
+
+ KisIDCompositeOpMap::const_iterator it;
+ m_valid = false;
+
+ for (it = s_idOpMap.begin(); it != s_idOpMap.end(); ++it) {
+
+ const KisID& kisId = (*it).first;
+
+ if (kisId.id() == id) {
+
+ m_id = (*it).first;
+ m_op = (*it).second;
+ m_valid = true;
+ break;
+ }
+ }
+}
+
+KisCompositeOp::KisCompositeOp(CompositeOp compositeOp)
+{
+ if (s_idOpMap.empty()) {
+ fillMap();
+ }
+
+ KisIDCompositeOpMap::const_iterator it;
+ m_valid = false;
+
+ for (it = s_idOpMap.begin(); it != s_idOpMap.end(); ++it) {
+
+ CompositeOp compOp = (*it).second;
+
+ if (compOp == compositeOp) {
+
+ m_id = (*it).first;
+ m_op = compositeOp;
+ m_valid = true;
+ break;
+ }
+ }
+}
+
+bool KisCompositeOp::operator==(const KisCompositeOp& other) const
+{
+ if (isValid() && other.isValid()) {
+ return op() == other.op();
+ }
+ return false;
+}
+
+bool KisCompositeOp::operator!=(const KisCompositeOp& other) const
+{
+ return !(*this == other);
+}
+
+void KisCompositeOp::fillMap()
+{
+ s_idOpMap[KisID("normal", i18n("Normal"))] = COMPOSITE_OVER;
+ s_idOpMap[KisID("alphadarken", i18n("Alpha Darken"))] = COMPOSITE_ALPHA_DARKEN;
+ s_idOpMap[KisID("in", i18n("In"))] = COMPOSITE_IN;
+ s_idOpMap[KisID("out", i18n("Out"))] = COMPOSITE_OUT;
+ s_idOpMap[KisID("atop", i18n("Atop"))] = COMPOSITE_ATOP;
+ s_idOpMap[KisID("xor", i18n("Xor"))] = COMPOSITE_XOR;
+ s_idOpMap[KisID("plus", i18n("Plus"))] = COMPOSITE_PLUS;
+ s_idOpMap[KisID("minus", i18n("Minus"))] = COMPOSITE_MINUS;
+ s_idOpMap[KisID("add", i18n("Add"))] = COMPOSITE_ADD;
+ s_idOpMap[KisID("subtract", i18n("Subtract"))] = COMPOSITE_SUBTRACT;
+ s_idOpMap[KisID("diff", i18n("Diff"))] = COMPOSITE_DIFF;
+ s_idOpMap[KisID("multiply", i18n("Multiply"))] = COMPOSITE_MULT;
+ s_idOpMap[KisID("divide", i18n("Divide"))] = COMPOSITE_DIVIDE;
+ s_idOpMap[KisID("dodge", i18n("Dodge"))] = COMPOSITE_DODGE;
+ s_idOpMap[KisID("burn", i18n("Burn"))] = COMPOSITE_BURN;
+ s_idOpMap[KisID("bumpmap", i18n("Bumpmap"))] = COMPOSITE_BUMPMAP;
+ s_idOpMap[KisID("copy", i18n("Copy"))] = COMPOSITE_COPY;
+ s_idOpMap[KisID("copyred", i18n("Copy Red"))] = COMPOSITE_COPY_RED;
+ s_idOpMap[KisID("copygreen", i18n("Copy Green"))] = COMPOSITE_COPY_GREEN;
+ s_idOpMap[KisID("copyblue", i18n("Copy Blue"))] = COMPOSITE_COPY_BLUE;
+ s_idOpMap[KisID("copyopacity", i18n("Copy Opacity"))] = COMPOSITE_COPY_OPACITY;
+ s_idOpMap[KisID("clear", i18n("Clear"))] = COMPOSITE_CLEAR;
+ s_idOpMap[KisID("dissolve", i18n("Dissolve"))] = COMPOSITE_DISSOLVE;
+ s_idOpMap[KisID("displace", i18n("Displace"))] = COMPOSITE_DISPLACE;
+#if 0
+ s_idOpMap[KisID("modulate", i18n("Modulate"))] = COMPOSITE_MODULATE;
+ s_idOpMap[KisID("threshold", i18n("Threshold"))] = COMPOSITE_THRESHOLD;
+#endif
+ s_idOpMap[KisID("nocomposition",i18n("No Composition"))] = COMPOSITE_NO;
+ s_idOpMap[KisID("darken", i18n("Darken"))] = COMPOSITE_DARKEN;
+ s_idOpMap[KisID("lighten", i18n("Lighten"))] = COMPOSITE_LIGHTEN;
+ s_idOpMap[KisID("hue", i18n("Hue"))] = COMPOSITE_HUE;
+ s_idOpMap[KisID("saturation", i18n("Saturation"))] = COMPOSITE_SATURATION;
+ s_idOpMap[KisID("value", i18n("Value"))] = COMPOSITE_VALUE;
+ s_idOpMap[KisID("color", i18n("Color"))] = COMPOSITE_COLOR;
+ s_idOpMap[KisID("colorize", i18n("Colorize"))] = COMPOSITE_COLORIZE;
+ s_idOpMap[KisID("luminize", i18n("Luminize"))] = COMPOSITE_LUMINIZE;
+ s_idOpMap[KisID("screen", i18n("Screen"))] = COMPOSITE_SCREEN;
+ s_idOpMap[KisID("overlay", i18n("Overlay"))] = COMPOSITE_OVERLAY;
+ s_idOpMap[KisID("copycyan", i18n("Copy Cyan"))] = COMPOSITE_COPY_CYAN;
+ s_idOpMap[KisID("copymagenta", i18n("Copy Magenta"))] = COMPOSITE_COPY_MAGENTA;
+ s_idOpMap[KisID("copyyellow", i18n("Copy Yellow"))] = COMPOSITE_COPY_YELLOW;
+ s_idOpMap[KisID("copyblack", i18n("Copy Black"))] = COMPOSITE_COPY_BLACK;
+ s_idOpMap[KisID("erase", i18n("Erase"))] = COMPOSITE_ERASE;
+ s_idOpMap[KisID("undefined", i18n("Undefined"))] = COMPOSITE_UNDEF;
+}
+
diff --git a/chalk/chalkcolor/kis_composite_op.h b/chalk/chalkcolor/kis_composite_op.h
new file mode 100644
index 00000000..bd4f10a2
--- /dev/null
+++ b/chalk/chalkcolor/kis_composite_op.h
@@ -0,0 +1,103 @@
+/*
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.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_COMPOSITE_OP_H_
+#define KIS_COMPOSITE_OP_H_
+
+#include <map>
+#include <tqvaluelist.h>
+
+//#include "kis_global.h"
+#include "kis_id.h"
+
+enum CompositeOp {
+ COMPOSITE_OVER,
+ COMPOSITE_IN,
+ COMPOSITE_OUT,
+ COMPOSITE_ATOP,
+ COMPOSITE_XOR,
+ COMPOSITE_PLUS,
+ COMPOSITE_MINUS,
+ COMPOSITE_ADD,
+ COMPOSITE_SUBTRACT,
+ COMPOSITE_DIFF,
+ COMPOSITE_MULT,
+ COMPOSITE_DIVIDE,
+ COMPOSITE_DODGE,
+ COMPOSITE_BURN,
+ COMPOSITE_BUMPMAP,
+ COMPOSITE_COPY,
+ COMPOSITE_COPY_RED,
+ COMPOSITE_COPY_GREEN,
+ COMPOSITE_COPY_BLUE,
+ COMPOSITE_COPY_OPACITY,
+ COMPOSITE_CLEAR,
+ COMPOSITE_DISSOLVE,
+ COMPOSITE_DISPLACE,
+#if 0
+ COMPOSITE_MODULATE,
+ COMPOSITE_THRESHOLD,
+#endif
+ COMPOSITE_NO,
+ COMPOSITE_DARKEN,
+ COMPOSITE_LIGHTEN,
+ COMPOSITE_HUE,
+ COMPOSITE_SATURATION,
+ COMPOSITE_VALUE,
+ COMPOSITE_COLOR,
+ COMPOSITE_COLORIZE,
+ COMPOSITE_LUMINIZE,
+ COMPOSITE_SCREEN,
+ COMPOSITE_OVERLAY,
+ COMPOSITE_COPY_CYAN,
+ COMPOSITE_COPY_MAGENTA,
+ COMPOSITE_COPY_YELLOW,
+ COMPOSITE_COPY_BLACK,
+ COMPOSITE_ERASE,
+ COMPOSITE_ALPHA_DARKEN,
+ COMPOSITE_UNDEF
+};
+
+class KisCompositeOp {
+public:
+ KisCompositeOp();
+ KisCompositeOp(const TQString& id);
+ KisCompositeOp(CompositeOp compositeOp);
+
+ KisID id() const { return m_id; }
+ CompositeOp op() const { return m_op; }
+
+ bool isValid() const { return m_valid; }
+
+ bool operator==(const KisCompositeOp& other) const;
+ bool operator!=(const KisCompositeOp& other) const;
+
+private:
+ void fillMap();
+
+private:
+ CompositeOp m_op;
+ KisID m_id;
+ bool m_valid;
+
+ typedef std::map<KisID, CompositeOp> KisIDCompositeOpMap;
+ static KisIDCompositeOpMap s_idOpMap;
+};
+
+typedef TQValueList<KisCompositeOp> KisCompositeOpList;
+
+#endif // KIS_COMPOSITE_OP_H
diff --git a/chalk/chalkcolor/kis_f16half_base_colorspace.cc b/chalk/chalkcolor/kis_f16half_base_colorspace.cc
new file mode 100644
index 00000000..d4886c5f
--- /dev/null
+++ b/chalk/chalkcolor/kis_f16half_base_colorspace.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.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 "kdebug.h"
+
+#include "kis_global.h"
+#include "kis_f16half_base_colorspace.h"
+
+TQ_UINT8 KisF16HalfBaseColorSpace::getAlpha(const TQ_UINT8 * U8_pixel) const
+{
+ if (m_alphaPos < 0) return OPACITY_OPAQUE;
+
+ U8_pixel += m_alphaPos;
+
+ const half *pixel = reinterpret_cast<const half *>(U8_pixel);
+ return HALF_TO_UINT8(*pixel);
+}
+
+void KisF16HalfBaseColorSpace::setAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 alpha, TQ_INT32 nPixels) const
+{
+ if (m_alphaPos < 0) return;
+ TQ_INT32 psize = pixelSize();
+
+ while (nPixels > 0) {
+
+ half *pixel = reinterpret_cast<half *>(U8_pixel + m_alphaPos);
+ *pixel = UINT8_TO_HALF(alpha);
+
+ --nPixels;
+ U8_pixel += psize;
+ }
+}
+
+void KisF16HalfBaseColorSpace::multiplyAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 U8_alpha, TQ_INT32 nPixels)
+{
+ if (m_alphaPos < 0) return;
+ TQ_INT32 psize = pixelSize();
+ half alpha = UINT8_TO_HALF(U8_alpha);
+
+ while (nPixels > 0) {
+
+ half *pixelAlpha = reinterpret_cast<half *>(U8_pixel + m_alphaPos);
+ *pixelAlpha *= alpha;
+
+ --nPixels;
+ U8_pixel += psize;
+ }
+}
+
+void KisF16HalfBaseColorSpace::applyAlphaU8Mask(TQ_UINT8 * U8_pixel, TQ_UINT8 * alpha8, TQ_INT32 nPixels)
+{
+ if (m_alphaPos < 0) return;
+
+ TQ_INT32 psize = pixelSize();
+
+ while (nPixels--) {
+
+ half *pixelAlpha = reinterpret_cast<half *>(U8_pixel + m_alphaPos);
+ *pixelAlpha *= UINT8_TO_HALF(*alpha8);
+
+ ++alpha8;
+ U8_pixel += psize;
+ }
+}
+
+void KisF16HalfBaseColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * U8_pixels, TQ_UINT8 * alpha8, TQ_INT32 nPixels)
+{
+ if (m_alphaPos < 0) return;
+
+ TQ_INT32 psize = pixelSize();
+
+ while (nPixels--) {
+
+ half *pixelAlpha = reinterpret_cast<half *>(U8_pixels + m_alphaPos);
+ *pixelAlpha *= UINT8_TO_HALF(MAX_SELECTED - *alpha8);
+
+ U8_pixels += psize;
+ ++alpha8;
+ }
+}
+
+TQString KisF16HalfBaseColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < (TQ_UINT32)nChannels());
+ const half *pixel = reinterpret_cast<const half *>(U8_pixel);
+ TQ_UINT32 channelPosition = channels()[channelIndex] -> pos() / sizeof(half);
+
+ return TQString().setNum(pixel[channelPosition]);
+}
+
+TQString KisF16HalfBaseColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < (TQ_UINT32)nChannels());
+ const half *pixel = reinterpret_cast<const half *>(U8_pixel);
+ TQ_UINT32 channelPosition = channels()[channelIndex] -> pos() / sizeof(half);
+
+ return TQString().setNum(100.0 * pixel[channelPosition]);
+}
+
+TQ_UINT8 KisF16HalfBaseColorSpace::scaleToU8(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos)
+{
+ const half *pixelChannel = reinterpret_cast<const half *>(U8_pixel + channelPos);
+ return HALF_TO_UINT8(*pixelChannel);
+}
+
+TQ_UINT16 KisF16HalfBaseColorSpace::scaleToU16(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos)
+{
+ const half *pixelChannel = reinterpret_cast<const half *>(U8_pixel + channelPos);
+ return HALF_TO_UINT16(*pixelChannel);
+}
+
diff --git a/chalk/chalkcolor/kis_f16half_base_colorspace.h b/chalk/chalkcolor/kis_f16half_base_colorspace.h
new file mode 100644
index 00000000..ff1dbf8c
--- /dev/null
+++ b/chalk/chalkcolor/kis_f16half_base_colorspace.h
@@ -0,0 +1,107 @@
+/*
+ * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_F16HALF_BASE_COLORSPACE_H_
+#define KIS_F16HALF_BASE_COLORSPACE_H_
+
+#include <tqcolor.h>
+
+#include <half.h>
+
+#include "kis_global.h"
+#include "kis_abstract_colorspace.h"
+#include "kis_integer_maths.h"
+
+/**
+ * This class is the base for all 16-bit float colorspaces using the
+ * OpenEXR half format. This format can be used with the OpenGL
+ * extensions GL_NV_half_float and GL_ARB_half_float_pixel.
+ */
+
+inline half UINT8_TO_HALF(uint c)
+{
+ return static_cast<half>(c) / UINT8_MAX;
+}
+
+inline uint HALF_TO_UINT8(half c)
+{
+ return static_cast<uint>(CLAMP(static_cast<int>(c * static_cast<int>(UINT8_MAX) + 0.5),
+ static_cast<int>(UINT8_MIN), static_cast<int>(UINT8_MAX)));
+}
+
+
+inline uint HALF_TO_UINT16(half c)
+{
+ return static_cast<uint>(CLAMP(static_cast<int>(c * static_cast<int>(UINT16_MAX) + 0.5),
+ static_cast<int>(UINT16_MIN), static_cast<int>(UINT16_MAX)));
+}
+
+inline half HALF_BLEND(half a, half b, half alpha)
+{
+ return (a - b) * alpha + b;
+}
+
+#define F16HALF_OPACITY_OPAQUE ((half)1.0f)
+#define F16HALF_OPACITY_TRANSPARENT ((half)0.0f)
+
+class KisF16HalfBaseColorSpace : public KisAbstractColorSpace {
+
+public:
+
+ KisF16HalfBaseColorSpace(const KisID & id, DWORD cmType, icColorSpaceSignature colorSpaceSignature,
+ KisColorSpaceFactoryRegistry * tqparent,
+ KisProfile *p)
+ : KisAbstractColorSpace(id, cmType, colorSpaceSignature, tqparent, p)
+ {
+ m_alphaSize = sizeof(half);
+ };
+
+ virtual TQ_UINT8 getAlpha(const TQ_UINT8 * pixel) const;
+ virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const;
+ virtual void multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels);
+
+ virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels);
+ virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels);
+
+ virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+ virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+
+ virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos);
+ virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos);
+
+ virtual bool hasHighDynamicRange() const { return true; }
+
+protected:
+ // For Alpha Composite
+ struct F16HalfMult {
+ inline half operator()(const half& a, const half& b) const {
+ return a * b;
+ }
+ };
+ struct Uint8ToF16Half {
+ inline half operator()(const TQ_UINT8 src) const {
+ return UINT8_TO_HALF(src);
+ }
+ };
+ struct F16HalfOpacityTest {
+ inline bool operator()(const half& opacity) const {
+ return opacity > F16HALF_OPACITY_TRANSPARENT + HALF_EPSILON;
+ }
+ };
+};
+
+#endif // KIS_F16HALF_BASE_COLORSPACE_H_
diff --git a/chalk/chalkcolor/kis_f32_base_colorspace.cc b/chalk/chalkcolor/kis_f32_base_colorspace.cc
new file mode 100644
index 00000000..27a6a312
--- /dev/null
+++ b/chalk/chalkcolor/kis_f32_base_colorspace.cc
@@ -0,0 +1,125 @@
+/*
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.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 "kdebug.h"
+
+#include "kis_global.h"
+#include "kis_f32_base_colorspace.h"
+
+TQ_UINT8 KisF32BaseColorSpace::getAlpha(const TQ_UINT8 * U8_pixel) const
+{
+ if (m_alphaPos < 0) return OPACITY_OPAQUE;
+
+ U8_pixel += m_alphaPos;
+
+ const float *pixel = reinterpret_cast<const float *>(U8_pixel);
+ return FLOAT_TO_UINT8(*pixel);
+}
+
+void KisF32BaseColorSpace::setAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 alpha, TQ_INT32 nPixels) const
+{
+ if (m_alphaPos < 0) return;
+ TQ_INT32 psize = pixelSize();
+
+ while (nPixels > 0) {
+
+ float *pixel = reinterpret_cast<float *>(U8_pixel + m_alphaPos);
+ *pixel = UINT8_TO_FLOAT(alpha);
+
+ --nPixels;
+ U8_pixel += psize;
+ }
+}
+
+void KisF32BaseColorSpace::multiplyAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 U8_alpha, TQ_INT32 nPixels)
+{
+ if (m_alphaPos < 0) return;
+ TQ_INT32 psize = pixelSize();
+ float alpha = UINT8_TO_FLOAT(U8_alpha);
+
+ while (nPixels > 0) {
+
+ float *pixelAlpha = reinterpret_cast<float *>(U8_pixel + m_alphaPos);
+ *pixelAlpha *= alpha;
+
+ --nPixels;
+ U8_pixel += psize;
+ }
+}
+
+void KisF32BaseColorSpace::applyAlphaU8Mask(TQ_UINT8 * U8_pixel, TQ_UINT8 * alpha8, TQ_INT32 nPixels)
+{
+ if (m_alphaPos < 0) return;
+
+ TQ_INT32 psize = pixelSize();
+
+ while (nPixels--) {
+
+ float *pixelAlpha = reinterpret_cast<float *>(U8_pixel + m_alphaPos);
+ *pixelAlpha *= UINT8_TO_FLOAT(*alpha8);
+
+ ++alpha8;
+ U8_pixel += psize;
+ }
+}
+
+void KisF32BaseColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * U8_pixels, TQ_UINT8 * alpha8, TQ_INT32 nPixels)
+{
+ if (m_alphaPos < 0) return;
+
+ TQ_INT32 psize = pixelSize();
+
+ while (nPixels--) {
+
+ float *pixelAlpha = reinterpret_cast<float *>(U8_pixels + m_alphaPos);
+ *pixelAlpha *= UINT8_TO_FLOAT(MAX_SELECTED - *alpha8);
+
+ U8_pixels += psize;
+ ++alpha8;
+ }
+}
+
+TQString KisF32BaseColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < (TQ_UINT32)nChannels());
+ const float *pixel = reinterpret_cast<const float *>(U8_pixel);
+ TQ_UINT32 channelPosition = channels()[channelIndex]->pos() / sizeof(float);
+
+ return TQString().setNum(pixel[channelPosition]);
+}
+
+TQString KisF32BaseColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < (TQ_UINT32)nChannels());
+ const float *pixel = reinterpret_cast<const float *>(U8_pixel);
+ TQ_UINT32 channelPosition = channels()[channelIndex]->pos() / sizeof(float);
+
+ return TQString().setNum(100.0 * pixel[channelPosition]);
+}
+
+TQ_UINT8 KisF32BaseColorSpace::scaleToU8(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos)
+{
+ const float *pixelChannel = reinterpret_cast<const float *>(U8_pixel + channelPos);
+ return FLOAT_TO_UINT8(*pixelChannel);
+}
+
+TQ_UINT16 KisF32BaseColorSpace::scaleToU16(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos)
+{
+ const float *pixelChannel = reinterpret_cast<const float *>(U8_pixel + channelPos);
+ return FLOAT_TO_UINT16(*pixelChannel);
+}
+
diff --git a/chalk/chalkcolor/kis_f32_base_colorspace.h b/chalk/chalkcolor/kis_f32_base_colorspace.h
new file mode 100644
index 00000000..60ecb9aa
--- /dev/null
+++ b/chalk/chalkcolor/kis_f32_base_colorspace.h
@@ -0,0 +1,83 @@
+/*
+ * Copyright (c) 2004 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_F32_BASE_COLORSPACE_H_
+#define KIS_F32_BASE_COLORSPACE_H_
+
+#include <tqcolor.h>
+
+#include "kis_global.h"
+#include "kis_abstract_colorspace.h"
+#include "kis_integer_maths.h"
+
+/**
+ * This class is the base for all 32-bit float colorspaces.
+ */
+
+inline float UINT8_TO_FLOAT(uint c)
+{
+ return static_cast<float>(c) / UINT8_MAX;
+}
+
+inline uint FLOAT_TO_UINT8(float c)
+{
+ return static_cast<uint>(CLAMP(static_cast<int>(c * static_cast<int>(UINT8_MAX) + 0.5),
+ static_cast<int>(UINT8_MIN), static_cast<int>(UINT8_MAX)));
+}
+
+
+inline uint FLOAT_TO_UINT16(float c)
+{
+ return static_cast<uint>(CLAMP(static_cast<int>(c * static_cast<int>(UINT16_MAX) + 0.5),
+ static_cast<int>(UINT16_MIN), static_cast<int>(UINT16_MAX)));
+}
+
+inline float FLOAT_BLEND(float a, float b, float alpha)
+{
+ return (a - b) * alpha + b;
+}
+
+#define F32_OPACITY_OPAQUE 1.0f
+#define F32_OPACITY_TRANSPARENT 0.0f
+
+class KisF32BaseColorSpace : public KisAbstractColorSpace {
+
+public:
+
+ KisF32BaseColorSpace(const KisID & id, DWORD cmType, icColorSpaceSignature colorSpaceSignature, KisColorSpaceFactoryRegistry * tqparent, KisProfile *p)
+ : KisAbstractColorSpace(id, cmType, colorSpaceSignature, tqparent, p)
+ {
+ m_alphaSize = sizeof(float);
+ };
+
+ virtual TQ_UINT8 getAlpha(const TQ_UINT8 * pixel) const;
+ virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const;
+ virtual void multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels);
+
+ virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels);
+ virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels);
+
+ virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+ virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+
+ virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos);
+ virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos);
+
+ virtual bool hasHighDynamicRange() const { return true; }
+};
+
+#endif // KIS_F32_BASE_COLORSPACE_H_
diff --git a/chalk/chalkcolor/kis_histogram_producer.cc b/chalk/chalkcolor/kis_histogram_producer.cc
new file mode 100644
index 00000000..bbea95ba
--- /dev/null
+++ b/chalk/chalkcolor/kis_histogram_producer.cc
@@ -0,0 +1,67 @@
+/*
+ * Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be>
+ *
+ * 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_histogram_producer.h"
+#include "kis_basic_histogram_producers.h"
+
+KisHistogramProducerFactoryRegistry* KisHistogramProducerFactoryRegistry::m_singleton = 0;
+
+KisHistogramProducerFactoryRegistry::KisHistogramProducerFactoryRegistry() {
+ Q_ASSERT(KisHistogramProducerFactoryRegistry::m_singleton == 0);
+}
+
+KisHistogramProducerFactoryRegistry::~KisHistogramProducerFactoryRegistry() {
+}
+
+KisHistogramProducerFactoryRegistry* KisHistogramProducerFactoryRegistry::instance() {
+ if(KisHistogramProducerFactoryRegistry::m_singleton == 0) {
+ KisHistogramProducerFactoryRegistry::m_singleton
+ = new KisHistogramProducerFactoryRegistry();
+ m_singleton->add( new KisGenericLabHistogramProducerFactory() );
+ }
+ return KisHistogramProducerFactoryRegistry::m_singleton;
+}
+
+KisIDList KisHistogramProducerFactoryRegistry::listKeysCompatibleWith(
+ KisColorSpace* colorSpace) const
+{
+ KisIDList list;
+ TQValueList<float> preferredList;
+ storageMap::const_iterator it = m_storage.begin();
+ storageMap::const_iterator endit = m_storage.end();
+ // O(n^2), can't this be done better? (But preferrably not by looking up the preferredness
+ // during the sorting...
+ while( it != endit ) {
+ if (it->second->isCompatibleWith(colorSpace)) {
+ float preferred = it->second->preferrednessLevelWith(colorSpace);
+ TQValueList<float>::iterator pit = preferredList.begin();
+ TQValueList<float>::iterator pend = preferredList.end();
+ KisIDList::iterator lit = list.begin();
+
+ while (pit != pend && preferred <= *pit) {
+ ++pit;
+ ++lit;
+ }
+
+ list.insert(lit, it->first);
+ preferredList.insert(pit, preferred);
+ }
+ ++it;
+ }
+ return list;
+}
diff --git a/chalk/chalkcolor/kis_histogram_producer.h b/chalk/chalkcolor/kis_histogram_producer.h
new file mode 100644
index 00000000..2d25b354
--- /dev/null
+++ b/chalk/chalkcolor/kis_histogram_producer.h
@@ -0,0 +1,129 @@
+/*
+ * Copyright (c) 2005 Bart Coppens <kde@bartcoppens.be>
+ *
+ * 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_HISTOGRAM_PRODUCER_
+#define _KIS_HISTOGRAM_PRODUCER_
+
+#include <tqglobal.h>
+#include <ksharedptr.h>
+
+#include <kis_colorspace.h>
+
+#include "kis_generic_registry.h"
+
+class KisRectIteratorPixel;
+class TQString;
+class KisChannelInfo;
+
+/**
+ * This class is an interface used in the generation of a histogram. It is a container of
+ * data, all mathematically interesting things will calculated by a KisHistogram.
+ *
+ * The default view will be the entire range each color can be in. And don't let the
+ * numberOfBins return anything else then 256 unless you have a very good reason for it.
+ *
+ * About the views: a view is a zoom combined with a start level: the entire
+ * range of a channel is 0.0 - 1.0: this is the position. Combined with a zoom, we can
+ * calculate what part of a channel will fall in a bin. This gives us an interface to
+ * that the views that is not dependent of the actual colorspace of the histogram.
+ * The 'size' value is the size, again from 0.0 to 1.0 of the displayed range.
+ *
+ * For comfort of the GUI, and because it is logical, channels are accessed in the order
+ * in which they are found in the channels() method. This is potentially different from
+ * the order in which they are internally ordered!
+ **/
+class KisHistogramProducer : public KShared {
+public:
+ KisHistogramProducer() : m_skipTransparent(true), m_skipUnselected(true) {}
+ virtual ~KisHistogramProducer() {}
+
+ // Methods to change the bins
+
+ /** Clears the data in this producer, but keeps its other settings */
+ virtual void clear() = 0;
+
+ /**
+ * Adds the values from the specified array of pixels to the bins -- does not
+ * reset anything.
+ *
+ * @param pixels A pointer an array of pixeldata in the given colorspace
+ * @param selectionMask a pointer to an array of bytes, where 0 is unselected and 1-255 is degree of selectedness. The array
+ * must be just as long as the array of pixels.
+ * @param nPixels The number of pixels
+ * @param colorSpace the colorspace that can decode the pixel data.
+ */
+ virtual void addRegionToBin(TQ_UINT8 * pixels, TQ_UINT8 * selectionMask, TQ_UINT32 nPixels, KisColorSpace* colorSpace) = 0;
+
+ // Methods to set what exactly is being added to the bins
+ virtual void setView(double from, double width) = 0;
+ virtual void setSkipTransparent(bool set) { m_skipTransparent = set; }
+ virtual void setSkipUnselected(bool set) { m_skipUnselected = set; }
+
+ // Methods with general information about this specific producer
+ virtual const KisID& id() const = 0;
+ virtual TQValueVector<KisChannelInfo *> channels() = 0;
+ virtual TQ_INT32 numberOfBins() = 0;
+ virtual TQString positionToString(double pos) const = 0;
+ virtual double viewFrom() const = 0;
+ virtual double viewWidth() const = 0;
+ virtual double maximalZoom() const = 0;
+
+ // Methods to get information on the data we have seen
+ virtual TQ_INT32 count() = 0;
+ virtual TQ_INT32 getBinAt(TQ_INT32 channel, TQ_INT32 position) = 0;
+ virtual TQ_INT32 outOfViewLeft(TQ_INT32 channel) = 0;
+ virtual TQ_INT32 outOfViewRight(TQ_INT32 channel) = 0;
+protected:
+ bool m_skipTransparent;
+ bool m_skipUnselected;
+};
+
+typedef KSharedPtr<KisHistogramProducer> KisHistogramProducerSP;
+
+class KisHistogramProducerFactory {
+public:
+ KisHistogramProducerFactory(const KisID& id) : m_id(id) {}
+ virtual ~KisHistogramProducerFactory() {}
+ /// Factory method, generates a new KisHistogramProducer
+ virtual KisHistogramProducerSP generate() = 0;
+ /// Returns if a colorspace can be used with this producer
+ virtual bool isCompatibleWith(KisColorSpace* colorSpace) const = 0;
+ /// Returns a float in the [0.0, 1.0] range, 0.0 means this is a very generic method
+ virtual float preferrednessLevelWith(KisColorSpace* colorSpace) const = 0;
+ virtual const KisID& id() const { return m_id; }
+protected:
+ KisID m_id;
+};
+
+class KisHistogramProducerFactoryRegistry
+ : public KisGenericRegistry<KisHistogramProducerFactory*> {
+public:
+ virtual ~KisHistogramProducerFactoryRegistry();
+ static KisHistogramProducerFactoryRegistry* instance();
+ /// returns a list, sorted by preferrence: higher preferance comes first
+ KisIDList listKeysCompatibleWith(KisColorSpace* colorSpace) const;
+
+private:
+ KisHistogramProducerFactoryRegistry();
+ KisHistogramProducerFactoryRegistry(const KisHistogramProducerFactoryRegistry&);
+ KisHistogramProducerFactoryRegistry operator=(const KisHistogramProducerFactoryRegistry&);
+
+ static KisHistogramProducerFactoryRegistry* m_singleton;
+};
+
+#endif // _KIS_HISTOGRAM_PRODUCER
diff --git a/chalk/chalkcolor/kis_profile.cc b/chalk/chalkcolor/kis_profile.cc
new file mode 100644
index 00000000..2d0ad98f
--- /dev/null
+++ b/chalk/chalkcolor/kis_profile.cc
@@ -0,0 +1,208 @@
+/*
+ * kis_profile.cc - part of Krayon
+ *
+ * Copyright (c) 2000 Matthias Elter <elter@kde.org>
+ * 2001 John Califf
+ * 2004 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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 <cfloat>
+#include <cmath>
+#include <config.h>
+#include LCMS_HEADER
+
+#include <tqimage.h>
+#include <tqtextstream.h>
+#include <tqfile.h>
+
+#include <kdebug.h>
+
+#include "kis_profile.h"
+#include "kis_global.h"
+
+#include "ksharedptr.h"
+
+#include <X11/Xlib.h>
+#include <X11/Xatom.h>
+#include <fixx11h.h>
+
+KisProfile::KisProfile(TQByteArray rawData)
+ : m_rawData(rawData),
+ m_filename( TQString() ),
+ m_valid( false ),
+ m_suitableForOutput(false)
+{
+ m_profile = cmsOpenProfileFromMem(rawData.data(), (DWORD)rawData.size());
+ init();
+}
+
+KisProfile::KisProfile(const TQString& file)
+ : m_filename(file),
+ m_valid( false ),
+ m_suitableForOutput( false )
+{
+}
+
+KisProfile::KisProfile(const cmsHPROFILE profile)
+ : m_profile(profile),
+ m_filename( TQString() ),
+ m_valid( true )
+{
+ size_t bytesNeeded=0;
+
+ // Make a raw data image ready for saving
+ _cmsSaveProfileToMem(m_profile, 0, &bytesNeeded); // calc size
+ if(m_rawData.tqresize(bytesNeeded))
+ {
+ _cmsSaveProfileToMem(m_profile, m_rawData.data(), &bytesNeeded); // fill buffer
+ cmsHPROFILE newprofile = cmsOpenProfileFromMem(m_rawData.data(), (DWORD) bytesNeeded);
+ cmsCloseProfile(m_profile);
+ m_profile = newprofile;
+ }
+ else
+ m_rawData.resize(0);
+
+ init();
+}
+
+KisProfile::~KisProfile()
+{
+ cmsCloseProfile(m_profile);
+}
+
+
+bool KisProfile::load()
+{
+ TQFile file(m_filename);
+ file.open(IO_ReadOnly);
+ m_rawData = file.readAll();
+ m_profile = cmsOpenProfileFromMem(m_rawData.data(), (DWORD)m_rawData.size());
+ file.close();
+
+ if (m_profile == 0) {
+ kdWarning() << "Failed to load profile from " << m_filename << endl;
+ }
+
+ return init();
+
+}
+
+bool KisProfile::init()
+{
+ if (m_profile) {
+ m_colorSpaceSignature = cmsGetColorSpace(m_profile);
+ m_deviceClass = cmsGetDeviceClass(m_profile);
+ m_productName = cmsTakeProductName(m_profile);
+ m_productDescription = cmsTakeProductDesc(m_profile);
+ m_productInfo = cmsTakeProductInfo(m_profile);
+ m_valid = true;
+
+ // Check if the profile can convert (something->this)
+// LPMATSHAPER OutMatShaper = cmsBuildOutputMatrixShaper(m_profile);
+// if( OutMatShaper )
+// {
+// m_suitableForOutput = true;
+// }
+ cmsCIEXYZTRIPLE Primaries;
+
+ if (cmsTakeColorants(&Primaries, m_profile))
+ {
+ m_suitableForOutput = true;
+ }
+
+#if 0
+ // XXX: It wasn't that easy to save a little memory: thsi gives an lcms error
+ // Okay, we know enough. Free the memory; we'll load it again if needed.
+
+ cmsCloseProfile(m_profile);
+ m_profile = 0;
+
+#endif
+ return true;
+ }
+ return false;
+}
+
+cmsHPROFILE KisProfile::profile()
+{
+#if 0
+ if (m_profile = 0) {
+ TQFile file(m_filename);
+ file.open(IO_ReadOnly);
+ m_rawData = file.readAll();
+ m_profile = cmsOpenProfileFromMem(m_rawData.data(), (DWORD)m_rawData.size());
+ file.close();
+ }
+#endif
+ return m_profile;
+}
+
+bool KisProfile::save()
+{
+ return false;
+}
+
+KisAnnotationSP KisProfile::annotation() const
+{
+ // XXX we hardcode icc, this is correct for lcms?
+ // XXX productName(), or just "ICC Profile"?
+ if (!m_rawData.isEmpty())
+ return new KisAnnotation("icc", productName(), m_rawData);
+ else
+ return 0;
+}
+
+KisProfile * KisProfile::getScreenProfile (int screen)
+{
+
+#ifdef Q_WS_X11
+
+ Atom type;
+ int format;
+ unsigned long nitems;
+ unsigned long bytes_after;
+ TQ_UINT8 * str;
+
+ static Atom icc_atom = XInternAtom( qt_xdisplay(), "_ICC_PROFILE", False );
+
+ if ( XGetWindowProperty ( qt_xdisplay(),
+ qt_xrootwin( screen ),
+ icc_atom,
+ 0,
+ INT_MAX,
+ False,
+ XA_CARDINAL,
+ &type,
+ &format,
+ &nitems,
+ &bytes_after,
+ (unsigned char **) &str)
+ ) {
+
+ TQByteArray bytes (nitems);
+ bytes.assign((char*)str, (TQ_UINT32)nitems);
+
+ return new KisProfile(bytes);
+ } else {
+ return NULL;
+ }
+#else
+ return NULL;
+
+#endif
+}
+
+
diff --git a/chalk/chalkcolor/kis_profile.h b/chalk/chalkcolor/kis_profile.h
new file mode 100644
index 00000000..5f732188
--- /dev/null
+++ b/chalk/chalkcolor/kis_profile.h
@@ -0,0 +1,98 @@
+/*
+ * kis_profile.h - part of Krayon
+ *
+ * Copyright (c) 2000 Matthias Elter <elter@kde.org>
+ * 2004 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_PROFILE_H
+#define KIS_PROFILE_H
+
+#include <config.h>
+
+#include LCMS_HEADER
+
+#include <tqvaluevector.h>
+#include <tqcstring.h>
+
+#include <kio/job.h>
+
+#include <kis_annotation.h>
+
+//XXX: Profiles should be loaded by the color strategies
+// and be available only through the color strategy
+// that matches the profile's color model
+class KisProfile {
+
+public:
+ KisProfile(TQByteArray rawData);
+ KisProfile(const TQString& file);
+ KisProfile(const cmsHPROFILE profile);
+
+ virtual ~KisProfile();
+
+ virtual bool load();
+ virtual bool save();
+
+ inline icColorSpaceSignature colorSpaceSignature() const { return m_colorSpaceSignature; }
+ inline icProfileClassSignature deviceClass() const { return m_deviceClass; }
+ inline TQString productName() const { return m_productName; }
+ inline TQString productDescription() const { return m_productDescription; }
+ inline TQString productInfo() const { return m_productInfo; }
+ inline TQString manufacturer() const { return m_manufacturer; }
+ cmsHPROFILE profile();
+
+ KisAnnotationSP annotation() const;
+
+ friend inline bool operator==( const KisProfile &, const KisProfile & );
+
+ inline bool valid() const { return m_valid; };
+
+ inline bool isSuitableForOutput() { return m_suitableForOutput; };
+
+ inline TQString filename() const { return m_filename; }
+
+public:
+
+ static KisProfile * getScreenProfile(int screen = -1);
+
+private:
+ bool init();
+
+ cmsHPROFILE m_profile;
+ icColorSpaceSignature m_colorSpaceSignature;
+ icProfileClassSignature m_deviceClass;
+ TQString m_productName;
+ TQString m_productDescription;
+ TQString m_productInfo;
+ TQString m_manufacturer;
+
+ TQByteArray m_rawData;
+
+ TQString m_filename;
+ bool m_valid;
+ bool m_suitableForOutput;
+
+};
+
+inline bool operator==( const KisProfile & p1, const KisProfile & p2 )
+{
+ return p1.m_profile == p2.m_profile;
+}
+
+#endif // KIS_PROFILE_H
+
diff --git a/chalk/chalkcolor/kis_u16_base_colorspace.cc b/chalk/chalkcolor/kis_u16_base_colorspace.cc
new file mode 100644
index 00000000..a735e35c
--- /dev/null
+++ b/chalk/chalkcolor/kis_u16_base_colorspace.cc
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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 "kdebug.h"
+
+#include "kis_global.h"
+#include "kis_abstract_colorspace.h"
+#include "kis_integer_maths.h"
+#include "kis_u16_base_colorspace.h"
+
+
+TQ_UINT8 KisU16BaseColorSpace::getAlpha(const TQ_UINT8 * U8_pixel) const
+{
+ if (m_alphaPos < 0) return OPACITY_OPAQUE;
+
+ U8_pixel+= m_alphaPos;
+
+ const TQ_UINT16 *pixel = reinterpret_cast<const TQ_UINT16 *>(U8_pixel);
+ return UINT16_TO_UINT8(*pixel);
+}
+
+
+void KisU16BaseColorSpace::setAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 alpha, TQ_INT32 nPixels) const
+{
+ if (m_alphaPos < 0) return;
+ TQ_INT32 psize = pixelSize();
+
+
+ while (nPixels > 0) {
+
+ TQ_UINT16 *pixel = reinterpret_cast<TQ_UINT16 *>(U8_pixel + m_alphaPos);
+ pixel[0] = UINT8_TO_UINT16(alpha);
+
+ --nPixels;
+ U8_pixel += psize;
+ }
+}
+
+void KisU16BaseColorSpace::multiplyAlpha(TQ_UINT8 *U8_pixel, TQ_UINT8 U8_alpha, TQ_INT32 nPixels)
+{
+ if (m_alphaPos < 0) return;
+
+ TQ_INT32 psize = pixelSize();
+ TQ_UINT16 alpha = UINT8_TO_UINT16(U8_alpha);
+
+ while (nPixels > 0) {
+
+ TQ_UINT16 *pixelAlpha = reinterpret_cast<TQ_UINT16 *>(U8_pixel + m_alphaPos);
+ *pixelAlpha = UINT16_MULT(*pixelAlpha, alpha);
+
+ --nPixels;
+ U8_pixel += psize;
+ }
+}
+
+void KisU16BaseColorSpace::applyAlphaU8Mask(TQ_UINT8 * U8_pixel, TQ_UINT8 * alpha8, TQ_INT32 nPixels)
+{
+ if (m_alphaPos < 0) return;
+
+ TQ_INT32 psize = pixelSize();
+
+ while (nPixels--) {
+
+ // Go to the alpha position (which is given in bytes from the start of the pixel,
+ // and cast to short.
+
+ TQ_UINT16 *pixelAlpha = reinterpret_cast<TQ_UINT16 *>(U8_pixel + m_alphaPos);
+ *pixelAlpha = UINT8_MULT(*pixelAlpha, *alpha8);
+
+ ++alpha8;
+ U8_pixel += psize;
+
+ }
+}
+
+void KisU16BaseColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * U8_pixels, TQ_UINT8 * alpha8, TQ_INT32 nPixels)
+{
+
+ if (m_alphaPos < 0) return;
+
+ TQ_INT32 psize = pixelSize();
+
+
+ while(nPixels--) {
+
+ TQ_UINT16 s_alpha8;
+ TQ_UINT32 p_alpha, s_alpha16;
+
+ TQ_UINT16 *alpha = reinterpret_cast<TQ_UINT16 *>(U8_pixels + m_alphaPos);
+
+ p_alpha = *(alpha);
+ s_alpha8 = MAX_SELECTED - *alpha8;
+ s_alpha16 = UINT8_TO_UINT16(s_alpha8);
+
+ // Go to the alpha position (which is given in bytes from the start of the pixel,
+ // and cast to short.
+
+ alpha[0] = UINT16_MULT(p_alpha, s_alpha16);
+
+ U8_pixels += psize;
+ ++alpha8;
+ }
+}
+
+TQString KisU16BaseColorSpace::channelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < (TQ_UINT32)nChannels());
+ const TQ_UINT16 *pixel = reinterpret_cast<const TQ_UINT16 *>(U8_pixel);
+ TQ_UINT32 channelPosition = channels()[channelIndex]->pos() / sizeof(TQ_UINT16);
+
+ return TQString().setNum(pixel[channelPosition]);
+}
+
+TQString KisU16BaseColorSpace::normalisedChannelValueText(const TQ_UINT8 *U8_pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < (TQ_UINT32)nChannels());
+ const TQ_UINT16 *pixel = reinterpret_cast<const TQ_UINT16 *>(U8_pixel);
+ TQ_UINT32 channelPosition = m_channels[channelIndex]->pos() / sizeof(TQ_UINT16);
+
+ return TQString().setNum(100.0 * static_cast<float>(pixel[channelPosition]) / UINT16_MAX);
+}
+
+TQ_UINT8 KisU16BaseColorSpace::scaleToU8(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos)
+{
+ const TQ_UINT16 *pixel = reinterpret_cast<const TQ_UINT16 *>(U8_pixel);
+ return UINT16_TO_UINT8(pixel[channelPos]);
+}
+
+TQ_UINT16 KisU16BaseColorSpace::scaleToU16(const TQ_UINT8 * U8_pixel, TQ_INT32 channelPos)
+{
+ const TQ_UINT16 *pixel = reinterpret_cast<const TQ_UINT16 *>(U8_pixel);
+ return pixel[channelPos];
+}
+
diff --git a/chalk/chalkcolor/kis_u16_base_colorspace.h b/chalk/chalkcolor/kis_u16_base_colorspace.h
new file mode 100644
index 00000000..756ab9b5
--- /dev/null
+++ b/chalk/chalkcolor/kis_u16_base_colorspace.h
@@ -0,0 +1,80 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_U16_BASE_COLORSPACE_H_
+#define KIS_U16_BASE_COLORSPACE_H_
+
+#include "kis_global.h"
+#include "kis_abstract_colorspace.h"
+#include "kis_integer_maths.h"
+
+/**
+ * This is the base class for 16-bit/channel colorspaces with 16-bit alpha
+ * channels. It defines a number of common methods, like handling 16-bit alpha
+ * and up- and down-scaling of channels.
+ */
+class KisU16BaseColorSpace : public KisAbstractColorSpace {
+
+public:
+
+ static const TQ_UINT16 U16_OPACITY_OPAQUE = UINT16_MAX;
+ static const TQ_UINT16 U16_OPACITY_TRANSPARENT = UINT16_MIN;
+
+public:
+
+ KisU16BaseColorSpace(const KisID & id, DWORD cmType, icColorSpaceSignature colorSpaceSignature,
+ KisColorSpaceFactoryRegistry * tqparent,
+ KisProfile *p)
+ : KisAbstractColorSpace(id, cmType, colorSpaceSignature,
+ tqparent,
+ p)
+ {
+ m_alphaSize = sizeof(TQ_UINT16);
+ };
+
+ virtual TQ_UINT8 getAlpha(const TQ_UINT8 * pixel) const;
+ virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const;
+ virtual void multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels);
+
+ virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels);
+ virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels);
+
+ virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+ virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+
+ virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos);
+ virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos);
+
+protected:
+ // For Alpha Composite
+ struct U16Mult {
+ inline TQ_UINT16 operator()(const TQ_UINT16& a, const TQ_UINT16& b) const {
+ return UINT16_MULT(a, b);
+ }
+ };
+ struct Uint8ToU16 {
+ inline TQ_UINT16 operator()(const TQ_UINT8 src) const {
+ return UINT8_TO_UINT16(src);
+ }
+ };
+ struct U16OpacityTest {
+ inline bool operator()(const TQ_UINT16& opacity) const {
+ return opacity != U16_OPACITY_TRANSPARENT;
+ }
+ };
+};
+#endif // KIS_U16_BASE_COLORSPACE_H_
diff --git a/chalk/chalkcolor/kis_u8_base_colorspace.cc b/chalk/chalkcolor/kis_u8_base_colorspace.cc
new file mode 100644
index 00000000..338d95d6
--- /dev/null
+++ b/chalk/chalkcolor/kis_u8_base_colorspace.cc
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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 <tqcolor.h>
+
+#include <kdebug.h>
+
+#include "kis_abstract_colorspace.h"
+#include "kis_u8_base_colorspace.h"
+#include "kis_integer_maths.h"
+
+TQ_UINT8 KisU8BaseColorSpace::getAlpha(const TQ_UINT8 * pixel) const
+{
+ return pixel[m_alphaPos];
+}
+
+
+
+void KisU8BaseColorSpace::setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const
+{
+ if (m_alphaPos < 0) return;
+ TQ_INT32 psize = pixelSize();
+
+ pixels += m_alphaPos;
+ while (nPixels > 0) {
+ *pixels = alpha;
+ --nPixels;
+ pixels += psize;
+ }
+
+}
+
+void KisU8BaseColorSpace::multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels)
+{
+ if (m_alphaPos < 0) return;
+ TQ_INT32 psize = pixelSize();
+
+ while (nPixels > 0) {
+ pixels[m_alphaPos] = UINT8_MULT(pixels[m_alphaPos], alpha);
+ --nPixels;
+ pixels += psize;
+ }
+}
+
+void KisU8BaseColorSpace::applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels)
+{
+ TQ_INT32 psize = pixelSize();
+
+ while (nPixels--) {
+
+ pixels[m_alphaPos] = UINT8_MULT(*(pixels + m_alphaPos) , *alpha);
+
+ alpha++;
+ pixels += psize;
+
+ }
+}
+
+void KisU8BaseColorSpace::applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels)
+{
+ TQ_INT32 psize = pixelSize();
+
+ while(nPixels--) {
+
+ TQ_UINT16 p_alpha, s_alpha;
+
+ p_alpha = getAlpha(pixels);
+ s_alpha = MAX_SELECTED - *alpha;
+
+ setAlpha(pixels, UINT8_MULT(p_alpha, s_alpha), 1);
+
+ pixels += psize;
+ ++alpha;
+ }
+}
+
+TQString KisU8BaseColorSpace::channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < (TQ_UINT32)nChannels());
+ TQ_UINT32 channelPosition = m_channels[channelIndex]->pos();
+
+ return TQString().setNum(pixel[channelPosition]);
+}
+
+TQString KisU8BaseColorSpace::normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < (TQ_UINT32)nChannels());
+ TQ_UINT32 channelPosition = m_channels[channelIndex]->pos();
+
+ return TQString().setNum(100.0 * static_cast<float>(pixel[channelPosition]) / UINT8_MAX);
+}
+
+
+TQ_UINT8 KisU8BaseColorSpace::scaleToU8(const TQ_UINT8 * pixel, TQ_INT32 channelPos)
+{
+ return pixel[channelPos];
+}
+
+TQ_UINT16 KisU8BaseColorSpace::scaleToU16(const TQ_UINT8 * pixel, TQ_INT32 channelPos)
+{
+ return UINT8_TO_UINT16(pixel[channelPos]);
+}
+
diff --git a/chalk/chalkcolor/kis_u8_base_colorspace.h b/chalk/chalkcolor/kis_u8_base_colorspace.h
new file mode 100644
index 00000000..098a1f59
--- /dev/null
+++ b/chalk/chalkcolor/kis_u8_base_colorspace.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <boud@valdyas.org>
+ *
+ * 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_U8_BASE_COLORSPACE_H_
+#define KIS_U8_BASE_COLORSPACE_H_
+
+#include <tqcolor.h>
+
+#include <tqcolor.h>
+
+#include "kis_global.h"
+#include "kis_abstract_colorspace.h"
+#include "kis_integer_maths.h"
+
+/**
+ * This class is the base for all homogenous 8-bit/channel colorspaces with 8-bit alpha channels
+ */
+class KisU8BaseColorSpace : public KisAbstractColorSpace {
+
+public:
+
+ KisU8BaseColorSpace(const KisID & id, DWORD cmType, icColorSpaceSignature colorSpaceSignature,
+ KisColorSpaceFactoryRegistry * tqparent,
+ KisProfile *p)
+ : KisAbstractColorSpace(id, cmType, colorSpaceSignature, tqparent, p)
+ {
+ m_alphaSize = sizeof(TQ_UINT8);
+ };
+
+ virtual TQ_UINT8 getAlpha(const TQ_UINT8 * pixel) const;
+ virtual void setAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const;
+ virtual void multiplyAlpha(TQ_UINT8 * pixels, TQ_UINT8 alpha, TQ_INT32 nPixels);
+
+ virtual void applyAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels);
+ virtual void applyInverseAlphaU8Mask(TQ_UINT8 * pixels, TQ_UINT8 * alpha, TQ_INT32 nPixels);
+
+ virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+ virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const;
+
+ virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos);
+ virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos);
+
+protected:
+ // For Alpha Composite
+ struct U8Mult {
+ inline TQ_UINT8 operator()(const TQ_UINT8& a, const TQ_UINT8& b) const {
+ return UINT8_MULT(a, b);
+ }
+ };
+ struct Uint8ToU8 {
+ inline TQ_UINT8 operator()(const TQ_UINT8 src) const {
+ return src;
+ }
+ };
+ struct U8OpacityTest {
+ inline bool operator()(const TQ_UINT8& opacity) const {
+ return opacity != OPACITY_TRANSPARENT;
+ }
+ };
+};
+
+
+#endif // KIS_U8_BASE_COLORSPACE_H_
diff --git a/chalk/chalkcolor/tests/Makefile.am b/chalk/chalkcolor/tests/Makefile.am
new file mode 100644
index 00000000..e78141e7
--- /dev/null
+++ b/chalk/chalkcolor/tests/Makefile.am
@@ -0,0 +1,16 @@
+AM_CPPFLAGS = \
+ -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../ \
+ $(all_includes)
+
+# The check_ target makes sure we don't install the modules,
+# $(KDE_CHECK_PLUGIN) assures a shared library is created.
+check_LTLIBRARIES = kunittest_kis_color_conversions_tester.la
+
+kunittest_kis_color_conversions_tester_la_SOURCES = kis_color_conversions_tester.cpp
+kunittest_kis_color_conversions_tester_la_LIBADD = -lkunittest ../libchalkcolor.la ../../libchalkcommon.la
+kunittest_kis_color_conversions_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
+
+check-local: kunittest_kis_color_conversions_tester.la
+ kunittestmodrunner
+
diff --git a/chalk/chalkcolor/tests/kis_color_conversions_tester.cpp b/chalk/chalkcolor/tests/kis_color_conversions_tester.cpp
new file mode 100644
index 00000000..d244b5dd
--- /dev/null
+++ b/chalk/chalkcolor/tests/kis_color_conversions_tester.cpp
@@ -0,0 +1,227 @@
+/*
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.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 <kunittest/runner.h>
+#include <kunittest/module.h>
+
+#include "kis_color_conversions_tester.h"
+#include "kis_color_conversions.h"
+
+using namespace KUnitTest;
+
+KUNITTEST_MODULE(kunittest_kis_color_conversions_tester, "Color Conversions Tester");
+KUNITTEST_MODULE_REGISTER_TESTER(KisColorConversionsTester);
+
+void KisColorConversionsTester::allTests()
+{
+ testRGBHSV();
+ testRGBHSL();
+}
+
+#define EPSILON 1e-6
+
+void KisColorConversionsTester::testRGBHSV()
+{
+ float r, g, b, h, s, v;
+
+ RGBToHSV(1, 0, 0, &h, &s, &v);
+ CHECK(h, 0.0f);
+ CHECK(s, 1.0f);
+ CHECK(v, 1.0f);
+
+ RGBToHSV(1, 1, 0, &h, &s, &v);
+ CHECK(h, 60.0f);
+ CHECK(s, 1.0f);
+ CHECK(v, 1.0f);
+
+ RGBToHSV(0, 1, 0, &h, &s, &v);
+ CHECK(h, 120.0f);
+ CHECK(s, 1.0f);
+ CHECK(v, 1.0f);
+
+ RGBToHSV(0, 1, 1, &h, &s, &v);
+ CHECK(h, 180.0f);
+ CHECK(s, 1.0f);
+ CHECK(v, 1.0f);
+
+ RGBToHSV(0, 0, 1, &h, &s, &v);
+ CHECK(h, 240.0f);
+ CHECK(s, 1.0f);
+ CHECK(v, 1.0f);
+
+ RGBToHSV(1, 0, 1, &h, &s, &v);
+ CHECK(h, 300.0f);
+ CHECK(s, 1.0f);
+ CHECK(v, 1.0f);
+
+ RGBToHSV(0, 0, 0, &h, &s, &v);
+ CHECK(h, -1.0f);
+ CHECK(s, 0.0f);
+ CHECK(v, 0.0f);
+
+ RGBToHSV(1, 1, 1, &h, &s, &v);
+ CHECK(h, -1.0f);
+ CHECK(s, 0.0f);
+ CHECK(v, 1.0f);
+
+ RGBToHSV(0.5, 0.25, 0.75, &h, &s, &v);
+ CHECK_TOLERANCE(h, 270.0f, EPSILON);
+ CHECK_TOLERANCE(s, 0.666667f, EPSILON);
+ CHECK_TOLERANCE(v, 0.75f, EPSILON);
+
+ HSVToRGB(0, 1, 1, &r, &g, &b);
+ CHECK(r, 1.0f);
+ CHECK(g, 0.0f);
+ CHECK(b, 0.0f);
+
+ HSVToRGB(60, 1, 1, &r, &g, &b);
+ CHECK(r, 1.0f);
+ CHECK(g, 1.0f);
+ CHECK(b, 0.0f);
+
+ HSVToRGB(120, 1, 1, &r, &g, &b);
+ CHECK(r, 0.0f);
+ CHECK(g, 1.0f);
+ CHECK(b, 0.0f);
+
+ HSVToRGB(180, 1, 1, &r, &g, &b);
+ CHECK(r, 0.0f);
+ CHECK(g, 1.0f);
+ CHECK(b, 1.0f);
+
+ HSVToRGB(240, 1, 1, &r, &g, &b);
+ CHECK(r, 0.0f);
+ CHECK(g, 0.0f);
+ CHECK(b, 1.0f);
+
+ HSVToRGB(300, 1, 1, &r, &g, &b);
+ CHECK(r, 1.0f);
+ CHECK(g, 0.0f);
+ CHECK(b, 1.0f);
+
+ HSVToRGB(-1, 0, 0, &r, &g, &b);
+ CHECK(r, 0.0f);
+ CHECK(g, 0.0f);
+ CHECK(b, 0.0f);
+
+ HSVToRGB(-1, 0, 1, &r, &g, &b);
+ CHECK(r, 1.0f);
+ CHECK(g, 1.0f);
+ CHECK(b, 1.0f);
+
+ HSVToRGB(270, 0.666667, 0.75, &r, &g, &b);
+ CHECK_TOLERANCE(r, 0.5f, EPSILON);
+ CHECK_TOLERANCE(g, 0.25f, EPSILON);
+ CHECK_TOLERANCE(b, 0.75f, EPSILON);
+}
+
+void KisColorConversionsTester::testRGBHSL()
+{
+ float r, g, b, h, s, l;
+
+ RGBToHSL(1, 0, 0, &h, &s, &l);
+ CHECK(h, 360.0f);
+ CHECK(s, 1.0f);
+ CHECK(l, 0.5f);
+
+ RGBToHSL(1, 1, 0, &h, &s, &l);
+ CHECK(h, 60.0f);
+ CHECK(s, 1.0f);
+ CHECK(l, 0.5f);
+
+ RGBToHSL(0, 1, 0, &h, &s, &l);
+ CHECK(h, 120.0f);
+ CHECK(s, 1.0f);
+ CHECK(l, 0.5f);
+
+ RGBToHSL(0, 1, 1, &h, &s, &l);
+ CHECK(h, 180.0f);
+ CHECK(s, 1.0f);
+ CHECK(l, 0.5f);
+
+ RGBToHSL(0, 0, 1, &h, &s, &l);
+ CHECK(h, 240.0f);
+ CHECK(s, 1.0f);
+ CHECK(l, 0.5f);
+
+ RGBToHSL(1, 0, 1, &h, &s, &l);
+ CHECK(h, 300.0f);
+ CHECK(s, 1.0f);
+ CHECK(l, 0.5f);
+
+ RGBToHSL(0, 0, 0, &h, &s, &l);
+ CHECK(h, -1.0f);
+ CHECK(s, 0.0f);
+ CHECK(l, 0.0f);
+
+ RGBToHSL(1, 1, 1, &h, &s, &l);
+ CHECK(h, -1.0f);
+ CHECK(s, 0.0f);
+ CHECK(l, 1.0f);
+
+ RGBToHSL(0.5, 0.25, 0.75, &h, &s, &l);
+ CHECK_TOLERANCE(h, 270.0f, EPSILON);
+ CHECK_TOLERANCE(s, 0.5f, EPSILON);
+ CHECK_TOLERANCE(l, 0.5f, EPSILON);
+
+ HSLToRGB(0, 1, 0.5, &r, &g, &b);
+ CHECK(r, 1.0f);
+ CHECK(g, 0.0f);
+ CHECK(b, 0.0f);
+
+ HSLToRGB(60, 1, 0.5, &r, &g, &b);
+ CHECK(r, 1.0f);
+ CHECK(g, 1.0f);
+ CHECK(b, 0.0f);
+
+ HSLToRGB(120, 1, 0.5, &r, &g, &b);
+ CHECK(r, 0.0f);
+ CHECK(g, 1.0f);
+ CHECK(b, 0.0f);
+
+ HSLToRGB(180, 1, 0.5, &r, &g, &b);
+ CHECK(r, 0.0f);
+ CHECK(g, 1.0f);
+ CHECK(b, 1.0f);
+
+ HSLToRGB(240, 1, 0.5, &r, &g, &b);
+ CHECK(r, 0.0f);
+ CHECK(g, 0.0f);
+ CHECK(b, 1.0f);
+
+ HSLToRGB(300, 1, 0.5, &r, &g, &b);
+ CHECK(r, 1.0f);
+ CHECK(g, 0.0f);
+ CHECK(b, 1.0f);
+
+ HSLToRGB(-1, 0, 0, &r, &g, &b);
+ CHECK(r, 0.0f);
+ CHECK(g, 0.0f);
+ CHECK(b, 0.0f);
+
+ HSLToRGB(-1, 0, 1, &r, &g, &b);
+ CHECK(r, 1.0f);
+ CHECK(g, 1.0f);
+ CHECK(b, 1.0f);
+
+ HSLToRGB(270, 0.5, 0.5, &r, &g, &b);
+ CHECK_TOLERANCE(r, 0.5f, EPSILON);
+ CHECK_TOLERANCE(g, 0.25f, EPSILON);
+ CHECK_TOLERANCE(b, 0.75f, EPSILON);
+}
+
diff --git a/chalk/chalkcolor/tests/kis_color_conversions_tester.h b/chalk/chalkcolor/tests/kis_color_conversions_tester.h
new file mode 100644
index 00000000..1223abbb
--- /dev/null
+++ b/chalk/chalkcolor/tests/kis_color_conversions_tester.h
@@ -0,0 +1,44 @@
+/*
+ * Copyright (c) 2005 Adrian Page <adrian@pagenet.plus.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_COLOR_CONVERSIONS_TESTER_H
+#define KIS_COLOR_CONVERSIONS_TESTER_H
+
+#include <kunittest/tester.h>
+
+#define CHECK_TOLERANCE( x, y, tolerance ) \
+if ((x) <= (y) + (tolerance) && (x) >= (y) - (tolerance)) \
+{ \
+ success(TQString(__FILE__) + "[" + TQString::number(__LINE__) + "]: passed " + #x); \
+} \
+else \
+{ \
+ failure(TQString(__FILE__) + "[" + TQString::number(__LINE__) + TQString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + TQString::number(x)); \
+} \
+
+
+class KisColorConversionsTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+ void testRGBHSV();
+ void testRGBHSL();
+};
+
+#endif
+