summaryrefslogtreecommitdiffstats
path: root/krita/colorspaces
diff options
context:
space:
mode:
authortpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
committertpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da>2010-01-20 01:29:50 +0000
commit8362bf63dea22bbf6736609b0f49c152f975eb63 (patch)
tree0eea3928e39e50fae91d4e68b21b1e6cbae25604 /krita/colorspaces
downloadkoffice-8362bf63dea22bbf6736609b0f49c152f975eb63.tar.gz
koffice-8362bf63dea22bbf6736609b0f49c152f975eb63.zip
Added old abandoned KDE3 version of koffice
git-svn-id: svn://anonsvn.kde.org/home/kde/branches/trinity/applications/koffice@1077364 283d02a7-25f6-0310-bc7c-ecb5cbfe19da
Diffstat (limited to 'krita/colorspaces')
-rw-r--r--krita/colorspaces/Makefile.am15
-rw-r--r--krita/colorspaces/README11
-rw-r--r--krita/colorspaces/cmyk_u16/Makefile.am30
-rw-r--r--krita/colorspaces/cmyk_u16/cmyk_u16_plugin.cc61
-rw-r--r--krita/colorspaces/cmyk_u16/cmyk_u16_plugin.h37
-rw-r--r--krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.cc714
-rw-r--r--krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h123
-rw-r--r--krita/colorspaces/cmyk_u16/krita_cmyk_u16_plugin.desktop85
-rw-r--r--krita/colorspaces/cmyk_u8/Makefile.am20
-rw-r--r--krita/colorspaces/cmyk_u8/cmyk_plugin.cc66
-rw-r--r--krita/colorspaces/cmyk_u8/cmyk_plugin.h37
-rw-r--r--krita/colorspaces/cmyk_u8/cmykplugin.rc7
-rw-r--r--krita/colorspaces/cmyk_u8/composite.h76
-rw-r--r--krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc710
-rw-r--r--krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.h126
-rw-r--r--krita/colorspaces/cmyk_u8/kritacmykplugin.desktop99
-rw-r--r--krita/colorspaces/cmyk_u8/templates/.directory5
-rw-r--r--krita/colorspaces/cmyk_u8/templates/Makefile.am8
-rw-r--r--krita/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.pngbin0 -> 431 bytes
-rw-r--r--krita/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgzbin0 -> 1655 bytes
-rw-r--r--krita/colorspaces/cmyk_u8/templates/white_2000x800.desktop100
-rw-r--r--krita/colorspaces/cmyk_u8/templates/white_2000x800.krabin0 -> 17590 bytes
-rw-r--r--krita/colorspaces/gray_u16/Makefile.am29
-rw-r--r--krita/colorspaces/gray_u16/gray_u16_plugin.cc63
-rw-r--r--krita/colorspaces/gray_u16/gray_u16_plugin.h37
-rw-r--r--krita/colorspaces/gray_u16/kis_gray_u16_colorspace.cc658
-rw-r--r--krita/colorspaces/gray_u16/kis_gray_u16_colorspace.h118
-rw-r--r--krita/colorspaces/gray_u16/krita_gray_u16_plugin.desktop83
-rw-r--r--krita/colorspaces/gray_u8/Makefile.am31
-rw-r--r--krita/colorspaces/gray_u8/gray_plugin.cc77
-rw-r--r--krita/colorspaces/gray_u8/gray_plugin.h36
-rw-r--r--krita/colorspaces/gray_u8/grayplugin.rc7
-rw-r--r--krita/colorspaces/gray_u8/kis_gray_colorspace.cc997
-rw-r--r--krita/colorspaces/gray_u8/kis_gray_colorspace.h114
-rw-r--r--krita/colorspaces/gray_u8/kritagrayplugin.desktop97
-rw-r--r--krita/colorspaces/gray_u8/templates/.directory48
-rw-r--r--krita/colorspaces/gray_u8/templates/Makefile.am8
-rw-r--r--krita/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.pngbin0 -> 1367 bytes
-rw-r--r--krita/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgzbin0 -> 1725 bytes
-rw-r--r--krita/colorspaces/gray_u8/templates/white_640x480.desktop99
-rw-r--r--krita/colorspaces/gray_u8/templates/white_640x480.krabin0 -> 2824 bytes
-rw-r--r--krita/colorspaces/gray_u8/tests/Makefile.am17
-rw-r--r--krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.cpp155
-rw-r--r--krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.h34
-rw-r--r--krita/colorspaces/lms_f32/Makefile.am28
-rw-r--r--krita/colorspaces/lms_f32/kis_lms_f32_colorspace.cc385
-rw-r--r--krita/colorspaces/lms_f32/kis_lms_f32_colorspace.h157
-rw-r--r--krita/colorspaces/lms_f32/krita_lms_f32_plugin.desktop77
-rw-r--r--krita/colorspaces/lms_f32/lms_f32_plugin.cc64
-rw-r--r--krita/colorspaces/lms_f32/lms_f32_plugin.h39
-rw-r--r--krita/colorspaces/lms_f32/lms_f32_plugin.rc9
-rw-r--r--krita/colorspaces/rgb_f16half/Makefile.am35
-rw-r--r--krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.cc952
-rw-r--r--krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.h144
-rw-r--r--krita/colorspaces/rgb_f16half/krita_rgb_f16half_plugin.desktop76
-rw-r--r--krita/colorspaces/rgb_f16half/rgb_f16half_plugin.cc63
-rw-r--r--krita/colorspaces/rgb_f16half/rgb_f16half_plugin.h38
-rw-r--r--krita/colorspaces/rgb_f16half/rgb_f16half_plugin.rc9
-rw-r--r--krita/colorspaces/rgb_f16half/tests/Makefile.am19
-rw-r--r--krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.cc545
-rw-r--r--krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.h47
-rw-r--r--krita/colorspaces/rgb_f32/Makefile.am34
-rw-r--r--krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc949
-rw-r--r--krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h165
-rw-r--r--krita/colorspaces/rgb_f32/krita_rgb_f32_plugin.desktop77
-rw-r--r--krita/colorspaces/rgb_f32/rgb_f32_plugin.cc63
-rw-r--r--krita/colorspaces/rgb_f32/rgb_f32_plugin.h38
-rw-r--r--krita/colorspaces/rgb_f32/rgb_f32_plugin.rc9
-rw-r--r--krita/colorspaces/rgb_f32/tests/Makefile.am17
-rw-r--r--krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.cc541
-rw-r--r--krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.h47
-rw-r--r--krita/colorspaces/rgb_u16/Makefile.am32
-rw-r--r--krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc869
-rw-r--r--krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h128
-rw-r--r--krita/colorspaces/rgb_u16/krita_rgb_u16_plugin.desktop80
-rw-r--r--krita/colorspaces/rgb_u16/rgb_u16_plugin.cc61
-rw-r--r--krita/colorspaces/rgb_u16/rgb_u16_plugin.h36
-rw-r--r--krita/colorspaces/rgb_u16/tests/Makefile.am17
-rw-r--r--krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.cc524
-rw-r--r--krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.h46
-rw-r--r--krita/colorspaces/rgb_u8/Makefile.am33
-rw-r--r--krita/colorspaces/rgb_u8/composite.h868
-rw-r--r--krita/colorspaces/rgb_u8/kis_rgb_colorspace.cc1501
-rw-r--r--krita/colorspaces/rgb_u8/kis_rgb_colorspace.h116
-rw-r--r--krita/colorspaces/rgb_u8/kritargbplugin.desktop99
-rw-r--r--krita/colorspaces/rgb_u8/rgb_plugin.cc74
-rw-r--r--krita/colorspaces/rgb_u8/rgb_plugin.h37
-rw-r--r--krita/colorspaces/rgb_u8/rgbplugin.rc9
-rw-r--r--krita/colorspaces/rgb_u8/templates/.directory6
-rw-r--r--krita/colorspaces/rgb_u8/templates/Makefile.am8
-rw-r--r--krita/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.pngbin0 -> 2363 bytes
-rw-r--r--krita/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgzbin0 -> 1818 bytes
-rw-r--r--krita/colorspaces/rgb_u8/templates/transparent_1024x768.desktop91
-rw-r--r--krita/colorspaces/rgb_u8/templates/transparent_1024x768.krabin0 -> 7141 bytes
-rw-r--r--krita/colorspaces/rgb_u8/templates/transparent_1280x1024.desktop92
-rw-r--r--krita/colorspaces/rgb_u8/templates/transparent_1280x1024.krabin0 -> 9806 bytes
-rw-r--r--krita/colorspaces/rgb_u8/templates/transparent_1600x1200.desktop97
-rw-r--r--krita/colorspaces/rgb_u8/templates/transparent_1600x1200.krabin0 -> 13147 bytes
-rw-r--r--krita/colorspaces/rgb_u8/templates/transparent_640x480.desktop92
-rw-r--r--krita/colorspaces/rgb_u8/templates/transparent_640x480.krabin0 -> 4947 bytes
-rw-r--r--krita/colorspaces/rgb_u8/templates/white_1024x768.desktop102
-rw-r--r--krita/colorspaces/rgb_u8/templates/white_1024x768.krabin0 -> 5323 bytes
-rw-r--r--krita/colorspaces/rgb_u8/templates/white_1280x1024.desktop95
-rw-r--r--krita/colorspaces/rgb_u8/templates/white_1280x1024.krabin0 -> 7988 bytes
-rw-r--r--krita/colorspaces/rgb_u8/templates/white_1600x1200.desktop95
-rw-r--r--krita/colorspaces/rgb_u8/templates/white_1600x1200.krabin0 -> 11442 bytes
-rw-r--r--krita/colorspaces/rgb_u8/templates/white_640x480.desktop102
-rw-r--r--krita/colorspaces/rgb_u8/templates/white_640x480.krabin0 -> 3164 bytes
-rw-r--r--krita/colorspaces/rgb_u8/tests/Makefile.am17
-rw-r--r--krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.cpp197
-rw-r--r--krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.h34
-rw-r--r--krita/colorspaces/wet/Makefile.am27
-rw-r--r--krita/colorspaces/wet/kis_texture_filter.cc43
-rw-r--r--krita/colorspaces/wet/kis_texture_filter.h38
-rw-r--r--krita/colorspaces/wet/kis_texture_painter.cc92
-rw-r--r--krita/colorspaces/wet/kis_texture_painter.h40
-rw-r--r--krita/colorspaces/wet/kis_wet_colorspace.cc514
-rw-r--r--krita/colorspaces/wet/kis_wet_colorspace.h219
-rw-r--r--krita/colorspaces/wet/kis_wet_palette_widget.cc245
-rw-r--r--krita/colorspaces/wet/kis_wet_palette_widget.h67
-rw-r--r--krita/colorspaces/wet/kis_wetness_visualisation_filter.cc77
-rw-r--r--krita/colorspaces/wet/kis_wetness_visualisation_filter.h50
-rw-r--r--krita/colorspaces/wet/kis_wetop.cc230
-rw-r--r--krita/colorspaces/wet/kis_wetop.h73
-rw-r--r--krita/colorspaces/wet/kritawetplugin.desktop86
-rw-r--r--krita/colorspaces/wet/todo24
-rw-r--r--krita/colorspaces/wet/wdgpressure.ui60
-rw-r--r--krita/colorspaces/wet/wet_plugin.cc128
-rw-r--r--krita/colorspaces/wet/wet_plugin.h45
-rw-r--r--krita/colorspaces/wet/wetdreams/Makefile6
-rw-r--r--krita/colorspaces/wet/wetdreams/wetmain.c517
-rw-r--r--krita/colorspaces/wet/wetdreams/wetpaint.c101
-rw-r--r--krita/colorspaces/wet/wetdreams/wetpaint.h4
-rw-r--r--krita/colorspaces/wet/wetdreams/wetphysics.c334
-rw-r--r--krita/colorspaces/wet/wetdreams/wetphysics.h9
-rw-r--r--krita/colorspaces/wet/wetdreams/wetpix.c332
-rw-r--r--krita/colorspaces/wet/wetdreams/wetpix.h87
-rw-r--r--krita/colorspaces/wet/wetdreams/wettexture.c84
-rw-r--r--krita/colorspaces/wet/wetdreams/wettexture.h9
-rw-r--r--krita/colorspaces/wet/wetphysicsfilter.cc424
-rw-r--r--krita/colorspaces/wet/wetphysicsfilter.h87
-rw-r--r--krita/colorspaces/wet/wetplugin.rc8
-rw-r--r--krita/colorspaces/wetsticky/Makefile.am25
-rw-r--r--krita/colorspaces/wetsticky/README42
-rw-r--r--krita/colorspaces/wetsticky/TODO7
-rw-r--r--krita/colorspaces/wetsticky/brushop/Makefile.am28
-rw-r--r--krita/colorspaces/wetsticky/brushop/README2
-rw-r--r--krita/colorspaces/wetsticky/brushop/kis_wsbrushop.cc117
-rw-r--r--krita/colorspaces/wetsticky/brushop/kis_wsbrushop.h56
-rw-r--r--krita/colorspaces/wetsticky/brushop/kritawsbrushpaintop.desktop73
-rw-r--r--krita/colorspaces/wetsticky/brushop/wetpaintbrush.pngbin0 -> 1328 bytes
-rw-r--r--krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc56
-rw-r--r--krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h43
-rw-r--r--krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc605
-rw-r--r--krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.h148
-rw-r--r--krita/colorspaces/wetsticky/kis_ws_engine_filter.cc180
-rw-r--r--krita/colorspaces/wetsticky/kis_ws_engine_filter.h77
-rw-r--r--krita/colorspaces/wetsticky/kritawsplugin.desktop46
-rw-r--r--krita/colorspaces/wetsticky/wet_sticky_plugin.cc60
-rw-r--r--krita/colorspaces/wetsticky/wet_sticky_plugin.h41
-rw-r--r--krita/colorspaces/wetsticky/ws/GNU0
-rw-r--r--krita/colorspaces/wetsticky/ws/GNU Public Licence.txt341
-rw-r--r--krita/colorspaces/wetsticky/ws/README4
-rw-r--r--krita/colorspaces/wetsticky/ws/TODO24
-rw-r--r--krita/colorspaces/wetsticky/ws/after.jpgbin0 -> 29607 bytes
-rw-r--r--krita/colorspaces/wetsticky/ws/anim.c154
-rw-r--r--krita/colorspaces/wetsticky/ws/before.jpgbin0 -> 15496 bytes
-rw-r--r--krita/colorspaces/wetsticky/ws/canvas.c514
-rw-r--r--krita/colorspaces/wetsticky/ws/canvas.h70
-rw-r--r--krita/colorspaces/wetsticky/ws/cmap.c681
-rw-r--r--krita/colorspaces/wetsticky/ws/constants.h69
-rw-r--r--krita/colorspaces/wetsticky/ws/engine.c802
-rw-r--r--krita/colorspaces/wetsticky/ws/engine.h33
-rw-r--r--krita/colorspaces/wetsticky/ws/engine3.c617
-rw-r--r--krita/colorspaces/wetsticky/ws/load_ppm.c244
-rw-r--r--krita/colorspaces/wetsticky/ws/main.c105
-rw-r--r--krita/colorspaces/wetsticky/ws/makefile55
-rw-r--r--krita/colorspaces/wetsticky/ws/mona.pgmbin0 -> 86269 bytes
-rw-r--r--krita/colorspaces/wetsticky/ws/ogl_interface.c302
-rw-r--r--krita/colorspaces/wetsticky/ws/test2.jpgbin0 -> 13050 bytes
-rw-r--r--krita/colorspaces/wetsticky/ws/test3.jpgbin0 -> 21238 bytes
-rw-r--r--krita/colorspaces/wetsticky/ws/types.h72
-rw-r--r--krita/colorspaces/wetsticky/ws/win_interface.h28
-rw-r--r--krita/colorspaces/wetsticky/ws/x_interface.c795
-rw-r--r--krita/colorspaces/wetsticky/wstool.ui262
-rw-r--r--krita/colorspaces/ycbcr_u16/Makefile.am27
-rw-r--r--krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.cc338
-rw-r--r--krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.h144
-rw-r--r--krita/colorspaces/ycbcr_u16/krita_ycbcr_u16_plugin.desktop71
-rw-r--r--krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc60
-rw-r--r--krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h37
-rw-r--r--krita/colorspaces/ycbcr_u8/Makefile.am29
-rw-r--r--krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.cc344
-rw-r--r--krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h144
-rw-r--r--krita/colorspaces/ycbcr_u8/krita_ycbcr_u8_plugin.desktop71
-rw-r--r--krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc62
-rw-r--r--krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h37
197 files changed, 27425 insertions, 0 deletions
diff --git a/krita/colorspaces/Makefile.am b/krita/colorspaces/Makefile.am
new file mode 100644
index 00000000..8f975e96
--- /dev/null
+++ b/krita/colorspaces/Makefile.am
@@ -0,0 +1,15 @@
+# Definition of the service type
+
+if have_openexr
+HALF_SUBDIRS=rgb_f16half
+endif
+
+SUBDIRS = rgb_u8 rgb_u16 rgb_f32 \
+ gray_u8 gray_u16 \
+ cmyk_u8 cmyk_u16 \
+ lms_f32 \
+ ycbcr_u8 ycbcr_u16 \
+ $(HALF_SUBDIRS) \
+ wet
+#wet wetsticky
+
diff --git a/krita/colorspaces/README b/krita/colorspaces/README
new file mode 100644
index 00000000..21e302ff
--- /dev/null
+++ b/krita/colorspaces/README
@@ -0,0 +1,11 @@
+About Modules
+
+Modules are plug-ins that implement exchangable core functionality
+for Krita, such as colour strategies. Modules are loaded at startup
+and shared among all Krita documents and views. That means that making
+modules stateful is iffy, and that you need to be careful about
+re-entrancy.
+
+Modules are named modules because the plugins, which are kpartgui's
+are already called plugins. Capito? Good.
+
diff --git a/krita/colorspaces/cmyk_u16/Makefile.am b/krita/colorspaces/cmyk_u16/Makefile.am
new file mode 100644
index 00000000..913ec6ab
--- /dev/null
+++ b/krita/colorspaces/cmyk_u16/Makefile.am
@@ -0,0 +1,30 @@
+kde_services_DATA = krita_cmyk_u16_plugin.desktop
+
+INCLUDES = -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../kritacolor/ \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+lib_LTLIBRARIES = libkrita_cmyk_u16.la
+libkrita_cmyk_u16_la_SOURCES = kis_cmyk_u16_colorspace.cc
+libkrita_cmyk_u16_la_LDFLAGS = $(all_libraries)
+libkrita_cmyk_u16_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = krita_cmyk_u16_plugin.la
+
+# Srcs for the plugin
+krita_cmyk_u16_plugin_la_SOURCES = cmyk_u16_plugin.cc
+noinst_HEADERS = cmyk_u16_plugin.h kis_cmyk_u16_colorspace.h
+
+krita_cmyk_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+krita_cmyk_u16_plugin_la_LIBADD = libkrita_cmyk_u16.la ../../kritacolor/libkritacolor.la
+
+krita_cmyk_u16_plugin_la_METASOURCES = AUTO
+#METASOURCES = AUTO # XXX: which of the two?
+
+
+SUBDIRS = .
+#$(TESTSDIR)
+
diff --git a/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.cc b/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.cc
new file mode 100644
index 00000000..a86b09f4
--- /dev/null
+++ b/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.cc
@@ -0,0 +1,61 @@
+/*
+* cmyk_u16_plugin.cc -- Part of Krita
+*
+* Copyright (c) 2004 Boudewijn Rempt ([email protected])
+* Copyright (c) 2005 Adrian Page <[email protected]>
+*
+* 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 <kinstance.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <kis_debug_areas.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_basic_histogram_producers.h>
+#include <kis_debug_areas.h>
+#include "cmyk_u16_plugin.h"
+#include "kis_cmyk_u16_colorspace.h"
+
+typedef KGenericFactory<CMYKU16Plugin> CMYKU16PluginFactory;
+K_EXPORT_COMPONENT_FACTORY( krita_cmyk_u16_plugin, CMYKU16PluginFactory( "krita" ) )
+
+
+CMYKU16Plugin::CMYKU16Plugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(CMYKU16PluginFactory::instance());
+
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") )
+ {
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry*>( parent );
+
+ KisColorSpace * colorSpaceCMYKU16 = new KisCmykU16ColorSpace(f, 0);
+ KisColorSpaceFactory * csf = new KisCmykU16ColorSpaceFactory();
+ Q_CHECK_PTR(colorSpaceCMYKU16);
+ f->add(csf);
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicU16HistogramProducer>
+ (KisID("CMYK16HISTO", i18n("CMYK16")), colorSpaceCMYKU16) );
+ }
+
+}
+
+CMYKU16Plugin::~CMYKU16Plugin()
+{
+}
+
+#include "cmyk_u16_plugin.moc"
diff --git a/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.h b/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.h
new file mode 100644
index 00000000..90dce548
--- /dev/null
+++ b/krita/colorspaces/cmyk_u16/cmyk_u16_plugin.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * 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 CMYK_U16_PLUGIN_H_
+#define CMYK_U16_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the CMYK U16 colour space strategy.
+ */
+class CMYKU16Plugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ CMYKU16Plugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~CMYKU16Plugin();
+
+};
+
+
+#endif // CMYK_U16_PLUGIN_H_
diff --git a/krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.cc b/krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.cc
new file mode 100644
index 00000000..92ac3c83
--- /dev/null
+++ b/krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.cc
@@ -0,0 +1,714 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * 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 <string.h>
+
+#include LCMS_HEADER
+
+#include <qimage.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include <kis_debug_areas.h>
+#include "kis_cmyk_u16_colorspace.h"
+#include "kis_u16_base_colorspace.h"
+#include "kis_color_conversions.h"
+#include "kis_integer_maths.h"
+#include "kis_colorspace_factory_registry.h"
+
+namespace {
+ const Q_INT32 MAX_CHANNEL_CMYK = 4;
+ const Q_INT32 MAX_CHANNEL_CMYKA = 5;
+}
+
+KisCmykU16ColorSpace::KisCmykU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) :
+ KisU16BaseColorSpace(KisID("CMYKA16", i18n("CMYK (16-bit integer/channel)")), TYPE_CMYK5_16, icSigCmykData, parent, p)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Cyan"), i18n("C"), 0 * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), Qt::cyan));
+ m_channels.push_back(new KisChannelInfo(i18n("Magenta"), i18n("M"), 1 * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), Qt::magenta));
+ m_channels.push_back(new KisChannelInfo(i18n("Yellow"), i18n("Y"), 2 * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), Qt::yellow));
+ m_channels.push_back(new KisChannelInfo(i18n("Black"), i18n("K"), 3 * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), Qt::black));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 4 * sizeof(Q_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(Q_UINT16)));
+
+ m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT16);
+
+ init();
+}
+
+KisCmykU16ColorSpace::~KisCmykU16ColorSpace()
+{
+}
+
+void KisCmykU16ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+ Q_UINT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalBlack = 0, newAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel *pixel = reinterpret_cast<const Pixel *>(*colors);
+
+ Q_UINT32 alpha = pixel->alpha;
+ Q_UINT32 alphaTimesWeight = UINT16_MULT(alpha, UINT8_TO_UINT16(*weights));
+
+ totalCyan += UINT16_MULT(pixel->cyan, alphaTimesWeight);
+ totalMagenta += UINT16_MULT(pixel->magenta, alphaTimesWeight);
+ totalYellow += UINT16_MULT(pixel->yellow, alphaTimesWeight);
+ totalBlack += UINT16_MULT(pixel->black, alphaTimesWeight);
+ newAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ Q_ASSERT(newAlpha <= U16_OPACITY_OPAQUE);
+
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->alpha = newAlpha;
+
+ if (newAlpha > 0) {
+ totalCyan = UINT16_DIVIDE(totalCyan, newAlpha);
+ totalMagenta = UINT16_DIVIDE(totalMagenta, newAlpha);
+ totalYellow = UINT16_DIVIDE(totalYellow, newAlpha);
+ totalBlack = UINT16_DIVIDE(totalBlack, newAlpha);
+ }
+
+ dstPixel->cyan = totalCyan;
+ dstPixel->magenta = totalMagenta;
+ dstPixel->yellow = totalYellow;
+ dstPixel->black = totalBlack;
+}
+
+void KisCmykU16ColorSpace::convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const
+{
+ Q_INT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalK = 0, totalAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel * pixel = reinterpret_cast<const Pixel *>( *colors );
+
+ Q_INT32 weight = *kernelValues;
+
+ if (weight != 0) {
+ totalCyan += pixel->cyan * weight;
+ totalMagenta += pixel->magenta * weight;
+ totalYellow += pixel->yellow * weight;
+ totalK += pixel->black * weight;
+ totalAlpha += pixel->alpha * weight;
+ }
+ colors++;
+ kernelValues++;
+ }
+
+ Pixel * p = reinterpret_cast< Pixel *>( dst );
+
+ if (channelFlags & KisChannelInfo::FLAG_COLOR) {
+ p->cyan = CLAMP( ( totalCyan / factor) + offset, 0, Q_UINT16_MAX);
+ p->magenta = CLAMP( ( totalMagenta / factor) + offset, 0, Q_UINT16_MAX);
+ p->yellow = CLAMP( ( totalYellow / factor) + offset, 0, Q_UINT16_MAX);
+ p->black = CLAMP( ( totalK / factor) + offset, 0, Q_UINT16_MAX);
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT16_MAX);
+ }
+}
+
+
+void KisCmykU16ColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels)
+{
+ Q_UINT32 psize = pixelSize();
+
+ while (nPixels--)
+ {
+ Pixel * p = reinterpret_cast< Pixel *>( src );
+ p->cyan = Q_UINT16_MAX - p->cyan;
+ p->magenta = Q_UINT16_MAX - p->magenta;
+ p->yellow = Q_UINT16_MAX - p->yellow;
+ p->black = Q_UINT16_MAX - p->black;
+ src += psize;
+ }
+}
+
+
+
+void KisCmykU16ColorSpace::applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *adj, Q_INT32 nPixels)
+{
+ Q_UINT32 psize = pixelSize();
+
+ Q_UINT8 * tmp = new Q_UINT8[nPixels * psize];
+ Q_UINT8 * tmpPtr = tmp;
+ memcpy(tmp, dst, nPixels * psize);
+
+ KisAbstractColorSpace::applyAdjustment(src, dst, adj, nPixels);
+
+ // Copy the alpha, which lcms doesn't do for us, grumble.
+
+ while (nPixels--)
+ {
+ Q_UINT16 *pixelAlphaSrc = reinterpret_cast<Q_UINT16 *>(tmpPtr + m_alphaPos);
+ Q_UINT16 *pixelAlphaDst = reinterpret_cast<Q_UINT16 *>(dst + m_alphaPos);
+
+ *pixelAlphaDst= *pixelAlphaSrc;
+
+ tmpPtr += psize;
+ dst += psize;
+ }
+
+ delete [] tmp;
+}
+
+QValueVector<KisChannelInfo *> KisCmykU16ColorSpace::channels() const
+{
+ return m_channels;
+}
+
+Q_UINT32 KisCmykU16ColorSpace::nChannels() const
+{
+ return MAX_CHANNEL_CMYKA;
+}
+
+Q_UINT32 KisCmykU16ColorSpace::nColorChannels() const
+{
+ return MAX_CHANNEL_CMYK;
+}
+
+Q_UINT32 KisCmykU16ColorSpace::pixelSize() const
+{
+ return MAX_CHANNEL_CMYKA * sizeof(Q_UINT16);
+}
+
+void KisCmykU16ColorSpace::getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex)
+{
+ if (channelIndex < (Q_UINT32)MAX_CHANNEL_CMYKA) {
+
+ memset(dstPixel, 0, MAX_CHANNEL_CMYKA * sizeof(Q_UINT16));
+
+ if (U16_OPACITY_TRANSPARENT != 0) {
+ dstPixel[PIXEL_ALPHA] = U16_OPACITY_TRANSPARENT;
+ }
+
+ memcpy(dstPixel + (channelIndex * sizeof(Q_UINT16)), srcPixel + (channelIndex * sizeof(Q_UINT16)), sizeof(Q_UINT16));
+ }
+}
+
+void KisCmykU16ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT16 *src = reinterpret_cast<const Q_UINT16 *>(srcRowStart);
+ Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(dstRowStart);
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ Q_UINT16 srcAlpha = src[PIXEL_ALPHA];
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask));
+ }
+ mask++;
+ }
+
+ if (srcAlpha != U16_OPACITY_TRANSPARENT) {
+
+ if (opacity != U16_OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, opacity);
+ }
+
+ if (srcAlpha == U16_OPACITY_OPAQUE) {
+ memcpy(dst, src, MAX_CHANNEL_CMYKA * sizeof(Q_UINT16));
+ } else {
+ Q_UINT16 dstAlpha = dst[PIXEL_ALPHA];
+
+ Q_UINT16 srcBlend;
+
+ if (dstAlpha == U16_OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_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, MAX_CHANNEL_CMYK * sizeof(Q_UINT16));
+ } else {
+ dst[PIXEL_CYAN] = UINT16_BLEND(src[PIXEL_CYAN], dst[PIXEL_CYAN], srcBlend);
+ dst[PIXEL_MAGENTA] = UINT16_BLEND(src[PIXEL_MAGENTA], dst[PIXEL_MAGENTA], srcBlend);
+ dst[PIXEL_YELLOW] = UINT16_BLEND(src[PIXEL_YELLOW], dst[PIXEL_YELLOW], srcBlend);
+ dst[PIXEL_BLACK] = UINT16_BLEND(src[PIXEL_BLACK], dst[PIXEL_BLACK], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_CMYKA;
+ dst += MAX_CHANNEL_CMYKA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart) {
+ maskRowStart += maskRowStride;
+ }
+ }
+}
+
+#define COMMON_COMPOSITE_OP_PROLOG() \
+ while (rows > 0) { \
+ \
+ const Q_UINT16 *src = reinterpret_cast<const Q_UINT16 *>(srcRowStart); \
+ Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(dstRowStart); \
+ Q_INT32 columns = numColumns; \
+ const Q_UINT8 *mask = maskRowStart; \
+ \
+ while (columns > 0) { \
+ \
+ Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; \
+ Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \
+ \
+ srcAlpha = QMIN(srcAlpha, dstAlpha); \
+ \
+ if (mask != 0) { \
+ Q_UINT8 U8_mask = *mask; \
+ \
+ if (U8_mask != OPACITY_OPAQUE) { \
+ srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); \
+ } \
+ mask++; \
+ } \
+ \
+ if (srcAlpha != U16_OPACITY_TRANSPARENT) { \
+ \
+ if (opacity != U16_OPACITY_OPAQUE) { \
+ srcAlpha = UINT16_MULT(srcAlpha, opacity); \
+ } \
+ \
+ Q_UINT16 srcBlend; \
+ \
+ if (dstAlpha == U16_OPACITY_OPAQUE) { \
+ srcBlend = srcAlpha; \
+ } else { \
+ Q_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 += MAX_CHANNEL_CMYKA; \
+ dst += MAX_CHANNEL_CMYKA; \
+ } \
+ \
+ rows--; \
+ srcRowStart += srcRowStride; \
+ dstRowStart += dstRowStride; \
+ if(maskRowStart) { \
+ maskRowStart += maskRowStride; \
+ } \
+ }
+
+void KisCmykU16ColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+
+ for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) {
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = UINT16_MULT(srcColor, dstColor);
+
+ dst[channel] = UINT16_BLEND(srcColor, dstColor, srcBlend);
+ }
+
+
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykU16ColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykU16ColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykU16ColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor));
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykU16ColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykU16ColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMIN(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX);
+ if (srcColor > UINT16_MAX - srcColor) srcColor = UINT16_MAX;
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykU16ColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMIN(srcColor, dstColor);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykU16ColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMAX(srcColor, dstColor);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykU16ColorSpace::compositeErase(Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT16 /*opacity*/)
+{
+ while (rows-- > 0)
+ {
+ const Pixel *s = reinterpret_cast<const Pixel *>(src);
+ Pixel *d = reinterpret_cast<Pixel *>(dst);
+ const Q_UINT8 *mask = srcAlphaMask;
+
+ for (Q_INT32 i = cols; i > 0; i--, s++, d++)
+ {
+ Q_UINT16 srcAlpha = s->alpha;
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_mask));
+ }
+ mask++;
+ }
+ d->alpha = UINT16_MULT(srcAlpha, d->alpha);
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ if(srcAlphaMask) {
+ srcAlphaMask += maskRowStride;
+ }
+ }
+}
+
+
+void KisCmykU16ColorSpace::bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *mask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 U8_opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op)
+{
+ Q_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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIVIDE:
+ compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, U8_opacity);
+ break;
+ case COMPOSITE_COPY_CYAN:
+ //compositeCopyCyan(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY_MAGENTA:
+ //compositeCopyMagenta(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY_YELLOW:
+ //compositeCopyYellow(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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LIGHTEN:
+ compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_HUE:
+ //compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SATURATION:
+ //compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_VALUE:
+ //compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COLOR:
+ //compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_OVERLAY:
+ compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DODGE:
+ compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BURN:
+ compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ALPHA_DARKEN:
+ abstractCompositeAlphaDarken<Q_UINT16, U16Mult, Uint8ToU16, U16OpacityTest,
+ PIXEL_ALPHA, MAX_CHANNEL_CMYK, MAX_CHANNEL_CMYKA>(
+ dst, dstRowStride, src, srcRowStride, mask, maskRowStride,
+ rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest());
+ break;
+ default:
+ break;
+ }
+}
+
+KisCompositeOpList KisCmykU16ColorSpace::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/krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h b/krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h
new file mode 100644
index 00000000..227e18d2
--- /dev/null
+++ b/krita/colorspaces/cmyk_u16/kis_cmyk_u16_colorspace.h
@@ -0,0 +1,123 @@
+/*
+ * Copyright (c) 2006 Boudewijn Rempt <[email protected]>
+ *
+ * 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_CMYK_U16_H_
+#define KIS_STRATEGY_COLORSPACE_CMYK_U16_H_
+
+#include <qcolor.h>
+
+#include <koffice_export.h>
+
+#include "kis_global.h"
+#include "kis_u16_base_colorspace.h"
+#include "kis_integer_maths.h"
+
+
+class KRITATOOL_EXPORT KisCmykU16ColorSpace : public KisU16BaseColorSpace {
+public:
+
+ struct Pixel {
+ Q_UINT16 cyan;
+ Q_UINT16 magenta;
+ Q_UINT16 yellow;
+ Q_UINT16 black;
+ Q_UINT16 alpha;
+ };
+
+public:
+ KisCmykU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p);
+ virtual ~KisCmykU16ColorSpace();
+
+ virtual bool willDegrade(ColorSpaceIndependence independence)
+ {
+ if (independence == TO_RGBA8)
+ return true;
+ else
+ return false;
+ };
+
+public:
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+
+ virtual void applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *adj, Q_INT32 nPixels);
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+ virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels);
+ virtual void convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const;
+ virtual void getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex);
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+protected:
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+
+private:
+ friend class KisCmykU16ColorSpaceTester;
+
+ static const Q_UINT8 PIXEL_CYAN = 0;
+ static const Q_UINT8 PIXEL_MAGENTA = 1;
+ static const Q_UINT8 PIXEL_YELLOW = 2;
+ static const Q_UINT8 PIXEL_BLACK = 3;
+ static const Q_UINT8 PIXEL_ALPHA = 4;
+};
+
+class KisCmykU16ColorSpaceFactory : public KisColorSpaceFactory
+{
+public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("CMYKA16", i18n("CMYK (16-bit integer/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return TYPE_CMYK5_16; };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icSigCmykData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisCmykU16ColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return "Offset printing, according to ISO/DIS 12647-2:2004, OFCOM, paper type 1 or 2 = coated art, 115 g/m2, screen ruling 60 cm-1, positive-acting plates"; };
+};
+
+#endif // KIS_STRATEGY_COLORSPACE_CMYK_U16_H_
diff --git a/krita/colorspaces/cmyk_u16/krita_cmyk_u16_plugin.desktop b/krita/colorspaces/cmyk_u16/krita_cmyk_u16_plugin.desktop
new file mode 100644
index 00000000..ea14371a
--- /dev/null
+++ b/krita/colorspaces/cmyk_u16/krita_cmyk_u16_plugin.desktop
@@ -0,0 +1,85 @@
+[Desktop Entry]
+Name=CMYK Color Model (16-bit integer)
+Name[bg]=Цветови модел CMYK (16 бита)
+Name[ca]=Model de color CMYK (enters de 16 bits)
+Name[cy]=Model Lliw CMYK (cyfanrif 16-did)
+Name[da]=CMYK-farvemodel (16-bit heltal)
+Name[de]=CMYK-Farbmodell (16-bit Ganzzahl)
+Name[el]=Χρωματικό μοντέλο CMYK (16-bit ακέραιοι)
+Name[en_GB]=CMYK Colour Model (16-bit integer)
+Name[eo]=CMYK-kolormodelo (16-bita entjero)
+Name[es]=Modelo de color CMYK (entero de 16 bits)
+Name[et]=CMYK värvimudel (16-bitine täisarv)
+Name[fa]=مدل رنگ CMYK )عدد صحیح ۱۶ بیتی(
+Name[fi]=CMYK-värimalli
+Name[fr]=Modèle de couleurs CMYK (entiers 16 bits)
+Name[fy]=CMYK-kleurmodel (16-bit ynteger)
+Name[gl]=Modelo de Cores CMYK (inteiro de 16-bit)
+Name[he]=מודל צבעים CMYK (16 סיביות)
+Name[hu]=CMYK színmodell (16 bites egész)
+Name[is]=CMYK litategund (16-bita)
+Name[it]=Modello di colore CMYK (intero a 16 bit)
+Name[ja]=CMYK カラーモデル (16 ビット整数)
+Name[km]=គំរូ​ពណ៌ CMYK (ចំនួនគត់ ១៦ ប៊ីត)
+Name[lt]=CMYK spalvų modelis (16-bitų sveikasis)
+Name[nb]=CMYK-fargemodell (16-bit heltall)
+Name[nds]=CMYK-Klöörmodell (16-Bit Heeltall)
+Name[ne]=CMYK रङ मोडेल (१६-बिट इन्टिजर)
+Name[nl]=CMYK-kleurmodel (16-bit integer)
+Name[pl]=Przestrzeń barw CMYK (16-bitowa liczbowa całkowita)
+Name[pt]=Modelo de Cor CMYK (inteiros de 16 bits)
+Name[pt_BR]=Modelo de Cor CMYK (inteiros de 16 bits)
+Name[ru]=CMYK (целое 16-бит)
+Name[se]=CMYK-ivdnemálle (16-bihttá lohku)
+Name[sk]=CMYK model farieb (16-bitové čísla)
+Name[sl]=Barvni model CMYK (16-bitno celo število)
+Name[sr]=CMYK модел боја (16-битно целобројно)
+Name[sr@Latn]=CMYK model boja (16-bitno celobrojno)
+Name[sv]=CMYK-färgmodell (16-bitars heltal)
+Name[uk]=Модель кольору CMYK (16-бітне ціле число)
+Name[uz]=CMYK rang usuli (16-bit butun)
+Name[uz@cyrillic]=CMYK ранг усули (16-бит бутун)
+Name[zh_CN]=CMYK 色彩模型(16 位整数)
+Name[zh_TW]=CMYK 色彩模型 (16-bit 整數)
+Comment=Color model for 16-bit integer per channel CMYK images
+Comment[bg]=Цветови модел за 16 битови изображения CMYK
+Comment[ca]=Model de color d'enters de 16 bits per a canal d'imatges CMYK
+Comment[cy]=Model lliw ar gyfer delweddau CMYK â chyfanrif 16-did/sianel
+Comment[da]=Farvemodel for 16-bit heltal pr kanal CMYK-billeder
+Comment[de]=Farbmodell für 16-bit pro Kanal CMYK-Bilder
+Comment[el]=Χρωματικό μοντέλο για 16-bit ακεραίους ανά κανάλι CMYK εικόνες
+Comment[en_GB]=Colour model for 16-bit integer per channel CMYK images
+Comment[es]=Modelo de color de entero de 16 bits por canal para imágenes CMYK
+Comment[et]=16-bitiste täisarvuliste kanalitega CMYK-piltide värvimudel
+Comment[fa]=مدل رنگ برای عدد صحیح ۱۶ بیتی در هر مجرای تصاویر CMYK
+Comment[fi]=Värimalli 8-bittisille/kanavaisille CMYK-kuville
+Comment[fr]=Modèle de couleurs pour des images CMYK à 16 bits/plage
+Comment[fy]=Kleurmodel foar 16-bit/kanaal fan CMYK-ôfbeeldings
+Comment[gl]=Modelo de Cores para imaxes CMYK de 16-bit por canal
+Comment[he]=מודל צבעים עבור תמונות CMYK של 16 סיביות/ערוצים
+Comment[hu]=Színmodell 16 bit/csatorna CMYK képekhez
+Comment[is]=Litategund fyrir 16-bita/rásir CMYK myndir
+Comment[it]=Modello di colore per immagini CMYK a canale di 16 bit
+Comment[ja]=16 ビット整数/チャンネル CMYK 画像のためのカラーモデル
+Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព CMYK ចំនួនគត់ ១៦ ប៊ីត​ក្នុង​មួយ​ឆានែល
+Comment[nb]=Fargemodell for CMYK-bilder med 16 bit per kanal
+Comment[nds]=Klöörmodell för CMYK-Biller mit 16-Bit Heeltall per Kanaal
+Comment[ne]=प्रति च्यानल CMYK छविहरूको १६ बिट इन्टिजरका लागि रङ मोडेल
+Comment[nl]=Kleurmodel voor 16-bit/kanaal van CMYK-afbeeldingen
+Comment[pl]=Przestrzeń barw dla obrazków CMYK z 16-bitowymi liczbami całkowitymi na kanał
+Comment[pt]=Modelo de cor para imagens CMYK com 16 bits por canal
+Comment[pt_BR]=Modelo de cor para imagens CMYK com 16 bits por canal
+Comment[ru]=Цветовое пространство CMYK (целое 16-бит/канал)
+Comment[se]=CMYK-ivdnemálle mas lea 16 bihttá kanálas
+Comment[sk]=Model farieb pre CMYK obrázky so 16 bitmi na kanál
+Comment[sl]=Barvni model za slike CMYK z 16 biti/kanal
+Comment[sr]=Модел боја за CMYK слике, 16-битно целобројно по каналу
+Comment[sr@Latn]=Model boja za CMYK slike, 16-bitno celobrojno po kanalu
+Comment[sv]=Färgmodell för 16-bitars heltal per kanal CMYK-bilder
+Comment[uk]=Модель кольору з 16-бітним цілим числом для кожного каналу зображень CMYK
+Comment[zh_CN]=16 位整数每通道 CYMK 图像的色彩模型
+Comment[zh_TW]=每色頻為 16-bit 的 CMYK 圖片色彩模型
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-KDE-Library=krita_cmyk_u16_plugin
+X-Krita-Version=2
diff --git a/krita/colorspaces/cmyk_u8/Makefile.am b/krita/colorspaces/cmyk_u8/Makefile.am
new file mode 100644
index 00000000..2816451f
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/Makefile.am
@@ -0,0 +1,20 @@
+kde_services_DATA = kritacmykplugin.desktop
+
+INCLUDES = -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../kritacolor/color_strategy \
+ -I$(srcdir)/../../kritacolor \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+kde_module_LTLIBRARIES = kritacmykplugin.la
+
+kritacmykplugin_la_SOURCES = cmyk_plugin.cc kis_cmyk_colorspace.cc
+noinst_HEADERS = cmyk_plugin.h kis_cmyk_colorspace.h
+
+kritacmykplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kritacmykplugin_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+kritacmykplugin_la_METASOURCES = AUTO
+
+
+SUBDIRS=templates
diff --git a/krita/colorspaces/cmyk_u8/cmyk_plugin.cc b/krita/colorspaces/cmyk_u8/cmyk_plugin.cc
new file mode 100644
index 00000000..ccd5a1b4
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/cmyk_plugin.cc
@@ -0,0 +1,66 @@
+/*
+ * cmyk_plugin.cc -- Part of Krita
+ *
+ * Copyright (c) 2004 Boudewijn Rempt ([email protected])
+ *
+ * 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 <kiconloader.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+#include <kis_debug_areas.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_basic_histogram_producers.h>
+
+#include "cmyk_plugin.h"
+
+#include "kis_cmyk_colorspace.h"
+
+typedef KGenericFactory<CMYKPlugin> CMYKPluginFactory;
+K_EXPORT_COMPONENT_FACTORY( kritacmykplugin, CMYKPluginFactory( "krita" ) )
+
+
+CMYKPlugin::CMYKPlugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(CMYKPluginFactory::instance());
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") )
+ {
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry*>( parent );
+
+ KisColorSpace * colorSpaceCMYK = new KisCmykColorSpace(f, 0);
+ KisColorSpaceFactory * csf = new KisCmykColorSpaceFactory();
+ Q_CHECK_PTR(colorSpaceCMYK);
+ f->add(csf);
+
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicU8HistogramProducer>
+ (KisID("CMYKHISTO", i18n("CMYK")), colorSpaceCMYK) );
+ }
+
+}
+
+CMYKPlugin::~CMYKPlugin()
+{
+}
+
+#include "cmyk_plugin.moc"
diff --git a/krita/colorspaces/cmyk_u8/cmyk_plugin.h b/krita/colorspaces/cmyk_u8/cmyk_plugin.h
new file mode 100644
index 00000000..c9cee97d
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/cmyk_plugin.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2003 Boudewijn Rempt ([email protected])
+ *
+ * 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 CMYK_PLUGIN_H_
+#define CMYK_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the CMYK colour space strategy.
+ */
+class CMYKPlugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ CMYKPlugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~CMYKPlugin();
+
+
+};
+
+#endif // CMYK_PLUGIN_H_
diff --git a/krita/colorspaces/cmyk_u8/cmykplugin.rc b/krita/colorspaces/cmyk_u8/cmykplugin.rc
new file mode 100644
index 00000000..915a1d0a
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/cmykplugin.rc
@@ -0,0 +1,7 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui library="kritacmykplugin" version="1">
+<Menu name="Image"><text>&amp;Image</text>
+ <Menu name="Mode"><text>&amp;Mode</text>
+ <Action name="convert to RGB(A)"/>
+ </Menu>
+</Menu></kpartgui>
diff --git a/krita/colorspaces/cmyk_u8/composite.h b/krita/colorspaces/cmyk_u8/composite.h
new file mode 100644
index 00000000..a037a054
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/composite.h
@@ -0,0 +1,76 @@
+/*
+ * Copyright (c) 2006 Boudewijn Rempt
+ *
+ * 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 COMPOSITE_CMYK
+#define COMPOSITE_CMYK
+
+void compositeCopyCyan(Q_INT32 stride,
+ Q_UINT8 *dst,
+ Q_INT32 dststride,
+ Q_UINT8 *src,
+ Q_INT32 srcstride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ compositeCopyChannel(PIXEL_CYAN, stride, dst, dststride, src, srcstride, rows, cols, opacity);
+}
+
+
+void compositeCopyMagenta(Q_INT32 stride,
+ Q_UINT8 *dst,
+ Q_INT32 dststride,
+ Q_UINT8 *src,
+ Q_INT32 srcstride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ compositeCopyChannel(PIXEL_MAGENTA, stride, dst, dststride, src, srcstride, rows, cols, opacity);
+
+}
+
+
+void compositeCopyYellow(Q_INT32 stride,
+ Q_UINT8 *dst,
+ Q_INT32 dststride,
+ Q_UINT8 *src,
+ Q_INT32 srcstride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ compositeCopyChannel(PIXEL_YELLOW, stride, dst, dststride, src, srcstride, rows, cols, opacity);
+
+}
+
+
+void compositeCopyBlack(Q_INT32 stride,
+ Q_UINT8 *dst,
+ Q_INT32 dststride,
+ Q_UINT8 *src,
+ Q_INT32 srcstride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ compositeCopyChannel(PIXEL_BLACK, stride, dst, dststride, src, srcstride, rows, cols, opacity);
+}
+
+
+#endif \ No newline at end of file
diff --git a/krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc b/krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc
new file mode 100644
index 00000000..d40be017
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.cc
@@ -0,0 +1,710 @@
+/*
+ * Copyright (c) 2003 Boudewijn Rempt ([email protected])
+ *
+ * This program is free software; you can CYANistribute 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 <qimage.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "kis_cmyk_colorspace.h"
+#include "kis_u8_base_colorspace.h"
+#include "kis_colorspace_factory_registry.h"
+
+#include "kis_profile.h"
+#include "kis_integer_maths.h"
+
+namespace cmyk {
+ const Q_INT32 MAX_CHANNEL_CMYK = 4;
+ const Q_INT32 MAX_CHANNEL_CMYKA = 5;
+}
+
+KisCmykColorSpace::KisCmykColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) :
+ KisU8BaseColorSpace(KisID("CMYK", i18n("CMYK")), TYPE_CMYK5_8, icSigCmykData, parent, p)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Cyan"), i18n("C"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, Qt::cyan));
+ m_channels.push_back(new KisChannelInfo(i18n("Magenta"), i18n("M"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, Qt::magenta));
+ m_channels.push_back(new KisChannelInfo(i18n("Yellow"), i18n("Y"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, Qt::yellow));
+ m_channels.push_back(new KisChannelInfo(i18n("Black"), i18n("K"), 3, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, Qt::black));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 4, KisChannelInfo::ALPHA, KisChannelInfo::UINT8, 1, Qt::white));
+
+ m_alphaPos = PIXEL_CMYK_ALPHA;
+
+ init();
+}
+
+KisCmykColorSpace::~KisCmykColorSpace()
+{
+}
+
+void KisCmykColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+ Q_UINT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalK = 0, totalAlpha = 0;
+
+ while (nColors--)
+ {
+ Q_UINT32 alpha = (*colors)[4];
+ Q_UINT32 alphaTimesWeight = alpha * *weights;
+
+ totalCyan += (*colors)[0] * alphaTimesWeight;
+ totalMagenta += (*colors)[1] * alphaTimesWeight;
+ totalYellow += (*colors)[2] * alphaTimesWeight;
+ totalK += (*colors)[3] * alphaTimesWeight;
+ totalAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ //Q_ASSERT(newAlpha <= 255*255);
+ if (totalAlpha > 255*255) totalAlpha = 255*255;
+
+ // Divide by 255.
+ dst[4] =(((totalAlpha + 0x80)>>8)+totalAlpha) >>8;
+
+ if (totalAlpha > 0) {
+ totalCyan = totalCyan / totalAlpha;
+ totalMagenta = totalMagenta / totalAlpha;
+ totalYellow = totalYellow / totalAlpha;
+ totalK = totalK / totalAlpha;
+ } // else the values are already 0 too
+
+ Q_UINT32 dstCyan = totalCyan;
+ if (dstCyan > 255) dstCyan = 255;
+ dst[0] = dstCyan;
+
+ Q_UINT32 dstMagenta = totalMagenta;
+ if (dstMagenta > 255) dstMagenta = 255;
+ dst[1] = dstMagenta;
+
+ Q_UINT32 dstYellow = totalYellow;
+ if (dstYellow > 255) dstYellow = 255;
+ dst[2] = dstYellow;
+
+ Q_UINT32 dstK = totalK;
+ if (dstK > 255) dstK = 255;
+ dst[3] = dstK;
+}
+
+
+void KisCmykColorSpace::convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const
+{
+ Q_INT32 totalCyan = 0, totalMagenta = 0, totalYellow = 0, totalK = 0, totalAlpha = 0;
+
+ while (nColors--)
+ {
+ Q_INT32 weight = *kernelValues;
+
+ if (weight != 0) {
+ totalCyan += (*colors)[PIXEL_CYAN] * weight;
+ totalMagenta += (*colors)[PIXEL_MAGENTA] * weight;
+ totalYellow += (*colors)[PIXEL_YELLOW] * weight;
+ totalK += (*colors)[PIXEL_BLACK] * weight;
+ totalAlpha += (*colors)[PIXEL_CMYK_ALPHA] * weight;
+ }
+ colors++;
+ kernelValues++;
+ }
+
+
+ if (channelFlags & KisChannelInfo::FLAG_COLOR) {
+ dst[PIXEL_CYAN] = CLAMP((totalCyan / factor) + offset, 0, Q_UINT8_MAX);
+ dst[PIXEL_MAGENTA] = CLAMP((totalMagenta / factor) + offset, 0, Q_UINT8_MAX);
+ dst[PIXEL_YELLOW] = CLAMP((totalYellow / factor) + offset, 0, Q_UINT8_MAX);
+ dst[PIXEL_BLACK] = CLAMP((totalK / factor) + offset, 0, Q_UINT8_MAX);
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ dst[PIXEL_CMYK_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT8_MAX);
+ }
+}
+
+
+void KisCmykColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels)
+{
+ Q_UINT32 psize = pixelSize();
+
+ while (nPixels--)
+ {
+ src[PIXEL_CYAN] = Q_UINT8_MAX - src[PIXEL_CYAN];
+ src[PIXEL_MAGENTA] = Q_UINT8_MAX - src[PIXEL_MAGENTA];
+ src[PIXEL_YELLOW] = Q_UINT8_MAX - src[PIXEL_YELLOW];
+ src[PIXEL_BLACK] = Q_UINT8_MAX - src[PIXEL_BLACK];
+ src += psize;
+ }
+}
+
+void KisCmykColorSpace::applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *adj, Q_INT32 nPixels)
+{
+ Q_UINT32 psize = pixelSize();
+
+ Q_UINT8 * tmp = new Q_UINT8[nPixels * psize];
+ Q_UINT8 * tmpPtr = tmp;
+ memcpy(tmp, dst, nPixels * psize);
+
+ KisAbstractColorSpace::applyAdjustment(src, dst, adj, nPixels);
+
+ // Copy the alpha, which lcms doesn't do for us, grumble.
+
+ while (nPixels--)
+ {
+ dst[4] = tmpPtr[4];
+
+ tmpPtr += psize;
+ dst += psize;
+ }
+
+ delete [] tmp;
+}
+
+QValueVector<KisChannelInfo *> KisCmykColorSpace::channels() const
+{
+ return m_channels;
+}
+
+Q_UINT32 KisCmykColorSpace::nChannels() const
+{
+ return cmyk::MAX_CHANNEL_CMYKA;
+}
+
+Q_UINT32 KisCmykColorSpace::nColorChannels() const
+{
+ return cmyk::MAX_CHANNEL_CMYK;
+}
+
+Q_UINT32 KisCmykColorSpace::pixelSize() const
+{
+ return cmyk::MAX_CHANNEL_CMYKA;
+}
+
+void KisCmykColorSpace::getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex)
+{
+ if (channelIndex < (Q_UINT32)cmyk::MAX_CHANNEL_CMYKA) {
+
+ memset(dstPixel, 0, cmyk::MAX_CHANNEL_CMYKA * sizeof(Q_UINT8));
+
+ if (OPACITY_TRANSPARENT != 0) {
+ dstPixel[PIXEL_CMYK_ALPHA] = OPACITY_TRANSPARENT;
+ }
+
+ memcpy(dstPixel + (channelIndex * sizeof(Q_UINT8)), srcPixel + (channelIndex * sizeof(Q_UINT8)), sizeof(Q_UINT8));
+ }
+}
+
+void KisCmykColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_CMYK_ALPHA];
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(srcAlpha, U8_mask);
+ }
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(srcAlpha, opacity);
+ }
+
+ if (srcAlpha == OPACITY_OPAQUE) {
+ memcpy(dst, src, cmyk::MAX_CHANNEL_CMYKA * sizeof(Q_UINT8));
+ } else {
+ Q_UINT8 dstAlpha = dst[PIXEL_CMYK_ALPHA];
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_CMYK_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ if (srcBlend == OPACITY_OPAQUE) {
+ memcpy(dst, src, cmyk::MAX_CHANNEL_CMYK * sizeof(Q_UINT8));
+ } else {
+ dst[PIXEL_CYAN] = UINT8_BLEND(src[PIXEL_CYAN], dst[PIXEL_CYAN], srcBlend);
+ dst[PIXEL_MAGENTA] = UINT8_BLEND(src[PIXEL_MAGENTA], dst[PIXEL_MAGENTA], srcBlend);
+ dst[PIXEL_YELLOW] = UINT8_BLEND(src[PIXEL_YELLOW], dst[PIXEL_YELLOW], srcBlend);
+ dst[PIXEL_BLACK] = UINT8_BLEND(src[PIXEL_BLACK], dst[PIXEL_BLACK], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += cmyk::MAX_CHANNEL_CMYKA;
+ dst += cmyk::MAX_CHANNEL_CMYKA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart) {
+ maskRowStart += maskRowStride;
+ }
+ }
+}
+
+#define COMMON_COMPOSITE_OP_PROLOG() \
+ while (rows > 0) { \
+ \
+ const Q_UINT8 *src = srcRowStart; \
+ Q_UINT8 *dst = dstRowStart; \
+ Q_INT32 columns = numColumns; \
+ const Q_UINT8 *mask = maskRowStart; \
+ \
+ while (columns > 0) { \
+ \
+ Q_UINT8 srcAlpha = src[PIXEL_CMYK_ALPHA]; \
+ Q_UINT8 dstAlpha = dst[PIXEL_CMYK_ALPHA]; \
+ \
+ srcAlpha = QMIN(srcAlpha, dstAlpha); \
+ \
+ if (mask != 0) { \
+ Q_UINT8 U8_mask = *mask; \
+ \
+ if (U8_mask != OPACITY_OPAQUE) { \
+ srcAlpha = UINT8_MULT(srcAlpha, U8_mask); \
+} \
+ mask++; \
+} \
+ \
+ if (srcAlpha != OPACITY_TRANSPARENT) { \
+ \
+ if (opacity != OPACITY_OPAQUE) { \
+ srcAlpha = UINT8_MULT(srcAlpha, opacity); \
+} \
+ \
+ Q_UINT8 srcBlend; \
+ \
+ if (dstAlpha == OPACITY_OPAQUE) { \
+ srcBlend = srcAlpha; \
+} else { \
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha); \
+ dst[PIXEL_CMYK_ALPHA] = newAlpha; \
+ \
+ if (newAlpha != 0) { \
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha); \
+} else { \
+ srcBlend = srcAlpha; \
+} \
+}
+
+#define COMMON_COMPOSITE_OP_EPILOG() \
+} \
+ \
+ columns--; \
+ src += cmyk::MAX_CHANNEL_CMYKA; \
+ dst += cmyk::MAX_CHANNEL_CMYKA; \
+} \
+ \
+ rows--; \
+ srcRowStart += srcRowStride; \
+ dstRowStart += dstRowStride; \
+ if(maskRowStart) { \
+ maskRowStart += maskRowStride; \
+} \
+}
+
+void KisCmykColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+
+ for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) {
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = UINT8_MULT(srcColor, dstColor);
+
+ dst[channel] = UINT8_BLEND(srcColor, dstColor, srcBlend);
+ }
+
+
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT8_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT8_MAX);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = UINT8_MAX - UINT8_MULT(UINT8_MAX - dstColor, UINT8_MAX - srcColor);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = UINT8_MULT(dstColor, dstColor + 2u * UINT8_MULT(srcColor, UINT8_MAX - dstColor));
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT8_MAX + 1u)) / (UINT8_MAX + 1u - srcColor), UINT8_MAX);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMIN(((UINT8_MAX - dstColor) * (UINT8_MAX + 1u)) / (srcColor + 1u), UINT8_MAX);
+ if (srcColor > UINT8_MAX - srcColor) srcColor = UINT8_MAX;
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMIN(srcColor, dstColor);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < cmyk::MAX_CHANNEL_CMYK; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMAX(srcColor, dstColor);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisCmykColorSpace::compositeErase(Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 /*opacity*/)
+{
+ while (rows-- > 0)
+ {
+ const Pixel *s = reinterpret_cast<const Pixel *>(src);
+ Pixel *d = reinterpret_cast<Pixel *>(dst);
+ const Q_UINT8 *mask = srcAlphaMask;
+
+ for (Q_INT32 i = cols; i > 0; i--, s++, d++)
+ {
+ Q_UINT8 srcAlpha = s->alpha;
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_BLEND(srcAlpha, OPACITY_OPAQUE, U8_mask);
+ }
+ mask++;
+ }
+ d->alpha = UINT8_MULT(srcAlpha, d->alpha);
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ if(srcAlphaMask) {
+ srcAlphaMask += maskRowStride;
+ }
+ }
+}
+
+void KisCmykColorSpace::bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *mask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op)
+{
+
+ switch (op.op()) {
+ case COMPOSITE_UNDEF:
+ // Undefined == no composition
+ break;
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIVIDE:
+ compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY_CYAN:
+ //compositeCopyCyan(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY_MAGENTA:
+ //compositeCopyMagenta(pixelSize(), dst, dstRowStride, src, srcRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY_YELLOW:
+ //compositeCopyYellow(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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LIGHTEN:
+ compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_HUE:
+ //compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SATURATION:
+ //compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_VALUE:
+ //compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COLOR:
+ //compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_OVERLAY:
+ compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DODGE:
+ compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BURN:
+ compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ALPHA_DARKEN:
+ abstractCompositeAlphaDarken<Q_UINT8, U8Mult, Uint8ToU8, U8OpacityTest,
+ PIXEL_CMYK_ALPHA, cmyk::MAX_CHANNEL_CMYK, cmyk::MAX_CHANNEL_CMYKA>(
+ dst, dstRowStride, src, srcRowStride, mask, maskRowStride,
+ rows, cols, opacity, U8Mult(), Uint8ToU8(), U8OpacityTest());
+ break;
+ default:
+ break;
+ }
+}
+
+KisCompositeOpList KisCmykColorSpace::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/krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.h b/krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.h
new file mode 100644
index 00000000..b918f1aa
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/kis_cmyk_colorspace.h
@@ -0,0 +1,126 @@
+/*
+ * Copyright (c) 2003 Boudewijn Rempt ([email protected])
+ *
+ * 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_CMYK_H_
+#define KIS_STRATEGY_COLORSPACE_CMYK_H_
+
+#include <qcolor.h>
+#include <qmap.h>
+#include <koffice_export.h>
+#include "kis_global.h"
+#include "kis_u8_base_colorspace.h"
+
+class KRITACORE_EXPORT KisCmykColorSpace : public KisU8BaseColorSpace {
+
+public:
+
+
+ struct Pixel {
+ Q_UINT16 cyan;
+ Q_UINT16 magenta;
+ Q_UINT16 yellow;
+ Q_UINT16 black;
+ Q_UINT16 alpha;
+ };
+public:
+ KisCmykColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p);
+ virtual ~KisCmykColorSpace();
+
+
+ virtual bool willDegrade(ColorSpaceIndependence independence)
+ {
+ if (independence == TO_RGBA8)
+ return true;
+ else
+ return false;
+ };
+
+
+
+public:
+
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+ virtual void applyAdjustment(const Q_UINT8 *src, Q_UINT8 *dst, KisColorAdjustment *adj, Q_INT32 nPixels);
+ virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels);
+ virtual void convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const;
+ // XXX: darken & intensity8?
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+ virtual void getSingleChannelPixel(Q_UINT8 *dstPixel, const Q_UINT8 *srcPixel, Q_UINT32 channelIndex);
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+protected:
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+
+private:
+
+ Q_UINT8 * m_qcolordata;
+
+ static const Q_UINT8 PIXEL_CYAN = 0;
+ static const Q_UINT8 PIXEL_MAGENTA = 1;
+ static const Q_UINT8 PIXEL_YELLOW = 2;
+ static const Q_UINT8 PIXEL_BLACK = 3;
+ static const Q_UINT8 PIXEL_CMYK_ALPHA = 4;
+};
+
+class KisCmykColorSpaceFactory : public KisColorSpaceFactory
+{
+public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("CMYK", i18n("CMYK (8-bit integer/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return TYPE_CMYK5_8; };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icSigCmykData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisCmykColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return "Offset printing, according to ISO/DIS 12647-2:2004, OFCOM, paper type 1 or 2 = coated art, 115 g/m2, screen ruling 60 cm-1, positive-acting plates"; }; // Do not i18n -- this is from a data file
+};
+
+#endif // KIS_STRATEGY_COLORSPACE_CMYK_H_
diff --git a/krita/colorspaces/cmyk_u8/kritacmykplugin.desktop b/krita/colorspaces/cmyk_u8/kritacmykplugin.desktop
new file mode 100644
index 00000000..5ae04a6f
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/kritacmykplugin.desktop
@@ -0,0 +1,99 @@
+[Desktop Entry]
+Name=CMYK Color Model
+Name[bg]=Цветови модел CMYK
+Name[br]=Gobari al livioù CMYK
+Name[ca]=Model de color CMYK
+Name[cy]=Model Lliw CMYK
+Name[da]=CMYK-farvemodel
+Name[de]=CMYK-Farbmodell
+Name[el]=Χρωματικό μοντέλο CMYK
+Name[en_GB]=CMYK Colour Model
+Name[eo]=CMYK-kolormodelo
+Name[es]=Modelo de color CMYK
+Name[et]=CMYK värvimudel
+Name[eu]=CMYK kolore-eredua
+Name[fa]=مدل رنگ CMYK
+Name[fi]=CMYK-värimalli
+Name[fr]=Modèle de couleurs CMYK
+Name[fy]=CMYK kleur-model
+Name[gl]=Modelo de Cores CMYK
+Name[he]=מודל צבעים CMYK
+Name[hi]=सीएमवायके रंग नमूना
+Name[hu]=CMYK színmodell
+Name[is]=CMYK litategund
+Name[it]=Modello di colore CMYK
+Name[ja]=CMYK カラーモデル
+Name[km]=គំរូពណ៌ CMYK
+Name[lt]=CMYK spalvų modelis
+Name[ms]=Model Warna CMYK
+Name[nb]=CMYK-fargemodell
+Name[nds]=CMYK-Klöörmodell
+Name[ne]=CMYK रङ मोडेलल
+Name[nl]=CMYK-kleurmodel
+Name[nn]=CMYK-fargemodell
+Name[pl]=Przestrzeń barw CMYK
+Name[pt]=Modelo de Cor CMYK
+Name[pt_BR]=Modelo de Cor CMYK
+Name[ru]=CMYK
+Name[se]=CMYK-ivdnemálle
+Name[sk]=Model farieb CMYK
+Name[sl]=Barvni model CMYK
+Name[sr]=CMYK модел боја
+Name[sr@Latn]=CMYK model boja
+Name[sv]=CMYK-färgmodell
+Name[ta]=CMYK வண்ண முறை
+Name[tr]=CMYK Renk Modeli
+Name[uk]=Модель кольору CMYK
+Name[uz]=CMYK rang usuli
+Name[uz@cyrillic]=CMYK ранг усули
+Name[zh_CN]=CMYK 色彩模型
+Name[zh_TW]=CMYK 色彩模型
+Comment=Color model for 8-bit/channel CMYK images
+Comment[bg]=Цветови модел за 8 битови изображения CMYK
+Comment[ca]=Model de color d'enters de 8 bits per a canal d'imatges CMYK
+Comment[cy]=Model lliw ar gyfer delweddau CMYK 8-did/sianel
+Comment[da]=Farvemodel for 8-bit/kanal CMYK-billeder
+Comment[de]=Farbmodell für 8-bit pro Kanal CMYK-Bilder
+Comment[el]=Χρωματικό μοντέλο για 8-bit/κανάλι CMYK εικόνες
+Comment[en_GB]=Colour model for 8-bit/channel CMYK images
+Comment[es]=Modelo de color para imágenes de 8 bits/canal CMYK
+Comment[et]=8-bitiste kanalitega CMYK-piltide värvimudel
+Comment[eu]=8 bit/kanaleko CMYK irudien kolore-eredua
+Comment[fa]=مدل رنگ برای تصاویر CMYK مجرا/۸ بیتی
+Comment[fi]=Värimalli 8-bittisille/kanavaisille CMYK-kuville
+Comment[fr]=Modèle de couleurs pour des images CMYK à 8 bits/plage
+Comment[fy]=Kleurmodel foar 8-bit/kanaal CMYK-ôfbeeldings
+Comment[gl]=Modelo de Cores para imaxer CMYK de 8-bit/canal
+Comment[he]=מודל צבעים עבור תמונות CMYK של 8 סיביות/ערוצים
+Comment[hi]=8-बिट/चैनल सीएमवायके छवियों के लिए रंग नमूना
+Comment[hu]=Színmodell 8 bit/csatorna CMYK képekhez
+Comment[is]=Litategund fyrir 8-bita/rásir CMYK myndir
+Comment[it]=Modello di colore per immagini CMYK a canale di 8 bit
+Comment[ja]=8 ビット/チャンネル CMYK 画像のためのカラーモデル
+Comment[km]=គំរូពណ៌សម្រាប់​រូបភាព CMYK ៨ ប៊ីត​ក្នុង​មួយ​ឆានែល
+Comment[ms]=Model warna bagi imej CMYK 8-bit/saluran
+Comment[nb]=Fargemodell for CMYK-bilder med 8 bit per kanal
+Comment[nds]=Klöörmodell för CMYK-Biller mit 8-Bit Heeltall per Kanaal
+Comment[ne]=८-बिट/च्यानल CMYK छविहरूका लागि रङ मोडेल
+Comment[nl]=Kleurmodel voor 8-bit/kanaal CMYK-afbeeldingen
+Comment[nn]=Fargemodell for CMYK-bilete med 8 bit per kanal
+Comment[pl]=Przestrzeń barw dla obrazków CMYK 8 bitów/kanał
+Comment[pt]=Modelo de cor para imagens CMYK com 8 bits por canal
+Comment[pt_BR]=Modelo de cor para imagens com 8-bits de canal CMYK
+Comment[ru]=Цветовое пространство CMYK (8-бит/канал)
+Comment[se]=CMYK-ivdnemálle mas lea 8 bihttá kanálas
+Comment[sk]=Model farieb pre CMYK obrázky s 8 bitmi na kanál
+Comment[sl]=Barvni model za slike CMYK z 8 biti/kanal
+Comment[sr]=Модел боја за CMYK слике са 8 битова по каналу
+Comment[sr@Latn]=Model boja za CMYK slike sa 8 bitova po kanalu
+Comment[sv]=Färgmodell för 8 bitar/kanal CMYK-bilder
+Comment[ta]=8/பிட்/வழி CMYK பிம்பங்களுக்கான வண்ண முறை
+Comment[tr]=8-bit/kanal CMYK görüntüler için renk modeli
+Comment[uk]=Модель кольору CMYK для зображень 8-біт/каналів
+Comment[zh_CN]=八位/通道 CMYK 图像的色彩模型
+Comment[zh_TW]=8-bit/色頻的 CMYK 圖片色彩模型
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-KDE-Library=kritacmykplugin
+X-Krita-Version=2
+
diff --git a/krita/colorspaces/cmyk_u8/templates/.directory b/krita/colorspaces/cmyk_u8/templates/.directory
new file mode 100644
index 00000000..f69b12ea
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/templates/.directory
@@ -0,0 +1,5 @@
+[Desktop Entry]
+Name=CMYK
+Name[fr]=CMJN
+Name[hi]=सीएमवायके
+X-KDE-DefaultTab=true
diff --git a/krita/colorspaces/cmyk_u8/templates/Makefile.am b/krita/colorspaces/cmyk_u8/templates/Makefile.am
new file mode 100644
index 00000000..7a975df8
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/templates/Makefile.am
@@ -0,0 +1,8 @@
+templates_DATA = .directory white_2000x800.desktop
+templatesdir = $(kde_datadir)/krita/templates/cmyk
+
+templatesrc_DATA = white_2000x800.kra
+templatesrcdir = $(kde_datadir)/krita/templates/cmyk/.source
+
+templatesicon_ICON = AUTO
+templatesicondir = $(kde_datadir)/krita/icons
diff --git a/krita/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png b/krita/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png
new file mode 100644
index 00000000..5c844c2f
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png
Binary files differ
diff --git a/krita/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz b/krita/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz
new file mode 100644
index 00000000..a1ad0ae5
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz
Binary files differ
diff --git a/krita/colorspaces/cmyk_u8/templates/white_2000x800.desktop b/krita/colorspaces/cmyk_u8/templates/white_2000x800.desktop
new file mode 100644
index 00000000..b1632e51
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/templates/white_2000x800.desktop
@@ -0,0 +1,100 @@
+[Desktop Entry]
+Type=Link
+URL=.source/white_2000x800.kra
+Icon=template_cmyk_empty
+Name=White 2000 x 800
+Name[bg]=Бяло 2000x800
+Name[br]=Gwenn 2000 x 800
+Name[ca]=Blanc 2000 x 800
+Name[cy]=Gwyn 2000 x 800
+Name[da]=Hvidt 2000 x 800
+Name[de]=Weiß 2000 x 800
+Name[el]=Λευκό 2000 x 800
+Name[es]=2000 x 800 blanco
+Name[et]=Valge 2000 x 800
+Name[eu]=Zuria 2000 x 800
+Name[fa]=سفید ۸۰۰ × ۲۰۰۰
+Name[fi]=Valkoinen 2000 x 800
+Name[fr]=Image blanche 2000 x 800
+Name[fy]=Wyt 2000 x 800
+Name[ga]=Bán 2000×800
+Name[gl]=Branco 2000 x 800
+Name[he]=לבן ‎2000 x 800
+Name[hi]=सफेद 2000 x 800
+Name[hu]=fehér 2000 x 800
+Name[is]=Hvít 2000 x 800
+Name[it]=Bianco 2000 × 800
+Name[ja]=白 2000 x 800
+Name[km]=ពណ៌​ស 2000 x 800
+Name[lt]=Baltas 2000 x 800
+Name[lv]=Balts 2000 x 800
+Name[ms]=Putih 2000 x 800
+Name[nb]=Hvit 2000 x 800
+Name[nds]=Witt 2000 x 800
+Name[ne]=सेतो २००० x ८००
+Name[nl]=Wit 2000 x 800
+Name[nn]=Kvitt 2000 × 800
+Name[pl]=Biały 2000 x 800
+Name[pt]=Branca 2000 x 800
+Name[pt_BR]=2000 x 800 em Branco
+Name[ru]=Белый 2000x800
+Name[se]=Vilges 2000 × 800
+Name[sk]=Biely 2000 x 800
+Name[sl]=Bela 2000 x 800
+Name[sr]=Бела 2000 x 800
+Name[sr@Latn]=Bela 2000 x 800
+Name[sv]=Vit 2000 x 800
+Name[ta]=வெள்ளை 2000 x 800
+Name[tr]=Beyaz 2000 x 800
+Name[uk]=Біле 2000 x 800
+Name[uz]=Oq 2000 x 800
+Name[uz@cyrillic]=Оқ 2000 x 800
+Name[zh_CN]=白色 2000 x 800
+Name[zh_TW]=白色 2000 x 800
+Comment=Creates a white CMYK image of 2000 x 800 pixels.
+Comment[bg]=Създаване на бяло изображения CMYK с размери 2000x800 пиксела.
+Comment[ca]=Crea una imatge blanca CMYK de 2000 x 800 píxels.
+Comment[cy]=Creu delwedd CMYK wen o 2000 x 800 picsel.
+Comment[da]=Laver et hvidt CMYK-billede på 2000 x 800 biledpunkter.
+Comment[de]=Erstellt ein weißes CMYK-Bild mit 2000 x 800 Pixeln.
+Comment[el]=Δημιουργεί μία λευκή CMYK εικόνα μεγέθους 2000 x 800 εικονοστοιχείων.
+Comment[es]=Crea una imagen CMYK blanca de 2000 x 800 píxeles.
+Comment[et]=Loob valge CMYK-pildi mõõtmetega 2000 x 800 pikslit.
+Comment[eu]=2000 x 800 pixeleko CMYK irudi zuri bat sortzen du.
+Comment[fa]=یک تصویر سفید CMYK ۲۰۰۰ × ۸۰۰ تصویردانه‌ای ایجاد می‌کند.
+Comment[fi]=Luo valkoisen 2000 x 800 pikselin CMYK-kuvan.
+Comment[fr]=Crée une image CMYK blanche de 2000 x 800 pixels.
+Comment[fy]=Makket in wite CMYK-ôfbeelding oan fan 2000 x 2000 byldpunten.
+Comment[gl]=Cria unha imaxe CMYK branca de 2000 x 800 pixels.
+Comment[he]=יצירת תמונת CMYK לבנה בגודל ‎2000 x 800 פיקסלים
+Comment[hi]=2000 x 800 पिक्सेल की सफेद सीएमवायके छवि बनाता है.
+Comment[hu]=Létrehoz egy fehér, 2000 x 800 képpontos CMYK képet.
+Comment[is]=Býr til hvíta CMYK mynd með 2000 x 800 punktum.
+Comment[it]=Crea un'immagine CMYK bianca di 2000 × 800 pixel.
+Comment[ja]=2000 x 800 ピクセルの CMYK 画像を作成
+Comment[km]=បង្កើត​រូបភាព CMYK ពណ៌​ស​មួយ ដែល​មាន​ទំហំ ២០០០ x ៨០០ ភីកសែល ។
+Comment[ms]=Cipta imej CMYK putih 2000 x 800 piksel.
+Comment[nb]=Lager et hvitt CMYK-bilde på 2000 x 800 piksler.
+Comment[nds]=Stellt en wittet CMYK-Bild mit 2000 x 800 Pixels op.
+Comment[ne]=२००० x ८०० पिक्सेलको सेतो CMYK छवि सिर्जना गर्दछ ।
+Comment[nl]=Maakt een witte CMYK-afbeelding aan van 2000 x 2000 pixels.
+Comment[nn]=Lagar eit kvitt CMYK-bilete på 2000 × 800 pikslar.
+Comment[pl]=Tworzy biały obrazek CMYK o rozmiarach 2000 na 800 pikseli.
+Comment[pt]=Cria uma imagem CMYK branca com 2000 x 800 pontos.
+Comment[pt_BR]=Cria uma imagem CMYK em branco de 2000 x 800 pixéis.
+Comment[ru]=Рисунок CMYK, 2000x800, белый фон
+Comment[se]=Ráhkada CMYK-gova mas leat 2000 × 800 govvačuoggá.
+Comment[sk]=Vytvorí biely obrázok CMYK s rozmermi 2000 x 800 pixelov.
+Comment[sl]=Ustvari belo sliko CMYK velikosti 2000 x 800 pik.
+Comment[sr]=Прави белу CMYK слику са 2000 x 800 пиксела.
+Comment[sr@Latn]=Pravi belu CMYK sliku sa 2000 x 800 piksela.
+Comment[sv]=Skapar en vit CMYK-bild med 2000 x 800 bildpunkter.
+Comment[ta]=2000 x 800 படத்துணுக்குகளில் ஒரு வெள்ளை CMYK பிம்பத்தை உருவாக்குகிறது.
+Comment[tr]=2000 x 800 piksel ebadında beyaz bir CMYK görüntü oluşturur.
+Comment[uk]=Створює біле зображення CMYK 2000 x 800 пікселів.
+Comment[uz]=Oʻlchami 2000 x 800 nuqta boʻlgan oq CMYK rasmni yaratish.
+Comment[uz@cyrillic]=Ўлчами 2000 x 800 нуқта бўлган оқ CMYK расмни яратиш.
+Comment[zh_CN]=创建 2000 x 800 像素的白色 CMYK 图像。
+Comment[zh_TW]=建立一個白色,2000 x 800 像素的 CMYK 圖片。
+X-Krita-Version=2
+
diff --git a/krita/colorspaces/cmyk_u8/templates/white_2000x800.kra b/krita/colorspaces/cmyk_u8/templates/white_2000x800.kra
new file mode 100644
index 00000000..7fb7a166
--- /dev/null
+++ b/krita/colorspaces/cmyk_u8/templates/white_2000x800.kra
Binary files differ
diff --git a/krita/colorspaces/gray_u16/Makefile.am b/krita/colorspaces/gray_u16/Makefile.am
new file mode 100644
index 00000000..d9ec51e1
--- /dev/null
+++ b/krita/colorspaces/gray_u16/Makefile.am
@@ -0,0 +1,29 @@
+# location for the rc file
+kde_services_DATA = krita_gray_u16_plugin.desktop
+
+INCLUDES = -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../kritacolor/color_strategy \
+ -I$(srcdir)/../../kritacolor/ \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+lib_LTLIBRARIES = libkrita_gray_u16.la
+libkrita_gray_u16_la_SOURCES = kis_gray_u16_colorspace.cc
+libkrita_gray_u16_la_LDFLAGS = $(all_libraries)
+libkrita_gray_u16_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = krita_gray_u16_plugin.la
+
+# Srcs for the plugin
+krita_gray_u16_plugin_la_SOURCES = gray_u16_plugin.cc
+noinst_HEADERS = gray_u16_plugin.h kis_gray_u16_colorspace.h
+
+krita_gray_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+krita_gray_u16_plugin_la_LIBADD = libkrita_gray_u16.la ../../kritacolor/libkritacolor.la
+
+krita_gray_u16_plugin_la_METASOURCES = AUTO
+
+
+SUBDIRS = .
+
diff --git a/krita/colorspaces/gray_u16/gray_u16_plugin.cc b/krita/colorspaces/gray_u16/gray_u16_plugin.cc
new file mode 100644
index 00000000..da32295f
--- /dev/null
+++ b/krita/colorspaces/gray_u16/gray_u16_plugin.cc
@@ -0,0 +1,63 @@
+/*
+* gray_u16_plugin.cc -- Part of Krita
+*
+* Copyright (c) 2004 Boudewijn Rempt ([email protected])
+* Copyright (c) 2005 Adrian Page <[email protected]>
+*
+* This program is free software; you can grayistribute 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 <kinstance.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <kis_debug_areas.h>
+
+#include <kis_colorspace_factory_registry.h>
+#include <kis_basic_histogram_producers.h>
+
+#include "gray_u16_plugin.h"
+#include "kis_gray_u16_colorspace.h"
+
+typedef KGenericFactory<GRAYU16Plugin> GRAYU16PluginFactory;
+K_EXPORT_COMPONENT_FACTORY( krita_gray_u16_plugin, GRAYU16PluginFactory( "krita" ) )
+
+
+GRAYU16Plugin::GRAYU16Plugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(GRAYU16PluginFactory::instance());
+
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") )
+ {
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry*>( parent );
+
+ KisColorSpace * colorSpaceGRAYU16 = new KisGrayU16ColorSpace(f, 0);
+ KisColorSpaceFactory * csf = new KisGrayU16ColorSpaceFactory();
+ Q_CHECK_PTR(colorSpaceGRAYU16);
+ f->add(csf);
+
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicU16HistogramProducer>
+ (KisID("GRAYA16HISTO", i18n("GRAY/Alpha16")), colorSpaceGRAYU16) );
+ }
+
+}
+
+GRAYU16Plugin::~GRAYU16Plugin()
+{
+}
+
+#include "gray_u16_plugin.moc"
diff --git a/krita/colorspaces/gray_u16/gray_u16_plugin.h b/krita/colorspaces/gray_u16/gray_u16_plugin.h
new file mode 100644
index 00000000..89b2e119
--- /dev/null
+++ b/krita/colorspaces/gray_u16/gray_u16_plugin.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2003 Boudewijn Rempt ([email protected])
+ *
+ * This program is free software; you can grayistribute 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 GRAY_U16_PLUGIN_H_
+#define GRAY_U16_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the GRAY U16 colour space strategy.
+ */
+class GRAYU16Plugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ GRAYU16Plugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~GRAYU16Plugin();
+
+};
+
+
+#endif // GRAY_U16_PLUGIN_H_
diff --git a/krita/colorspaces/gray_u16/kis_gray_u16_colorspace.cc b/krita/colorspaces/gray_u16/kis_gray_u16_colorspace.cc
new file mode 100644
index 00000000..410d2c9b
--- /dev/null
+++ b/krita/colorspaces/gray_u16/kis_gray_u16_colorspace.cc
@@ -0,0 +1,658 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <[email protected]>
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * 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 <qimage.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+
+#include "kis_gray_u16_colorspace.h"
+#include "kis_u16_base_colorspace.h"
+#include "kis_color_conversions.h"
+#include "kis_integer_maths.h"
+#include "kis_colorspace_factory_registry.h"
+
+namespace {
+ const Q_INT32 MAX_CHANNEL_GRAY = 1;
+ const Q_INT32 MAX_CHANNEL_GRAYA = 2;
+}
+
+KisGrayU16ColorSpace::KisGrayU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) :
+ KisU16BaseColorSpace(KisID("GRAYA16", i18n("Grayscale (16-bit integer/channel)")), TYPE_GRAYA_16, icSigGrayData, parent, p)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Gray"), i18n("G"), PIXEL_GRAY * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16)));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(Q_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(Q_UINT16)));
+
+/* LPGAMMATABLE Gamma = cmsBuildGamma(256, 2.2);
+ cmsHPROFILE hProfile = cmsCreateGrayProfile(cmsD50_xyY(), Gamma);
+ cmsFreeGamma(Gamma);
+*/
+
+ m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT16);
+
+ init();
+}
+
+KisGrayU16ColorSpace::~KisGrayU16ColorSpace()
+{
+}
+
+void KisGrayU16ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+ Q_UINT32 totalGray = 0, newAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel *pixel = reinterpret_cast<const Pixel *>(*colors);
+
+ Q_UINT32 alpha = pixel->alpha;
+ Q_UINT32 alphaTimesWeight = UINT16_MULT(alpha, UINT8_TO_UINT16(*weights));
+
+ totalGray += UINT16_MULT(pixel->gray, alphaTimesWeight);
+ newAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ Q_ASSERT(newAlpha <= U16_OPACITY_OPAQUE);
+
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->alpha = newAlpha;
+
+ if (newAlpha > 0) {
+ totalGray = UINT16_DIVIDE(totalGray, newAlpha);
+ }
+
+ dstPixel->gray = totalGray;
+}
+
+void KisGrayU16ColorSpace::convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst,
+ Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const
+{
+ Q_INT32 totalGray = 0, totalAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel * pixel = reinterpret_cast<const Pixel *>( *colors );
+
+ Q_INT32 weight = *kernelValues;
+
+ if (weight != 0) {
+ totalGray += pixel->gray * weight;
+ totalAlpha += pixel->alpha * weight;
+ }
+ colors++;
+ kernelValues++;
+ }
+
+ Pixel * p = reinterpret_cast< Pixel *>( dst );
+
+ if (channelFlags & KisChannelInfo::FLAG_COLOR) {
+ p->gray = CLAMP( ( totalGray / factor) + offset, 0, Q_UINT16_MAX);
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT16_MAX);
+ }
+}
+
+
+void KisGrayU16ColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels)
+{
+ Q_UINT32 psize = pixelSize();
+
+ while (nPixels--)
+ {
+ Pixel * p = reinterpret_cast< Pixel *>( src );
+ p->gray = Q_UINT16_MAX - p->gray;
+ src += psize;
+ }
+}
+
+
+
+Q_UINT8 KisGrayU16ColorSpace::intensity8(const Q_UINT8 * src) const
+{
+ const Pixel * p = reinterpret_cast<const Pixel *>( src );
+ return UINT16_TO_UINT8(p->gray);
+}
+
+
+QValueVector<KisChannelInfo *> KisGrayU16ColorSpace::channels() const
+{
+ return m_channels;
+}
+
+Q_UINT32 KisGrayU16ColorSpace::nChannels() const
+{
+ return MAX_CHANNEL_GRAYA;
+}
+
+Q_UINT32 KisGrayU16ColorSpace::nColorChannels() const
+{
+ return MAX_CHANNEL_GRAY;
+}
+
+Q_UINT32 KisGrayU16ColorSpace::pixelSize() const
+{
+ return MAX_CHANNEL_GRAYA * sizeof(Q_UINT16);
+}
+
+void KisGrayU16ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT16 *src = reinterpret_cast<const Q_UINT16 *>(srcRowStart);
+ Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(dstRowStart);
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ Q_UINT16 srcAlpha = src[PIXEL_ALPHA];
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask));
+ }
+ mask++;
+ }
+
+ if (srcAlpha != U16_OPACITY_TRANSPARENT) {
+
+ if (opacity != U16_OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, opacity);
+ }
+
+ if (srcAlpha == U16_OPACITY_OPAQUE) {
+ memcpy(dst, src, MAX_CHANNEL_GRAYA * sizeof(Q_UINT16));
+ } else {
+ Q_UINT16 dstAlpha = dst[PIXEL_ALPHA];
+
+ Q_UINT16 srcBlend;
+
+ if (dstAlpha == U16_OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_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, MAX_CHANNEL_GRAY * sizeof(Q_UINT16));
+ } else {
+ dst[PIXEL_GRAY] = UINT16_BLEND(src[PIXEL_GRAY], dst[PIXEL_GRAY], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_GRAYA;
+ dst += MAX_CHANNEL_GRAYA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart) {
+ maskRowStart += maskRowStride;
+ }
+ }
+}
+
+#define COMMON_COMPOSITE_OP_PROLOG() \
+ while (rows > 0) { \
+ \
+ const Q_UINT16 *src = reinterpret_cast<const Q_UINT16 *>(srcRowStart); \
+ Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(dstRowStart); \
+ Q_INT32 columns = numColumns; \
+ const Q_UINT8 *mask = maskRowStart; \
+ \
+ while (columns > 0) { \
+ \
+ Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; \
+ Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \
+ \
+ srcAlpha = QMIN(srcAlpha, dstAlpha); \
+ \
+ if (mask != 0) { \
+ Q_UINT8 U8_mask = *mask; \
+ \
+ if (U8_mask != OPACITY_OPAQUE) { \
+ srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); \
+ } \
+ mask++; \
+ } \
+ \
+ if (srcAlpha != U16_OPACITY_TRANSPARENT) { \
+ \
+ if (opacity != U16_OPACITY_OPAQUE) { \
+ srcAlpha = UINT16_MULT(srcAlpha, opacity); \
+ } \
+ \
+ Q_UINT16 srcBlend; \
+ \
+ if (dstAlpha == U16_OPACITY_OPAQUE) { \
+ srcBlend = srcAlpha; \
+ } else { \
+ Q_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 += MAX_CHANNEL_GRAYA; \
+ dst += MAX_CHANNEL_GRAYA; \
+ } \
+ \
+ rows--; \
+ srcRowStart += srcRowStride; \
+ dstRowStart += dstRowStride; \
+ if(maskRowStart) { \
+ maskRowStart += maskRowStride; \
+ } \
+ }
+
+void KisGrayU16ColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ Q_UINT16 srcColor = src[PIXEL_GRAY];
+ Q_UINT16 dstColor = dst[PIXEL_GRAY];
+
+ srcColor = UINT16_MULT(srcColor, dstColor);
+
+ dst[PIXEL_GRAY] = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisGrayU16ColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisGrayU16ColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisGrayU16ColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor));
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisGrayU16ColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisGrayU16ColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = kMin(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX);
+ srcColor = kClamp(UINT16_MAX - srcColor, 0u, UINT16_MAX);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisGrayU16ColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMIN(srcColor, dstColor);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisGrayU16ColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_GRAY; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMAX(srcColor, dstColor);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+
+void KisGrayU16ColorSpace::compositeErase(Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT16 /*opacity*/)
+{
+ while (rows-- > 0)
+ {
+ const Pixel *s = reinterpret_cast<const Pixel *>(src);
+ Pixel *d = reinterpret_cast<Pixel *>(dst);
+ const Q_UINT8 *mask = srcAlphaMask;
+
+ for (Q_INT32 i = cols; i > 0; i--, s++, d++)
+ {
+ Q_UINT16 srcAlpha = s->alpha;
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_mask));
+ }
+ mask++;
+ }
+ d->alpha = UINT16_MULT(srcAlpha, d->alpha);
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ if(srcAlphaMask) {
+ srcAlphaMask += maskRowStride;
+ }
+ }
+}
+
+void KisGrayU16ColorSpace::bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *mask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 U8_opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op)
+{
+ Q_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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIVIDE:
+ compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LIGHTEN:
+ compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_HUE:
+ //compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SATURATION:
+ //compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_VALUE:
+ //compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COLOR:
+ //compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_OVERLAY:
+ compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DODGE:
+ compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BURN:
+ compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ALPHA_DARKEN:
+ abstractCompositeAlphaDarken<Q_UINT16, U16Mult, Uint8ToU16, U16OpacityTest,
+ PIXEL_ALPHA, MAX_CHANNEL_GRAY, MAX_CHANNEL_GRAYA>(
+ dst, dstRowStride, src, srcRowStride, mask, maskRowStride,
+ rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest());
+ break;
+ default:
+ break;
+ }
+}
+
+KisCompositeOpList KisGrayU16ColorSpace::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/krita/colorspaces/gray_u16/kis_gray_u16_colorspace.h b/krita/colorspaces/gray_u16/kis_gray_u16_colorspace.h
new file mode 100644
index 00000000..2a206564
--- /dev/null
+++ b/krita/colorspaces/gray_u16/kis_gray_u16_colorspace.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <[email protected]>
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * This program is free software; you can grayistribute 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_GRAY_U16_H_
+#define KIS_STRATEGY_COLORSPACE_GRAY_U16_H_
+
+#include <qcolor.h>
+
+#include <koffice_export.h>
+
+#include "kis_global.h"
+#include "kis_u16_base_colorspace.h"
+#include "kis_integer_maths.h"
+
+
+class KRITATOOL_EXPORT KisGrayU16ColorSpace : public KisU16BaseColorSpace {
+public:
+
+ struct Pixel {
+ Q_UINT16 gray;
+ Q_UINT16 alpha;
+ };
+
+ virtual bool willDegrade(ColorSpaceIndependence independence)
+ {
+ if (independence == TO_RGBA8)
+ return true;
+ else
+ return false;
+ };
+
+
+public:
+ KisGrayU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p);
+ virtual ~KisGrayU16ColorSpace();
+
+public:
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+ virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels);
+ virtual void convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const;
+ virtual Q_UINT8 intensity8(const Q_UINT8 * src) const;
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+
+protected:
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+
+private:
+ friend class KisGrayU16ColorSpaceTester;
+
+ static const Q_UINT8 PIXEL_GRAY = 0;
+ static const Q_UINT8 PIXEL_ALPHA = 1;
+};
+
+class KisGrayU16ColorSpaceFactory : public KisColorSpaceFactory
+{
+public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("GRAYA16", i18n("Grayscale (16-bit integer/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return TYPE_GRAY_16; };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icSigGrayData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisGrayU16ColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return "gray built-in - (lcms internal)"; };
+};
+
+#endif // KIS_STRATEGY_COLORSPACE_GRAY_U16_H_
diff --git a/krita/colorspaces/gray_u16/krita_gray_u16_plugin.desktop b/krita/colorspaces/gray_u16/krita_gray_u16_plugin.desktop
new file mode 100644
index 00000000..8ba4e38e
--- /dev/null
+++ b/krita/colorspaces/gray_u16/krita_gray_u16_plugin.desktop
@@ -0,0 +1,83 @@
+[Desktop Entry]
+Name=Grayscale Color Model (16-bit integer)
+Name[bg]=Цветови модел сива гама (16 бита)
+Name[ca]=Model de color d'escala de grisos (enters de 16 bits)
+Name[cy]=Model Lliw Graddlwyd (cyfanrif 16-did)
+Name[da]=Farvemodel med gråskala (16-bit heltal)
+Name[de]=Graustufen-Farbmodell (16-bit Ganzzahl)
+Name[el]=Χρωματικό μοντέλο διαβαθμίσεων του γκρι (16 bit ακέραιοι)
+Name[en_GB]=Greyscale Colour Model (16-bit integer)
+Name[eo]=Grizoskala kolormodelo (16-bita entjero)
+Name[es]=Modelo de color de escala de grises (entero de 16 bits)
+Name[et]=Halltooni värvimudel (16-bitine)
+Name[fa]=مدل رنگ مقیاس خاکستری )عدد صحیح ۱۶ بیتی(
+Name[fi]=Harmaasävyvärimalli (16-bittinen)
+Name[fr]=Modèle de couleurs en nivaux de gris (entiers 16 bits)
+Name[fy]=Kleurmodel foar griiswearden (16-bit yntegers)
+Name[gl]=Modelo de Cores en Escala de Gris (inteiro de 16-bit)
+Name[he]=מודל צבעים של גווני אפור )16 סיביות(
+Name[hu]=Szürkeárnyalatos színmodell (16 bites egész)
+Name[is]=Gráskala litategund (16-bita heiltala)
+Name[it]=Modello di colore a scala di grigio (intero a 16 bit)
+Name[ja]=グレースケール カラーモデル (16 ビット整数)
+Name[km]=គំរូ​ពណ៌​មាត្រដ្ឋានប្រផេះ (ចំនួនគត់ ១៦ ប៊ីត)
+Name[nb]=Fargemodell med gråtoner (16-bit heltall)
+Name[nds]=Griestöön-Klöörmodell (16-Bit Heeltall)
+Name[ne]=ग्रेस्केल रङ मोडेल (१६-बिट इन्टिजर)
+Name[nl]=Kleurmodel voor grijswaarden (16-bit integers)
+Name[pl]=Skala szarości (16-bitowa liczba całkowita)
+Name[pt]=Modelo de Cor de Tons de Cinzento (inteiros de 16 bits)
+Name[pt_BR]=Modelo de Cor de Tons de Cinza (inteiros de 16 bits)
+Name[ru]=Градации серого (целое 16-бит)
+Name[se]=Ránesivdnemálle (16-bihttá lohku)
+Name[sk]=Čiernobiely/šedý model farieb (16-bitové čísla)
+Name[sl]=Sivinski barvni model (16-bitno celo število)
+Name[sr]=Модел боја у сивим нијансама (16-битно целобројно)
+Name[sr@Latn]=Model boja u sivim nijansama (16-bitno celobrojno)
+Name[sv]=Färgmodell med gråskala (16-bitars heltal)
+Name[uk]=Модель кольору відтінків сірого (16-бітне ціле число)
+Name[uz]=Kul rang usuli (16-bit butun)
+Name[uz@cyrillic]=Кул ранг усули (16-бит бутун)
+Name[zh_CN]=灰度色彩模型(16 位整数)
+Name[zh_TW]=灰階色彩模型 (16-bit 整數)
+Comment=Color model for 16-bit integer per channel Grayscale images
+Comment[bg]=Цветови модел за 16 битови изображения в сива гама
+Comment[ca]=Model de color d'enters de 16 bits per a canal d'imatges d'escala de grisos
+Comment[cy]=Model lliw ar gyfer delweddau Graddlwyd â chyfanrif 16-did/sianel
+Comment[da]=Farvemodel for 16-bit heltal pr kanal Gråskala-billeder
+Comment[de]=Farbmodell für 16-bit Ganzzahl pro Kanal Graustufen-Bilder
+Comment[el]=Χρωματικό μοντέλο για 16-bit ακεραίους ανά κανάλι με διαβαθμίσεις του γκρι εικόνες
+Comment[en_GB]=Colour model for 16-bit integer per channel Greyscale images
+Comment[es]=Modelo de color de entero de 16 bits por canal para imágenes de escala de grises
+Comment[et]=16-bitiste täisarvuliste kanalitega halltoonis piltide värvimudel
+Comment[fa]=مدل رنگ برای عدد صحیح ۱۶ بیتی در هر تصویر مقیاس خاکستری مجرا
+Comment[fi]=Värimalli 16-bittisille harmaasävykuville
+Comment[fr]=Modèle de couleurs pour des images en nivaux de gris à 16 bits/plage
+Comment[fy]=Kleurmodel foar16-bit/kanaal griiswearde-ôfbeeldings
+Comment[gl]=Modelo de cor para imaxes en escala de grises de 16-bit por canal
+Comment[he]=מודל צבעים עבור תמונות של 16 סיביות בגווני אפור
+Comment[hu]=Színmodell 16 bit/csatorna szürkeárnyalatos képekhez
+Comment[is]=Litategund fyrir 16-bita heiltölu á rás gráskala myndir
+Comment[it]=Modello di colore per immagini in scala di grigio a canale di 16 bit
+Comment[ja]=16 ビット整数/チャンネル グレースケール画像のためのカラーモデル
+Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព​មាត្រដ្ឋាន​ប្រផេះ​ចំនួន​គត់ ១៦ ប៊ីត​ក្នុង​មួយ​ឆានែល
+Comment[nb]=Fargemodell for gråtonebilde med 16 bit per kanal
+Comment[nds]=Klöörmodell för Griestöön-Biller mit 16-Bit Heeltall per Kanaal
+Comment[ne]=प्रति च्यानल ग्रेस्केल छविहरूका १६-बिट च्यानलका लागि रङ मोडेल
+Comment[nl]=Kleurmodel voor 16-bit/kanaal grijswaarde-afbeeldingen
+Comment[pl]=Przestrzeń barw dla obrazków w skali szarości z 16-bitową liczbą całkowitą na kanał
+Comment[pt]=Modelo de cor para imagens de tons de cinzento com 16 bits por canal
+Comment[pt_BR]=Modelo de cor para imagens de tons de cinza com 16 bits por canal
+Comment[ru]=Цветовое пространство градаций серого (целое 16-бит/канал)
+Comment[sk]=Model farieb pre ČB/šedé obrázky so 16 bitmi na kanál
+Comment[sl]=Barvni model za 16-bitna cela števila/kanal sivinske slike
+Comment[sr]=Модел боја за слике у сивим нијансама, 16-битно целобројно по каналу
+Comment[sr@Latn]=Model boja za slike u sivim nijansama, 16-bitno celobrojno po kanalu
+Comment[sv]=Färgmodell för 16-bitars heltal per kanal gråskalebilder
+Comment[uk]=Модель кольору для зображень відтінків сірого, 16-біт/канал
+Comment[zh_CN]=每通道 16 位整数的灰度图像色彩模型
+Comment[zh_TW]=每色頻為 16-bit 的灰階圖片色彩模型
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-Krita-Version=2
+X-KDE-Library=krita_gray_u16_plugin
diff --git a/krita/colorspaces/gray_u8/Makefile.am b/krita/colorspaces/gray_u8/Makefile.am
new file mode 100644
index 00000000..6c84b6b3
--- /dev/null
+++ b/krita/colorspaces/gray_u8/Makefile.am
@@ -0,0 +1,31 @@
+kde_services_DATA = kritagrayplugin.desktop
+
+INCLUDES = -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../kritacolor/ \
+ -I$(interfacedir) \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+
+lib_LTLIBRARIES = libkritagrayscale.la
+libkritagrayscale_la_SOURCES = kis_gray_colorspace.cc
+libkritagrayscale_la_LDFLAGS = $(all_libraries)
+libkritagrayscale_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+kde_module_LTLIBRARIES = kritagrayplugin.la
+
+kritagrayplugin_la_SOURCES = gray_plugin.cc
+noinst_HEADERS = gray_plugin.h kis_gray_colorspace.h
+
+kritagrayplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kritagrayplugin_la_LIBADD = libkritagrayscale.la ../../kritacolor/libkritacolor.la
+
+kritagrayplugin_la_METASOURCES = AUTO
+
+if include_kunittest_tests
+TESTSDIR = tests
+endif
+
+SUBDIRS = . templates $(TESTSDIR)
+
diff --git a/krita/colorspaces/gray_u8/gray_plugin.cc b/krita/colorspaces/gray_u8/gray_plugin.cc
new file mode 100644
index 00000000..50fe51cc
--- /dev/null
+++ b/krita/colorspaces/gray_u8/gray_plugin.cc
@@ -0,0 +1,77 @@
+/*
+ * gray_plugin.cc -- Part of Krita
+ *
+ * Copyright (c) 2004 Boudewijn Rempt ([email protected])
+ *
+ * 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 <kiconloader.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+#include <kis_debug_areas.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_basic_histogram_producers.h>
+
+#include "gray_plugin.h"
+#include "kis_gray_colorspace.h"
+
+typedef KGenericFactory<GrayPlugin> GrayPluginFactory;
+K_EXPORT_COMPONENT_FACTORY( kritagrayplugin, GrayPluginFactory( "kritacore" ) )
+
+
+GrayPlugin::GrayPlugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(GrayPluginFactory::instance());
+
+ // This is not a gui plugin; only load it when the doc is created.
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") )
+ {
+
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry*>( parent );
+
+ // .22 gamma grayscale or something like that. Taken from the lcms tutorial...
+ LPGAMMATABLE Gamma = cmsBuildGamma(256, 2.2);
+ cmsHPROFILE hProfile = cmsCreateGrayProfile(cmsD50_xyY(), Gamma);
+ cmsFreeGamma(Gamma);
+ KisProfile *defProfile = new KisProfile(hProfile);
+
+ f->addProfile(defProfile);
+
+ KisColorSpace * colorSpaceGrayA = new KisGrayColorSpace(f, 0);
+
+ KisColorSpaceFactory * csf = new KisGrayColorSpaceFactory();
+ Q_CHECK_PTR(colorSpaceGrayA);
+
+ f->add(csf);
+
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicU8HistogramProducer>
+ (KisID("GRAYA8HISTO", i18n("GRAY/Alpha8")), colorSpaceGrayA) );
+ }
+
+}
+
+GrayPlugin::~GrayPlugin()
+{
+}
+
+#include "gray_plugin.moc"
diff --git a/krita/colorspaces/gray_u8/gray_plugin.h b/krita/colorspaces/gray_u8/gray_plugin.h
new file mode 100644
index 00000000..9359fa72
--- /dev/null
+++ b/krita/colorspaces/gray_u8/gray_plugin.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2003 Boudewijn Rempt ([email protected])
+ *
+ * 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 GRAY_PLUGIN_H_
+#define GRAY_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the GRAY colour space strategy.
+ */
+class GrayPlugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ GrayPlugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~GrayPlugin();
+
+};
+
+#endif // GRAY_PLUGIN_H_
diff --git a/krita/colorspaces/gray_u8/grayplugin.rc b/krita/colorspaces/gray_u8/grayplugin.rc
new file mode 100644
index 00000000..e14278e7
--- /dev/null
+++ b/krita/colorspaces/gray_u8/grayplugin.rc
@@ -0,0 +1,7 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui library="kritagrayplugin" version="1">
+<Menu name="Image"><text>&amp;Image</text>
+ <Menu name="Mode"><text>&amp;Mode</text>
+ <Action name="convert to Gray(A)"/>
+ </Menu>
+</Menu></kpartgui>
diff --git a/krita/colorspaces/gray_u8/kis_gray_colorspace.cc b/krita/colorspaces/gray_u8/kis_gray_colorspace.cc
new file mode 100644
index 00000000..f5e46416
--- /dev/null
+++ b/krita/colorspaces/gray_u8/kis_gray_colorspace.cc
@@ -0,0 +1,997 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <[email protected]>
+ * Copyright (c) 2004 Cyrille Berger
+ * Copyright (c) 2004 Boudewijn Rempt <[email protected]>
+ *
+ * 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 <qimage.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kglobal.h>
+
+#include "kis_abstract_colorspace.h"
+#include "kis_u8_base_colorspace.h"
+#include "kis_gray_colorspace.h"
+#include "kis_integer_maths.h"
+
+#define downscale(quantum) (quantum) //((unsigned char) ((quantum)/257UL))
+#define upscale(value) (value) // ((Q_UINT8) (257UL*(value)))
+
+namespace {
+ const Q_INT32 MAX_CHANNEL_GRAYSCALE = 1;
+ const Q_INT32 MAX_CHANNEL_GRAYSCALEA = 2;
+}
+
+KisGrayColorSpace::KisGrayColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) :
+ KisU8BaseColorSpace(KisID("GRAYA", i18n("Grayscale")), TYPE_GRAYA_8, icSigGrayData, parent, p)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Gray"), i18n("G"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 1, KisChannelInfo::ALPHA, KisChannelInfo::UINT8));
+
+ m_alphaPos = PIXEL_GRAY_ALPHA;
+
+ init();
+}
+
+
+KisGrayColorSpace::~KisGrayColorSpace()
+{
+}
+
+void KisGrayColorSpace::setPixel(Q_UINT8 *pixel, Q_UINT8 gray, Q_UINT8 alpha) const
+{
+ pixel[PIXEL_GRAY] = gray;
+ pixel[PIXEL_GRAY_ALPHA] = alpha;
+}
+
+void KisGrayColorSpace::getPixel(const Q_UINT8 *pixel, Q_UINT8 *gray, Q_UINT8 *alpha) const
+{
+ *gray = pixel[PIXEL_GRAY];
+ *alpha = pixel[PIXEL_GRAY_ALPHA];
+}
+
+void KisGrayColorSpace::getAlpha(const Q_UINT8 *pixel, Q_UINT8 *alpha) const
+{
+ *alpha = pixel[PIXEL_GRAY_ALPHA];
+}
+
+void KisGrayColorSpace::setAlpha(Q_UINT8 *pixels, Q_UINT8 alpha, Q_INT32 nPixels) const
+{
+ while (nPixels > 0) {
+ pixels[PIXEL_GRAY_ALPHA] = alpha;
+ --nPixels;
+ pixels += MAX_CHANNEL_GRAYSCALEA;
+ }
+}
+
+void KisGrayColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+ Q_UINT32 totalGray = 0, newAlpha = 0;
+
+ while (nColors--)
+ {
+ Q_UINT32 alpha = (*colors)[PIXEL_GRAY_ALPHA];
+ Q_UINT32 alphaTimesWeight = UINT8_MULT(alpha, *weights);
+
+ totalGray += (*colors)[PIXEL_GRAY] * alphaTimesWeight;
+ newAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ Q_ASSERT(newAlpha <= 255);
+
+ dst[PIXEL_GRAY_ALPHA] = newAlpha;
+
+ if (newAlpha > 0) {
+ totalGray = UINT8_DIVIDE(totalGray, newAlpha);
+ }
+
+ // Divide by 255.
+ totalGray += 0x80;
+ Q_UINT32 dstGray = ((totalGray >> 8) + totalGray) >> 8;
+ Q_ASSERT(dstGray <= 255);
+ dst[PIXEL_GRAY] = dstGray;
+}
+
+void KisGrayColorSpace::convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const
+{
+ Q_INT32 totalGray = 0, totalAlpha = 0;
+
+ while (nColors--)
+ {
+ Q_INT32 weight = *kernelValues;
+
+ if (weight != 0) {
+ totalGray += (*colors)[PIXEL_GRAY] * weight;
+ totalAlpha += (*colors)[PIXEL_GRAY_ALPHA] * weight;
+ }
+ colors++;
+ kernelValues++;
+ }
+
+
+ if (channelFlags & KisChannelInfo::FLAG_COLOR) {
+ dst[PIXEL_GRAY] = CLAMP((totalGray / factor) + offset, 0, Q_UINT8_MAX);
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ dst[PIXEL_GRAY_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT8_MAX);
+ }
+
+}
+
+
+void KisGrayColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels)
+{
+ Q_UINT32 psize = pixelSize();
+
+ while (nPixels--)
+ {
+ src[PIXEL_GRAY] = Q_UINT8_MAX - src[PIXEL_GRAY];
+ src += psize;
+ }
+}
+
+void KisGrayColorSpace::darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const
+{
+ Q_UINT32 pSize = pixelSize();
+
+ while (nPixels--) {
+ if (compensate) {
+ dst[PIXEL_GRAY] = (Q_INT8) QMIN(255,((src[PIXEL_GRAY] * shade) / (compensation * 255)));
+ }
+ else {
+ dst[PIXEL_GRAY] = (Q_INT8) QMIN(255, (src[PIXEL_GRAY] * shade / 255));
+ }
+ dst += pSize;
+ src += pSize;
+ }
+}
+
+Q_UINT8 KisGrayColorSpace::intensity8(const Q_UINT8 * src) const
+{
+ return src[PIXEL_GRAY];
+}
+
+QValueVector<KisChannelInfo *> KisGrayColorSpace::channels() const
+{
+ return m_channels;
+}
+
+Q_UINT32 KisGrayColorSpace::nChannels() const
+{
+ return MAX_CHANNEL_GRAYSCALEA;
+}
+
+Q_UINT32 KisGrayColorSpace::nColorChannels() const
+{
+ return MAX_CHANNEL_GRAYSCALE;
+}
+
+Q_UINT32 KisGrayColorSpace::pixelSize() const
+{
+ return MAX_CHANNEL_GRAYSCALEA;
+}
+
+void KisGrayColorSpace::bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *mask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op)
+{
+ switch (op.op()) {
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_MULT:
+ compositeMultiply(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIVIDE:
+ compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DARKEN:
+ compositeDarken(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LIGHTEN:
+ compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SCREEN:
+ compositeScreen(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_OVERLAY:
+ compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DODGE:
+ compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BURN:
+ compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY:
+ compositeCopy(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_CLEAR: {
+ Q_UINT8 *d;
+ Q_INT32 linesize;
+
+ linesize = MAX_CHANNEL_GRAYSCALEA*sizeof(Q_UINT8) * cols;
+ d = dst;
+ while (rows-- > 0) {
+ memset(d, 0, linesize);
+ d += dstRowStride;
+ }
+ }
+ break;
+ case COMPOSITE_ALPHA_DARKEN:
+ compositeAlphaDarken(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+
+ default:
+ break;
+ }
+}
+
+KisCompositeOpList KisGrayColorSpace::userVisiblecompositeOps() const
+{
+ KisCompositeOpList list;
+
+ list.append(KisCompositeOp(COMPOSITE_OVER));
+ 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;
+}
+
+void KisGrayColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA];
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(srcAlpha, opacity);
+ }
+
+ if (srcAlpha == OPACITY_OPAQUE) {
+ memcpy(dst, src, MAX_CHANNEL_GRAYSCALEA * sizeof(Q_UINT8));
+ } else {
+ Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA];
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_GRAY_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ if (srcBlend == OPACITY_OPAQUE) {
+ memcpy(dst, src, MAX_CHANNEL_GRAYSCALE * sizeof(Q_UINT8));
+ } else {
+ dst[PIXEL_GRAY] = UINT8_BLEND(src[PIXEL_GRAY], dst[PIXEL_GRAY], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_GRAYSCALEA;
+ dst += MAX_CHANNEL_GRAYSCALEA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisGrayColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_GRAY_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ Q_UINT8 srcColor = src[PIXEL_GRAY];
+ Q_UINT8 dstColor = dst[PIXEL_GRAY];
+
+ srcColor = UINT8_MULT(srcColor, dstColor);
+
+ dst[PIXEL_GRAY] = UINT8_BLEND(srcColor, dstColor, srcBlend);
+ }
+
+ columns--;
+ src += MAX_CHANNEL_GRAYSCALEA;
+ dst += MAX_CHANNEL_GRAYSCALEA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisGrayColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_GRAY_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT8_MAX + 1)) / (1 + srcColor), UINT8_MAX);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_GRAYSCALEA;
+ dst += MAX_CHANNEL_GRAYSCALEA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisGrayColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_GRAY_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = UINT8_MAX - UINT8_MULT(UINT8_MAX - dstColor, UINT8_MAX - srcColor);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_GRAYSCALEA;
+ dst += MAX_CHANNEL_GRAYSCALEA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisGrayColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_GRAY_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = UINT8_MULT(dstColor, dstColor + UINT8_MULT(2 * srcColor, UINT8_MAX - dstColor));
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_GRAYSCALEA;
+ dst += MAX_CHANNEL_GRAYSCALEA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisGrayColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_GRAY_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT8_MAX + 1)) / (UINT8_MAX + 1 - srcColor), UINT8_MAX);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_GRAYSCALEA;
+ dst += MAX_CHANNEL_GRAYSCALEA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisGrayColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_GRAY_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = kMin(((UINT8_MAX - dstColor) * (UINT8_MAX + 1)) / (srcColor + 1), UINT8_MAX);
+ srcColor = kClamp(UINT8_MAX - srcColor, 0u, UINT8_MAX);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_GRAYSCALEA;
+ dst += MAX_CHANNEL_GRAYSCALEA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisGrayColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_GRAY_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMIN(srcColor, dstColor);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_GRAYSCALEA;
+ dst += MAX_CHANNEL_GRAYSCALEA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisGrayColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_GRAY_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_GRAY_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_GRAYSCALE; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMAX(srcColor, dstColor);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_GRAYSCALEA;
+ dst += MAX_CHANNEL_GRAYSCALEA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisGrayColorSpace::compositeErase(Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 /*opacity*/)
+{
+ Q_INT32 i;
+ Q_UINT8 srcAlpha;
+
+ while (rows-- > 0)
+ {
+ const Q_UINT8 *s = src;
+ Q_UINT8 *d = dst;
+ const Q_UINT8 *mask = srcAlphaMask;
+
+ for (i = cols; i > 0; i--, s+=MAX_CHANNEL_GRAYSCALEA, d+=MAX_CHANNEL_GRAYSCALEA)
+ {
+ srcAlpha = s[PIXEL_GRAY_ALPHA];
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_BLEND(srcAlpha, OPACITY_OPAQUE, *mask);
+ mask++;
+ }
+ d[PIXEL_GRAY_ALPHA] = UINT8_MULT(srcAlpha, d[PIXEL_GRAY_ALPHA]);
+ }
+
+ dst += dstRowSize;
+ if(srcAlphaMask)
+ srcAlphaMask += maskRowStride;
+ src += srcRowSize;
+ }
+}
+
+void KisGrayColorSpace::compositeAlphaDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride,
+ const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride,
+ const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride,
+ Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_GRAY_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_GRAY_ALPHA];
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(srcAlpha, opacity);
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT && srcAlpha >= dstAlpha) {
+ dst[PIXEL_GRAY_ALPHA] = srcAlpha;
+ memcpy(dst, src, MAX_CHANNEL_GRAYSCALE * sizeof(Q_UINT8));
+ }
+
+ columns--;
+ src += MAX_CHANNEL_GRAYSCALEA;
+ dst += MAX_CHANNEL_GRAYSCALEA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
diff --git a/krita/colorspaces/gray_u8/kis_gray_colorspace.h b/krita/colorspaces/gray_u8/kis_gray_colorspace.h
new file mode 100644
index 00000000..d6784017
--- /dev/null
+++ b/krita/colorspaces/gray_u8/kis_gray_colorspace.h
@@ -0,0 +1,114 @@
+/*
+ * Copyright (c) 2004 Cyrille Berger <[email protected]>
+ *
+ * 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_GRAYSCALE_H_
+#define KIS_STRATEGY_COLORSPACE_GRAYSCALE_H_
+#include <qcolor.h>
+
+#include <klocale.h>
+
+#include <koffice_export.h>
+
+#include "kis_global.h"
+#include "kis_abstract_colorspace.h"
+#include "kis_u8_base_colorspace.h"
+
+class KRITACORE_EXPORT KisGrayColorSpace : public KisU8BaseColorSpace {
+public:
+ KisGrayColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p);
+ virtual ~KisGrayColorSpace();
+
+ virtual bool willDegrade(ColorSpaceIndependence /*independence*/)
+ {
+ return false;
+ };
+
+public:
+
+ void setPixel(Q_UINT8 *pixel, Q_UINT8 gray, Q_UINT8 alpha) const;
+ void getPixel(const Q_UINT8 *pixel, Q_UINT8 *gray, Q_UINT8 *alpha) const;
+
+ virtual void getAlpha(const Q_UINT8 *pixel, Q_UINT8 *alpha) const;
+ virtual void setAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const;
+
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+ virtual void convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const;
+ virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels);
+ virtual void darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const;
+ virtual Q_UINT8 intensity8(const Q_UINT8 * src) const;
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dststride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+ KisCompositeOpList userVisiblecompositeOps() const;
+
+protected:
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeAlphaDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+
+
+private:
+ friend class KisGrayColorSpaceTester;
+
+ static const Q_UINT8 PIXEL_GRAY = 0;
+ static const Q_UINT8 PIXEL_GRAY_ALPHA = 1;
+};
+
+class KisGrayColorSpaceFactory : public KisColorSpaceFactory
+{
+public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("GRAYA", i18n("Grayscale (8-bit integer/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return TYPE_GRAYA_8; };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icSigGrayData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisGrayColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return "gray built-in - (lcms internal)"; };
+};
+
+#endif // KIS_STRATEGY_COLORSPACE_GRAYSCALE_H_
diff --git a/krita/colorspaces/gray_u8/kritagrayplugin.desktop b/krita/colorspaces/gray_u8/kritagrayplugin.desktop
new file mode 100644
index 00000000..cd810f81
--- /dev/null
+++ b/krita/colorspaces/gray_u8/kritagrayplugin.desktop
@@ -0,0 +1,97 @@
+[Desktop Entry]
+Name=Grayscale Color Model
+Name[bg]=Цветови модел със степени на сивото
+Name[ca]=Model de color d'escala de grisos
+Name[cy]=Model Lliw Graddlwyd
+Name[da]=Farvemodel med gråskala
+Name[de]=Graustufen-Farbmodell
+Name[el]=Χρωματικό μοντέλο διαβαθμίσεων του γκρι
+Name[en_GB]=Greyscale Colour Model
+Name[eo]=Grizoskala kolormodelo
+Name[es]=Modelo de color de escala de grises
+Name[et]=Halltooni värvimudel
+Name[eu]=Gris-eskala kolore-eredua
+Name[fa]=مدل رنگ مقیاس خاکستری
+Name[fi]=Harmaasävyvärimalli
+Name[fr]=Modèle de couleurs en niveaux de gris
+Name[fy]=Griiswearden kleurmodel
+Name[gl]=Modelo de Cores en Escala de Gris
+Name[he]=מודל צבעים של גווני אפור
+Name[hi]=श्वेत-श्याम रंग नमूना
+Name[hu]=Szürkeárnyalatos színmodell
+Name[is]=Gráskala litategund
+Name[it]=Modello di colore in scala di grigio
+Name[ja]=グレースケール カラーモデル
+Name[km]=គំរូ​ពណ៌​មាត្រដ្ឋាន​ប្រផេះ
+Name[lv]=Pelēktoņu krāsu modelis
+Name[ms]=Model Warna Skala Kelabu
+Name[nb]=Fargemodell med gråtoner
+Name[nds]=Griestöön-Klöörmodell
+Name[ne]=ग्रेस्केल रङ मोडेल
+Name[nl]=Grijswaarden kleurmodel
+Name[nn]=Fargemodell med gråtonar
+Name[pl]=Skala szarości
+Name[pt]=Modelo de Cor de Tons de Cinzento
+Name[pt_BR]=Modelo de Cor em Tons de Cinza
+Name[ru]=Градации серого
+Name[se]=Ránesivnniid ivdnemálle
+Name[sk]=Model farieb ČB/šedý
+Name[sl]=Sivinski barvni model
+Name[sr]=Модел боја за сиве нијансе
+Name[sr@Latn]=Model boja za sive nijanse
+Name[sv]=Gråskalefärgmodell
+Name[ta]=பழுப்புநிற வண்ண மாதிரி
+Name[tr]=Griton Renk Modeli
+Name[uk]=Модель кольору "відтінки сірого"
+Name[uz]=Kul rang usuli
+Name[uz@cyrillic]=Кул ранг усули
+Name[zh_CN]=灰度色彩模型
+Name[zh_TW]=灰階色彩模型
+Comment=Color model for 8-bit grayscale images
+Comment[bg]=Цветови модел за 8 битови сиви изображения
+Comment[ca]=Model de color d'escala de grisos de 8 bits
+Comment[cy]=Model lliw ar gyfer delweddau graddlwyd 8-did
+Comment[da]=Farvemodel for 8-bit gråskala-billeder
+Comment[de]=Farbmodell für 8-bit Graustufenbilder
+Comment[el]=Χρωματικό μοντέλο για 8-bit με διαβαθμίσεις του γκρι εικόνες
+Comment[en_GB]=Colour model for 8-bit greyscale images
+Comment[eo]=Kolormodelo por 8-bitaj grizoskalaj bildoj
+Comment[es]=Modelo de color de imágenes de escala de grises para 8 bits
+Comment[et]=8-bitiste halltoonis piltide värvimudel
+Comment[eu]=8 bit/kanaleko gris-eskalako irudien kolore-eredua
+Comment[fa]=مدل رنگ برای تصاویر مقیاس خاکستری ۸ بیتی
+Comment[fi]=Värimalli 8-bittisille harmaasävykuville
+Comment[fr]=Modèle de couleurs pour des images en niveaux de gris 8 bits
+Comment[fy]=Kleurmodel foar ôfbeeldings yn 8-bit griiswearden
+Comment[gl]=Modelo de Cores de escala de gris de for 8-bit
+Comment[he]=מודל צבעים עבור תמונות של 8 סיביות בגווני אפור
+Comment[hi]=8-बिट श्वेत-श्याम छवियों के लिए रंग नमूना
+Comment[hu]=Színmodell 8 bites szürkeárnyalatos képekhez
+Comment[is]=Litategund fyrir 8-bita gráskala myndir
+Comment[it]=Modello di colore per immagini a 8 bit in scala di grigio
+Comment[ja]=8 ビット グレースケール画像のためのカラーモデル
+Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព​មាត្រដ្ឋាន​ប្រផេះ ៨ ប៊ីត
+Comment[ms]=Model warna bagi imej skala kelabu 8-bit
+Comment[nb]=Fargemodell for 8-bits gråtonebilder
+Comment[nds]=Klöörmodell för Griestöön-Biller mit 8-Bit Heeltall
+Comment[ne]=८-बिट ग्रेस्केल छविहरूका लागि रङ मोडेल
+Comment[nl]=Kleurmodel voor afbeeldingen in 8-bit grijswaarden
+Comment[nn]=Fargemodell for 8-bits gråtonebilete
+Comment[pl]=Przestrzeń braw dla 8-bitowych obrazków w skali szarości
+Comment[pt]=Modelo de cor para imagens de tons de cinzento com 8 bits
+Comment[pt_BR]=Modelo de cor para imagens com 8-bits de tons de cinza
+Comment[ru]=Цветовое пространство градаций серого (8-бит)
+Comment[sk]=Model farieb pre ČB/šedé obrázky s 8 bitmi na kanál
+Comment[sl]=Barvni model za 8 bitne sivinske slike
+Comment[sr]=Модел боја за слике у 8-битним сивим нијансама
+Comment[sr@Latn]=Model boja za slike u 8-bitnim sivim nijansama
+Comment[sv]=Färgmodell för 8-bitars gråskalebilder
+Comment[ta]=8-பிட் பழுப்புநிற பிம்பங்களுக்கு வண்ண மாதிரி
+Comment[tr]=8-bit griton görüntüler için renk modeli.
+Comment[uk]=Модель кольору зображень відтінків сірого (8-бітів)
+Comment[zh_CN]=8 位灰度图像的色彩模型
+Comment[zh_TW]=8-bit 灰階圖片的色彩模型
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-KDE-Library=kritagrayplugin
+X-Krita-Version=2
diff --git a/krita/colorspaces/gray_u8/templates/.directory b/krita/colorspaces/gray_u8/templates/.directory
new file mode 100644
index 00000000..e408f23f
--- /dev/null
+++ b/krita/colorspaces/gray_u8/templates/.directory
@@ -0,0 +1,48 @@
+[Desktop Entry]
+Name=Grayscale
+Name[bg]=Гама на сивото
+Name[br]=SkeulLouet
+Name[ca]=Escala de grisos
+Name[cy]=Graddlwyd
+Name[da]=Gråskala
+Name[de]=Graustufen
+Name[el]=Διαβαθμίσεις του γκρι
+Name[eo]=Grizoskalo
+Name[es]=Escala de grises
+Name[et]=Halltoonid
+Name[fa]=مقیاس خاکستری
+Name[fi]=Harmaasävyinen
+Name[fr]=Niveaux de gris
+Name[fy]=Griiswearden
+Name[ga]=Liathscála
+Name[gl]=Escala de Gris
+Name[he]=גווני אפור
+Name[hi]=श्वेत-श्याम
+Name[hu]=Szürkeárnyalatok
+Name[is]=Gráskali
+Name[it]=Scala di grigio
+Name[ja]=グレースケール
+Name[km]=មាត្រដ្ឋាន​ប្រផេះ​
+Name[lv]=Pelēktoņu
+Name[nb]=Gråtoner
+Name[nds]=Griestöön
+Name[ne]=ग्रेस्केल
+Name[nl]=Grijswaarden
+Name[pl]=Skala szarości
+Name[pt]=Tons de Cinzento
+Name[pt_BR]=Tons de Cinza
+Name[ru]=Градации серого
+Name[se]=Ránesivnnit
+Name[sk]=Čiernobiely
+Name[sl]=Sivinska
+Name[sr]=Сиве нијансе
+Name[sr@Latn]=Sive nijanse
+Name[sv]=Gråskala
+Name[ta]=பழுப்புநிற வண்ணம்
+Name[tr]=Griton
+Name[uk]=Відтінки сірого
+Name[uz]=Oq-qora
+Name[uz@cyrillic]=Оқ-қора
+Name[zh_CN]=灰度
+Name[zh_TW]=灰階
+X-KDE-DefaultTab=true
diff --git a/krita/colorspaces/gray_u8/templates/Makefile.am b/krita/colorspaces/gray_u8/templates/Makefile.am
new file mode 100644
index 00000000..2b185223
--- /dev/null
+++ b/krita/colorspaces/gray_u8/templates/Makefile.am
@@ -0,0 +1,8 @@
+templates_DATA = .directory white_640x480.desktop
+templatesdir = $(kde_datadir)/krita/templates/gray
+
+templatesrc_DATA =white_640x480.kra
+templatesrcdir = $(kde_datadir)/krita/templates/gray/.source
+
+templatesicon_ICON = AUTO
+templatesicondir = $(kde_datadir)/krita/icons
diff --git a/krita/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png b/krita/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png
new file mode 100644
index 00000000..3ea63818
--- /dev/null
+++ b/krita/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png
Binary files differ
diff --git a/krita/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz b/krita/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz
new file mode 100644
index 00000000..93af227f
--- /dev/null
+++ b/krita/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz
Binary files differ
diff --git a/krita/colorspaces/gray_u8/templates/white_640x480.desktop b/krita/colorspaces/gray_u8/templates/white_640x480.desktop
new file mode 100644
index 00000000..cea93b17
--- /dev/null
+++ b/krita/colorspaces/gray_u8/templates/white_640x480.desktop
@@ -0,0 +1,99 @@
+[Desktop Entry]
+Type=Link
+URL=.source/white_640x480.kra
+Icon=template_gray_empty
+Name=White Background, 640 x 480
+Name[bg]=Бял фон, 640x480
+Name[ca]=Fons blanc, 640 x 480
+Name[cy]=Cefndir Gwyn, 640 x 480
+Name[da]=Hvid baggrund, 640 x 480
+Name[de]=Weißer Hintergrund, 640 x 480
+Name[el]=Λευκό φόντο, 640 x 480
+Name[eo]=Blanka fono, 640 x 480
+Name[es]=Fondo blanco, 640 x 480
+Name[et]=Valge taust, 640 x 480
+Name[eu]=Atzeko plano zuria, 640 x 480
+Name[fa]=زمینۀ سفید، ۴۸۰ × ۶۴۰
+Name[fi]=Valkoinen tausta, 640 x 480
+Name[fr]=Fond blanc 640 x 480
+Name[fy]=Wite eftergrûn, 640 x 480
+Name[ga]=Cúlra Bán, 640×480
+Name[gl]=Fondo Branco, 640 x 480
+Name[he]=רקע לבן, ‎640 x 480
+Name[hi]=सफेद पृष्ठभूमि, 640 x 480
+Name[hu]=Fehér háttér, 640 x 480
+Name[is]=Hvítur bakgrunnur, 640 x 480
+Name[it]=Sfondo bianco, 640 × 480
+Name[ja]=白い背景 640 x 480
+Name[km]=ផ្ទៃខាងក្រោយ​ពណ៌​ស, 640 x 480
+Name[lt]=Baltas fonas, 640 x 480
+Name[lv]=Balts fons, 640x480
+Name[ms]=Latar Belakang Putih, 640 x 480
+Name[nb]=Hvit bakgrunn, 640 x 480
+Name[nds]=Witt Achtergrund, 640 x 480
+Name[ne]=सेतो पृष्ठभूमि, ६४० x ४८०
+Name[nl]=Witte achtergrond, 640 x 480
+Name[nn]=Kvit bakgrunn, 640 × 480
+Name[pl]=Białe tło, 640 x 480
+Name[pt]=Fundo Branco, 640 x 480
+Name[pt_BR]=Fundo em branco, 640 x 480
+Name[ru]=Рисунок 640x480, белый фон
+Name[se]=Vilges duogáš, 640 × 480
+Name[sk]=Biele pozadie, 640 x 480
+Name[sl]=Belo ozadje, 640 x 480
+Name[sr]=Бела позадина, 640 x 480
+Name[sr@Latn]=Bela pozadina, 640 x 480
+Name[sv]=Vit bakgrund, 640 x 480
+Name[ta]=வெள்ளை பின்னணி, 640 x 480
+Name[tr]=Beyaz Arkaplan, 640 x 480
+Name[uk]=Біле тло, 640 x 480
+Name[uz]=Oq orqa fon 640 x 480
+Name[uz@cyrillic]=Оқ орқа фон 640 x 480
+Name[zh_CN]=白色背景,640 x 480
+Name[zh_TW]=白色背景, 640 x 480
+Comment=Creates an image of 640 x 480 pixels with a white background.
+Comment[bg]=Създаване на изображение с размери 640x480 пиксела и бял фон.
+Comment[ca]=Crea una imatge de 640 x 480 píxels amb el fons blanc.
+Comment[cy]=Creu delwedd o 640 x 480 o bicseli efo cefndir gwyn.
+Comment[da]=Laver et billede på 640 x 480 billedpunkter med en hvid baggrund.
+Comment[de]=Erstellt ein Bild mit 640 x 480 Pixeln mit einem weißen Hintergrund.
+Comment[el]=Δημιουργεί μία εικόνα μεγέθους 640 x 480 εικονοστοιχείων με λευκό φόντο.
+Comment[es]=Crea una imagen de 640 x 480 píxeles con un fondo blanco.
+Comment[et]=Loob valge taustaga pildi mõõtmetega 640 x 800 pikslit.
+Comment[eu]=640 x 480 pixeleko atzeko planoa zuria duen irudi bat sortzen du.
+Comment[fa]=تصویری ۴۸۰ × ۶۴۰ تصویردانه‌ای با یک زمینۀ سفید ایجاد می‌کند.
+Comment[fi]=Luo 640 x 480 pikselin kuvan valkoisella taustalla.
+Comment[fr]=Crée une image de 640 x 480 pixels avec un fond blanc.
+Comment[fy]=Makket in ôfbylding oan fan 640 x 480 byldpunten, mei in wite eftergrûn
+Comment[gl]=Cria unha imaxe de 640 x 480 pixels cun fondo branco.
+Comment[he]=יצירת תמונת בגודל ‎640 x 480 פיקסלים עם רקע לבן
+Comment[hi]=640 x 480 पिक्सेल का, सफेद पृष्ठभूमि युक्त छवि बनाता है
+Comment[hu]=Létrehoz egy 640 x 480 képpontos képet fehér háttérrel.
+Comment[is]=Býr til hvíta mynd í 640 x 480 punkta upplausn með hvítum bakgrunni.
+Comment[it]=Crea un'immagine di 640 × 480 pixel con uno sfondo bianco.
+Comment[ja]=640 x 480 ピクセルの白い背景の画像を作成
+Comment[km]=បង្កើត​រូបភាព​ទំហំ 640 x 480 ភីកសែល ដែល​មាន​ផ្ទៃ​ខាង​ក្រោយ​ពណ៌​ស ។
+Comment[ms]=Cipta imej 640 x 480 piksel dengan latar belakang putih.
+Comment[nb]=Lager et bilde på 640 x 480 piksler med hvit bakgrunn.
+Comment[nds]=Stellt en Bild mit 640 x 480 Pixels mit witten Achtergrund op.
+Comment[ne]=सेतो पृष्ठभूमि सहित ६४० x ४८० पिक्सेलको छवि सिर्जना गर्दछ ।
+Comment[nl]=Maakt een afbeelding aan van 640 x 480 pixels, met een witte achtergrond.
+Comment[nn]=Lagar eit bilete på 640 × 480 pikslar med ein kvit bakgrunn.
+Comment[pl]=Tworzy obrazek z białym tłem o rozmiarach 640 x 480 pikseli.
+Comment[pt]=Cria uma imagem de 640 x 480 pontos com um fundo branco.
+Comment[pt_BR]=Cria uma imagem de 640 x 480 pixéis com um fundo branco.
+Comment[ru]=Рисунок 640x480, белый фон
+Comment[se]=Ráhkada vilges govva mas leat 640 × 480 govvačuogga.
+Comment[sk]=Vytvorí obrázok s rozmermi 640 x 480 pixelov a bielym pozadím.
+Comment[sl]=Ustvari sliko velikosti 640 x 480 pik z belim ozadjem.
+Comment[sr]=Прави слику од 640 x 480 пиксела са белом позадином.
+Comment[sr@Latn]=Pravi sliku od 640 x 480 piksela sa belom pozadinom.
+Comment[sv]=Skapar en bild med 640 x 480 bildpunkter och en vit bakgrund.
+Comment[ta]=640 x 480 படத்துணுக்குகளில் வெள்ளை பின்னணியுடன் ஒரு பிம்பத்தை உருவாக்குகிறது.
+Comment[tr]=640 x 480 piksel ebadında beyaz arkaplana sahip bir görüntü oluşturur
+Comment[uk]=Створює зображення 640 x 480 пікселів з білим тлом.
+Comment[uz]=Oʻlchami 640 x 480 nuqta va foni oq boʻlgan rasmni yaratish.
+Comment[uz@cyrillic]=Ўлчами 640 x 480 нуқта ва фони оқ бўлган расмни яратиш.
+Comment[zh_CN]=创建白色背景的 640 x 480 像素的图像。
+Comment[zh_TW]=建立一個 640 x 480 像素,白色背景的圖片。
+X-Krita-Version=2
diff --git a/krita/colorspaces/gray_u8/templates/white_640x480.kra b/krita/colorspaces/gray_u8/templates/white_640x480.kra
new file mode 100644
index 00000000..f1865a64
--- /dev/null
+++ b/krita/colorspaces/gray_u8/templates/white_640x480.kra
Binary files differ
diff --git a/krita/colorspaces/gray_u8/tests/Makefile.am b/krita/colorspaces/gray_u8/tests/Makefile.am
new file mode 100644
index 00000000..f5f14f7c
--- /dev/null
+++ b/krita/colorspaces/gray_u8/tests/Makefile.am
@@ -0,0 +1,17 @@
+AM_CPPFLAGS = -I$(srcdir)/.. \
+ -I$(srcdir)/../../../sdk \
+ -I$(srcdir)/../../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../../color_strategy/ \
+ $(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_strategy_colorspace_grayscale_tester.la
+
+kunittest_kis_strategy_colorspace_grayscale_tester_la_SOURCES = kis_strategy_colorspace_grayscale_tester.cpp
+kunittest_kis_strategy_colorspace_grayscale_tester_la_LIBADD = -lkunittest ../libkritagrayscale.la
+kunittest_kis_strategy_colorspace_grayscale_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
+
+check-local: kunittest_kis_strategy_colorspace_grayscale_tester.la
+ kunittestmodrunner
+
diff --git a/krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.cpp b/krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.cpp
new file mode 100644
index 00000000..3c91d6d1
--- /dev/null
+++ b/krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.cpp
@@ -0,0 +1,155 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_factory.h"
+#include "kis_strategy_colorspace_grayscale_tester.h"
+#include "kis_gray_colorspace.h"
+
+using namespace KUnitTest;
+
+KUNITTEST_MODULE( kunittest_kis_strategy_colorspace_grayscale_tester, "Greyscale ColorSpace Tester" );
+KUNITTEST_MODULE_REGISTER_TESTER( KisGrayColorSpaceTester );
+
+void KisGrayColorSpaceTester::allTests()
+{
+ // We need this so that the colour profile loading can operate without crashing.
+ KisFactory *factory = new KisFactory();
+
+ testBasics();
+ testMixColors();
+
+ delete factory;
+}
+
+#define MAX_CHANNEL_GRAYSCALEA 2
+
+#define GRAY_CHANNEL 0
+#define ALPHA_CHANNEL 1
+
+void KisGrayColorSpaceTester::testBasics()
+{
+ KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile());
+ KisGrayColorSpace *cs = new KisGrayColorSpace(profile);
+
+
+ Q_UINT8 pixel[MAX_CHANNEL_GRAYSCALEA];
+
+ pixel[KisGrayColorSpace::PIXEL_GRAY] = 255;
+ pixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 128;
+
+ QString valueText = cs->channelValueText(pixel, GRAY_CHANNEL);
+ CHECK(valueText, QString("255"));
+
+ valueText = cs->channelValueText(pixel, ALPHA_CHANNEL);
+ CHECK(valueText, QString("128"));
+
+ valueText = cs->normalisedChannelValueText(pixel, GRAY_CHANNEL);
+ CHECK(valueText, QString().setNum(1.0));
+
+ valueText = cs->normalisedChannelValueText(pixel, ALPHA_CHANNEL);
+ CHECK(valueText, QString().setNum(128.0 / 255.0));
+
+ cs->setPixel(pixel, 128, 192l);
+ CHECK((uint)pixel[KisGrayColorSpace::PIXEL_GRAY], 128u);
+ CHECK((uint)pixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 192u);
+
+ Q_UINT8 gray;
+ Q_UINT8 alpha;
+
+ cs->getPixel(pixel, &gray, &alpha);
+ CHECK((uint)gray, 128u);
+ CHECK((uint)alpha, 192u);
+
+ delete cs;
+}
+
+void KisGrayColorSpaceTester::testMixColors()
+{
+ KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile());
+ KisAbstractColorSpace * cs = new KisGrayColorSpace(profile);
+
+ Q_UINT8 pixel1[MAX_CHANNEL_GRAYSCALEA];
+ Q_UINT8 pixel2[MAX_CHANNEL_GRAYSCALEA];
+ Q_UINT8 outputPixel[MAX_CHANNEL_GRAYSCALEA];
+
+ pixel1[KisGrayColorSpace::PIXEL_GRAY] = 255;
+ pixel1[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 255;
+
+ pixel2[KisGrayColorSpace::PIXEL_GRAY] = 0;
+ pixel2[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 0;
+
+ const Q_UINT8 *pixelPtrs[2];
+ Q_UINT8 weights[2];
+
+ pixelPtrs[0] = pixel1;
+ pixelPtrs[1] = pixel2;
+
+ weights[0] = 255;
+ weights[1] = 0;
+
+ cs->mixColors(pixelPtrs, weights, 2, outputPixel);
+
+ CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY], 255);
+ CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 255);
+
+ weights[0] = 0;
+ weights[1] = 255;
+
+ cs->mixColors(pixelPtrs, weights, 2, outputPixel);
+
+ CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY], 0);
+ CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 0);
+
+ weights[0] = 128;
+ weights[1] = 127;
+
+ cs->mixColors(pixelPtrs, weights, 2, outputPixel);
+
+ CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY], 255);
+ CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 128);
+
+ pixel1[KisGrayColorSpace::PIXEL_GRAY] = 200;
+ pixel1[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 255;
+
+ pixel2[KisGrayColorSpace::PIXEL_GRAY] = 100;
+ pixel2[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 255;
+
+ cs->mixColors(pixelPtrs, weights, 2, outputPixel);
+
+ CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY], 150);
+ CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 255);
+
+ pixel1[KisGrayColorSpace::PIXEL_GRAY] = 0;
+ pixel1[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 0;
+
+ pixel2[KisGrayColorSpace::PIXEL_GRAY] = 255;
+ pixel2[KisGrayColorSpace::PIXEL_GRAY_ALPHA] = 254;
+
+ weights[0] = 89;
+ weights[1] = 166;
+
+ cs->mixColors(pixelPtrs, weights, 2, outputPixel);
+
+ CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY], 255);
+ CHECK((int)outputPixel[KisGrayColorSpace::PIXEL_GRAY_ALPHA], 165);
+}
+
+
diff --git a/krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.h b/krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.h
new file mode 100644
index 00000000..9b5f8d5e
--- /dev/null
+++ b/krita/colorspaces/gray_u8/tests/kis_strategy_colorspace_grayscale_tester.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_GRAYSCALE_TESTER_H
+#define KIS_STRATEGY_COLORSPACE_GRAYSCALE_TESTER_H
+
+#include <kunittest/tester.h>
+
+class KisGrayColorSpaceTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+ void testMixColors();
+ void testBasics();
+};
+
+#endif
+
diff --git a/krita/colorspaces/lms_f32/Makefile.am b/krita/colorspaces/lms_f32/Makefile.am
new file mode 100644
index 00000000..f34e9a20
--- /dev/null
+++ b/krita/colorspaces/lms_f32/Makefile.am
@@ -0,0 +1,28 @@
+# Install the desktop file needed to detect the plugin
+kde_services_DATA = krita_lms_f32_plugin.desktop
+
+INCLUDES = \
+ -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../kritacolor/ \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+
+lib_LTLIBRARIES = libkrita_lms_f32.la
+libkrita_lms_f32_la_SOURCES = kis_lms_f32_colorspace.cc
+libkrita_lms_f32_la_LDFLAGS = $(all_libraries)
+libkrita_lms_f32_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = krita_lms_f32_plugin.la
+
+# Srcs for the plugin
+krita_lms_f32_plugin_la_SOURCES = lms_f32_plugin.cc
+noinst_HEADERS = lms_f32_plugin.h kis_lms_f32_colorspace.h
+
+krita_lms_f32_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+krita_lms_f32_plugin_la_LIBADD = libkrita_lms_f32.la ../../kritacolor/libkritacolor.la
+
+krita_lms_f32_plugin_la_METASOURCES = AUTO
+
diff --git a/krita/colorspaces/lms_f32/kis_lms_f32_colorspace.cc b/krita/colorspaces/lms_f32/kis_lms_f32_colorspace.cc
new file mode 100644
index 00000000..0c8b91bf
--- /dev/null
+++ b/krita/colorspaces/lms_f32/kis_lms_f32_colorspace.cc
@@ -0,0 +1,385 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <[email protected]>
+ * Copyright (c) 2004 Boudewijn Rempt <[email protected]>
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ * Copyright (c) 2005 Cyrille Berger <[email protected]>
+ *
+ * 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 <qimage.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "kis_lms_f32_colorspace.h"
+#include "kis_color_conversions.h"
+
+namespace {
+ const Q_INT32 MAX_CHANNEL_LMS = 3;
+ const Q_INT32 MAX_CHANNEL_LMSA = 4;
+}
+
+#include "kis_integer_maths.h"
+
+#define FLOAT_MAX 1.0f //temp
+
+#define EPSILON 1e-6
+
+// FIXME: lcms doesn't support 32-bit float
+#define F32_LCMS_TYPE TYPE_BGRA_16
+
+// disable the lcms handling by setting profile=0
+KisLmsF32ColorSpace::KisLmsF32ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile */*p*/) :
+ KisF32BaseColorSpace(KisID("LMSAF32", i18n("LMS (32-bit float/channel)")), F32_LCMS_TYPE, icSig3colorData, parent, 0)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Long"), i18n("L"), PIXEL_LONGWAVE * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float)));
+ m_channels.push_back(new KisChannelInfo(i18n("Middle"), i18n("M"), PIXEL_MIDDLEWAVE * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float)));
+ m_channels.push_back(new KisChannelInfo(i18n("Short"), i18n("S"), PIXEL_SHORTWAVE * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float)));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(float), KisChannelInfo::ALPHA, KisChannelInfo::FLOAT32, sizeof(float)));
+
+ m_alphaPos = PIXEL_ALPHA * sizeof(float);
+}
+
+KisLmsF32ColorSpace::~KisLmsF32ColorSpace()
+{
+}
+
+void KisLmsF32ColorSpace::setPixel(Q_UINT8 *dst, float longWave, float middleWave, float shortWave, float alpha) const
+{
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->longWave = longWave;
+ dstPixel->middleWave = middleWave;
+ dstPixel->shortWave = shortWave;
+ dstPixel->alpha = alpha;
+}
+
+void KisLmsF32ColorSpace::getPixel(const Q_UINT8 *src, float *longWave, float *middleWave, float *shortWave, float *alpha) const
+{
+ const Pixel *srcPixel = reinterpret_cast<const Pixel *>(src);
+
+ *longWave = srcPixel->longWave;
+ *middleWave = srcPixel->middleWave;
+ *shortWave = srcPixel->shortWave;
+ *alpha = srcPixel->alpha;
+}
+
+void KisLmsF32ColorSpace::fromQColor(const QColor& c, Q_UINT8 *dstU8, KisProfile * /*profile*/)
+{
+ Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
+
+ dst->longWave = computeLong(c.red(),c.green(),c.blue());
+ dst->middleWave = computeMiddle(c.red(),c.green(),c.blue());
+ dst->shortWave = computeShort(c.red(),c.green(),c.blue());
+}
+
+void KisLmsF32ColorSpace::fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dstU8, KisProfile * /*profile*/)
+{
+ Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
+
+ dst->longWave = computeLong(c.red(),c.green(),c.blue());
+ dst->middleWave = computeMiddle(c.red(),c.green(),c.blue());
+ dst->shortWave = computeShort(c.red(),c.green(),c.blue());
+ dst->alpha = UINT8_TO_FLOAT(opacity);
+}
+
+void KisLmsF32ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, KisProfile * /*profile*/)
+{
+ const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
+
+ c->setRgb(computeRed(src->longWave,src->middleWave,src->shortWave), computeGreen(src->longWave,src->middleWave,src->shortWave), computeBlue(src->longWave,src->middleWave,src->shortWave));
+}
+
+void KisLmsF32ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_UINT8 *opacity, KisProfile * /*profile*/)
+{
+ const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
+
+ c->setRgb(computeRed(src->longWave,src->middleWave,src->shortWave), computeGreen(src->longWave,src->middleWave,src->shortWave), computeBlue(src->longWave,src->middleWave,src->shortWave));
+ *opacity = FLOAT_TO_UINT8(src->alpha);
+}
+
+Q_UINT8 KisLmsF32ColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8)
+{
+ const Pixel *src1 = reinterpret_cast<const Pixel *>(src1U8);
+ const Pixel *src2 = reinterpret_cast<const Pixel *>(src2U8);
+
+ return FLOAT_TO_UINT8(QMAX(QABS(src2->longWave - src1->longWave),
+ QMAX(QABS(src2->middleWave - src1->middleWave),
+ QABS(src2->shortWave - src1->shortWave))));
+}
+
+void KisLmsF32ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+ float totalLong = 0, totalMiddle = 0, totalShort = 0, newAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel *pixel = reinterpret_cast<const Pixel *>(*colors);
+
+ float alpha = pixel->alpha;
+ float alphaTimesWeight = alpha * UINT8_TO_FLOAT(*weights);
+
+ totalLong += pixel->longWave * alphaTimesWeight;
+ totalMiddle += pixel->middleWave * alphaTimesWeight;
+ totalShort += pixel->shortWave * alphaTimesWeight;
+ newAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ Q_ASSERT(newAlpha <= F32_OPACITY_OPAQUE);
+
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->alpha = newAlpha;
+
+ if (newAlpha > EPSILON) {
+ totalLong = totalLong / newAlpha;
+ totalMiddle = totalMiddle / newAlpha;
+ totalShort = totalShort / newAlpha;
+ }
+
+ dstPixel->longWave = totalLong;
+ dstPixel->middleWave = totalMiddle;
+ dstPixel->shortWave = totalShort;
+}
+
+QValueVector<KisChannelInfo *> KisLmsF32ColorSpace::channels() const
+{
+ return m_channels;
+}
+
+Q_UINT32 KisLmsF32ColorSpace::nChannels() const
+{
+ return MAX_CHANNEL_LMSA;
+}
+
+Q_UINT32 KisLmsF32ColorSpace::nColorChannels() const
+{
+ return MAX_CHANNEL_LMS;
+}
+
+Q_UINT32 KisLmsF32ColorSpace::pixelSize() const
+{
+ return MAX_CHANNEL_LMSA * sizeof(float);
+}
+
+QImage KisLmsF32ColorSpace::convertToQImage(const Q_UINT8 *dataU8, Q_INT32 width, Q_INT32 height,
+ KisProfile * /*dstProfile*/,
+ Q_INT32 /*renderingIntent*/, float /*exposure*/)
+
+{
+ const float *data = reinterpret_cast<const float *>(dataU8);
+
+ QImage img = QImage(width, height, 32, 0, QImage::LittleEndian);
+ img.setAlphaBuffer(true);
+
+ Q_INT32 i = 0;
+ uchar *j = img.bits();
+
+ while ( i < width * height * MAX_CHANNEL_LMSA) {
+ double l = *( data + i + PIXEL_LONGWAVE );
+ double m = *( data + i + PIXEL_MIDDLEWAVE );
+ double s = *( data + i + PIXEL_SHORTWAVE );
+ *( j + 3) = FLOAT_TO_UINT8(*( data + i + PIXEL_ALPHA ));
+ *( j + 2 ) = computeRed(l,m,s);
+ *( j + 1 ) = computeGreen(l,m,s);
+ *( j + 0 ) = computeBlue(l,m,s);
+ i += MAX_CHANNEL_LMSA;
+ j += MAX_CHANNEL_LMSA;
+ }
+
+ /*
+ if (srcProfile != 0 && dstProfile != 0) {
+ convertPixelsTo(img.bits(), srcProfile,
+ img.bits(), this, dstProfile,
+ width * height, renderingIntent);
+ }
+ */
+ return img;
+}
+
+
+void KisLmsF32ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ while (rows > 0) {
+
+ const float *src = reinterpret_cast<const float *>(srcRowStart);
+ float *dst = reinterpret_cast<float *>(dstRowStart);
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ float srcAlpha = src[PIXEL_ALPHA];
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha *= UINT8_TO_FLOAT(U8_mask);
+ }
+ mask++;
+ }
+
+ if (srcAlpha > F32_OPACITY_TRANSPARENT + EPSILON) {
+
+ if (opacity < F32_OPACITY_OPAQUE - EPSILON) {
+ srcAlpha *= opacity;
+ }
+
+ if (srcAlpha > F32_OPACITY_OPAQUE - EPSILON) {
+ memcpy(dst, src, MAX_CHANNEL_LMSA * sizeof(float));
+ } else {
+ float dstAlpha = dst[PIXEL_ALPHA];
+
+ float srcBlend;
+
+ if (dstAlpha > F32_OPACITY_OPAQUE - EPSILON) {
+ srcBlend = srcAlpha;
+ } else {
+ float newAlpha = dstAlpha + (F32_OPACITY_OPAQUE - dstAlpha) * srcAlpha;
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha > EPSILON) {
+ srcBlend = srcAlpha / newAlpha;
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ if (srcBlend > F32_OPACITY_OPAQUE - EPSILON) {
+ memcpy(dst, src, MAX_CHANNEL_LMS * sizeof(float));
+ } else {
+ dst[PIXEL_LONGWAVE] = FLOAT_BLEND(src[PIXEL_LONGWAVE], dst[PIXEL_LONGWAVE], srcBlend);
+ dst[PIXEL_MIDDLEWAVE] = FLOAT_BLEND(src[PIXEL_MIDDLEWAVE], dst[PIXEL_MIDDLEWAVE], srcBlend);
+ dst[PIXEL_SHORTWAVE] = FLOAT_BLEND(src[PIXEL_SHORTWAVE], dst[PIXEL_SHORTWAVE], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_LMSA;
+ dst += MAX_CHANNEL_LMSA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart) {
+ maskRowStart += maskRowStride;
+ }
+ }
+}
+
+void KisLmsF32ColorSpace::compositeErase(Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ float /*opacity*/)
+{
+ while (rows-- > 0)
+ {
+ const Pixel *s = reinterpret_cast<const Pixel *>(src);
+ Pixel *d = reinterpret_cast<Pixel *>(dst);
+ const Q_UINT8 *mask = srcAlphaMask;
+
+ for (Q_INT32 i = cols; i > 0; i--, s++, d++)
+ {
+ float srcAlpha = s->alpha;
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = FLOAT_BLEND(srcAlpha, F32_OPACITY_OPAQUE, UINT8_TO_FLOAT(U8_mask));
+ }
+ mask++;
+ }
+ d->alpha = srcAlpha * d->alpha;
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ if(srcAlphaMask) {
+ srcAlphaMask += maskRowStride;
+ }
+ }
+}
+
+void KisLmsF32ColorSpace::compositeCopy(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride,
+ const Q_UINT8 */*maskRowStart*/, Q_INT32 /*maskRowStride*/, Q_INT32 rows, Q_INT32 numColumns, float /*opacity*/)
+{
+ while (rows > 0) {
+ memcpy(dstRowStart, srcRowStart, numColumns * sizeof(Pixel));
+ --rows;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ }
+}
+
+void KisLmsF32ColorSpace::bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *mask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 U8_opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op)
+{
+ float opacity = UINT8_TO_FLOAT(U8_opacity);
+
+ switch (op.op()) {
+ case COMPOSITE_UNDEF:
+ // Undefined == no composition
+ break;
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY:
+ compositeCopy(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ default:
+ break;
+ }
+}
+
+KisCompositeOpList KisLmsF32ColorSpace::userVisiblecompositeOps() const
+{
+ KisCompositeOpList list;
+
+ list.append(KisCompositeOp(COMPOSITE_OVER));
+ return list;
+}
+
diff --git a/krita/colorspaces/lms_f32/kis_lms_f32_colorspace.h b/krita/colorspaces/lms_f32/kis_lms_f32_colorspace.h
new file mode 100644
index 00000000..8d5d27d9
--- /dev/null
+++ b/krita/colorspaces/lms_f32/kis_lms_f32_colorspace.h
@@ -0,0 +1,157 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <[email protected]>
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ * Copyright (c) 2005 Cyrille Berger <[email protected]>
+ *
+ * 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_LMS_F32_H_
+#define KIS_STRATEGY_COLORSPACE_LMS_F32_H_
+
+#include <qcolor.h>
+
+#include <klocale.h>
+
+#include <koffice_export.h>
+
+#include "kis_global.h"
+#include "kis_f32_base_colorspace.h"
+
+class KisColorSpaceFactoryRegistry;
+
+class KRITATOOL_EXPORT KisLmsF32ColorSpace : public KisF32BaseColorSpace {
+public:
+ KisLmsF32ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p);
+ virtual ~KisLmsF32ColorSpace();
+
+ virtual bool willDegrade(ColorSpaceIndependence independence)
+ {
+ if (independence == TO_RGBA8 || independence == TO_LAB16)
+ return true;
+ else
+ return false;
+ };
+
+
+public:
+ void setPixel(Q_UINT8 *pixel, float longWave, float middleWave, float shortWave, float alpha) const;
+ void getPixel(const Q_UINT8 *pixel, float *longWave, float *middleWave, float *shortWave, float *alpha) const;
+
+ virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0);
+ virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0);
+
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0);
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0);
+
+ virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2);
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+
+ virtual bool hasHighDynamicRange() const { return false; }
+
+ virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
+ KisProfile * dstProfile,
+ Q_INT32 renderingIntent,
+ float exposure = 0.0f);
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+
+protected:
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeCopy(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+
+private:
+ inline Q_UINT8 computeRed(float l, float m, float s) const
+ {
+ return FLOAT_TO_UINT8(4.4679*l - 3.58738*m + 0.1193*s);
+ }
+ inline Q_UINT8 computeGreen(float l, float m, float s) const
+ {
+ return FLOAT_TO_UINT8(-1.2186*l + 2.3809*m - 0.1624*s);
+ }
+ inline Q_UINT8 computeBlue(float l, float m, float s) const
+ {
+ return FLOAT_TO_UINT8(0.0497*l - 0.2439*m + 1.2045*s);
+ }
+ inline float computeLong(Q_UINT8 r, Q_UINT8 g, Q_UINT8 b) const
+ {
+ return 0.3811*UINT8_TO_FLOAT(r) + 0.5783*UINT8_TO_FLOAT(g) + 0.0402*UINT8_TO_FLOAT(b);
+ }
+ inline float computeMiddle(Q_UINT8 r, Q_UINT8 g, Q_UINT8 b) const
+ {
+ return 0.1967*UINT8_TO_FLOAT(r) + 0.7244*UINT8_TO_FLOAT(g) + 0.0782*UINT8_TO_FLOAT(b);
+ }
+ inline float computeShort(Q_UINT8 r, Q_UINT8 g, Q_UINT8 b) const
+ {
+ return 0.0241*UINT8_TO_FLOAT(r) + 0.1288*UINT8_TO_FLOAT(g) + 0.8444*UINT8_TO_FLOAT(b);
+ }
+
+ friend class KisLmsF32ColorSpaceTester;
+
+ static const Q_UINT8 PIXEL_LONGWAVE = 0;
+ static const Q_UINT8 PIXEL_MIDDLEWAVE = 1;
+ static const Q_UINT8 PIXEL_SHORTWAVE = 2;
+ static const Q_UINT8 PIXEL_ALPHA = 3;
+
+ struct Pixel {
+ float longWave;
+ float middleWave;
+ float shortWave;
+ float alpha;
+ };
+};
+
+class KisLmsF32ColorSpaceFactory : public KisColorSpaceFactory
+{
+public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("LMSAF32", i18n("LMS Cone Space (32-bit float/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return 0; }; // FIXME: lcms do not support LMS cone space
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icMaxEnumData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisLmsF32ColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return "sRGB built-in - (lcms internal)"; };
+};
+
+#endif // KIS_STRATEGY_COLORSPACE_LMS_F32_H_
+
diff --git a/krita/colorspaces/lms_f32/krita_lms_f32_plugin.desktop b/krita/colorspaces/lms_f32/krita_lms_f32_plugin.desktop
new file mode 100644
index 00000000..89951209
--- /dev/null
+++ b/krita/colorspaces/lms_f32/krita_lms_f32_plugin.desktop
@@ -0,0 +1,77 @@
+[Desktop Entry]
+Name=LMS Color Model (32-bit float)
+Name[bg]=Цветови модел LMS (32 бита)
+Name[ca]=Model de color LMS (paleta de 32 bits)
+Name[cy]=Model Lliw LMS (arnawf 32-did)
+Name[da]=LMS-farvemodel (32-bit float)
+Name[de]=LMS-Farbmodell (32-bit Fließkomma)
+Name[el]=Χρωματικό μοντέλο LMS (32 bit δεκαδικοί)
+Name[en_GB]=LMS Colour Model (32-bit float)
+Name[eo]=LMS-kolormodelo (32-bita flupunkto)
+Name[es]=Modelo de color LMS (decimal de 32 bits)
+Name[et]=LMS värvimudel (32-bitine murdarv)
+Name[fa]=مدل رنگ LMS )شناور ۳۲ بیتی(
+Name[fr]=Modèle de couleurs LMS (flottants 32 bits)
+Name[fy]=LMS-kleurmodel (32-bit float)
+Name[gl]=Modelo de Cores LMS (vírgula flutuante 32-bit)
+Name[he]=מודל צבעים LMS (32 סיביות)
+Name[hu]=LMS színmodell (32 bites lebegőpontos)
+Name[is]=LMS litategund (32-bita fleytitala)
+Name[it]=Modello di colore LMS (virgola mobile a 32 bit)
+Name[ja]=LMS カラーモデル (32 ビット浮動小数)
+Name[km]=គំរូ​ពណ៌ LMS (ចំនួន​ទស្សភាគ ៣២ ប៊ីត)
+Name[nb]=LMS-fargemodell (32-bit flyttall)
+Name[nds]=LMS-Klöörmodell (32-Bit Fleetkomma)
+Name[ne]=LMS रङ मोडेल (३२-बिट उत्प्लावन)
+Name[nl]=LMS-kleurmodel (32-bit float)
+Name[pl]=Przestrzeń barw LMS (32-bitowa liczba zmiennoprzecinkowa)
+Name[pt]=Modelo de Cor LMS (v. flutuante de 32-bits)
+Name[pt_BR]=Modelo de Cor LMS (ponto flutuante de 32-bits)
+Name[ru]=LMS (32-бит с плавающей точкой)
+Name[sk]=Model farieb LMS (32-bitové reálne čísla)
+Name[sl]=Barvni model LMS (32-bitna decimalno število)
+Name[sr]=LMS модел боја (32-битно реално)
+Name[sr@Latn]=LMS model boja (32-bitno realno)
+Name[sv]=LMS-färgmodell (32-bitars flyttal)
+Name[uk]=Модель кольору LMS (32-бітне дробове число)
+Name[uz]=LMS rang usuli (32-bit kasr)
+Name[uz@cyrillic]=LMS ранг усули (32-бит каср)
+Name[zh_CN]=LMS 色彩模型(32 位浮点)
+Name[zh_TW]=LMS 色彩模型 (32-bit 浮點數)
+Comment=Color model for LMS cone space (Long Middle and Short wavelengths)
+Comment[bg]=Цветови модел за интервали LMS (дълги, средни и къси вълни)
+Comment[ca]=Model de color per a conus d'espai LMC (amples d'ona llargs, mitjos i curts)
+Comment[cy]=Model lliw ar gyfer gofod côn LMS (tonfeddi Hir, Canolig a Byr)
+Comment[da]=Farvemodel for LMS-keglerum (Lange, mellemliggende og korte bølgelængder)
+Comment[de]=Farbmodell für LMS cone space (Lange, Mittelere und Kurze Wellenlängen)
+Comment[el]=Χρωματικό μοντέλο για χώρο χρωμάτων LMS (Μακρά μεσαία και σύντομα μήκη κύματος)
+Comment[en_GB]=Colour model for LMS cone space (Long Middle and Short wavelengths)
+Comment[es]=Modelo de color para el espacio cónico LMS (con longitudes de onda larga, media y corta)
+Comment[et]=LMS koonuse (pikad, keskmised ja lühikesed lainepikkused) värvimudel
+Comment[fa]=مدل رنگ برای فضای مخروط LMS )طول موج بلند، متوسط و کوتاه(
+Comment[fr]=Modèle de couleurs pour l'espace conique LMS (longueurs d'ondes longues, moyennes et courtes)
+Comment[fy]=Kleurmodel Foar LMS-kegelromte (lange, middelt en koarte golflingten)
+Comment[gl]=Modelo de Cores para o espazo do cone LMS (Long Middle and Short wavelengths)
+Comment[hu]=Színmodell az LMS kúptérhez (hosszú, közepes és rövid hullámhosszak)
+Comment[is]=Litategund fyrir LMS keilubil (löng miðlungs og stutt bylgjulengd)
+Comment[it]=Modello di colore per lo spazio conico LMS (lunghezze d'onda lunghe, medie e corte)
+Comment[km]=មូដែល​ពណ៌​សម្រាប់ LMS ដែល​មាន​ចន្លោះ​រាង​សាជី​មូល​ (ប្រវែង​រលក​ខ្លី និង​ពាក់​កណ្ដាល​វែង)
+Comment[nb]=Fargemodell for LMS-kjeglerom (Long Middle og Short bølgelengder)
+Comment[nds]=Klöörmodell för LMS-Kegelruum (Lang, middel un kort Bülgenlängden)
+Comment[ne]=LMS शंकु खाली स्थान (लामो मध्य र छोटो तरङलम्बाइहरू) का लागि रङ मोडेल
+Comment[nl]=Kleurmodel voor LMS-kegelruimte (lange, middel en korte golflengten)
+Comment[pl]=Przestrzeń barw dla przestrzeni stożkowej LMS (średnie długie i krótkie długości fal)
+Comment[pt]=Modelo de cor para o espaço cónico do LMS (comprimentos de onda longos, médios e curtos)
+Comment[pt_BR]=Modelo de cor para o espaço cônico do LMS (comprimentos de onda longos, médios e curtos)
+Comment[ru]=Цветовое пространство LMS (Long Middle and Short wavelengths)
+Comment[sk]=Model farieb pre LMS kónický priestor (dlhé, stredné a krátke vlnové dĺžky)
+Comment[sl]=Barvni model za prostor stožca LMS (dolge, srednje in kratke valovne dolžine)
+Comment[sr]=Модел боја за LMS конусни простор (дуге средње и кратке таласне дужине)
+Comment[sr@Latn]=Model boja za LMS konusni prostor (duge srednje i kratke talasne dužine)
+Comment[sv]=Färgmodell för LMS-konrymd (Långa, mellanliggande och korta våglängder)
+Comment[uk]=Модель кольорів для конусного простору LMS (довгі середні і короткі довжини кольорів)
+Comment[zh_TW]=LMS cone space 顏色模式(Long Middle and Short 波長)
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-KDE-Library=krita_lms_f32_plugin
+X-Krita-Version=2
diff --git a/krita/colorspaces/lms_f32/lms_f32_plugin.cc b/krita/colorspaces/lms_f32/lms_f32_plugin.cc
new file mode 100644
index 00000000..67df5e4f
--- /dev/null
+++ b/krita/colorspaces/lms_f32/lms_f32_plugin.cc
@@ -0,0 +1,64 @@
+/*
+* lms_f32_plugin.cc -- Part of Krita
+*
+* Copyright (c) 2004 Boudewijn Rempt ([email protected])
+* Copyright (c) 2005 Adrian Page <[email protected]>
+* Copyright (c) 2005 Cyrille Berger <[email protected]>
+*
+* 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 <kinstance.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <kis_debug_areas.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_basic_histogram_producers.h>
+
+#include "lms_f32_plugin.h"
+#include "kis_lms_f32_colorspace.h"
+
+typedef KGenericFactory<LMSF32Plugin> LMSF32PluginFactory;
+K_EXPORT_COMPONENT_FACTORY( krita_lms_f32_plugin, LMSF32PluginFactory( "krita" ) )
+
+
+LMSF32Plugin::LMSF32Plugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(LMSF32PluginFactory::instance());
+
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") )
+ {
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry*>(parent);
+
+ KisColorSpace * colorSpaceLMSF32 = new KisLmsF32ColorSpace(f, 0);
+
+ KisColorSpaceFactory * csf = new KisLmsF32ColorSpaceFactory();
+ f->add(csf);
+
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicF32HistogramProducer>
+ (KisID("LMSF32HISTO", i18n("Float32")), colorSpaceLMSF32) );
+ }
+
+}
+
+LMSF32Plugin::~LMSF32Plugin()
+{
+}
+
+#include "lms_f32_plugin.moc"
diff --git a/krita/colorspaces/lms_f32/lms_f32_plugin.h b/krita/colorspaces/lms_f32/lms_f32_plugin.h
new file mode 100644
index 00000000..b8d02b18
--- /dev/null
+++ b/krita/colorspaces/lms_f32/lms_f32_plugin.h
@@ -0,0 +1,39 @@
+/*
+ * Copyright (c) 2003 Boudewijn Rempt ([email protected])
+ * Copyright (c) 2005 Cyrille Berger <[email protected]>
+ *
+ * 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 LMS_F32_PLUGIN_H_
+#define LMS_F32_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the LMS F32 colour space strategy.
+ */
+class LMSF32Plugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ LMSF32Plugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~LMSF32Plugin();
+
+};
+
+
+#endif // LMS_F32_PLUGIN_H_
diff --git a/krita/colorspaces/lms_f32/lms_f32_plugin.rc b/krita/colorspaces/lms_f32/lms_f32_plugin.rc
new file mode 100644
index 00000000..ac6ec45f
--- /dev/null
+++ b/krita/colorspaces/lms_f32/lms_f32_plugin.rc
@@ -0,0 +1,9 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui library="krita_lms_f32_plugin" version="1">
+<Menu name="Image"><text>&amp;Image</text>
+ <Menu name="Mode"><text>&amp;Mode</text>
+ <Action name="convert to RGB(A) (32-bit float)"/>
+ </Menu>
+</Menu>
+
+</kpartgui>
diff --git a/krita/colorspaces/rgb_f16half/Makefile.am b/krita/colorspaces/rgb_f16half/Makefile.am
new file mode 100644
index 00000000..d49bd2ef
--- /dev/null
+++ b/krita/colorspaces/rgb_f16half/Makefile.am
@@ -0,0 +1,35 @@
+# Install the desktop file needed to detect the plugin
+kde_services_DATA = krita_rgb_f16half_plugin.desktop
+
+INCLUDES = \
+ -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../kritacolor/ \
+ $(OPENEXR_CFLAGS) \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+
+lib_LTLIBRARIES = libkrita_rgb_f16half.la
+libkrita_rgb_f16half_la_SOURCES = kis_rgb_f16half_colorspace.cc
+libkrita_rgb_f16half_la_LDFLAGS = $(all_libraries)
+libkrita_rgb_f16half_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = krita_rgb_f16half_plugin.la
+
+# Srcs for the plugin
+krita_rgb_f16half_plugin_la_SOURCES = rgb_f16half_plugin.cc
+noinst_HEADERS = rgb_f16half_plugin.h kis_rgb_f16half_colorspace.h
+
+krita_rgb_f16half_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+krita_rgb_f16half_plugin_la_LIBADD = libkrita_rgb_f16half.la ../../kritacolor/libkritacolor.la
+
+krita_rgb_f16half_plugin_la_METASOURCES = AUTO
+
+if include_kunittest_tests
+TESTSDIR = tests
+endif
+
+SUBDIRS = . $(TESTSDIR)
+
diff --git a/krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.cc b/krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.cc
new file mode 100644
index 00000000..a1826b97
--- /dev/null
+++ b/krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.cc
@@ -0,0 +1,952 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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 <qimage.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "kis_rgb_f16half_colorspace.h"
+#include "kis_f32_base_colorspace.h"
+#include "kis_color_conversions.h"
+
+namespace {
+ const Q_INT32 MAX_CHANNEL_RGB = 3;
+ const Q_INT32 MAX_CHANNEL_RGBA = 4;
+}
+
+#include "kis_integer_maths.h"
+
+#ifndef HAVE_POWF
+#undef powf
+#define powf pow
+#endif
+
+//#define HALF_MAX ((half)1.0f) //temp
+
+#define EPSILON HALF_EPSILON
+
+// FIXME: lcms doesn't support 16-bit float
+#define RGBAF16HALF_LCMS_TYPE TYPE_BGRA_16
+
+KisRgbF16HalfColorSpace::KisRgbF16HalfColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) :
+ KisF16HalfBaseColorSpace(KisID("RGBAF16HALF", i18n("RGB (16-bit float/channel)")), RGBAF16HALF_LCMS_TYPE, icSigRgbData, parent, p)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Red"), i18n("R"), PIXEL_RED * sizeof(half), KisChannelInfo::COLOR, KisChannelInfo::FLOAT16, sizeof(half)));
+ m_channels.push_back(new KisChannelInfo(i18n("Green"), i18n("G"), PIXEL_GREEN * sizeof(half), KisChannelInfo::COLOR, KisChannelInfo::FLOAT16, sizeof(half)));
+ m_channels.push_back(new KisChannelInfo(i18n("Blue"), i18n("B"), PIXEL_BLUE * sizeof(half), KisChannelInfo::COLOR, KisChannelInfo::FLOAT16, sizeof(half)));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(half), KisChannelInfo::ALPHA, KisChannelInfo::FLOAT16, sizeof(half)));
+
+ //cmsHPROFILE hProfile = cmsCreate_sRGBProfile();
+ //setDefaultProfile( new KisProfile(hProfile, RGBAF16HALF_LCMS_TYPE) );
+
+ m_alphaPos = PIXEL_ALPHA * sizeof(half);
+}
+
+KisRgbF16HalfColorSpace::~KisRgbF16HalfColorSpace()
+{
+}
+
+void KisRgbF16HalfColorSpace::setPixel(Q_UINT8 *dst, half red, half green, half blue, half alpha) const
+{
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->red = red;
+ dstPixel->green = green;
+ dstPixel->blue = blue;
+ dstPixel->alpha = alpha;
+}
+
+void KisRgbF16HalfColorSpace::getPixel(const Q_UINT8 *src, half *red, half *green, half *blue, half *alpha) const
+{
+ const Pixel *srcPixel = reinterpret_cast<const Pixel *>(src);
+
+ *red = srcPixel->red;
+ *green = srcPixel->green;
+ *blue = srcPixel->blue;
+ *alpha = srcPixel->alpha;
+}
+
+void KisRgbF16HalfColorSpace::fromQColor(const QColor& c, Q_UINT8 *dstU8, KisProfile *)
+{
+ Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
+
+ dst->red = UINT8_TO_HALF(c.red());
+ dst->green = UINT8_TO_HALF(c.green());
+ dst->blue = UINT8_TO_HALF(c.blue());
+}
+
+void KisRgbF16HalfColorSpace::fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dstU8, KisProfile *)
+{
+ Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
+
+ dst->red = UINT8_TO_HALF(c.red());
+ dst->green = UINT8_TO_HALF(c.green());
+ dst->blue = UINT8_TO_HALF(c.blue());
+ dst->alpha = UINT8_TO_HALF(opacity);
+}
+
+void KisRgbF16HalfColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, KisProfile *)
+{
+ const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
+
+ c->setRgb(HALF_TO_UINT8(src->red), HALF_TO_UINT8(src->green), HALF_TO_UINT8(src->blue));
+}
+
+void KisRgbF16HalfColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_UINT8 *opacity, KisProfile *)
+{
+ const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
+
+ c->setRgb(HALF_TO_UINT8(src->red), HALF_TO_UINT8(src->green), HALF_TO_UINT8(src->blue));
+ *opacity = HALF_TO_UINT8(src->alpha);
+}
+
+Q_UINT8 KisRgbF16HalfColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8)
+{
+ const Pixel *src1 = reinterpret_cast<const Pixel *>(src1U8);
+ const Pixel *src2 = reinterpret_cast<const Pixel *>(src2U8);
+
+ return HALF_TO_UINT8(QMAX(QABS(src2->red - src1->red),
+ QMAX(QABS(src2->green - src1->green),
+ QABS(src2->blue - src1->blue))));
+}
+
+void KisRgbF16HalfColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+ half totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel *pixel = reinterpret_cast<const Pixel *>(*colors);
+
+ half alpha = pixel->alpha;
+ half alphaTimesWeight = alpha * UINT8_TO_HALF(*weights);
+
+ totalRed += pixel->red * alphaTimesWeight;
+ totalGreen += pixel->green * alphaTimesWeight;
+ totalBlue += pixel->blue * alphaTimesWeight;
+ newAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ Q_ASSERT(newAlpha <= F16HALF_OPACITY_OPAQUE);
+
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->alpha = newAlpha;
+
+ if (newAlpha > EPSILON) {
+ totalRed = totalRed / newAlpha;
+ totalGreen = totalGreen / newAlpha;
+ totalBlue = totalBlue / newAlpha;
+ }
+
+ dstPixel->red = totalRed;
+ dstPixel->green = totalGreen;
+ dstPixel->blue = totalBlue;
+}
+
+void KisRgbF16HalfColorSpace::convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const
+{
+ half totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel * pixel = reinterpret_cast<const Pixel *>( *colors );
+
+ half weight = *kernelValues;
+
+ if (weight != 0) {
+ totalRed += pixel->red * UINT8_TO_HALF(weight);
+ totalGreen += pixel->green * UINT8_TO_HALF(weight);
+ totalBlue += pixel->blue * UINT8_TO_HALF(weight);
+ totalAlpha += pixel->alpha * UINT8_TO_HALF(weight);
+ }
+ colors++;
+ kernelValues++;
+ }
+
+ Pixel * p = reinterpret_cast< Pixel *>( dst );
+
+ if (channelFlags & KisChannelInfo::FLAG_COLOR) {
+ p->red = CLAMP( ( totalRed / factor) + offset, 0, HALF_MAX);
+ p->green = CLAMP( ( totalGreen / factor) + offset, 0, HALF_MAX);
+ p->blue = CLAMP( ( totalBlue / factor) + offset, 0, HALF_MAX);
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, HALF_MAX);
+ }
+}
+
+
+void KisRgbF16HalfColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels)
+{
+ Q_UINT32 psize = pixelSize();
+
+ while (nPixels--)
+ {
+ Pixel * p = reinterpret_cast< Pixel *>( src );
+ p->red = 1.0 - p->red;
+ p->green = 1.0 - p->green;
+ p->blue = 1.0 - p->blue;
+ src += psize;
+ }
+
+}
+
+
+Q_UINT8 KisRgbF16HalfColorSpace::intensity8(const Q_UINT8 * src) const
+{
+ const Pixel * p = reinterpret_cast<const Pixel *>( src );
+
+ return HALF_TO_UINT8((p->red * 0.30 + p->green * 0.59 + p->blue * 0.11) + 0.5);
+}
+
+
+QValueVector<KisChannelInfo *> KisRgbF16HalfColorSpace::channels() const
+{
+ return m_channels;
+}
+
+Q_UINT32 KisRgbF16HalfColorSpace::nChannels() const
+{
+ return MAX_CHANNEL_RGBA;
+}
+
+Q_UINT32 KisRgbF16HalfColorSpace::nColorChannels() const
+{
+ return MAX_CHANNEL_RGB;
+}
+
+Q_UINT32 KisRgbF16HalfColorSpace::pixelSize() const
+{
+ return MAX_CHANNEL_RGBA * sizeof(half);
+}
+
+Q_UINT8 convertToDisplay(float value, float exposureFactor, float gamma)
+{
+ //value *= pow(2, exposure + 2.47393);
+ value *= exposureFactor;
+
+ value = powf(value, gamma);
+
+ // scale middle gray to the target framebuffer value
+
+ value *= 84.66f;
+
+ int valueInt = (int)(value + 0.5);
+
+ return CLAMP(valueInt, 0, 255);
+}
+
+QImage KisRgbF16HalfColorSpace::convertToQImage(const Q_UINT8 *dataU8, Q_INT32 width, Q_INT32 height,
+ KisProfile * /*dstProfile*/,
+ Q_INT32 /*renderingIntent*/, float exposure)
+
+{
+ const half *data = reinterpret_cast<const half *>(dataU8);
+
+ QImage img = QImage(width, height, 32, 0, QImage::LittleEndian);
+ img.setAlphaBuffer(true);
+
+ Q_INT32 i = 0;
+ uchar *j = img.bits();
+
+ // XXX: For now assume gamma 2.2.
+ float gamma = 1 / 2.2;
+ float exposureFactor = powf(2, exposure + 2.47393);
+
+ while ( i < width * height * MAX_CHANNEL_RGBA) {
+ *( j + 3) = HALF_TO_UINT8(*( data + i + PIXEL_ALPHA ));
+ *( j + 2 ) = convertToDisplay(*( data + i + PIXEL_RED ), exposureFactor, gamma);
+ *( j + 1 ) = convertToDisplay(*( data + i + PIXEL_GREEN ), exposureFactor, gamma);
+ *( j + 0 ) = convertToDisplay(*( data + i + PIXEL_BLUE ), exposureFactor, gamma);
+ i += MAX_CHANNEL_RGBA;
+ j += MAX_CHANNEL_RGBA;
+ }
+
+ /*
+ if (srcProfile != 0 && dstProfile != 0) {
+ convertPixelsTo(img.bits(), srcProfile,
+ img.bits(), this, dstProfile,
+ width * height, renderingIntent);
+ }
+ */
+ return img;
+}
+
+
+void KisRgbF16HalfColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ while (rows > 0) {
+
+ const half *src = reinterpret_cast<const half *>(srcRowStart);
+ half *dst = reinterpret_cast<half *>(dstRowStart);
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ half srcAlpha = src[PIXEL_ALPHA];
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha *= UINT8_TO_HALF(U8_mask);
+ }
+ mask++;
+ }
+
+ if (srcAlpha > F16HALF_OPACITY_TRANSPARENT + EPSILON) {
+
+ if (opacity < F16HALF_OPACITY_OPAQUE - EPSILON) {
+ srcAlpha *= opacity;
+ }
+
+ if (srcAlpha > F16HALF_OPACITY_OPAQUE - EPSILON) {
+ memcpy(dst, src, MAX_CHANNEL_RGBA * sizeof(half));
+ } else {
+ half dstAlpha = dst[PIXEL_ALPHA];
+
+ half srcBlend;
+
+ if (dstAlpha > F16HALF_OPACITY_OPAQUE - EPSILON) {
+ srcBlend = srcAlpha;
+ } else {
+ half newAlpha = dstAlpha + (F16HALF_OPACITY_OPAQUE - dstAlpha) * srcAlpha;
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha > EPSILON) {
+ srcBlend = srcAlpha / newAlpha;
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ if (srcBlend > F16HALF_OPACITY_OPAQUE - EPSILON) {
+ memcpy(dst, src, MAX_CHANNEL_RGB * sizeof(half));
+ } else {
+ dst[PIXEL_RED] = HALF_BLEND(src[PIXEL_RED], dst[PIXEL_RED], srcBlend);
+ dst[PIXEL_GREEN] = HALF_BLEND(src[PIXEL_GREEN], dst[PIXEL_GREEN], srcBlend);
+ dst[PIXEL_BLUE] = HALF_BLEND(src[PIXEL_BLUE], dst[PIXEL_BLUE], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart) {
+ maskRowStart += maskRowStride;
+ }
+ }
+}
+
+#define COMMON_COMPOSITE_OP_PROLOG() \
+ while (rows > 0) { \
+ \
+ const half *src = reinterpret_cast<const half *>(srcRowStart); \
+ half *dst = reinterpret_cast<half *>(dstRowStart); \
+ Q_INT32 columns = numColumns; \
+ const Q_UINT8 *mask = maskRowStart; \
+ \
+ while (columns > 0) { \
+ \
+ half srcAlpha = src[PIXEL_ALPHA]; \
+ half dstAlpha = dst[PIXEL_ALPHA]; \
+ \
+ srcAlpha = QMIN(srcAlpha, dstAlpha); \
+ \
+ if (mask != 0) { \
+ Q_UINT8 U8_mask = *mask; \
+ \
+ if (U8_mask != OPACITY_OPAQUE) { \
+ srcAlpha *= UINT8_TO_HALF(U8_mask); \
+ } \
+ mask++; \
+ } \
+ \
+ if (srcAlpha > F16HALF_OPACITY_TRANSPARENT + EPSILON) { \
+ \
+ if (opacity < F16HALF_OPACITY_OPAQUE - EPSILON) { \
+ srcAlpha *= opacity; \
+ } \
+ \
+ half srcBlend; \
+ \
+ if (dstAlpha > F16HALF_OPACITY_OPAQUE - EPSILON) { \
+ srcBlend = srcAlpha; \
+ } else { \
+ half newAlpha = dstAlpha + (F16HALF_OPACITY_OPAQUE - dstAlpha) * srcAlpha; \
+ dst[PIXEL_ALPHA] = newAlpha; \
+ \
+ if (newAlpha > EPSILON) { \
+ srcBlend = srcAlpha / newAlpha; \
+ } else { \
+ srcBlend = srcAlpha; \
+ } \
+ }
+
+#define COMMON_COMPOSITE_OP_EPILOG() \
+ } \
+ \
+ columns--; \
+ src += MAX_CHANNEL_RGBA; \
+ dst += MAX_CHANNEL_RGBA; \
+ } \
+ \
+ rows--; \
+ srcRowStart += srcRowStride; \
+ dstRowStart += dstRowStride; \
+ if(maskRowStart) { \
+ maskRowStart += maskRowStride; \
+ } \
+ }
+
+void KisRgbF16HalfColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ half srcColor = src[PIXEL_RED];
+ half dstColor = dst[PIXEL_RED];
+
+ srcColor = srcColor * dstColor;
+
+ dst[PIXEL_RED] = HALF_BLEND(srcColor, dstColor, srcBlend);
+
+ srcColor = src[PIXEL_GREEN];
+ dstColor = dst[PIXEL_GREEN];
+
+ srcColor = srcColor * dstColor;
+
+ dst[PIXEL_GREEN] = HALF_BLEND(srcColor, dstColor, srcBlend);
+
+ srcColor = src[PIXEL_BLUE];
+ dstColor = dst[PIXEL_BLUE];
+
+ srcColor = srcColor * dstColor;
+
+ dst[PIXEL_BLUE] = HALF_BLEND(srcColor, dstColor, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ half srcColor = src[channel];
+ half dstColor = dst[channel];
+
+ srcColor = QMIN(dstColor / (srcColor + EPSILON), HALF_MAX);
+
+ half newColor = HALF_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ half srcColor = src[channel];
+ half dstColor = dst[channel];
+
+ srcColor = HALF_MAX - ((HALF_MAX - dstColor) * (HALF_MAX - srcColor));
+
+ half newColor = HALF_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ half srcColor = src[channel];
+ half dstColor = dst[channel];
+
+ srcColor = dstColor * (dstColor + 2 * (srcColor * (HALF_MAX - dstColor)));
+
+ half newColor = HALF_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ half srcColor = src[channel];
+ half dstColor = dst[channel];
+
+ srcColor = QMIN(dstColor / (HALF_MAX + EPSILON - srcColor), HALF_MAX);
+
+ half newColor = HALF_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ half srcColor = src[channel];
+ half dstColor = dst[channel];
+
+ srcColor = QMIN((HALF_MAX - dstColor) / (srcColor + EPSILON), HALF_MAX);
+ srcColor = CLAMP(HALF_MAX - srcColor, 0, HALF_MAX);
+
+ half newColor = HALF_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ half srcColor = src[channel];
+ half dstColor = dst[channel];
+
+ srcColor = QMIN(srcColor, dstColor);
+
+ half newColor = HALF_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ half srcColor = src[channel];
+ half dstColor = dst[channel];
+
+ srcColor = QMAX(srcColor, dstColor);
+
+ half newColor = HALF_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeHue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float srcRed = src[PIXEL_RED];
+ float srcGreen = src[PIXEL_GREEN];
+ float srcBlue = src[PIXEL_BLUE];
+
+ float dstRed = dst[PIXEL_RED];
+ float dstGreen = dst[PIXEL_GREEN];
+ float dstBlue = dst[PIXEL_BLUE];
+
+ float srcHue;
+ float srcSaturation;
+ float srcValue;
+
+ float dstHue;
+ float dstSaturation;
+ float dstValue;
+
+ RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue);
+ RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ HSVToRGB(srcHue, dstSaturation, dstValue, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeSaturation(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float srcRed = src[PIXEL_RED];
+ float srcGreen = src[PIXEL_GREEN];
+ float srcBlue = src[PIXEL_BLUE];
+
+ float dstRed = dst[PIXEL_RED];
+ float dstGreen = dst[PIXEL_GREEN];
+ float dstBlue = dst[PIXEL_BLUE];
+
+ float srcHue;
+ float srcSaturation;
+ float srcValue;
+
+ float dstHue;
+ float dstSaturation;
+ float dstValue;
+
+ RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue);
+ RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ HSVToRGB(dstHue, srcSaturation, dstValue, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeValue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float srcRed = src[PIXEL_RED];
+ float srcGreen = src[PIXEL_GREEN];
+ float srcBlue = src[PIXEL_BLUE];
+
+ float dstRed = dst[PIXEL_RED];
+ float dstGreen = dst[PIXEL_GREEN];
+ float dstBlue = dst[PIXEL_BLUE];
+
+ float srcHue;
+ float srcSaturation;
+ float srcValue;
+
+ float dstHue;
+ float dstSaturation;
+ float dstValue;
+
+ RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue);
+ RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ HSVToRGB(dstHue, dstSaturation, srcValue, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeColor(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, half opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float srcRed = src[PIXEL_RED];
+ float srcGreen = src[PIXEL_GREEN];
+ float srcBlue = src[PIXEL_BLUE];
+
+ float dstRed = dst[PIXEL_RED];
+ float dstGreen = dst[PIXEL_GREEN];
+ float dstBlue = dst[PIXEL_BLUE];
+
+ float srcHue;
+ float srcSaturation;
+ float srcLightness;
+
+ float dstHue;
+ float dstSaturation;
+ float dstLightness;
+
+ RGBToHSL(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcLightness);
+ RGBToHSL(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstLightness);
+
+ HSLToRGB(srcHue, srcSaturation, dstLightness, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF16HalfColorSpace::compositeErase(Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ half /*opacity*/)
+{
+ while (rows-- > 0)
+ {
+ const Pixel *s = reinterpret_cast<const Pixel *>(src);
+ Pixel *d = reinterpret_cast<Pixel *>(dst);
+ const Q_UINT8 *mask = srcAlphaMask;
+
+ for (Q_INT32 i = cols; i > 0; i--, s++, d++)
+ {
+ half srcAlpha = s->alpha;
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = HALF_BLEND(srcAlpha, F16HALF_OPACITY_OPAQUE, UINT8_TO_HALF(U8_mask));
+ }
+ mask++;
+ }
+ d->alpha = srcAlpha * d->alpha;
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ if(srcAlphaMask) {
+ srcAlphaMask += maskRowStride;
+ }
+ }
+}
+
+void KisRgbF16HalfColorSpace::bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *mask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 U8_opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op)
+{
+ half opacity = UINT8_TO_HALF(U8_opacity);
+
+ switch (op.op()) {
+ case COMPOSITE_UNDEF:
+ // Undefined == no composition
+ break;
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIVIDE:
+ compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LIGHTEN:
+ compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_HUE:
+ compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SATURATION:
+ compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_VALUE:
+ compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COLOR:
+ compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_OVERLAY:
+ compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DODGE:
+ compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BURN:
+ compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ALPHA_DARKEN:
+ abstractCompositeAlphaDarken<half, F16HalfMult, Uint8ToF16Half, F16HalfOpacityTest,
+ PIXEL_ALPHA, MAX_CHANNEL_RGB, MAX_CHANNEL_RGBA>(
+ dst, dstRowStride, src, srcRowStride, mask, maskRowStride,
+ rows, cols,
+ U8_opacity, F16HalfMult(), Uint8ToF16Half(), F16HalfOpacityTest());
+ break;
+ default:
+ break;
+ }
+}
+
+KisCompositeOpList KisRgbF16HalfColorSpace::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));
+ list.append(KisCompositeOp(COMPOSITE_HUE));
+ list.append(KisCompositeOp(COMPOSITE_SATURATION));
+ list.append(KisCompositeOp(COMPOSITE_VALUE));
+ list.append(KisCompositeOp(COMPOSITE_COLOR));
+
+ return list;
+}
+
diff --git a/krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.h b/krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.h
new file mode 100644
index 00000000..c56d7f63
--- /dev/null
+++ b/krita/colorspaces/rgb_f16half/kis_rgb_f16half_colorspace.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_RGB_F16HALF_COLORSPACE_H_
+#define KIS_RGB_F16HALF_COLORSPACE_H_
+
+#include <qcolor.h>
+
+#include <klocale.h>
+
+#include <koffice_export.h>
+
+#include "kis_global.h"
+#include "kis_f16half_base_colorspace.h"
+
+
+class KRITATOOL_EXPORT KisRgbF16HalfColorSpace : public KisF16HalfBaseColorSpace {
+public:
+ KisRgbF16HalfColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p);
+ virtual ~KisRgbF16HalfColorSpace();
+
+ virtual bool willDegrade(ColorSpaceIndependence independence)
+ {
+ if (independence == TO_RGBA8 || independence == TO_LAB16)
+ return true;
+ else
+ return false;
+ };
+
+
+public:
+ void setPixel(Q_UINT8 *pixel, half red, half green, half blue, half alpha) const;
+ void getPixel(const Q_UINT8 *pixel, half *red, half *green, half *blue, half *alpha) const;
+
+ virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0);
+ virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0);
+
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0);
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0);
+
+ virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2);
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+ virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels);
+ virtual void convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const;
+ virtual Q_UINT8 intensity8(const Q_UINT8 * src) const;
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+
+ virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
+ KisProfile * dstProfile,
+ Q_INT32 renderingIntent,
+ float exposure = 0.0f);
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+
+protected:
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeHue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeSaturation(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeValue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeColor(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+ void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, half opacity);
+
+private:
+ friend class KisRgbF16HalfColorSpaceTester;
+
+ static const Q_UINT8 PIXEL_BLUE = 0;
+ static const Q_UINT8 PIXEL_GREEN = 1;
+ static const Q_UINT8 PIXEL_RED = 2;
+ static const Q_UINT8 PIXEL_ALPHA = 3;
+
+ struct Pixel {
+ half blue;
+ half green;
+ half red;
+ half alpha;
+ };
+};
+
+// FIXME: lcms doesn't support 16-bit float
+#define RGBAF16HALF_LCMS_TYPE TYPE_BGRA_16
+
+class KisRgbF16HalfColorSpaceFactory : public KisColorSpaceFactory
+{
+public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("RGBAF16HALF", i18n("RGB (16-bit float/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return RGBAF16HALF_LCMS_TYPE; };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisRgbF16HalfColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return "sRGB built-in - (lcms internal)"; };
+};
+
+#endif // KIS_RGB_F16HALF_COLORSPACE_H_
+
diff --git a/krita/colorspaces/rgb_f16half/krita_rgb_f16half_plugin.desktop b/krita/colorspaces/rgb_f16half/krita_rgb_f16half_plugin.desktop
new file mode 100644
index 00000000..8ebf7b17
--- /dev/null
+++ b/krita/colorspaces/rgb_f16half/krita_rgb_f16half_plugin.desktop
@@ -0,0 +1,76 @@
+[Desktop Entry]
+Name=RGB Color Model (16-bit float 'half')
+Name[bg]=Цветови модел RGB (16-bit float 'half')
+Name[ca]=Model de color RGB (paleta 'mitja' de 16 bits)
+Name[cy]=Model Lliw RGB (arnawf 16-did 'hanner')
+Name[da]=RGB-farvemodel (16-bit heltal 'halv')
+Name[de]=RGB-Farbmodell (16-bit Fließkomma 'Halb')
+Name[el]=Χρωματικό μοντέλο RGB (16 bit μισοί δεκαδικοί)
+Name[en_GB]=RGB Colour Model (16-bit float 'half')
+Name[es]=Modelo de color RGB (decimal «medio» de 16 bits)
+Name[et]=RGB värvimudel (16-bitine murdarv 'half')
+Name[fa]=مدل رنگ RGB )»نیمه« شناور ۱۶ بیتی(
+Name[fr]=Modèle de couleurs RVB (demi flottants 16 bits)
+Name[fy]=RGB-kleurmodel (16-bit float 'heal')
+Name[gl]=Modelo de Cores RGB (vírgula flutuante 16-bit 'half')
+Name[he]=מודל צבעים RGB (16 סיביות)
+Name[hu]=RGB színmodell (16 bites lebegőpontos - 'feles')
+Name[is]=RGB litategund (16-bita fleytitala)
+Name[it]=Modello di colore RGB (semi-virgola mobile a 16 bit)
+Name[ja]=RGB カラーモデル (16-bit float 'half')
+Name[km]=ម៉ូដែល​ពណ៌​RGB (ចំនួន​ទសភាគ 16 ប៊ីត​ 'ពាក់​កណ្ដាល')
+Name[nb]=RGB-fargemodell (16-bit flytende 'halv')
+Name[nds]=RGB-Klöörmodell (16-Bit Fleetkomma "half")
+Name[ne]=RGB रङ मोडेल (१६-बिट उत्प्लावन 'आधा')
+Name[nl]=RGB-kleurmodel (16-bit float 'half')
+Name[pl]=Przestrzeń barw RGB ("połowa" 16-bitowej liczby zmiennoprzecinkowej)
+Name[pt]=Modelo de Cor RGB (v. flutuante de 16-bits 'half')
+Name[pt_BR]=Modelo de Cor RGB (ponto flutuante de 16-bits 'half')
+Name[ru]=RGB (16-бит с плавающей точкой)
+Name[sk]=Model farieb RGB (16-bitové reálne čísla 'half')
+Name[sl]=Barvni model RGB (16-bitno celo število, »polovica«)
+Name[sr]=RGB модел боја (16-битно реално „полу“)
+Name[sr@Latn]=RGB model boja (16-bitno realno „polu“)
+Name[sv]=RGB-färgmodell (16-bitars flyttal 'halva')
+Name[uk]=Модель кольору RGB (16-бітне дробове число "half")
+Name[uz]=RGB rang usuli (16-bit 'yarim' kasr)
+Name[uz@cyrillic]=RGB ранг усули (16-бит 'ярим' каср)
+Name[zh_TW]=RGB 色彩模型 (32-bit 浮點數「半」)
+Comment=Color model for 16-bit floating point 'half' per channel RGB images
+Comment[bg]=Цветови модел за 16 битови изображения RGB за полуканал
+Comment[ca]=Model de color per a paleta 'mitja' de 16 bits-canal d'imatges RGB
+Comment[da]=Farvemodel for 16-bit decimaltal 'halvdel' pr kanal RGB-billeder
+Comment[de]=Farbmodell für 16-bit Fließkomma 'Halb' pro Kanal RGB-Bilder
+Comment[el]=Χρωματικό μοντέλο για 16-bit μισούς δεκαδικούς ανά κανάλι RGB εικόνες
+Comment[en_GB]=Colour model for 16-bit floating point 'half' per channel RGB images
+Comment[es]=Modelo de color decimal «medio» de 16 bits por canal para imágenes RGB
+Comment[et]=16-bitiste murdarvuliste ('half') kanalitega RGB-piltide värvimudel
+Comment[fa]=مدل رنگ برای ممیز »نیمه« شناور برای هر تصویر RGB مجرا
+Comment[fi]=Värimalli 16-bittisille/kanavaisille RGB-kuville
+Comment[fr]=Modèle de couleurs pour des images RVB en 16 bits flottants (demi) par canal
+Comment[fy]=Kleurmodel foar RGB-ôfbeeldings mei 16-bit driuwende komma 'heal' de kanaal
+Comment[gl]=Espazo de cores para imaxes RGB de 16-bit de vírgula flutuante 'half' por canal
+Comment[he]=מודל צבעים עבור תמונות RGB של 16 סיביות/ערוצים
+Comment[hu]=Színmodell 16 bit (lebegőpontos, 'feles')/csatorna RGB képekhez
+Comment[is]=Litategund fyrir 16-bita fleytitölu á rás RGB myndir
+Comment[it]=Modello di colore per immagini RGB in semi-virgola mobile a canale di 16 bit
+Comment[km]=ម៉ូលដែល​ពណ៌​ 16 ប៊ីត​ចំណុច​ដែល​អណ្ដែត​ 'ពាក្យ​កណ្ដាល' ក្នុង​ឆានែល​រូបភាព​ RGB
+Comment[nb]=Fargemodell for RGB-bilde med 16 bit flyttall 'halv' per kanal
+Comment[nds]=Klöörmodell för RGB-Biller mit 16-Bit Fleetkomma "half" per Kanaal
+Comment[ne]='आधा' प्रति च्यानल RGB छविहरूको १६-बिट उत्प्लावन बिन्दुका लागि रङ मोडेल
+Comment[nl]=Kleurmodel voor RGB-afbeeldingen met 16-bit drijvende komma 'half' per kanaal
+Comment[pl]=Przestrzeń barw dla obrazków RGB z "połową" 16-bitowej liczby zmiennoprzecinkowej na kanał
+Comment[pt]=Modelo de cor para imagens RGB com 16 bits de vírgula flutuante 'half' por canal
+Comment[pt_BR]=Modelo de cor para imagens RGB com 16 bits de ponto flutuante 'half' por canal
+Comment[ru]=Цветовое пространство RGB (16-бит/канал с плавающей точкой)
+Comment[sk]=Model farieb pre RGB obrázky so 16-bitovými reálnymi číslami 'half' na kanál
+Comment[sl]=Barvni model za slike RGB s 16-bitno plavajočo vejico na kanal
+Comment[sr]=Модел боја за RGB слике, 16-битно реално „полу“ по каналу
+Comment[sr@Latn]=Model boja za RGB slike, 16-bitno realno „polu“ po kanalu
+Comment[sv]=Färgmodell för 16-bitars flyttal 'halva' per kanal RGB-bilder
+Comment[uk]=Модель кольорів для 16-бітних зображень RGB, з плаваючою комою, "половина" на канал
+Comment[zh_TW]=每色頻 16-bit 半浮點 RGB 圖片的色彩模型
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-KDE-Library=krita_rgb_f16half_plugin
+X-Krita-Version=2
diff --git a/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.cc b/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.cc
new file mode 100644
index 00000000..0674cde7
--- /dev/null
+++ b/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.cc
@@ -0,0 +1,63 @@
+/*
+* rgb_f32_plugin.cc -- Part of Krita
+*
+* Copyright (c) 2004 Boudewijn Rempt ([email protected])
+* Copyright (c) 2005 Adrian Page <[email protected]>
+*
+* 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 <kinstance.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <kis_debug_areas.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_basic_histogram_producers.h>
+
+#include "rgb_f16half_plugin.h"
+#include "kis_rgb_f16half_colorspace.h"
+
+typedef KGenericFactory<RGBF16HalfPlugin> RGBF16HalfPluginFactory;
+K_EXPORT_COMPONENT_FACTORY( krita_rgb_f16half_plugin, RGBF16HalfPluginFactory( "krita" ) )
+
+
+RGBF16HalfPlugin::RGBF16HalfPlugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(RGBF16HalfPluginFactory::instance());
+
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") )
+ {
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry*>( parent );
+
+ KisColorSpace * colorSpaceRGBF16Half = new KisRgbF16HalfColorSpace(f, 0);
+ KisColorSpaceFactory *csf = new KisRgbF16HalfColorSpaceFactory();
+ Q_CHECK_PTR(colorSpaceRGBF16Half);
+ f->add(csf);
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicF16HalfHistogramProducer>
+ (KisID("RGBF16HALFHISTO", i18n("Float16 Half")), colorSpaceRGBF16Half) );
+ }
+
+}
+
+RGBF16HalfPlugin::~RGBF16HalfPlugin()
+{
+}
+
+#include "rgb_f16half_plugin.moc"
+
diff --git a/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.h b/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.h
new file mode 100644
index 00000000..00c361a1
--- /dev/null
+++ b/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2003 Boudewijn Rempt ([email protected])
+ *
+ * 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 RGB_F16HALF_PLUGIN_H_
+#define RGB_F16HALF_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the RGB F16Half colour space strategy.
+ */
+class RGBF16HalfPlugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ RGBF16HalfPlugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~RGBF16HalfPlugin();
+
+};
+
+
+#endif // RGB_F16HALF_PLUGIN_H_
diff --git a/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.rc b/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.rc
new file mode 100644
index 00000000..0155b2c5
--- /dev/null
+++ b/krita/colorspaces/rgb_f16half/rgb_f16half_plugin.rc
@@ -0,0 +1,9 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui library="krita_rgb_f16half_plugin" version="1">
+<Menu name="Image"><text>&amp;Image</text>
+ <Menu name="Mode"><text>&amp;Mode</text>
+ <Action name="convert to RGB(A) (16-bit float 'half')"/>
+ </Menu>
+</Menu>
+
+</kpartgui>
diff --git a/krita/colorspaces/rgb_f16half/tests/Makefile.am b/krita/colorspaces/rgb_f16half/tests/Makefile.am
new file mode 100644
index 00000000..4b8ff499
--- /dev/null
+++ b/krita/colorspaces/rgb_f16half/tests/Makefile.am
@@ -0,0 +1,19 @@
+AM_CPPFLAGS = -I$(srcdir)/.. \
+ -I$(srcdir)/../../../sdk \
+ -I$(srcdir)/../../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../../color_strategy/ \
+ -I$(srcdir)/../../../modules/rgb_f32 \
+ $(OPENEXR_CFLAGS) \
+ $(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_rgb_f16half_colorspace_tester.la
+
+kunittest_kis_rgb_f16half_colorspace_tester_la_SOURCES = kis_rgb_f16half_colorspace_tester.cc
+kunittest_kis_rgb_f16half_colorspace_tester_la_LIBADD = -lkunittest ../libkrita_rgb_f16half.la
+kunittest_kis_rgb_f16half_colorspace_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
+
+check-local: kunittest_kis_rgb_f16half_colorspace_tester.la
+ kunittestmodrunner
+
diff --git a/krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.cc b/krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.cc
new file mode 100644
index 00000000..20f417d9
--- /dev/null
+++ b/krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.cc
@@ -0,0 +1,545 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_factory.h"
+#include "kis_rgb_f16half_colorspace.h"
+#include "kis_rgb_f16half_colorspace_tester.h"
+#include "kis_rgb_f32_colorspace.h"
+#include "kis_integer_maths.h"
+#include "kis_paint_device.h"
+
+using namespace KUnitTest;
+
+KUNITTEST_MODULE( kunittest_kis_rgb_f16half_colorspace_tester, "RGBA 16-bit float half colorspace tester" );
+KUNITTEST_MODULE_REGISTER_TESTER( KisRgbF16HalfColorSpaceTester );
+
+#define PIXEL_BLUE 0
+#define PIXEL_GREEN 1
+#define PIXEL_RED 2
+#define PIXEL_ALPHA 3
+
+#define NUM_CHANNELS 4
+#define NUM_COLOUR_CHANNELS 3
+#define CHANNEL_SIZE ((int)sizeof(half))
+
+#define RED_CHANNEL 0
+#define GREEN_CHANNEL 1
+#define BLUE_CHANNEL 2
+#define ALPHA_CHANNEL 3
+
+//#define MAX_CHANNEL_VALUE 1.0f
+//#define MIN_CHANNEL_VALUE 0.0f
+
+#define CHANNEL_VALUE_ZERO ((half)0)
+#define CHANNEL_VALUE_ONE ((half)1)
+
+void KisRgbF16HalfColorSpaceTester::allTests()
+{
+ // We need this so that the colour profile loading can operate without crashing.
+ KisFactory *factory = new KisFactory();
+
+ testBasics();
+ testToQImage();
+ testCompositeOps();
+ testMixColors();
+
+ delete factory;
+}
+
+void KisRgbF16HalfColorSpaceTester::testBasics()
+{
+
+
+ KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile());
+
+ KisRgbF16HalfColorSpace *cs = new KisRgbF16HalfColorSpace(profile);
+ KisAbstractColorSpace * csSP = cs;
+
+ CHECK(cs->hasAlpha(), true);
+ CHECK(cs->nChannels(), NUM_CHANNELS);
+ CHECK(cs->nColorChannels(), NUM_COLOUR_CHANNELS);
+ CHECK(cs->pixelSize(), NUM_CHANNELS * CHANNEL_SIZE);
+
+ QValueVector<KisChannelInfo *> channels = cs->channels();
+
+ // Red
+ CHECK(channels[0]->pos(), PIXEL_RED * CHANNEL_SIZE);
+ CHECK(channels[0]->size(), CHANNEL_SIZE);
+ CHECK(channels[0]->channelType(), COLOR);
+
+ // Green
+ CHECK(channels[1]->pos(), PIXEL_GREEN * CHANNEL_SIZE);
+ CHECK(channels[1]->size(), CHANNEL_SIZE);
+ CHECK(channels[1]->channelType(), COLOR);
+
+ // Blue
+ CHECK(channels[2]->pos(), PIXEL_BLUE * CHANNEL_SIZE);
+ CHECK(channels[2]->size(), CHANNEL_SIZE);
+ CHECK(channels[2]->channelType(), COLOR);
+
+ // Alpha
+ CHECK(channels[3]->pos(), PIXEL_ALPHA * CHANNEL_SIZE);
+ CHECK(channels[3]->size(), CHANNEL_SIZE);
+ CHECK(channels[3]->channelType(), ALPHA);
+
+ KisPaintDeviceSP pd = new KisPaintDevice(cs, "test");
+
+ KisRgbF16HalfColorSpace::Pixel defaultPixel;
+
+ memcpy(&defaultPixel, pd->dataManager()->defaultPixel(), sizeof(defaultPixel));
+
+ CHECK(defaultPixel.red, CHANNEL_VALUE_ZERO);
+ CHECK(defaultPixel.green, CHANNEL_VALUE_ZERO);
+ CHECK(defaultPixel.blue, CHANNEL_VALUE_ZERO);
+ CHECK(defaultPixel.alpha, F16HALF_OPACITY_TRANSPARENT);
+
+ half pixel[NUM_CHANNELS];
+
+ cs->fromQColor(qRgb(255, 255, 255), reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], CHANNEL_VALUE_ONE);
+ CHECK(pixel[PIXEL_GREEN], CHANNEL_VALUE_ONE);
+ CHECK(pixel[PIXEL_BLUE], CHANNEL_VALUE_ONE);
+
+ cs->fromQColor(qRgb(0, 0, 0), reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], CHANNEL_VALUE_ZERO);
+ CHECK(pixel[PIXEL_GREEN], CHANNEL_VALUE_ZERO);
+ CHECK(pixel[PIXEL_BLUE], CHANNEL_VALUE_ZERO);
+
+ cs->fromQColor(qRgb(128, 64, 192), reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], UINT8_TO_HALF(128));
+ CHECK(pixel[PIXEL_GREEN], UINT8_TO_HALF(64));
+ CHECK(pixel[PIXEL_BLUE], UINT8_TO_HALF(192));
+
+ cs->fromQColor(qRgb(255, 255, 255), OPACITY_OPAQUE, reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], CHANNEL_VALUE_ONE);
+ CHECK(pixel[PIXEL_GREEN], CHANNEL_VALUE_ONE);
+ CHECK(pixel[PIXEL_BLUE], CHANNEL_VALUE_ONE);
+ CHECK(pixel[PIXEL_ALPHA], CHANNEL_VALUE_ONE);
+
+ cs->fromQColor(qRgb(255, 255, 255), OPACITY_TRANSPARENT, reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], CHANNEL_VALUE_ONE);
+ CHECK(pixel[PIXEL_GREEN], CHANNEL_VALUE_ONE);
+ CHECK(pixel[PIXEL_BLUE], CHANNEL_VALUE_ONE);
+ CHECK(pixel[PIXEL_ALPHA], F16HALF_OPACITY_TRANSPARENT);
+
+ cs->fromQColor(qRgb(255, 255, 255), OPACITY_OPAQUE / 2, reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], CHANNEL_VALUE_ONE);
+ CHECK(pixel[PIXEL_GREEN], CHANNEL_VALUE_ONE);
+ CHECK(pixel[PIXEL_BLUE], CHANNEL_VALUE_ONE);
+ CHECK(pixel[PIXEL_ALPHA], UINT8_TO_HALF(OPACITY_OPAQUE / 2));
+
+ pixel[PIXEL_RED] = CHANNEL_VALUE_ONE;
+ pixel[PIXEL_GREEN] = CHANNEL_VALUE_ONE;
+ pixel[PIXEL_BLUE] = CHANNEL_VALUE_ONE;
+
+ QColor c;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c);
+
+ CHECK(c.red(), 255);
+ CHECK(c.green(), 255);
+ CHECK(c.blue(), 255);
+
+ pixel[PIXEL_RED] = CHANNEL_VALUE_ZERO;
+ pixel[PIXEL_GREEN] = CHANNEL_VALUE_ZERO;
+ pixel[PIXEL_BLUE] = CHANNEL_VALUE_ZERO;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c);
+
+ CHECK(c.red(), 0);
+ CHECK(c.green(), 0);
+ CHECK(c.blue(), 0);
+
+ pixel[PIXEL_RED] = CHANNEL_VALUE_ONE / 4;
+ pixel[PIXEL_GREEN] = CHANNEL_VALUE_ONE / 2;
+ pixel[PIXEL_BLUE] = (3 * CHANNEL_VALUE_ONE) / 4;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c);
+
+ CHECK(c.red(), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 4));
+ CHECK(c.green(), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2));
+ CHECK(c.blue(), (int)HALF_TO_UINT8((3 * CHANNEL_VALUE_ONE) / 4));
+
+ pixel[PIXEL_RED] = CHANNEL_VALUE_ONE;
+ pixel[PIXEL_GREEN] = CHANNEL_VALUE_ONE;
+ pixel[PIXEL_BLUE] = CHANNEL_VALUE_ONE;
+ pixel[PIXEL_ALPHA] = CHANNEL_VALUE_ONE;
+
+ Q_UINT8 opacity;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), 255);
+ CHECK(c.green(), 255);
+ CHECK(c.blue(), 255);
+ CHECK(opacity, OPACITY_OPAQUE);
+
+ pixel[PIXEL_ALPHA] = F16HALF_OPACITY_OPAQUE;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), 255);
+ CHECK(c.green(), 255);
+ CHECK(c.blue(), 255);
+ CHECK(opacity, OPACITY_OPAQUE);
+
+ pixel[PIXEL_RED] = CHANNEL_VALUE_ZERO;
+ pixel[PIXEL_GREEN] = CHANNEL_VALUE_ZERO;
+ pixel[PIXEL_BLUE] = CHANNEL_VALUE_ZERO;
+ pixel[PIXEL_ALPHA] = F16HALF_OPACITY_TRANSPARENT;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), 0);
+ CHECK(c.green(), 0);
+ CHECK(c.blue(), 0);
+ CHECK(opacity, OPACITY_TRANSPARENT);
+
+ pixel[PIXEL_RED] = CHANNEL_VALUE_ONE / 4;
+ pixel[PIXEL_GREEN] = CHANNEL_VALUE_ONE / 2;
+ pixel[PIXEL_BLUE] = (3 * CHANNEL_VALUE_ONE) / 4;
+ pixel[PIXEL_ALPHA] = CHANNEL_VALUE_ONE / 2;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 4));
+ CHECK(c.green(), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2));
+ CHECK(c.blue(), (int)HALF_TO_UINT8((3 * CHANNEL_VALUE_ONE) / 4));
+ CHECK((int)opacity, (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2));
+
+ #define NUM_PIXELS 4
+
+ KisRgbF16HalfColorSpace::Pixel pixels[NUM_PIXELS] = {
+ {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE / 4},
+ {CHANNEL_VALUE_ONE / 4, CHANNEL_VALUE_ONE / 2, CHANNEL_VALUE_ONE / 3, CHANNEL_VALUE_ONE / 2},
+ {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ZERO},
+ {CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ONE}
+ };
+
+ cs->setAlpha(reinterpret_cast<Q_UINT8 *>(pixels), OPACITY_OPAQUE / 2, NUM_PIXELS);
+
+ CHECK(pixels[0].red, CHANNEL_VALUE_ONE);
+ CHECK(pixels[0].green, CHANNEL_VALUE_ONE);
+ CHECK(pixels[0].blue, CHANNEL_VALUE_ONE);
+ CHECK(pixels[0].alpha, UINT8_TO_HALF(OPACITY_OPAQUE / 2));
+
+ CHECK(pixels[1].red, (half)(CHANNEL_VALUE_ONE / 3));
+ CHECK(pixels[1].green, (half)(CHANNEL_VALUE_ONE / 2));
+ CHECK(pixels[1].blue, (half)(CHANNEL_VALUE_ONE / 4));
+ CHECK(pixels[1].alpha, UINT8_TO_HALF(OPACITY_OPAQUE / 2));
+
+ CHECK(pixels[2].red, CHANNEL_VALUE_ONE);
+ CHECK(pixels[2].green, CHANNEL_VALUE_ONE);
+ CHECK(pixels[2].blue, CHANNEL_VALUE_ONE);
+ CHECK(pixels[2].alpha, UINT8_TO_HALF(OPACITY_OPAQUE / 2));
+
+ CHECK(pixels[3].red, CHANNEL_VALUE_ZERO);
+ CHECK(pixels[3].green, CHANNEL_VALUE_ZERO);
+ CHECK(pixels[3].blue, CHANNEL_VALUE_ZERO);
+ CHECK(pixels[3].alpha, UINT8_TO_HALF(OPACITY_OPAQUE / 2));
+
+ pixel[PIXEL_RED] = CHANNEL_VALUE_ONE;
+ pixel[PIXEL_GREEN] = CHANNEL_VALUE_ONE / 2;
+ pixel[PIXEL_BLUE] = CHANNEL_VALUE_ONE / 4;
+ pixel[PIXEL_ALPHA] = CHANNEL_VALUE_ZERO;
+
+ QString valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), RED_CHANNEL);
+ CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE));
+
+ valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), GREEN_CHANNEL);
+ CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE / 2));
+
+ valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), BLUE_CHANNEL);
+ CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE / 4));
+
+ valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), ALPHA_CHANNEL);
+ CHECK(valueText, QString().setNum(CHANNEL_VALUE_ZERO));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), RED_CHANNEL);
+ CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), GREEN_CHANNEL);
+ CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE / 2));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), BLUE_CHANNEL);
+ CHECK(valueText, QString().setNum(CHANNEL_VALUE_ONE / 4));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), ALPHA_CHANNEL);
+ CHECK(valueText, QString().setNum(CHANNEL_VALUE_ZERO));
+
+ cs->setPixel(reinterpret_cast<Q_UINT8 *>(pixel), 0.128, 0.192, 0.64, 0.99);
+ CHECK(pixel[PIXEL_RED], (half)0.128f);
+ CHECK(pixel[PIXEL_GREEN], (half)0.192f);
+ CHECK(pixel[PIXEL_BLUE], (half)0.64f);
+ CHECK(pixel[PIXEL_ALPHA], (half)0.99f);
+
+ half red;
+ half green;
+ half blue;
+ half alpha;
+
+ cs->getPixel(reinterpret_cast<const Q_UINT8 *>(pixel), &red, &green, &blue, &alpha);
+ CHECK(red, (half)0.128f);
+ CHECK(green, (half)0.192f);
+ CHECK(blue, (half)0.64f);
+ CHECK(alpha, (half)0.99f);
+
+ CHECK(HALF_TO_UINT8(-0.5), 0u);
+ CHECK(HALF_TO_UINT8(0), 0u);
+ CHECK_TOLERANCE(HALF_TO_UINT8(0.5), UINT8_MAX / 2, 1u);
+ CHECK(HALF_TO_UINT8(1), UINT8_MAX);
+ CHECK(HALF_TO_UINT8(1.5), UINT8_MAX);
+
+ CHECK(HALF_TO_UINT16(-0.5), 0u);
+ CHECK(HALF_TO_UINT16(0), 0u);
+ CHECK_TOLERANCE(HALF_TO_UINT16(0.5), UINT16_MAX / 2, 1u);
+ CHECK(HALF_TO_UINT16(1), UINT16_MAX);
+ CHECK(HALF_TO_UINT16(1.5), UINT16_MAX);
+}
+
+void KisRgbF16HalfColorSpaceTester::testMixColors()
+{
+ KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile());
+ KisAbstractColorSpace * cs = new KisRgbF16HalfColorSpace(profile);
+
+ // Test mixColors.
+ half pixel1[NUM_CHANNELS];
+ half pixel2[NUM_CHANNELS];
+ half outputPixel[NUM_CHANNELS];
+
+ outputPixel[PIXEL_RED] = 0;
+ outputPixel[PIXEL_GREEN] = 0;
+ outputPixel[PIXEL_BLUE] = 0;
+ outputPixel[PIXEL_ALPHA] = 0;
+
+ pixel1[PIXEL_RED] = CHANNEL_VALUE_ONE;
+ pixel1[PIXEL_GREEN] = CHANNEL_VALUE_ONE;
+ pixel1[PIXEL_BLUE] = CHANNEL_VALUE_ONE;
+ pixel1[PIXEL_ALPHA] = CHANNEL_VALUE_ONE;
+
+ pixel2[PIXEL_RED] = 0;
+ pixel2[PIXEL_GREEN] = 0;
+ pixel2[PIXEL_BLUE] = 0;
+ pixel2[PIXEL_ALPHA] = 0;
+
+ const Q_UINT8 *pixelPtrs[2];
+ Q_UINT8 weights[2];
+
+ pixelPtrs[0] = reinterpret_cast<const Q_UINT8 *>(pixel1);
+ pixelPtrs[1] = reinterpret_cast<const Q_UINT8 *>(pixel2);
+
+ weights[0] = 255;
+ weights[1] = 0;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK(outputPixel[PIXEL_RED], CHANNEL_VALUE_ONE);
+ CHECK(outputPixel[PIXEL_GREEN], CHANNEL_VALUE_ONE);
+ CHECK(outputPixel[PIXEL_BLUE], CHANNEL_VALUE_ONE);
+ CHECK(outputPixel[PIXEL_ALPHA], CHANNEL_VALUE_ONE);
+
+ weights[0] = 0;
+ weights[1] = 255;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK(outputPixel[PIXEL_RED], (half)0.0f);
+ CHECK(outputPixel[PIXEL_GREEN], (half)0.0f);
+ CHECK(outputPixel[PIXEL_BLUE], (half)0.0f);
+ CHECK(outputPixel[PIXEL_ALPHA], (half)0.0f);
+
+ weights[0] = 128;
+ weights[1] = 127;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK(outputPixel[PIXEL_RED], CHANNEL_VALUE_ONE);
+ CHECK(outputPixel[PIXEL_GREEN], CHANNEL_VALUE_ONE);
+ CHECK(outputPixel[PIXEL_BLUE], CHANNEL_VALUE_ONE);
+ CHECK(outputPixel[PIXEL_ALPHA], (half)((128 * CHANNEL_VALUE_ONE) / 255));
+
+ pixel1[PIXEL_RED] = 20000;
+ pixel1[PIXEL_GREEN] = 10000;
+ pixel1[PIXEL_BLUE] = 5000;
+ pixel1[PIXEL_ALPHA] = CHANNEL_VALUE_ONE;
+
+ pixel2[PIXEL_RED] = 10000;
+ pixel2[PIXEL_GREEN] = 20000;
+ pixel2[PIXEL_BLUE] = 2000;
+ pixel2[PIXEL_ALPHA] = CHANNEL_VALUE_ONE;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK_TOLERANCE(outputPixel[PIXEL_RED], (128 * 20000 + 127 * 10000) / 255, 5);
+ CHECK_TOLERANCE(outputPixel[PIXEL_GREEN], (128 * 10000 + 127 * 20000) / 255, 5);
+ CHECK_TOLERANCE(outputPixel[PIXEL_BLUE], (128 * 5000 + 127 * 2000) / 255, 5);
+ CHECK(outputPixel[PIXEL_ALPHA], CHANNEL_VALUE_ONE);
+
+ pixel1[PIXEL_RED] = 0;
+ pixel1[PIXEL_GREEN] = 0;
+ pixel1[PIXEL_BLUE] = 0;
+ pixel1[PIXEL_ALPHA] = 0;
+
+ pixel2[PIXEL_RED] = CHANNEL_VALUE_ONE;
+ pixel2[PIXEL_GREEN] = CHANNEL_VALUE_ONE;
+ pixel2[PIXEL_BLUE] = CHANNEL_VALUE_ONE;
+ pixel2[PIXEL_ALPHA] = CHANNEL_VALUE_ONE;
+
+ weights[0] = 89;
+ weights[1] = 166;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK(outputPixel[PIXEL_RED], CHANNEL_VALUE_ONE);
+ CHECK(outputPixel[PIXEL_GREEN], CHANNEL_VALUE_ONE);
+ CHECK(outputPixel[PIXEL_BLUE], CHANNEL_VALUE_ONE);
+ CHECK_TOLERANCE(outputPixel[PIXEL_ALPHA], (89 * 0 + 166 * CHANNEL_VALUE_ONE) / 255, 5);
+}
+
+#define PIXELS_WIDTH 2
+#define PIXELS_HEIGHT 2
+
+void KisRgbF16HalfColorSpaceTester::testToQImage()
+{
+ KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile());
+
+ KisAbstractColorSpace * cs = new KisRgbF16HalfColorSpace(profile);
+
+ KisRgbF16HalfColorSpace::Pixel pixels[PIXELS_WIDTH * PIXELS_HEIGHT] = {
+ {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE / 4},
+ {CHANNEL_VALUE_ONE / 4, CHANNEL_VALUE_ONE / 2, CHANNEL_VALUE_ONE / 3, CHANNEL_VALUE_ONE / 2},
+ {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ZERO},
+ {CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ONE}
+ };
+
+ QImage image = cs->convertToQImage(reinterpret_cast<const Q_UINT8 *>(pixels), PIXELS_WIDTH, PIXELS_HEIGHT, 0, 0);
+
+ QRgb c = image.pixel(0, 0);
+
+ // Exposure comes into play here.
+ /*
+ CHECK(qRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE));
+ CHECK(qGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE));
+ CHECK(qBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE));
+ CHECK(qAlpha(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 4));
+
+ c = image.pixel(1, 0);
+
+ CHECK(qRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 3));
+ CHECK(qGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2));
+ CHECK(qBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 4));
+ CHECK(qAlpha(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE / 2));
+
+ c = image.pixel(0, 1);
+
+ CHECK(qRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE));
+ CHECK(qGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE));
+ CHECK(qBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE));
+ CHECK(qAlpha(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO));
+
+ c = image.pixel(1, 1);
+
+ CHECK(qRed(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO));
+ CHECK(qGreen(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO));
+ CHECK(qBlue(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ZERO));
+ CHECK(qAlpha(c), (int)HALF_TO_UINT8(CHANNEL_VALUE_ONE));
+ */
+}
+
+#define NUM_ROWS 2
+#define NUM_COLUMNS 2
+#define SRC_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE)
+#define DST_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE)
+#define MASK_ROW_STRIDE NUM_COLUMNS
+
+/*
+1 alpha 1 0 alpha 1
+1 alpha 0.5 0 alpha 1
+1 alpha 0.5 0 alpha 0.5
+1 alpha 0 0 alpha 0.5
+
+*/
+
+void KisRgbF16HalfColorSpaceTester::testCompositeOps()
+{
+ KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile());
+
+ KisRgbF16HalfColorSpace *cs = new KisRgbF16HalfColorSpace(profile);
+
+ KisRgbF16HalfColorSpace::Pixel srcPixel;
+ KisRgbF16HalfColorSpace::Pixel dstPixel;
+
+ srcPixel.red = UINT8_TO_HALF(102);
+ srcPixel.green = UINT8_TO_HALF(170);
+ srcPixel.blue = UINT8_TO_HALF(238);
+ srcPixel.alpha = F16HALF_OPACITY_OPAQUE;
+
+ dstPixel = srcPixel;
+
+ cs->compositeDivide(reinterpret_cast<Q_UINT8 *>(&dstPixel), 1, reinterpret_cast<const Q_UINT8 *>(&srcPixel),
+ 1, 0, 0, 1, 1, F16HALF_OPACITY_OPAQUE);
+ /*
+ CHECK(dstPixel.red, (Q_UINT16)UINT8_TO_UINT16(253));
+ CHECK(dstPixel.green, (Q_UINT16)UINT8_TO_UINT16(254));
+ CHECK(dstPixel.blue, (Q_UINT16)UINT8_TO_UINT16(254));
+ CHECK(dstPixel.alpha, KisRgbF16HalfColorSpace::F16HALF_OPACITY_OPAQUE);
+
+ Q_UINT16 srcColor = 43690;
+ Q_UINT16 dstColor = 43690;
+
+ srcColor = QMIN((dstColor * (65535u + 1u) + (srcColor / 2u)) / (1u + srcColor), 65535u);
+
+ CHECK((int)srcColor, 65534);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, 65535u);
+
+ CHECK((int)newColor, 65534);
+ */
+
+ /*
+ KisRgbF16HalfColorSpace::Pixel srcPixels[NUM_ROWS * NUM_COLUMNS] = {
+ {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE / 4},
+ {CHANNEL_VALUE_ONE / 4, CHANNEL_VALUE_ONE / 2, CHANNEL_VALUE_ONE / 3, CHANNEL_VALUE_ONE / 2},
+ {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ZERO},
+ {CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ONE}
+ };
+
+ KisRgbF16HalfColorSpace::Pixel dstPixels[NUM_ROWS * NUM_COLUMNS] = {
+ {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE / 4},
+ {CHANNEL_VALUE_ONE / 4, CHANNEL_VALUE_ONE / 2, CHANNEL_VALUE_ONE / 3, CHANNEL_VALUE_ONE / 2},
+ {CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ONE, CHANNEL_VALUE_ZERO},
+ {CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ZERO, CHANNEL_VALUE_ONE}
+ };
+
+ cs->compositeOver(reinterpret_cast<Q_UINT8 *>(dstPixels), DST_ROW_STRIDE, reinterpret_cast<const Q_UINT8 *>(srcPixels),
+ SRC_ROW_STRIDE, mask, MASK_ROW_STRIDE, NUM_ROWS, NUM_COLUMNS, opacity);
+ */
+
+ delete cs;
+}
+
diff --git a/krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.h b/krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.h
new file mode 100644
index 00000000..db740fa4
--- /dev/null
+++ b/krita/colorspaces/rgb_f16half/tests/kis_rgb_f16half_colorspace_tester.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_RGB_F16HALF_COLORSPACE_TESTER_H
+#define KIS_RGB_F16HALF_COLORSPACE_TESTER_H
+
+#include <kunittest/tester.h>
+
+#define CHECK_TOLERANCE( x, y, tolerance ) \
+if ((x) <= (y) + (tolerance) && (x) >= (y) - (tolerance)) \
+{ \
+ success(QString(__FILE__) + "[" + QString::number(__LINE__) + "]: passed " + #x); \
+} \
+else \
+{ \
+ failure(QString(__FILE__) + "[" + QString::number(__LINE__) + QString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + QString::number(x)); \
+} \
+
+class KisRgbF16HalfColorSpaceTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+ void testBasics();
+ void testMixColors();
+ void testToQImage();
+ void testCompositeOps();
+};
+
+#endif
+
diff --git a/krita/colorspaces/rgb_f32/Makefile.am b/krita/colorspaces/rgb_f32/Makefile.am
new file mode 100644
index 00000000..07c65b00
--- /dev/null
+++ b/krita/colorspaces/rgb_f32/Makefile.am
@@ -0,0 +1,34 @@
+# Install the desktop file needed to detect the plugin
+kde_services_DATA = krita_rgb_f32_plugin.desktop
+
+INCLUDES = \
+ -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../kritacolor/ \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+
+lib_LTLIBRARIES = libkrita_rgb_f32.la
+libkrita_rgb_f32_la_SOURCES = kis_rgb_f32_colorspace.cc
+libkrita_rgb_f32_la_LDFLAGS = $(all_libraries)
+libkrita_rgb_f32_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = krita_rgb_f32_plugin.la
+
+# Srcs for the plugin
+krita_rgb_f32_plugin_la_SOURCES = rgb_f32_plugin.cc
+noinst_HEADERS = rgb_f32_plugin.h kis_rgb_f32_colorspace.h
+
+krita_rgb_f32_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+krita_rgb_f32_plugin_la_LIBADD = libkrita_rgb_f32.la ../../kritacolor/libkritacolor.la
+
+krita_rgb_f32_plugin_la_METASOURCES = AUTO
+
+if include_kunittest_tests
+TESTSDIR = tests
+endif
+
+SUBDIRS = . $(TESTSDIR)
+
diff --git a/krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc b/krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc
new file mode 100644
index 00000000..7db6bd9e
--- /dev/null
+++ b/krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.cc
@@ -0,0 +1,949 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <[email protected]>
+ * Copyright (c) 2004 Boudewijn Rempt <[email protected]>
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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 <qimage.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "kis_rgb_f32_colorspace.h"
+#include "kis_color_conversions.h"
+
+namespace {
+ const Q_INT32 MAX_CHANNEL_RGB = 3;
+ const Q_INT32 MAX_CHANNEL_RGBA = 4;
+}
+
+#include "kis_integer_maths.h"
+
+#ifndef HAVE_POWF
+#undef powf
+#define powf pow
+#endif
+
+#define FLOAT_MAX 1.0f //temp
+
+#define EPSILON 1e-6
+
+// FIXME: lcms doesn't support 32-bit float
+#define F32_LCMS_TYPE TYPE_BGRA_16
+
+// disable the lcms handling by setting profile=0
+KisRgbF32ColorSpace::KisRgbF32ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile */*p*/) :
+ KisF32BaseColorSpace(KisID("RGBAF32", i18n("RGB (32-bit float/channel)")), F32_LCMS_TYPE, icSigRgbData, parent, 0)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Red"), i18n("R"), PIXEL_RED * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float)));
+ m_channels.push_back(new KisChannelInfo(i18n("Green"), i18n("G"), PIXEL_GREEN * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float)));
+ m_channels.push_back(new KisChannelInfo(i18n("Blue"), i18n("B"), PIXEL_BLUE * sizeof(float), KisChannelInfo::COLOR, KisChannelInfo::FLOAT32, sizeof(float)));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(float), KisChannelInfo::ALPHA, KisChannelInfo::FLOAT32, sizeof(float)));
+
+ m_alphaPos = PIXEL_ALPHA * sizeof(float);
+}
+
+KisRgbF32ColorSpace::~KisRgbF32ColorSpace()
+{
+}
+
+void KisRgbF32ColorSpace::setPixel(Q_UINT8 *dst, float red, float green, float blue, float alpha) const
+{
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->red = red;
+ dstPixel->green = green;
+ dstPixel->blue = blue;
+ dstPixel->alpha = alpha;
+}
+
+void KisRgbF32ColorSpace::getPixel(const Q_UINT8 *src, float *red, float *green, float *blue, float *alpha) const
+{
+ const Pixel *srcPixel = reinterpret_cast<const Pixel *>(src);
+
+ *red = srcPixel->red;
+ *green = srcPixel->green;
+ *blue = srcPixel->blue;
+ *alpha = srcPixel->alpha;
+}
+
+void KisRgbF32ColorSpace::fromQColor(const QColor& c, Q_UINT8 *dstU8, KisProfile * /*profile*/)
+{
+ Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
+
+ dst->red = UINT8_TO_FLOAT(c.red());
+ dst->green = UINT8_TO_FLOAT(c.green());
+ dst->blue = UINT8_TO_FLOAT(c.blue());
+}
+
+void KisRgbF32ColorSpace::fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dstU8, KisProfile * /*profile*/)
+{
+ Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
+
+ dst->red = UINT8_TO_FLOAT(c.red());
+ dst->green = UINT8_TO_FLOAT(c.green());
+ dst->blue = UINT8_TO_FLOAT(c.blue());
+ dst->alpha = UINT8_TO_FLOAT(opacity);
+}
+
+void KisRgbF32ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, KisProfile * /*profile*/)
+{
+ const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
+
+ c->setRgb(FLOAT_TO_UINT8(src->red), FLOAT_TO_UINT8(src->green), FLOAT_TO_UINT8(src->blue));
+}
+
+void KisRgbF32ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_UINT8 *opacity, KisProfile * /*profile*/)
+{
+ const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
+
+ c->setRgb(FLOAT_TO_UINT8(src->red), FLOAT_TO_UINT8(src->green), FLOAT_TO_UINT8(src->blue));
+ *opacity = FLOAT_TO_UINT8(src->alpha);
+}
+
+Q_UINT8 KisRgbF32ColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8)
+{
+ const Pixel *src1 = reinterpret_cast<const Pixel *>(src1U8);
+ const Pixel *src2 = reinterpret_cast<const Pixel *>(src2U8);
+
+ return FLOAT_TO_UINT8(QMAX(QABS(src2->red - src1->red),
+ QMAX(QABS(src2->green - src1->green),
+ QABS(src2->blue - src1->blue))));
+}
+
+void KisRgbF32ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+ float totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel *pixel = reinterpret_cast<const Pixel *>(*colors);
+
+ float alpha = pixel->alpha;
+ float alphaTimesWeight = alpha * UINT8_TO_FLOAT(*weights);
+
+ totalRed += pixel->red * alphaTimesWeight;
+ totalGreen += pixel->green * alphaTimesWeight;
+ totalBlue += pixel->blue * alphaTimesWeight;
+ newAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ Q_ASSERT(newAlpha <= F32_OPACITY_OPAQUE);
+
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->alpha = newAlpha;
+
+ if (newAlpha > EPSILON) {
+ totalRed = totalRed / newAlpha;
+ totalGreen = totalGreen / newAlpha;
+ totalBlue = totalBlue / newAlpha;
+ }
+
+ dstPixel->red = totalRed;
+ dstPixel->green = totalGreen;
+ dstPixel->blue = totalBlue;
+}
+
+void KisRgbF32ColorSpace::convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const
+{
+ float totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel * pixel = reinterpret_cast<const Pixel *>( *colors );
+
+ float weight = *kernelValues;
+
+ if (weight != 0) {
+ totalRed += pixel->red * weight;
+ totalGreen += pixel->green * weight;
+ totalBlue += pixel->blue * weight;
+ totalAlpha += pixel->alpha * weight;
+ }
+ colors++;
+ kernelValues++;
+ }
+
+ Pixel * p = reinterpret_cast< Pixel *>( dst );
+
+ if (channelFlags & KisChannelInfo::FLAG_COLOR) {
+ p->red = CLAMP( ( totalRed / factor) + offset, 0, FLOAT_MAX);
+ p->green = CLAMP( ( totalGreen / factor) + offset, 0, FLOAT_MAX);
+ p->blue = CLAMP( ( totalBlue / factor) + offset, 0, FLOAT_MAX);
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, FLOAT_MAX);
+ }
+}
+
+
+void KisRgbF32ColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels)
+{
+ Q_UINT32 psize = pixelSize();
+
+ while (nPixels--)
+ {
+ Pixel * p = reinterpret_cast< Pixel *>( src );
+ p->red = FLOAT_MAX - p->red;
+ p->green = FLOAT_MAX - p->green;
+ p->blue = FLOAT_MAX - p->blue;
+ src += psize;
+ }
+
+}
+
+Q_UINT8 KisRgbF32ColorSpace::intensity8(const Q_UINT8 * src) const
+{
+ const Pixel * p = reinterpret_cast<const Pixel *>( src );
+
+ return FLOAT_TO_UINT8((p->red * 0.30 + p->green * 0.59 + p->blue * 0.11) + 0.5);
+}
+
+
+
+QValueVector<KisChannelInfo *> KisRgbF32ColorSpace::channels() const
+{
+ return m_channels;
+}
+
+Q_UINT32 KisRgbF32ColorSpace::nChannels() const
+{
+ return MAX_CHANNEL_RGBA;
+}
+
+Q_UINT32 KisRgbF32ColorSpace::nColorChannels() const
+{
+ return MAX_CHANNEL_RGB;
+}
+
+Q_UINT32 KisRgbF32ColorSpace::pixelSize() const
+{
+ return MAX_CHANNEL_RGBA * sizeof(float);
+}
+
+Q_UINT8 convertToDisplay(float value, float exposureFactor, float gamma)
+{
+ //value *= pow(2, exposure + 2.47393);
+ value *= exposureFactor;
+
+ value = powf(value, gamma);
+
+ // scale middle gray to the target framebuffer value
+
+ value *= 84.66f;
+
+ int valueInt = (int)(value + 0.5);
+
+ return CLAMP(valueInt, 0, 255);
+}
+
+QImage KisRgbF32ColorSpace::convertToQImage(const Q_UINT8 *dataU8, Q_INT32 width, Q_INT32 height,
+ KisProfile * /*dstProfile*/,
+ Q_INT32 /*renderingIntent*/, float exposure)
+
+{
+ const float *data = reinterpret_cast<const float *>(dataU8);
+
+ QImage img = QImage(width, height, 32, 0, QImage::LittleEndian);
+ img.setAlphaBuffer(true);
+
+ Q_INT32 i = 0;
+ uchar *j = img.bits();
+
+ // XXX: For now assume gamma 2.2.
+ float gamma = 1 / 2.2;
+ float exposureFactor = powf(2, exposure + 2.47393);
+
+ while ( i < width * height * MAX_CHANNEL_RGBA) {
+ *( j + 3) = FLOAT_TO_UINT8(*( data + i + PIXEL_ALPHA ));
+ *( j + 2 ) = convertToDisplay(*( data + i + PIXEL_RED ), exposureFactor, gamma);
+ *( j + 1 ) = convertToDisplay(*( data + i + PIXEL_GREEN ), exposureFactor, gamma);
+ *( j + 0 ) = convertToDisplay(*( data + i + PIXEL_BLUE ), exposureFactor, gamma);
+ i += MAX_CHANNEL_RGBA;
+ j += MAX_CHANNEL_RGBA;
+ }
+
+ /*
+ if (srcProfile != 0 && dstProfile != 0) {
+ convertPixelsTo(img.bits(), srcProfile,
+ img.bits(), this, dstProfile,
+ width * height, renderingIntent);
+ }
+ */
+ return img;
+}
+
+
+void KisRgbF32ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ while (rows > 0) {
+
+ const float *src = reinterpret_cast<const float *>(srcRowStart);
+ float *dst = reinterpret_cast<float *>(dstRowStart);
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ float srcAlpha = src[PIXEL_ALPHA];
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha *= UINT8_TO_FLOAT(U8_mask);
+ }
+ mask++;
+ }
+
+ if (srcAlpha > F32_OPACITY_TRANSPARENT + EPSILON) {
+
+ if (opacity < F32_OPACITY_OPAQUE - EPSILON) {
+ srcAlpha *= opacity;
+ }
+
+ if (srcAlpha > F32_OPACITY_OPAQUE - EPSILON) {
+ memcpy(dst, src, MAX_CHANNEL_RGBA * sizeof(float));
+ } else {
+ float dstAlpha = dst[PIXEL_ALPHA];
+
+ float srcBlend;
+
+ if (dstAlpha > F32_OPACITY_OPAQUE - EPSILON) {
+ srcBlend = srcAlpha;
+ } else {
+ float newAlpha = dstAlpha + (F32_OPACITY_OPAQUE - dstAlpha) * srcAlpha;
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha > EPSILON) {
+ srcBlend = srcAlpha / newAlpha;
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ if (srcBlend > F32_OPACITY_OPAQUE - EPSILON) {
+ memcpy(dst, src, MAX_CHANNEL_RGB * sizeof(float));
+ } else {
+ dst[PIXEL_RED] = FLOAT_BLEND(src[PIXEL_RED], dst[PIXEL_RED], srcBlend);
+ dst[PIXEL_GREEN] = FLOAT_BLEND(src[PIXEL_GREEN], dst[PIXEL_GREEN], srcBlend);
+ dst[PIXEL_BLUE] = FLOAT_BLEND(src[PIXEL_BLUE], dst[PIXEL_BLUE], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart) {
+ maskRowStart += maskRowStride;
+ }
+ }
+}
+
+#define COMMON_COMPOSITE_OP_PROLOG() \
+ while (rows > 0) { \
+ \
+ const float *src = reinterpret_cast<const float *>(srcRowStart); \
+ float *dst = reinterpret_cast<float *>(dstRowStart); \
+ Q_INT32 columns = numColumns; \
+ const Q_UINT8 *mask = maskRowStart; \
+ \
+ while (columns > 0) { \
+ \
+ float srcAlpha = src[PIXEL_ALPHA]; \
+ float dstAlpha = dst[PIXEL_ALPHA]; \
+ \
+ srcAlpha = QMIN(srcAlpha, dstAlpha); \
+ \
+ if (mask != 0) { \
+ Q_UINT8 U8_mask = *mask; \
+ \
+ if (U8_mask != OPACITY_OPAQUE) { \
+ srcAlpha *= UINT8_TO_FLOAT(U8_mask); \
+ } \
+ mask++; \
+ } \
+ \
+ if (srcAlpha > F32_OPACITY_TRANSPARENT + EPSILON) { \
+ \
+ if (opacity < F32_OPACITY_OPAQUE - EPSILON) { \
+ srcAlpha *= opacity; \
+ } \
+ \
+ float srcBlend; \
+ \
+ if (dstAlpha > F32_OPACITY_OPAQUE - EPSILON) { \
+ srcBlend = srcAlpha; \
+ } else { \
+ float newAlpha = dstAlpha + (F32_OPACITY_OPAQUE - dstAlpha) * srcAlpha; \
+ dst[PIXEL_ALPHA] = newAlpha; \
+ \
+ if (newAlpha > EPSILON) { \
+ srcBlend = srcAlpha / newAlpha; \
+ } else { \
+ srcBlend = srcAlpha; \
+ } \
+ }
+
+#define COMMON_COMPOSITE_OP_EPILOG() \
+ } \
+ \
+ columns--; \
+ src += MAX_CHANNEL_RGBA; \
+ dst += MAX_CHANNEL_RGBA; \
+ } \
+ \
+ rows--; \
+ srcRowStart += srcRowStride; \
+ dstRowStart += dstRowStride; \
+ if(maskRowStart) { \
+ maskRowStart += maskRowStride; \
+ } \
+ }
+
+void KisRgbF32ColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float srcColor = src[PIXEL_RED];
+ float dstColor = dst[PIXEL_RED];
+
+ srcColor = srcColor * dstColor;
+
+ dst[PIXEL_RED] = FLOAT_BLEND(srcColor, dstColor, srcBlend);
+
+ srcColor = src[PIXEL_GREEN];
+ dstColor = dst[PIXEL_GREEN];
+
+ srcColor = srcColor * dstColor;
+
+ dst[PIXEL_GREEN] = FLOAT_BLEND(srcColor, dstColor, srcBlend);
+
+ srcColor = src[PIXEL_BLUE];
+ dstColor = dst[PIXEL_BLUE];
+
+ srcColor = srcColor * dstColor;
+
+ dst[PIXEL_BLUE] = FLOAT_BLEND(srcColor, dstColor, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ float srcColor = src[channel];
+ float dstColor = dst[channel];
+
+ srcColor = QMIN(dstColor / (srcColor + EPSILON), FLOAT_MAX);
+
+ float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ float srcColor = src[channel];
+ float dstColor = dst[channel];
+
+ srcColor = FLOAT_MAX - ((FLOAT_MAX - dstColor) * (FLOAT_MAX - srcColor));
+
+ float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ float srcColor = src[channel];
+ float dstColor = dst[channel];
+
+ srcColor = dstColor * (dstColor + 2 * (srcColor * (FLOAT_MAX - dstColor)));
+
+ float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ float srcColor = src[channel];
+ float dstColor = dst[channel];
+
+ srcColor = QMIN(dstColor / (FLOAT_MAX + EPSILON - srcColor), FLOAT_MAX);
+
+ float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ float srcColor = src[channel];
+ float dstColor = dst[channel];
+
+ srcColor = QMIN((FLOAT_MAX - dstColor) / (srcColor + EPSILON), FLOAT_MAX);
+ srcColor = CLAMP(FLOAT_MAX - srcColor, 0, FLOAT_MAX);
+
+ float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ float srcColor = src[channel];
+ float dstColor = dst[channel];
+
+ srcColor = QMIN(srcColor, dstColor);
+
+ float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ float srcColor = src[channel];
+ float dstColor = dst[channel];
+
+ srcColor = QMAX(srcColor, dstColor);
+
+ float newColor = FLOAT_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeHue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float srcRed = src[PIXEL_RED];
+ float srcGreen = src[PIXEL_GREEN];
+ float srcBlue = src[PIXEL_BLUE];
+
+ float dstRed = dst[PIXEL_RED];
+ float dstGreen = dst[PIXEL_GREEN];
+ float dstBlue = dst[PIXEL_BLUE];
+
+ float srcHue;
+ float srcSaturation;
+ float srcValue;
+
+ float dstHue;
+ float dstSaturation;
+ float dstValue;
+
+ RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue);
+ RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ HSVToRGB(srcHue, dstSaturation, dstValue, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeSaturation(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float srcRed = src[PIXEL_RED];
+ float srcGreen = src[PIXEL_GREEN];
+ float srcBlue = src[PIXEL_BLUE];
+
+ float dstRed = dst[PIXEL_RED];
+ float dstGreen = dst[PIXEL_GREEN];
+ float dstBlue = dst[PIXEL_BLUE];
+
+ float srcHue;
+ float srcSaturation;
+ float srcValue;
+
+ float dstHue;
+ float dstSaturation;
+ float dstValue;
+
+ RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue);
+ RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ HSVToRGB(dstHue, srcSaturation, dstValue, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeValue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float srcRed = src[PIXEL_RED];
+ float srcGreen = src[PIXEL_GREEN];
+ float srcBlue = src[PIXEL_BLUE];
+
+ float dstRed = dst[PIXEL_RED];
+ float dstGreen = dst[PIXEL_GREEN];
+ float dstBlue = dst[PIXEL_BLUE];
+
+ float srcHue;
+ float srcSaturation;
+ float srcValue;
+
+ float dstHue;
+ float dstSaturation;
+ float dstValue;
+
+ RGBToHSV(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcValue);
+ RGBToHSV(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ HSVToRGB(dstHue, dstSaturation, srcValue, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeColor(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, float opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float srcRed = src[PIXEL_RED];
+ float srcGreen = src[PIXEL_GREEN];
+ float srcBlue = src[PIXEL_BLUE];
+
+ float dstRed = dst[PIXEL_RED];
+ float dstGreen = dst[PIXEL_GREEN];
+ float dstBlue = dst[PIXEL_BLUE];
+
+ float srcHue;
+ float srcSaturation;
+ float srcLightness;
+
+ float dstHue;
+ float dstSaturation;
+ float dstLightness;
+
+ RGBToHSL(srcRed, srcGreen, srcBlue, &srcHue, &srcSaturation, &srcLightness);
+ RGBToHSL(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstLightness);
+
+ HSLToRGB(srcHue, srcSaturation, dstLightness, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = FLOAT_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = FLOAT_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = FLOAT_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbF32ColorSpace::compositeErase(Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ float /*opacity*/)
+{
+ while (rows-- > 0)
+ {
+ const Pixel *s = reinterpret_cast<const Pixel *>(src);
+ Pixel *d = reinterpret_cast<Pixel *>(dst);
+ const Q_UINT8 *mask = srcAlphaMask;
+
+ for (Q_INT32 i = cols; i > 0; i--, s++, d++)
+ {
+ float srcAlpha = s->alpha;
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = FLOAT_BLEND(srcAlpha, F32_OPACITY_OPAQUE, UINT8_TO_FLOAT(U8_mask));
+ }
+ mask++;
+ }
+ d->alpha = srcAlpha * d->alpha;
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ if(srcAlphaMask) {
+ srcAlphaMask += maskRowStride;
+ }
+ }
+}
+
+void KisRgbF32ColorSpace::bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *mask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 U8_opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op)
+{
+ float opacity = UINT8_TO_FLOAT(U8_opacity);
+
+ switch (op.op()) {
+ case COMPOSITE_UNDEF:
+ // Undefined == no composition
+ break;
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIVIDE:
+ compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LIGHTEN:
+ compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_HUE:
+ compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SATURATION:
+ compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_VALUE:
+ compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COLOR:
+ compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_OVERLAY:
+ compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DODGE:
+ compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BURN:
+ compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ALPHA_DARKEN:
+ abstractCompositeAlphaDarken<float, F32Mult, Uint8ToF32, F32OpacityTest,
+ PIXEL_ALPHA, MAX_CHANNEL_RGB, MAX_CHANNEL_RGBA>(
+ dst, dstRowStride, src, srcRowStride, mask, maskRowStride,
+ rows, cols, U8_opacity, F32Mult(), Uint8ToF32(), F32OpacityTest());
+ default:
+ break;
+ }
+}
+
+KisCompositeOpList KisRgbF32ColorSpace::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));
+ list.append(KisCompositeOp(COMPOSITE_HUE));
+ list.append(KisCompositeOp(COMPOSITE_SATURATION));
+ list.append(KisCompositeOp(COMPOSITE_VALUE));
+ list.append(KisCompositeOp(COMPOSITE_COLOR));
+
+ return list;
+}
+
diff --git a/krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h b/krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h
new file mode 100644
index 00000000..a1681be5
--- /dev/null
+++ b/krita/colorspaces/rgb_f32/kis_rgb_f32_colorspace.h
@@ -0,0 +1,165 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <[email protected]>
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_RGB_F32_H_
+#define KIS_STRATEGY_COLORSPACE_RGB_F32_H_
+
+#include <qcolor.h>
+
+#include <klocale.h>
+
+#include <koffice_export.h>
+
+#include "kis_global.h"
+#include "kis_f32_base_colorspace.h"
+
+class KisColorSpaceFactoryRegistry;
+
+class KRITATOOL_EXPORT KisRgbF32ColorSpace : public KisF32BaseColorSpace {
+public:
+ KisRgbF32ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p);
+ virtual ~KisRgbF32ColorSpace();
+
+ virtual bool willDegrade(ColorSpaceIndependence independence)
+ {
+ if (independence == TO_RGBA8 || independence == TO_LAB16)
+ return true;
+ else
+ return false;
+ };
+
+
+
+public:
+ void setPixel(Q_UINT8 *pixel, float red, float green, float blue, float alpha) const;
+ void getPixel(const Q_UINT8 *pixel, float *red, float *green, float *blue, float *alpha) const;
+
+ virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0);
+ virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0);
+
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0);
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0);
+
+ virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2);
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+ virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels);
+ virtual void convolveColors(Q_UINT8** colors, Q_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const;
+ virtual Q_UINT8 intensity8(const Q_UINT8 * src) const;
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+
+
+ virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
+ KisProfile * dstProfile,
+ Q_INT32 renderingIntent,
+ float exposure = 0.0f);
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+
+protected:
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeHue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeSaturation(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeValue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeColor(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+ void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, float opacity);
+
+private:
+ friend class KisRgbF32ColorSpaceTester;
+
+ static const Q_UINT8 PIXEL_BLUE = 0;
+ static const Q_UINT8 PIXEL_GREEN = 1;
+ static const Q_UINT8 PIXEL_RED = 2;
+ static const Q_UINT8 PIXEL_ALPHA = 3;
+
+ struct Pixel {
+ float blue;
+ float green;
+ float red;
+ float alpha;
+ };
+
+ // For Alpha Composite
+ struct F32Mult {
+ inline float operator()(const float& a, const float& b) const {
+ return a * b;
+ }
+ };
+ struct Uint8ToF32 {
+ inline float operator()(const Q_UINT8 src) const {
+ return UINT8_TO_FLOAT(src);
+ }
+ };
+ struct F32OpacityTest {
+ inline bool operator()(const float& opacity) const {
+ return opacity > F32_OPACITY_TRANSPARENT + 1e-6; // #define EPSILON in the .cc
+ }
+ };
+};
+
+// FIXME: lcms doesn't support 32-bit float
+#define F32_LCMS_TYPE TYPE_BGRA_16
+
+class KisRgbF32ColorSpaceFactory : public KisColorSpaceFactory
+{
+public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("RGBAF32", i18n("RGB (32-bit float/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return F32_LCMS_TYPE; };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisRgbF32ColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return "sRGB built-in - (lcms internal)"; };
+};
+
+#endif // KIS_STRATEGY_COLORSPACE_RGB_F32_H_
+
diff --git a/krita/colorspaces/rgb_f32/krita_rgb_f32_plugin.desktop b/krita/colorspaces/rgb_f32/krita_rgb_f32_plugin.desktop
new file mode 100644
index 00000000..67ea396d
--- /dev/null
+++ b/krita/colorspaces/rgb_f32/krita_rgb_f32_plugin.desktop
@@ -0,0 +1,77 @@
+[Desktop Entry]
+Name=RGB Color Model (32-bit float)
+Name[bg]=Цветови модел RGB (32 бита)
+Name[ca]=Model de color RGB (paleta de 32 bits)
+Name[cy]=Model Lliw RGB (arnawf 32-did)
+Name[da]=RGB-farvemodel (32-bit float)
+Name[de]=RGB-Farbmodell (32-bit Fließkomma)
+Name[el]=Χρωματικό μοντέλο RGB (32 bit δεκαδικοί)
+Name[en_GB]=RGB Colour Model (32-bit float)
+Name[eo]=RGB-kolormodelo (32-bita flupunkto)
+Name[es]=Modelo de color RGB (decimal de 32 bits)
+Name[et]=RGB värvimudel (32-bitine murdarv)
+Name[fa]=مدل رنگ RGB )شناور ۳۲ بیتی(
+Name[fr]=Modèle de couleurs RVB (flottants 32 bits)
+Name[fy]=RGB-kleurmodel (32-bit float)
+Name[gl]=Espazo de Cores RGB (flutuante de 32-bit)
+Name[he]=מודל צבעים RGB (32 סיביות)
+Name[hu]=RGB színmodell (32 bites lebegőpontos)
+Name[is]=RGB litategund (32-bita fleytitala)
+Name[it]=Modello di colore RGB (virgola mobile a 32 bit)
+Name[ja]=RGB カラーモデル (32 ビット浮動小数)
+Name[km]=គំរូ​ពណ៌ RGB (ចំនួន​ទស្សភាគ 32 ប៊ីត)
+Name[nb]=RGB-fargemodell (32-bit flyttall)
+Name[nds]=RGB-Klöörmodell (32-Bit Fleetkomma)
+Name[ne]=RGB रङ मोडेल (३२-बिट उत्प्लावन)
+Name[nl]=RGB-kleurmodel (32-bit float)
+Name[pl]=Przestrzeń barw RGB (32-bitowa zmiennoprzecinkowa)
+Name[pt]=Modelo de Cor RGB (v. flutuante de 32-bits)
+Name[pt_BR]=Modelo de Cor RGB (ponto flutuante de 32-bits)
+Name[ru]=RGB (32-бит с плавающей точкой)
+Name[sk]=Model farieb RGB (32-bitové reálne čísla)
+Name[sl]=Barvni model RGB (32-bitno celo število)
+Name[sr]=RGB модел боја (32-битно реално)
+Name[sr@Latn]=RGB model boja (32-bitno realno)
+Name[sv]=RGB-färgmodell (32-bitars heltal)
+Name[uk]=Модель кольорів RGB (32-бітне дробове число)
+Name[uz]=RGB rang usuli (32-bit kasr)
+Name[uz@cyrillic]=RGB ранг усули (32-бит каср)
+Name[zh_TW]=RGB 色彩模型 (32-bit 浮點數)
+Comment=Color model for 32-bit floating point per channel RGB images
+Comment[bg]=Цветови модел за 32 битови изображения RGB
+Comment[ca]=Model de color per a punt flotant de 32 bits-canal d'imatges RGB
+Comment[da]=Farvemodel for 32-bit decimaltal pr kanal RGB-billeder
+Comment[de]=Farbmodell für 32-bit Fließkomma pro Kanal RGB-Bilder
+Comment[el]=Χρωματικό μοντέλο για 32-bit δεκαδικούς ανά κανάλι RGB εικόνες
+Comment[en_GB]=Colour model for 32-bit floating point per channel RGB images
+Comment[es]=Modelo de color decimal de 32 bits por canal para imágenes RGB
+Comment[et]=32-bitiste murdarvuliste kanalitega RGB-piltide värvimudel
+Comment[fa]=مدل رنگ برای ممیز شناور ۳۲ بیتی برای هر تصویر RGB مجرا
+Comment[fr]=Modèle de couleurs pour des images RVB en 32 bits flottants par canal
+Comment[fy]=Kleurmodel foar RGB-ôfbyldings mei 32-bit Driuwende komma de kanaal
+Comment[gl]=Espazo de cores para imaxes RGB de 32-bit vírgula flutuante por canal
+Comment[he]=מודל צבעים עבור תמונות RGB של 32 סיביות/ערוצים
+Comment[hu]=Színmodell 32 bit (lebegőpontos)/csatorna RGB képekhez
+Comment[is]=Litategund fyrir 32-bita fleytitölu á rás RGB myndir
+Comment[it]=Modello di colore per immagini RGB in virgola mobile a canale di 32 bit
+Comment[ja]=32 ビット浮動小数/チャンネル RGB 画像のためのカラーモデル
+Comment[km]=ម៉ូដែល​ពណ៌​សម្រាប់​ចំណុច​ចំនួន​ទស្សភាគ 32-bit ក្នុង​ឆានែល​រូបភាព RGB
+Comment[nb]=Fargemodell for RGB-bilde med 32 bit flyttall per kanal
+Comment[nds]=Klöörmodell för RGB-Biller mit 32-Bit Fleetkomma per Kanaal
+Comment[ne]=प्रति च्यानल RGB छविहरूको ३२-बिट उत्प्लावन बिन्दुका लागि रङ मोडेल
+Comment[nl]=Kleurmodel voor RGB-afbeeldingen met 32-bit drijvende komma per kanaal
+Comment[pl]=Przestrzeń barw dla obrazków RGB z 32-bitową liczbą zmiennoprzecinkową na kanał
+Comment[pt]=Modelo de cor para imagens RGB com 32 bits de vírgula flutuante por canal
+Comment[pt_BR]=Modelo de cor para imagens RGB com 32 bits de ponto flutuante por canal
+Comment[ru]=Цветовое пространство RGB (32-бит/канал с плавающей точкой)
+Comment[sk]=Model farieb pre RGB obrázky s 32-bitovými reálnymi číslami na kanál
+Comment[sl]=Barvni model za slike RGB z 32-bitno plavajočo vejico na kanal
+Comment[sr]=Модел боја за RGB слике, 32-битно реално по каналу
+Comment[sr@Latn]=Model boja za RGB slike, 32-bitno realno po kanalu
+Comment[sv]=Färgmodell för 32-bitars flyttal per kanal RGB-bilder
+Comment[uk]=Модель кольорів для зображень RGB 32-біт з плаваючою комою на канал
+Comment[zh_TW]=每色頻 32-bit 浮點 RGB 圖片的色彩模型
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-Krita-Version=2
+X-KDE-Library=krita_rgb_f32_plugin
diff --git a/krita/colorspaces/rgb_f32/rgb_f32_plugin.cc b/krita/colorspaces/rgb_f32/rgb_f32_plugin.cc
new file mode 100644
index 00000000..01dc514a
--- /dev/null
+++ b/krita/colorspaces/rgb_f32/rgb_f32_plugin.cc
@@ -0,0 +1,63 @@
+/*
+* rgb_f32_plugin.cc -- Part of Krita
+*
+* Copyright (c) 2004 Boudewijn Rempt ([email protected])
+* Copyright (c) 2005 Adrian Page <[email protected]>
+*
+* 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 <kinstance.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <kis_debug_areas.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_basic_histogram_producers.h>
+
+#include "rgb_f32_plugin.h"
+#include "kis_rgb_f32_colorspace.h"
+
+typedef KGenericFactory<RGBF32Plugin> RGBF32PluginFactory;
+K_EXPORT_COMPONENT_FACTORY( krita_rgb_f32_plugin, RGBF32PluginFactory( "krita" ) )
+
+
+RGBF32Plugin::RGBF32Plugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(RGBF32PluginFactory::instance());
+
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") )
+ {
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry*>(parent);
+
+ KisColorSpace * colorSpaceRGBF32 = new KisRgbF32ColorSpace(f, 0);
+
+ KisColorSpaceFactory * csf = new KisRgbF32ColorSpaceFactory();
+ f->add(csf);
+
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicF32HistogramProducer>
+ (KisID("RGBF32HISTO", i18n("Float32")), colorSpaceRGBF32) );
+ }
+
+}
+
+RGBF32Plugin::~RGBF32Plugin()
+{
+}
+
+#include "rgb_f32_plugin.moc"
diff --git a/krita/colorspaces/rgb_f32/rgb_f32_plugin.h b/krita/colorspaces/rgb_f32/rgb_f32_plugin.h
new file mode 100644
index 00000000..f847dc3d
--- /dev/null
+++ b/krita/colorspaces/rgb_f32/rgb_f32_plugin.h
@@ -0,0 +1,38 @@
+/*
+ * Copyright (c) 2003 Boudewijn Rempt ([email protected])
+ *
+ * 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 RGB_F32_PLUGIN_H_
+#define RGB_F32_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the RGB F32 colour space strategy.
+ */
+class RGBF32Plugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ RGBF32Plugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~RGBF32Plugin();
+
+};
+
+
+#endif // RGB_F32_PLUGIN_H_
diff --git a/krita/colorspaces/rgb_f32/rgb_f32_plugin.rc b/krita/colorspaces/rgb_f32/rgb_f32_plugin.rc
new file mode 100644
index 00000000..14aab641
--- /dev/null
+++ b/krita/colorspaces/rgb_f32/rgb_f32_plugin.rc
@@ -0,0 +1,9 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui library="krita_rgb_f32_plugin" version="1">
+<Menu name="Image"><text>&amp;Image</text>
+ <Menu name="Mode"><text>&amp;Mode</text>
+ <Action name="convert to RGB(A) (32-bit float)"/>
+ </Menu>
+</Menu>
+
+</kpartgui>
diff --git a/krita/colorspaces/rgb_f32/tests/Makefile.am b/krita/colorspaces/rgb_f32/tests/Makefile.am
new file mode 100644
index 00000000..943af1d0
--- /dev/null
+++ b/krita/colorspaces/rgb_f32/tests/Makefile.am
@@ -0,0 +1,17 @@
+AM_CPPFLAGS = -I$(srcdir)/.. \
+ -I$(srcdir)/../../../sdk \
+ -I$(srcdir)/../../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../../color_strategy/ \
+ $(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_strategy_colorspace_rgb_f32_tester.la
+
+kunittest_kis_strategy_colorspace_rgb_f32_tester_la_SOURCES = kis_strategy_colorspace_rgb_f32_tester.cc
+kunittest_kis_strategy_colorspace_rgb_f32_tester_la_LIBADD = -lkunittest ../libkrita_rgb_f32.la
+kunittest_kis_strategy_colorspace_rgb_f32_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
+
+check-local: kunittest_kis_strategy_colorspace_rgb_f32_tester.la
+ kunittestmodrunner
+
diff --git a/krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.cc b/krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.cc
new file mode 100644
index 00000000..5694f3e3
--- /dev/null
+++ b/krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.cc
@@ -0,0 +1,541 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_factory.h"
+#include "kis_strategy_colorspace_rgb_f32_tester.h"
+#include "kis_rgb_f32_colorspace.h"
+#include "kis_integer_maths.h"
+#include "kis_paint_device.h"
+
+using namespace KUnitTest;
+
+KUNITTEST_MODULE( kunittest_kis_strategy_colorspace_rgb_f32_tester, "RGBA 32-bit float colorspace tester" );
+KUNITTEST_MODULE_REGISTER_TESTER( KisRgbF32ColorSpaceTester );
+
+#define PIXEL_BLUE 0
+#define PIXEL_GREEN 1
+#define PIXEL_RED 2
+#define PIXEL_ALPHA 3
+
+#define NUM_CHANNELS 4
+#define NUM_COLOUR_CHANNELS 3
+#define CHANNEL_SIZE ((int)sizeof(float))
+
+#define RED_CHANNEL 0
+#define GREEN_CHANNEL 1
+#define BLUE_CHANNEL 2
+#define ALPHA_CHANNEL 3
+
+#define MAX_CHANNEL_VALUE 1.0f
+#define MIN_CHANNEL_VALUE 0.0f
+
+
+void KisRgbF32ColorSpaceTester::allTests()
+{
+ // We need this so that the colour profile loading can operate without crashing.
+ KisFactory *factory = new KisFactory();
+
+ testBasics();
+ testToQImage();
+ testCompositeOps();
+ testMixColors();
+
+ delete factory;
+}
+
+void KisRgbF32ColorSpaceTester::testBasics()
+{
+ KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile());
+
+ KisRgbF32ColorSpace *cs = new KisRgbF32ColorSpace(profile);
+ KisAbstractColorSpace * csSP = cs;
+
+ CHECK(cs->hasAlpha(), true);
+ CHECK(cs->nChannels(), NUM_CHANNELS);
+ CHECK(cs->nColorChannels(), NUM_COLOUR_CHANNELS);
+ CHECK(cs->pixelSize(), NUM_CHANNELS * CHANNEL_SIZE);
+
+ QValueVector<KisChannelInfo *> channels = cs->channels();
+
+ // Red
+ CHECK(channels[0]->pos(), PIXEL_RED * CHANNEL_SIZE);
+ CHECK(channels[0]->size(), CHANNEL_SIZE);
+ CHECK(channels[0]->channelType(), COLOR);
+
+ // Green
+ CHECK(channels[1]->pos(), PIXEL_GREEN * CHANNEL_SIZE);
+ CHECK(channels[1]->size(), CHANNEL_SIZE);
+ CHECK(channels[1]->channelType(), COLOR);
+
+ // Blue
+ CHECK(channels[2]->pos(), PIXEL_BLUE * CHANNEL_SIZE);
+ CHECK(channels[2]->size(), CHANNEL_SIZE);
+ CHECK(channels[2]->channelType(), COLOR);
+
+ // Alpha
+ CHECK(channels[3]->pos(), PIXEL_ALPHA * CHANNEL_SIZE);
+ CHECK(channels[3]->size(), CHANNEL_SIZE);
+ CHECK(channels[3]->channelType(), ALPHA);
+
+ KisPaintDeviceSP pd = new KisPaintDevice(cs, "test");
+
+ KisRgbF32ColorSpace::Pixel defaultPixel;
+
+ memcpy(&defaultPixel, pd->dataManager()->defaultPixel(), sizeof(defaultPixel));
+
+ CHECK(defaultPixel.red, 0.0f);
+ CHECK(defaultPixel.green, 0.0f);
+ CHECK(defaultPixel.blue, 0.0f);
+ CHECK(defaultPixel.alpha, F32_OPACITY_TRANSPARENT);
+
+ float pixel[NUM_CHANNELS];
+
+ cs->fromQColor(qRgb(255, 255, 255), reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], MAX_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE);
+
+ cs->fromQColor(qRgb(0, 0, 0), reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], MIN_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_GREEN], MIN_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_BLUE], MIN_CHANNEL_VALUE);
+
+ cs->fromQColor(qRgb(128, 64, 192), reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], UINT8_TO_FLOAT(128));
+ CHECK(pixel[PIXEL_GREEN], UINT8_TO_FLOAT(64));
+ CHECK(pixel[PIXEL_BLUE], UINT8_TO_FLOAT(192));
+
+ cs->fromQColor(qRgb(255, 255, 255), OPACITY_OPAQUE, reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], MAX_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_ALPHA], MAX_CHANNEL_VALUE);
+
+ cs->fromQColor(qRgb(255, 255, 255), OPACITY_TRANSPARENT, reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], MAX_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_ALPHA], F32_OPACITY_TRANSPARENT);
+
+ cs->fromQColor(qRgb(255, 255, 255), OPACITY_OPAQUE / 2, reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK(pixel[PIXEL_RED], MAX_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE);
+ CHECK(pixel[PIXEL_ALPHA], UINT8_TO_FLOAT(OPACITY_OPAQUE / 2));
+
+ pixel[PIXEL_RED] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE;
+
+ QColor c;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c);
+
+ CHECK(c.red(), 255);
+ CHECK(c.green(), 255);
+ CHECK(c.blue(), 255);
+
+ pixel[PIXEL_RED] = MIN_CHANNEL_VALUE;
+ pixel[PIXEL_GREEN] = MIN_CHANNEL_VALUE;
+ pixel[PIXEL_BLUE] = MIN_CHANNEL_VALUE;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c);
+
+ CHECK(c.red(), 0);
+ CHECK(c.green(), 0);
+ CHECK(c.blue(), 0);
+
+ pixel[PIXEL_RED] = MAX_CHANNEL_VALUE / 4;
+ pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2;
+ pixel[PIXEL_BLUE] = (3 * MAX_CHANNEL_VALUE) / 4;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c);
+
+ CHECK(c.red(), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 4));
+ CHECK(c.green(), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2));
+ CHECK(c.blue(), (int)FLOAT_TO_UINT8((3 * MAX_CHANNEL_VALUE) / 4));
+
+ pixel[PIXEL_RED] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_ALPHA] = MAX_CHANNEL_VALUE;
+
+ Q_UINT8 opacity;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), 255);
+ CHECK(c.green(), 255);
+ CHECK(c.blue(), 255);
+ CHECK(opacity, OPACITY_OPAQUE);
+
+ pixel[PIXEL_ALPHA] = F32_OPACITY_OPAQUE;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), 255);
+ CHECK(c.green(), 255);
+ CHECK(c.blue(), 255);
+ CHECK(opacity, OPACITY_OPAQUE);
+
+ pixel[PIXEL_RED] = MIN_CHANNEL_VALUE;
+ pixel[PIXEL_GREEN] = MIN_CHANNEL_VALUE;
+ pixel[PIXEL_BLUE] = MIN_CHANNEL_VALUE;
+ pixel[PIXEL_ALPHA] = F32_OPACITY_TRANSPARENT;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), 0);
+ CHECK(c.green(), 0);
+ CHECK(c.blue(), 0);
+ CHECK(opacity, OPACITY_TRANSPARENT);
+
+ pixel[PIXEL_RED] = MAX_CHANNEL_VALUE / 4;
+ pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2;
+ pixel[PIXEL_BLUE] = (3 * MAX_CHANNEL_VALUE) / 4;
+ pixel[PIXEL_ALPHA] = MAX_CHANNEL_VALUE / 2;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 4));
+ CHECK(c.green(), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2));
+ CHECK(c.blue(), (int)FLOAT_TO_UINT8((3 * MAX_CHANNEL_VALUE) / 4));
+ CHECK((int)opacity, (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2));
+
+ #define NUM_PIXELS 4
+
+ KisRgbF32ColorSpace::Pixel pixels[NUM_PIXELS] = {
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4},
+ {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2},
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE},
+ {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE}
+ };
+
+ cs->setAlpha(reinterpret_cast<Q_UINT8 *>(pixels), OPACITY_OPAQUE / 2, NUM_PIXELS);
+
+ CHECK(pixels[0].red, MAX_CHANNEL_VALUE);
+ CHECK(pixels[0].green, MAX_CHANNEL_VALUE);
+ CHECK(pixels[0].blue, MAX_CHANNEL_VALUE);
+ CHECK(pixels[0].alpha, UINT8_TO_FLOAT(OPACITY_OPAQUE / 2));
+
+ CHECK(pixels[1].red, MAX_CHANNEL_VALUE / 3);
+ CHECK(pixels[1].green, MAX_CHANNEL_VALUE / 2);
+ CHECK(pixels[1].blue, MAX_CHANNEL_VALUE / 4);
+ CHECK(pixels[1].alpha, UINT8_TO_FLOAT(OPACITY_OPAQUE / 2));
+
+ CHECK(pixels[2].red, MAX_CHANNEL_VALUE);
+ CHECK(pixels[2].green, MAX_CHANNEL_VALUE);
+ CHECK(pixels[2].blue, MAX_CHANNEL_VALUE);
+ CHECK(pixels[2].alpha, UINT8_TO_FLOAT(OPACITY_OPAQUE / 2));
+
+ CHECK(pixels[3].red, MIN_CHANNEL_VALUE);
+ CHECK(pixels[3].green, MIN_CHANNEL_VALUE);
+ CHECK(pixels[3].blue, MIN_CHANNEL_VALUE);
+ CHECK(pixels[3].alpha, UINT8_TO_FLOAT(OPACITY_OPAQUE / 2));
+
+ pixel[PIXEL_RED] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2;
+ pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE / 4;
+ pixel[PIXEL_ALPHA] = MIN_CHANNEL_VALUE;
+
+ QString valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), RED_CHANNEL);
+ CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE));
+
+ valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), GREEN_CHANNEL);
+ CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 2));
+
+ valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), BLUE_CHANNEL);
+ CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 4));
+
+ valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), ALPHA_CHANNEL);
+ CHECK(valueText, QString().setNum(MIN_CHANNEL_VALUE));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), RED_CHANNEL);
+ CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), GREEN_CHANNEL);
+ CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 2));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), BLUE_CHANNEL);
+ CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 4));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), ALPHA_CHANNEL);
+ CHECK(valueText, QString().setNum(MIN_CHANNEL_VALUE));
+
+ cs->setPixel(reinterpret_cast<Q_UINT8 *>(pixel), 0.128, 0.192, 0.64, 0.99);
+ CHECK(pixel[PIXEL_RED], 0.128f);
+ CHECK(pixel[PIXEL_GREEN], 0.192f);
+ CHECK(pixel[PIXEL_BLUE], 0.64f);
+ CHECK(pixel[PIXEL_ALPHA], 0.99f);
+
+ float red;
+ float green;
+ float blue;
+ float alpha;
+
+ cs->getPixel(reinterpret_cast<const Q_UINT8 *>(pixel), &red, &green, &blue, &alpha);
+ CHECK(red, 0.128f);
+ CHECK(green, 0.192f);
+ CHECK(blue, 0.64f);
+ CHECK(alpha, 0.99f);
+
+ CHECK(FLOAT_TO_UINT8(-0.5), 0u);
+ CHECK(FLOAT_TO_UINT8(0), 0u);
+ CHECK_TOLERANCE(FLOAT_TO_UINT8(0.5), UINT8_MAX / 2, 1u);
+ CHECK(FLOAT_TO_UINT8(1), UINT8_MAX);
+ CHECK(FLOAT_TO_UINT8(1.5), UINT8_MAX);
+
+ CHECK(FLOAT_TO_UINT16(-0.5), 0u);
+ CHECK(FLOAT_TO_UINT16(0), 0u);
+ CHECK_TOLERANCE(FLOAT_TO_UINT16(0.5), UINT16_MAX / 2, 1u);
+ CHECK(FLOAT_TO_UINT16(1), UINT16_MAX);
+ CHECK(FLOAT_TO_UINT16(1.5), UINT16_MAX);
+}
+
+void KisRgbF32ColorSpaceTester::testMixColors()
+{
+ KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile());
+
+ KisAbstractColorSpace * cs = new KisRgbF32ColorSpace(profile);
+
+ // Test mixColors.
+ float pixel1[NUM_CHANNELS];
+ float pixel2[NUM_CHANNELS];
+ float outputPixel[NUM_CHANNELS];
+
+ outputPixel[PIXEL_RED] = 0;
+ outputPixel[PIXEL_GREEN] = 0;
+ outputPixel[PIXEL_BLUE] = 0;
+ outputPixel[PIXEL_ALPHA] = 0;
+
+ pixel1[PIXEL_RED] = MAX_CHANNEL_VALUE;
+ pixel1[PIXEL_GREEN] = MAX_CHANNEL_VALUE;
+ pixel1[PIXEL_BLUE] = MAX_CHANNEL_VALUE;
+ pixel1[PIXEL_ALPHA] = MAX_CHANNEL_VALUE;
+
+ pixel2[PIXEL_RED] = 0;
+ pixel2[PIXEL_GREEN] = 0;
+ pixel2[PIXEL_BLUE] = 0;
+ pixel2[PIXEL_ALPHA] = 0;
+
+ const Q_UINT8 *pixelPtrs[2];
+ Q_UINT8 weights[2];
+
+ pixelPtrs[0] = reinterpret_cast<const Q_UINT8 *>(pixel1);
+ pixelPtrs[1] = reinterpret_cast<const Q_UINT8 *>(pixel2);
+
+ weights[0] = 255;
+ weights[1] = 0;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK(outputPixel[PIXEL_RED], MAX_CHANNEL_VALUE);
+ CHECK(outputPixel[PIXEL_GREEN], MAX_CHANNEL_VALUE);
+ CHECK(outputPixel[PIXEL_BLUE], MAX_CHANNEL_VALUE);
+ CHECK(outputPixel[PIXEL_ALPHA], MAX_CHANNEL_VALUE);
+
+ weights[0] = 0;
+ weights[1] = 255;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK(outputPixel[PIXEL_RED], 0.0f);
+ CHECK(outputPixel[PIXEL_GREEN], 0.0f);
+ CHECK(outputPixel[PIXEL_BLUE], 0.0f);
+ CHECK(outputPixel[PIXEL_ALPHA], 0.0f);
+
+ weights[0] = 128;
+ weights[1] = 127;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK(outputPixel[PIXEL_RED], MAX_CHANNEL_VALUE);
+ CHECK(outputPixel[PIXEL_GREEN], MAX_CHANNEL_VALUE);
+ CHECK(outputPixel[PIXEL_BLUE], MAX_CHANNEL_VALUE);
+ CHECK(outputPixel[PIXEL_ALPHA], (128 * MAX_CHANNEL_VALUE) / 255);
+
+ pixel1[PIXEL_RED] = 20000;
+ pixel1[PIXEL_GREEN] = 10000;
+ pixel1[PIXEL_BLUE] = 5000;
+ pixel1[PIXEL_ALPHA] = MAX_CHANNEL_VALUE;
+
+ pixel2[PIXEL_RED] = 10000;
+ pixel2[PIXEL_GREEN] = 20000;
+ pixel2[PIXEL_BLUE] = 2000;
+ pixel2[PIXEL_ALPHA] = MAX_CHANNEL_VALUE;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK_TOLERANCE(outputPixel[PIXEL_RED], (128 * 20000 + 127 * 10000) / 255, 5);
+ CHECK_TOLERANCE(outputPixel[PIXEL_GREEN], (128 * 10000 + 127 * 20000) / 255, 5);
+ CHECK_TOLERANCE(outputPixel[PIXEL_BLUE], (128 * 5000 + 127 * 2000) / 255, 5);
+ CHECK(outputPixel[PIXEL_ALPHA], MAX_CHANNEL_VALUE);
+
+ pixel1[PIXEL_RED] = 0;
+ pixel1[PIXEL_GREEN] = 0;
+ pixel1[PIXEL_BLUE] = 0;
+ pixel1[PIXEL_ALPHA] = 0;
+
+ pixel2[PIXEL_RED] = MAX_CHANNEL_VALUE;
+ pixel2[PIXEL_GREEN] = MAX_CHANNEL_VALUE;
+ pixel2[PIXEL_BLUE] = MAX_CHANNEL_VALUE;
+ pixel2[PIXEL_ALPHA] = MAX_CHANNEL_VALUE;
+
+ weights[0] = 89;
+ weights[1] = 166;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK(outputPixel[PIXEL_RED], MAX_CHANNEL_VALUE);
+ CHECK(outputPixel[PIXEL_GREEN], MAX_CHANNEL_VALUE);
+ CHECK(outputPixel[PIXEL_BLUE], MAX_CHANNEL_VALUE);
+ CHECK_TOLERANCE(outputPixel[PIXEL_ALPHA], (89 * 0 + 166 * MAX_CHANNEL_VALUE) / 255, 5);
+}
+
+#define PIXELS_WIDTH 2
+#define PIXELS_HEIGHT 2
+
+void KisRgbF32ColorSpaceTester::testToQImage()
+{
+ KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile());
+
+ KisAbstractColorSpace * cs = new KisRgbF32ColorSpace(profile);
+
+ KisRgbF32ColorSpace::Pixel pixels[PIXELS_WIDTH * PIXELS_HEIGHT] = {
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4},
+ {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2},
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE},
+ {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE}
+ };
+
+ QImage image = cs->convertToQImage(reinterpret_cast<const Q_UINT8 *>(pixels), PIXELS_WIDTH, PIXELS_HEIGHT, 0, 0);
+
+ QRgb c = image.pixel(0, 0);
+
+ // Exposure comes into play here.
+ /*
+ CHECK(qRed(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qGreen(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qBlue(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qAlpha(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 4));
+
+ c = image.pixel(1, 0);
+
+ CHECK(qRed(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 3));
+ CHECK(qGreen(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2));
+ CHECK(qBlue(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 4));
+ CHECK(qAlpha(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE / 2));
+
+ c = image.pixel(0, 1);
+
+ CHECK(qRed(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qGreen(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qBlue(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qAlpha(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE));
+
+ c = image.pixel(1, 1);
+
+ CHECK(qRed(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE));
+ CHECK(qGreen(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE));
+ CHECK(qBlue(c), (int)FLOAT_TO_UINT8(MIN_CHANNEL_VALUE));
+ CHECK(qAlpha(c), (int)FLOAT_TO_UINT8(MAX_CHANNEL_VALUE));
+ */
+}
+
+#define NUM_ROWS 2
+#define NUM_COLUMNS 2
+#define SRC_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE)
+#define DST_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE)
+#define MASK_ROW_STRIDE NUM_COLUMNS
+
+/*
+1 alpha 1 0 alpha 1
+1 alpha 0.5 0 alpha 1
+1 alpha 0.5 0 alpha 0.5
+1 alpha 0 0 alpha 0.5
+
+*/
+
+void KisRgbF32ColorSpaceTester::testCompositeOps()
+{
+ KisProfile *profile = new KisProfile(cmsCreate_sRGBProfile());
+
+ KisRgbF32ColorSpace *cs = new KisRgbF32ColorSpace(profile);
+
+ KisRgbF32ColorSpace::Pixel srcPixel;
+ KisRgbF32ColorSpace::Pixel dstPixel;
+
+ srcPixel.red = UINT8_TO_FLOAT(102);
+ srcPixel.green = UINT8_TO_FLOAT(170);
+ srcPixel.blue = UINT8_TO_FLOAT(238);
+ srcPixel.alpha = F32_OPACITY_OPAQUE;
+
+ dstPixel = srcPixel;
+
+ cs->compositeDivide(reinterpret_cast<Q_UINT8 *>(&dstPixel), 1, reinterpret_cast<const Q_UINT8 *>(&srcPixel),
+ 1, 0, 0, 1, 1, F32_OPACITY_OPAQUE);
+ /*
+ CHECK(dstPixel.red, (Q_UINT16)UINT8_TO_UINT16(253));
+ CHECK(dstPixel.green, (Q_UINT16)UINT8_TO_UINT16(254));
+ CHECK(dstPixel.blue, (Q_UINT16)UINT8_TO_UINT16(254));
+ CHECK(dstPixel.alpha, KisRgbF32ColorSpace::F32_OPACITY_OPAQUE);
+
+ Q_UINT16 srcColor = 43690;
+ Q_UINT16 dstColor = 43690;
+
+ srcColor = QMIN((dstColor * (65535u + 1u) + (srcColor / 2u)) / (1u + srcColor), 65535u);
+
+ CHECK((int)srcColor, 65534);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, 65535u);
+
+ CHECK((int)newColor, 65534);
+ */
+
+ /*
+ KisRgbF32ColorSpace::Pixel srcPixels[NUM_ROWS * NUM_COLUMNS] = {
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4},
+ {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2},
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE},
+ {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE}
+ };
+
+ KisRgbF32ColorSpace::Pixel dstPixels[NUM_ROWS * NUM_COLUMNS] = {
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4},
+ {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2},
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE},
+ {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE}
+ };
+
+ cs->compositeOver(reinterpret_cast<Q_UINT8 *>(dstPixels), DST_ROW_STRIDE, reinterpret_cast<const Q_UINT8 *>(srcPixels),
+ SRC_ROW_STRIDE, mask, MASK_ROW_STRIDE, NUM_ROWS, NUM_COLUMNS, opacity);
+ */
+
+ delete cs;
+}
+
diff --git a/krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.h b/krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.h
new file mode 100644
index 00000000..d6e47704
--- /dev/null
+++ b/krita/colorspaces/rgb_f32/tests/kis_strategy_colorspace_rgb_f32_tester.h
@@ -0,0 +1,47 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_RGB_F32_TESTER_H
+#define KIS_STRATEGY_COLORSPACE_RGB_F32_TESTER_H
+
+#include <kunittest/tester.h>
+
+#define CHECK_TOLERANCE( x, y, tolerance ) \
+if ((x) <= (y) + (tolerance) && (x) >= (y) - (tolerance)) \
+{ \
+ success(QString(__FILE__) + "[" + QString::number(__LINE__) + "]: passed " + #x); \
+} \
+else \
+{ \
+ failure(QString(__FILE__) + "[" + QString::number(__LINE__) + QString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + QString::number(x)); \
+} \
+
+class KisRgbF32ColorSpaceTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+ void testBasics();
+ void testMixColors();
+ void testToQImage();
+ void testCompositeOps();
+};
+
+#endif
+
diff --git a/krita/colorspaces/rgb_u16/Makefile.am b/krita/colorspaces/rgb_u16/Makefile.am
new file mode 100644
index 00000000..927debfa
--- /dev/null
+++ b/krita/colorspaces/rgb_u16/Makefile.am
@@ -0,0 +1,32 @@
+# location for the rc file
+kde_services_DATA = krita_rgb_u16_plugin.desktop
+
+INCLUDES = -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../kritacolor \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+lib_LTLIBRARIES = libkrita_rgb_u16.la
+libkrita_rgb_u16_la_SOURCES = kis_rgb_u16_colorspace.cc
+libkrita_rgb_u16_la_LDFLAGS = $(all_libraries)
+libkrita_rgb_u16_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = krita_rgb_u16_plugin.la
+
+# Srcs for the plugin
+krita_rgb_u16_plugin_la_SOURCES = rgb_u16_plugin.cc
+noinst_HEADERS = rgb_u16_plugin.h kis_rgb_u16_colorspace.h
+
+krita_rgb_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+krita_rgb_u16_plugin_la_LIBADD = libkrita_rgb_u16.la ../../kritacolor/libkritacolor.la
+
+krita_rgb_u16_plugin_la_METASOURCES = AUTO
+
+if include_kunittest_tests
+TESTSDIR = tests
+endif
+
+SUBDIRS = . $(TESTSDIR)
+
diff --git a/krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc b/krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc
new file mode 100644
index 00000000..7ec94671
--- /dev/null
+++ b/krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.cc
@@ -0,0 +1,869 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <[email protected]>
+ * Copyright (c) 2004 Boudewijn Rempt <[email protected]>
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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 <qimage.h>
+#include <qcolor.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+#include <kglobal.h>
+
+#include "kis_rgb_u16_colorspace.h"
+#include "kis_u16_base_colorspace.h"
+#include "kis_color_conversions.h"
+#include "kis_integer_maths.h"
+
+namespace {
+ const Q_INT32 MAX_CHANNEL_RGB = 3;
+ const Q_INT32 MAX_CHANNEL_RGBA = 4;
+}
+
+// XXX: already defined is superclass?
+//const Q_UINT16 KisRgbU16ColorSpace::U16_OPACITY_OPAQUE;
+//const Q_UINT16 KisRgbU16ColorSpace::U16_OPACITY_TRANSPARENT;
+
+KisRgbU16ColorSpace::KisRgbU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) :
+ KisU16BaseColorSpace(KisID("RGBA16", i18n("RGB (16-bit integer/channel)")), TYPE_BGRA_16, icSigRgbData, parent, p)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Red"), i18n("R"), PIXEL_RED * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), QColor(255,0,0)));
+ m_channels.push_back(new KisChannelInfo(i18n("Green"), i18n("G"), PIXEL_GREEN * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), QColor(0,255,0)));
+ m_channels.push_back(new KisChannelInfo(i18n("Blue"), i18n("B"), PIXEL_BLUE * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16), QColor(0,0,255)));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), PIXEL_ALPHA * sizeof(Q_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(Q_UINT16)));
+
+ m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT16);
+
+ init();
+}
+
+KisRgbU16ColorSpace::~KisRgbU16ColorSpace()
+{
+}
+
+void KisRgbU16ColorSpace::setPixel(Q_UINT8 *dst, Q_UINT16 red, Q_UINT16 green, Q_UINT16 blue, Q_UINT16 alpha) const
+{
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->red = red;
+ dstPixel->green = green;
+ dstPixel->blue = blue;
+ dstPixel->alpha = alpha;
+}
+
+void KisRgbU16ColorSpace::getPixel(const Q_UINT8 *src, Q_UINT16 *red, Q_UINT16 *green, Q_UINT16 *blue, Q_UINT16 *alpha) const
+{
+ const Pixel *srcPixel = reinterpret_cast<const Pixel *>(src);
+
+ *red = srcPixel->red;
+ *green = srcPixel->green;
+ *blue = srcPixel->blue;
+ *alpha = srcPixel->alpha;
+}
+
+void KisRgbU16ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+ Q_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel *pixel = reinterpret_cast<const Pixel *>(*colors);
+
+ Q_UINT32 alpha = pixel->alpha;
+ Q_UINT32 alphaTimesWeight = UINT16_MULT(alpha, UINT8_TO_UINT16(*weights));
+
+ totalRed += UINT16_MULT(pixel->red, alphaTimesWeight);
+ totalGreen += UINT16_MULT(pixel->green, alphaTimesWeight);
+ totalBlue += UINT16_MULT(pixel->blue, alphaTimesWeight);
+ newAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ Q_ASSERT(newAlpha <= U16_OPACITY_OPAQUE);
+
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->alpha = newAlpha;
+
+ if (newAlpha > 0) {
+ totalRed = UINT16_DIVIDE(totalRed, newAlpha);
+ totalGreen = UINT16_DIVIDE(totalGreen, newAlpha);
+ totalBlue = UINT16_DIVIDE(totalBlue, newAlpha);
+ }
+
+ dstPixel->red = totalRed;
+ dstPixel->green = totalGreen;
+ dstPixel->blue = totalBlue;
+}
+
+
+void KisRgbU16ColorSpace::convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst,
+ Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const
+{
+ Q_INT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel * pixel = reinterpret_cast<const Pixel *>( *colors );
+
+ Q_INT32 weight = *kernelValues;
+
+ if (weight != 0) {
+ totalRed += pixel->red * weight;
+ totalGreen += pixel->green * weight;
+ totalBlue += pixel->blue * weight;
+ totalAlpha +=pixel->alpha * weight;
+ }
+ colors++;
+ kernelValues++;
+ }
+
+ Pixel * p = reinterpret_cast< Pixel *>( dst );
+
+ if (channelFlags & KisChannelInfo::FLAG_COLOR) {
+ p->red = CLAMP( ( totalRed / factor) + offset, 0, Q_UINT16_MAX);
+ p->green = CLAMP( ( totalGreen / factor) + offset, 0, Q_UINT16_MAX);
+ p->blue = CLAMP( ( totalBlue / factor) + offset, 0, Q_UINT16_MAX);
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ p->alpha = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT16_MAX);
+ }
+}
+
+
+void KisRgbU16ColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels)
+{
+ Q_UINT32 psize = pixelSize();
+
+ while (nPixels--)
+ {
+ Pixel * p = reinterpret_cast< Pixel *>( src );
+ p->red = Q_UINT16_MAX - p->red;
+ p->green = Q_UINT16_MAX - p->green;
+ p->blue = Q_UINT16_MAX - p->blue;
+ src += psize;
+ }
+}
+
+Q_UINT8 KisRgbU16ColorSpace::intensity8(const Q_UINT8 * src) const
+{
+ const Pixel * p = reinterpret_cast<const Pixel *>( src );
+
+ return UINT16_TO_UINT8(static_cast<Q_UINT16>((p->red * 0.30 + p->green * 0.59 + p->blue * 0.11) + 0.5));
+}
+
+
+QValueVector<KisChannelInfo *> KisRgbU16ColorSpace::channels() const
+{
+ return m_channels;
+}
+
+Q_UINT32 KisRgbU16ColorSpace::nChannels() const
+{
+ return MAX_CHANNEL_RGBA;
+}
+
+Q_UINT32 KisRgbU16ColorSpace::nColorChannels() const
+{
+ return MAX_CHANNEL_RGB;
+}
+
+Q_UINT32 KisRgbU16ColorSpace::pixelSize() const
+{
+ return MAX_CHANNEL_RGBA * sizeof(Q_UINT16);
+}
+
+
+void KisRgbU16ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT16 *src = reinterpret_cast<const Q_UINT16 *>(srcRowStart);
+ Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(dstRowStart);
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ Q_UINT16 srcAlpha = src[PIXEL_ALPHA];
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask));
+ }
+ mask++;
+ }
+
+ if (srcAlpha != U16_OPACITY_TRANSPARENT) {
+
+ if (opacity != U16_OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, opacity);
+ }
+
+ if (srcAlpha == U16_OPACITY_OPAQUE) {
+ memcpy(dst, src, MAX_CHANNEL_RGBA * sizeof(Q_UINT16));
+ } else {
+ Q_UINT16 dstAlpha = dst[PIXEL_ALPHA];
+
+ Q_UINT16 srcBlend;
+
+ if (dstAlpha == U16_OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_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, MAX_CHANNEL_RGB * sizeof(Q_UINT16));
+ } else {
+ dst[PIXEL_RED] = UINT16_BLEND(src[PIXEL_RED], dst[PIXEL_RED], srcBlend);
+ dst[PIXEL_GREEN] = UINT16_BLEND(src[PIXEL_GREEN], dst[PIXEL_GREEN], srcBlend);
+ dst[PIXEL_BLUE] = UINT16_BLEND(src[PIXEL_BLUE], dst[PIXEL_BLUE], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart) {
+ maskRowStart += maskRowStride;
+ }
+ }
+}
+
+#define COMMON_COMPOSITE_OP_PROLOG() \
+ while (rows > 0) { \
+ \
+ const Q_UINT16 *src = reinterpret_cast<const Q_UINT16 *>(srcRowStart); \
+ Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(dstRowStart); \
+ Q_INT32 columns = numColumns; \
+ const Q_UINT8 *mask = maskRowStart; \
+ \
+ while (columns > 0) { \
+ \
+ Q_UINT16 srcAlpha = src[PIXEL_ALPHA]; \
+ Q_UINT16 dstAlpha = dst[PIXEL_ALPHA]; \
+ \
+ srcAlpha = QMIN(srcAlpha, dstAlpha); \
+ \
+ if (mask != 0) { \
+ Q_UINT8 U8_mask = *mask; \
+ \
+ if (U8_mask != OPACITY_OPAQUE) { \
+ srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask)); \
+ } \
+ mask++; \
+ } \
+ \
+ if (srcAlpha != U16_OPACITY_TRANSPARENT) { \
+ \
+ if (opacity != U16_OPACITY_OPAQUE) { \
+ srcAlpha = UINT16_MULT(srcAlpha, opacity); \
+ } \
+ \
+ Q_UINT16 srcBlend; \
+ \
+ if (dstAlpha == U16_OPACITY_OPAQUE) { \
+ srcBlend = srcAlpha; \
+ } else { \
+ Q_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 += MAX_CHANNEL_RGBA; \
+ dst += MAX_CHANNEL_RGBA; \
+ } \
+ \
+ rows--; \
+ srcRowStart += srcRowStride; \
+ dstRowStart += dstRowStride; \
+ if(maskRowStart) { \
+ maskRowStart += maskRowStride; \
+ } \
+ }
+
+void KisRgbU16ColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = UINT16_MULT(srcColor, dstColor);
+
+ dst[channel] = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT16_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT16_MAX);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = UINT16_MAX - UINT16_MULT(UINT16_MAX - dstColor, UINT16_MAX - srcColor);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = UINT16_MULT(dstColor, dstColor + 2u * UINT16_MULT(srcColor, UINT16_MAX - dstColor));
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT16_MAX + 1u)) / (UINT16_MAX + 1u - srcColor), UINT16_MAX);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = kMin(((UINT16_MAX - dstColor) * (UINT16_MAX + 1u)) / (srcColor + 1u), UINT16_MAX);
+ srcColor = kClamp(UINT16_MAX - srcColor, 0u, UINT16_MAX);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMIN(srcColor, dstColor);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT16 srcColor = src[channel];
+ Q_UINT16 dstColor = dst[channel];
+
+ srcColor = QMAX(srcColor, dstColor);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeHue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float FSrcRed = static_cast<float>(src[PIXEL_RED]) / UINT16_MAX;
+ float FSrcGreen = static_cast<float>(src[PIXEL_GREEN]) / UINT16_MAX;
+ float FSrcBlue = static_cast<float>(src[PIXEL_BLUE]) / UINT16_MAX;
+
+ Q_UINT16 dstRed = dst[PIXEL_RED];
+ Q_UINT16 dstGreen = dst[PIXEL_GREEN];
+ Q_UINT16 dstBlue = dst[PIXEL_BLUE];
+
+ float FDstRed = static_cast<float>(dstRed) / UINT16_MAX;
+ float FDstGreen = static_cast<float>(dstGreen) / UINT16_MAX;
+ float FDstBlue = static_cast<float>(dstBlue) / UINT16_MAX;
+
+ float srcHue;
+ float srcSaturation;
+ float srcValue;
+
+ float dstHue;
+ float dstSaturation;
+ float dstValue;
+
+ RGBToHSV(FSrcRed, FSrcGreen, FSrcBlue, &srcHue, &srcSaturation, &srcValue);
+ RGBToHSV(FDstRed, FDstGreen, FDstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ HSVToRGB(srcHue, dstSaturation, dstValue, &FSrcRed, &FSrcGreen, &FSrcBlue);
+
+ Q_UINT16 srcRed = static_cast<Q_UINT16>(FSrcRed * UINT16_MAX + 0.5);
+ Q_UINT16 srcGreen = static_cast<Q_UINT16>(FSrcGreen * UINT16_MAX + 0.5);
+ Q_UINT16 srcBlue = static_cast<Q_UINT16>(FSrcBlue * UINT16_MAX + 0.5);
+
+ dst[PIXEL_RED] = UINT16_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = UINT16_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = UINT16_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeSaturation(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float FSrcRed = static_cast<float>(src[PIXEL_RED]) / UINT16_MAX;
+ float FSrcGreen = static_cast<float>(src[PIXEL_GREEN]) / UINT16_MAX;
+ float FSrcBlue = static_cast<float>(src[PIXEL_BLUE]) / UINT16_MAX;
+
+ Q_UINT16 dstRed = dst[PIXEL_RED];
+ Q_UINT16 dstGreen = dst[PIXEL_GREEN];
+ Q_UINT16 dstBlue = dst[PIXEL_BLUE];
+
+ float FDstRed = static_cast<float>(dstRed) / UINT16_MAX;
+ float FDstGreen = static_cast<float>(dstGreen) / UINT16_MAX;
+ float FDstBlue = static_cast<float>(dstBlue) / UINT16_MAX;
+
+ float srcHue;
+ float srcSaturation;
+ float srcValue;
+
+ float dstHue;
+ float dstSaturation;
+ float dstValue;
+
+ RGBToHSV(FSrcRed, FSrcGreen, FSrcBlue, &srcHue, &srcSaturation, &srcValue);
+ RGBToHSV(FDstRed, FDstGreen, FDstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ HSVToRGB(dstHue, srcSaturation, dstValue, &FSrcRed, &FSrcGreen, &FSrcBlue);
+
+ Q_UINT16 srcRed = static_cast<Q_UINT16>(FSrcRed * UINT16_MAX + 0.5);
+ Q_UINT16 srcGreen = static_cast<Q_UINT16>(FSrcGreen * UINT16_MAX + 0.5);
+ Q_UINT16 srcBlue = static_cast<Q_UINT16>(FSrcBlue * UINT16_MAX + 0.5);
+
+ dst[PIXEL_RED] = UINT16_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = UINT16_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = UINT16_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeValue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float FSrcRed = static_cast<float>(src[PIXEL_RED]) / UINT16_MAX;
+ float FSrcGreen = static_cast<float>(src[PIXEL_GREEN]) / UINT16_MAX;
+ float FSrcBlue = static_cast<float>(src[PIXEL_BLUE]) / UINT16_MAX;
+
+ Q_UINT16 dstRed = dst[PIXEL_RED];
+ Q_UINT16 dstGreen = dst[PIXEL_GREEN];
+ Q_UINT16 dstBlue = dst[PIXEL_BLUE];
+
+ float FDstRed = static_cast<float>(dstRed) / UINT16_MAX;
+ float FDstGreen = static_cast<float>(dstGreen) / UINT16_MAX;
+ float FDstBlue = static_cast<float>(dstBlue) / UINT16_MAX;
+
+ float srcHue;
+ float srcSaturation;
+ float srcValue;
+
+ float dstHue;
+ float dstSaturation;
+ float dstValue;
+
+ RGBToHSV(FSrcRed, FSrcGreen, FSrcBlue, &srcHue, &srcSaturation, &srcValue);
+ RGBToHSV(FDstRed, FDstGreen, FDstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ HSVToRGB(dstHue, dstSaturation, srcValue, &FSrcRed, &FSrcGreen, &FSrcBlue);
+
+ Q_UINT16 srcRed = static_cast<Q_UINT16>(FSrcRed * UINT16_MAX + 0.5);
+ Q_UINT16 srcGreen = static_cast<Q_UINT16>(FSrcGreen * UINT16_MAX + 0.5);
+ Q_UINT16 srcBlue = static_cast<Q_UINT16>(FSrcBlue * UINT16_MAX + 0.5);
+
+ dst[PIXEL_RED] = UINT16_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = UINT16_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = UINT16_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeColor(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT16 opacity)
+{
+ COMMON_COMPOSITE_OP_PROLOG();
+
+ {
+ float FSrcRed = static_cast<float>(src[PIXEL_RED]) / UINT16_MAX;
+ float FSrcGreen = static_cast<float>(src[PIXEL_GREEN]) / UINT16_MAX;
+ float FSrcBlue = static_cast<float>(src[PIXEL_BLUE]) / UINT16_MAX;
+
+ Q_UINT16 dstRed = dst[PIXEL_RED];
+ Q_UINT16 dstGreen = dst[PIXEL_GREEN];
+ Q_UINT16 dstBlue = dst[PIXEL_BLUE];
+
+ float FDstRed = static_cast<float>(dstRed) / UINT16_MAX;
+ float FDstGreen = static_cast<float>(dstGreen) / UINT16_MAX;
+ float FDstBlue = static_cast<float>(dstBlue) / UINT16_MAX;
+
+ float srcHue;
+ float srcSaturation;
+ float srcLightness;
+
+ float dstHue;
+ float dstSaturation;
+ float dstLightness;
+
+ RGBToHSL(FSrcRed, FSrcGreen, FSrcBlue, &srcHue, &srcSaturation, &srcLightness);
+ RGBToHSL(FDstRed, FDstGreen, FDstBlue, &dstHue, &dstSaturation, &dstLightness);
+
+ HSLToRGB(srcHue, srcSaturation, dstLightness, &FSrcRed, &FSrcGreen, &FSrcBlue);
+
+ Q_UINT16 srcRed = static_cast<Q_UINT16>(FSrcRed * UINT16_MAX + 0.5);
+ Q_UINT16 srcGreen = static_cast<Q_UINT16>(FSrcGreen * UINT16_MAX + 0.5);
+ Q_UINT16 srcBlue = static_cast<Q_UINT16>(FSrcBlue * UINT16_MAX + 0.5);
+
+ dst[PIXEL_RED] = UINT16_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = UINT16_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = UINT16_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ COMMON_COMPOSITE_OP_EPILOG();
+}
+
+void KisRgbU16ColorSpace::compositeErase(Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT16 /*opacity*/)
+{
+ while (rows-- > 0)
+ {
+ const Pixel *s = reinterpret_cast<const Pixel *>(src);
+ Pixel *d = reinterpret_cast<Pixel *>(dst);
+ const Q_UINT8 *mask = srcAlphaMask;
+
+ for (Q_INT32 i = cols; i > 0; i--, s++, d++)
+ {
+ Q_UINT16 srcAlpha = s->alpha;
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_mask));
+ }
+ mask++;
+ }
+ d->alpha = UINT16_MULT(srcAlpha, d->alpha);
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ if(srcAlphaMask) {
+ srcAlphaMask += maskRowStride;
+ }
+ }
+}
+
+void KisRgbU16ColorSpace::bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *mask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 U8_opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op)
+{
+ Q_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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIVIDE:
+ compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LIGHTEN:
+ compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_HUE:
+ compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SATURATION:
+ compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_VALUE:
+ compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COLOR:
+ compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_OVERLAY:
+ compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DODGE:
+ compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BURN:
+ compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ALPHA_DARKEN:
+ abstractCompositeAlphaDarken<Q_UINT16, U16Mult, Uint8ToU16, U16OpacityTest,
+ PIXEL_ALPHA, MAX_CHANNEL_RGB, MAX_CHANNEL_RGBA>(
+ dst, dstRowStride, src, srcRowStride, mask, maskRowStride,
+ rows, cols, opacity, U16Mult(), Uint8ToU16(), U16OpacityTest());
+ break;
+ default:
+ break;
+ }
+}
+
+KisCompositeOpList KisRgbU16ColorSpace::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));
+ list.append(KisCompositeOp(COMPOSITE_HUE));
+ list.append(KisCompositeOp(COMPOSITE_SATURATION));
+ list.append(KisCompositeOp(COMPOSITE_VALUE));
+ list.append(KisCompositeOp(COMPOSITE_COLOR));
+
+ return list;
+}
diff --git a/krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h b/krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h
new file mode 100644
index 00000000..73a79eb3
--- /dev/null
+++ b/krita/colorspaces/rgb_u16/kis_rgb_u16_colorspace.h
@@ -0,0 +1,128 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <[email protected]>
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_RGB_U16_H_
+#define KIS_STRATEGY_COLORSPACE_RGB_U16_H_
+
+#include <klocale.h>
+
+#include <koffice_export.h>
+
+#include "kis_global.h"
+#include "kis_u16_base_colorspace.h"
+#include "kis_integer_maths.h"
+
+
+class KRITATOOL_EXPORT KisRgbU16ColorSpace : public KisU16BaseColorSpace {
+public:
+
+ struct Pixel {
+ Q_UINT16 blue;
+ Q_UINT16 green;
+ Q_UINT16 red;
+ Q_UINT16 alpha;
+ };
+public:
+ KisRgbU16ColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p);
+ virtual ~KisRgbU16ColorSpace();
+
+ virtual bool willDegrade(ColorSpaceIndependence independence)
+ {
+ if (independence == TO_RGBA8)
+ return true;
+ else
+ return false;
+ };
+
+
+
+public:
+ void setPixel(Q_UINT8 *pixel, Q_UINT16 red, Q_UINT16 green, Q_UINT16 blue, Q_UINT16 alpha) const;
+ void getPixel(const Q_UINT8 *pixel, Q_UINT16 *red, Q_UINT16 *green, Q_UINT16 *blue, Q_UINT16 *alpha) const;
+
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+ virtual void convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const;
+ virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels);
+ virtual Q_UINT8 intensity8(const Q_UINT8 * src) const;
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+protected:
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeHue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeSaturation(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeValue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeColor(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+ void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT16 opacity);
+
+private:
+ friend class KisRgbU16ColorSpaceTester;
+
+ static const Q_UINT8 PIXEL_BLUE = 0;
+ static const Q_UINT8 PIXEL_GREEN = 1;
+ static const Q_UINT8 PIXEL_RED = 2;
+ static const Q_UINT8 PIXEL_ALPHA = 3;
+};
+
+class KisRgbU16ColorSpaceFactory : public KisColorSpaceFactory
+{
+public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("RGBA16", i18n("RGB (16-bit integer/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return TYPE_BGRA_16; };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisRgbU16ColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return "sRGB built-in - (lcms internal)"; };
+};
+
+#endif // KIS_STRATEGY_COLORSPACE_RGB_U16_H_
diff --git a/krita/colorspaces/rgb_u16/krita_rgb_u16_plugin.desktop b/krita/colorspaces/rgb_u16/krita_rgb_u16_plugin.desktop
new file mode 100644
index 00000000..4cf76766
--- /dev/null
+++ b/krita/colorspaces/rgb_u16/krita_rgb_u16_plugin.desktop
@@ -0,0 +1,80 @@
+[Desktop Entry]
+Name=RGB Color Model (16-bit integer)
+Name[bg]=Цветови модел RGB (16 бита)
+Name[ca]=Model de color RGB (enter de 16 bits)
+Name[cy]=Model Lliw RGB (cyfanrif 16-did)
+Name[da]=RGB-farvemodel (16-bit heltal)
+Name[de]=RGB-Farbmodell (16-bit Ganzzahl)
+Name[el]=Χρωματικό μοντέλο RGB (16 bit ακέραιοι)
+Name[en_GB]=RGB Colour Model (16-bit integer)
+Name[eo]=RGB-kolormodelo (16-bita entjero)
+Name[es]=Modelo de color RGB (entero de 16 bits)
+Name[et]=RGB värvimudel (16-bitine täisarv)
+Name[fa]=مدل رنگ RGB )عدد صحیح ۱۶ بیتی(
+Name[fr]=Modèle de couleurs RVB (entiers 16 bits)
+Name[fy]=RGB-kleurmodel (16-bit integer)
+Name[gl]=Modelo de Cores RGB (inteiros de 16-bit)
+Name[he]=מודל צבעים RGB (16 סיביות)
+Name[hu]=RGB színmodell (16 bites egész)
+Name[is]=RGB litategund (16-bita heiltala)
+Name[it]=Modello di colore RGB (intero a 16 bit)
+Name[ja]=RGB カラーモデル (16 ビット整数)
+Name[km]=គំរូ​ពណ៌ RGB (ចំនួនគត់ 16 ប៊ីត)
+Name[lt]=RGB spalvų modelis (16-bitų sveikasis)
+Name[nb]=RGB-fargemodell (16-bit heltall)
+Name[nds]=RGB-Klöörmodell (16-Bit Heeltall)
+Name[ne]=RGB रङ मोडेल (१६-बिट इन्टिजर)
+Name[nl]=RGB-kleurmodel (16-bit integer)
+Name[pl]=Przestrzeń barw RGB (16-bitowa liczba całkowita)
+Name[pt]=Modelo de Cor RGB (inteiro de 16-bits)
+Name[pt_BR]=Modelo de Cor RGB (inteiro de 16-bits)
+Name[ru]=RGB (целое 16-бит)
+Name[sk]=Model farieb RGB (16-bitové čísla)
+Name[sl]=Barvni model RGB (16-bitno celo število)
+Name[sr]=RGB модел боја (16-битно целобројно)
+Name[sr@Latn]=RGB model boja (16-bitno celobrojno)
+Name[sv]=RGB-färgmodell (16-bitars heltal)
+Name[uk]=Модель кольору RGB (16-бітне ціле число)
+Name[uz]=RGB rang usuli (16-bit butun)
+Name[uz@cyrillic]=RGB ранг усули (16-бит бутун)
+Name[zh_TW]=RGB 色彩模型 (16-bit 整數)
+Comment=Color model for 16-bit integer per channel RGB images
+Comment[bg]=Цветови модел за 16 битови изображения RGB
+Comment[ca]=Model de color enter de 16 bits per canal d'imatges RGB
+Comment[cy]=Model lliw ar gyfer delweddau RGB â chyfanrif 16-did/sianel
+Comment[da]=Farvemodel for 16-bit heltal pr kanal RGB-billeder
+Comment[de]=Farbmodell für 16-bit Ganzzahl pro Kanal RGB-Bilder
+Comment[el]=Χρωματικό μοντέλο για 16-bit ακέραιους ανά κανάλι RGB εικόνες
+Comment[en_GB]=Colour model for 16-bit integer per channel RGB images
+Comment[es]=Modelo de color de entero de 16 bits por canal para imágenes RGB
+Comment[et]=16-bitiste täisarvuliste kanalitega RGB-piltide värvimudel
+Comment[fa]=مدل رنگ برای عدد صحیح ۱۶ بیتی برای هر تصویر RGB مجرا
+Comment[fr]=Modèle de couleurs pour des images RVB en 16 bits/plage
+Comment[fy]=Kleurmodel foar RGB-ôfbyldings mei16-bit/kanaal
+Comment[gl]=Modelo de cores para imaxes RGB de inteiro de 16-bit por canal
+Comment[he]=מודל צבעים עבור תמונות RGB של 16 סיביות/ערוצים
+Comment[hu]=Színmodell 16 bites egész/csatorna RGB képekhez
+Comment[is]=Litategund fyrir 16-bita heiltölu á rás RGB myndir
+Comment[it]=Modello di colore per immagini RGB in interi a canale di 16 bit
+Comment[ja]=16 ビット整数/チャンネル RGB 画像のためのカラーモデル
+Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព RGB ចំនួនគត់ 16 ប៊ីត​ក្នុង​មួយ​ឆានែល
+Comment[nb]=Fargemodell for RGB-bilde med 16 bit heltall per kanal
+Comment[nds]=Klöörmodell för RGB-Biller mit 16-Bit Heeltall per Kanaal
+Comment[ne]=प्रति च्यानल RGB छविहरूको १६-बिट इन्टिजरका लागि रङ मोडेल
+Comment[nl]=Kleurmodel voor RGB-afbeeldingen met 16-bit/kanaal
+Comment[pl]=Przestrzeń barw dla obrazków RGB o 16-bitowych liczbach całkowitych na kanał
+Comment[pt]=Modelo de cor para imagens RGB com 16 bits por canal
+Comment[pt_BR]=Modelo de cor para imagens RGB com 16 bits por canal
+Comment[ru]=Цветовое пространство RGB (целое 16-бит/канал)
+Comment[sk]=Model farieb pre RGB obrázky so 16-bitovými číslami na kanál
+Comment[sl]=Barvni model za slike RGB s 16-bitnim celim številom na kanal
+Comment[sr]=Модел боја за RGB слике, 16-битно целобројно по каналу
+Comment[sr@Latn]=Model boja za RGB slike, 16-bitno celobrojno po kanalu
+Comment[sv]=Färgmodell för 16-bitars heltal/kanal RGB-bilder
+Comment[uk]=Модель кольорів для зображень RGB 32-біт ціле число на канал
+Comment[zh_TW]=每色頻 16-bit 整數 RGB 圖片的色彩模型
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-KDE-Library=krita_rgb_u16_plugin
+X-Krita-Version=2
+
diff --git a/krita/colorspaces/rgb_u16/rgb_u16_plugin.cc b/krita/colorspaces/rgb_u16/rgb_u16_plugin.cc
new file mode 100644
index 00000000..0f88b158
--- /dev/null
+++ b/krita/colorspaces/rgb_u16/rgb_u16_plugin.cc
@@ -0,0 +1,61 @@
+/*
+* rgb_u16_plugin.cc -- Part of Krita
+*
+* Copyright (c) 2004 Boudewijn Rempt ([email protected])
+* Copyright (c) 2005 Adrian Page <[email protected]>
+*
+* 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 <kinstance.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <kis_debug_areas.h>
+#include <kis_colorspace_factory_registry.h>
+
+#include "rgb_u16_plugin.h"
+#include "kis_rgb_u16_colorspace.h"
+#include "kis_basic_histogram_producers.h"
+
+typedef KGenericFactory<RGBU16Plugin> RGBU16PluginFactory;
+K_EXPORT_COMPONENT_FACTORY( krita_rgb_u16_plugin, RGBU16PluginFactory( "krita" ) )
+
+
+RGBU16Plugin::RGBU16Plugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(RGBU16PluginFactory::instance());
+
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") )
+ {
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry *>( parent );
+
+ KisColorSpace * colorSpaceRGBU16 = new KisRgbU16ColorSpace(f, 0);
+ KisColorSpaceFactory * csFactory = new KisRgbU16ColorSpaceFactory();
+ f->add( csFactory );
+
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicU16HistogramProducer>
+ (KisID("RGB16HISTO", i18n("RGB16")), colorSpaceRGBU16) );
+ }
+
+}
+
+RGBU16Plugin::~RGBU16Plugin()
+{
+}
+
+#include "rgb_u16_plugin.moc"
diff --git a/krita/colorspaces/rgb_u16/rgb_u16_plugin.h b/krita/colorspaces/rgb_u16/rgb_u16_plugin.h
new file mode 100644
index 00000000..643833ce
--- /dev/null
+++ b/krita/colorspaces/rgb_u16/rgb_u16_plugin.h
@@ -0,0 +1,36 @@
+/*
+ * Copyright (c) 2003 Boudewijn Rempt ([email protected])
+ *
+ * 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 RGB_U16_PLUGIN_H_
+#define RGB_U16_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the RGB U16 colour space strategy.
+ */
+class RGBU16Plugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ RGBU16Plugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~RGBU16Plugin();
+};
+
+
+#endif // RGB_U16_PLUGIN_H_
diff --git a/krita/colorspaces/rgb_u16/tests/Makefile.am b/krita/colorspaces/rgb_u16/tests/Makefile.am
new file mode 100644
index 00000000..f8c8dc36
--- /dev/null
+++ b/krita/colorspaces/rgb_u16/tests/Makefile.am
@@ -0,0 +1,17 @@
+AM_CPPFLAGS = -I$(srcdir)/.. \
+ -I$(srcdir)/../../../sdk \
+ -I$(srcdir)/../../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../../color_strategy/ \
+ $(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_strategy_colorspace_rgb_u16_tester.la
+
+kunittest_kis_strategy_colorspace_rgb_u16_tester_la_SOURCES = kis_strategy_colorspace_rgb_u16_tester.cc
+kunittest_kis_strategy_colorspace_rgb_u16_tester_la_LIBADD = -lkunittest ../libkrita_rgb_u16.la
+kunittest_kis_strategy_colorspace_rgb_u16_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
+
+check-local: kunittest_kis_strategy_colorspace_rgb_u16_tester.la
+ kunittestmodrunner
+
diff --git a/krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.cc b/krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.cc
new file mode 100644
index 00000000..b41d46bc
--- /dev/null
+++ b/krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.cc
@@ -0,0 +1,524 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_factory.h"
+#include "kis_strategy_colorspace_rgb_u16_tester.h"
+#include "kis_rgb_u16_colorspace.h"
+#include "kis_integer_maths.h"
+#include "kis_paint_device.h"
+
+using namespace KUnitTest;
+
+KUNITTEST_MODULE( kunittest_kis_strategy_colorspace_rgb_u16_tester, "RGB 16-bit integer colorspace tester" );
+KUNITTEST_MODULE_REGISTER_TESTER( KisRgbU16ColorSpaceTester );
+
+#define PIXEL_BLUE 0
+#define PIXEL_GREEN 1
+#define PIXEL_RED 2
+#define PIXEL_ALPHA 3
+
+#define NUM_CHANNELS 4
+#define NUM_COLOUR_CHANNELS 3
+#define CHANNEL_SIZE 2
+
+#define RED_CHANNEL 0
+#define GREEN_CHANNEL 1
+#define BLUE_CHANNEL 2
+#define ALPHA_CHANNEL 3
+
+#define MAX_CHANNEL_VALUE UINT16_MAX
+#define MIN_CHANNEL_VALUE UINT16_MIN
+
+void KisRgbU16ColorSpaceTester::allTests()
+{
+ // We need this so that the colour profile loading can operate without crashing.
+ KisFactory *factory = new KisFactory();
+
+ testBasics();
+ testToQImage();
+ testCompositeOps();
+ testMixColors();
+
+ delete factory;
+}
+
+void KisRgbU16ColorSpaceTester::testBasics()
+{
+ KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile());
+
+ KisRgbU16ColorSpace *cs = new KisRgbU16ColorSpace(defProfile);
+ KisAbstractColorSpace * csSP = cs;
+
+ CHECK(cs->hasAlpha(), true);
+ CHECK(cs->nChannels(), NUM_CHANNELS);
+ CHECK(cs->nColorChannels(), NUM_COLOUR_CHANNELS);
+ CHECK(cs->pixelSize(), NUM_CHANNELS * CHANNEL_SIZE);
+
+ QValueVector<KisChannelInfo *> channels = cs->channels();
+
+ // Red
+ CHECK(channels[0]->pos(), PIXEL_RED * CHANNEL_SIZE);
+ CHECK(channels[0]->size(), CHANNEL_SIZE);
+ CHECK(channels[0]->channelType(), COLOR);
+
+ // Green
+ CHECK(channels[1]->pos(), PIXEL_GREEN * CHANNEL_SIZE);
+ CHECK(channels[1]->size(), CHANNEL_SIZE);
+ CHECK(channels[1]->channelType(), COLOR);
+
+ // Blue
+ CHECK(channels[2]->pos(), PIXEL_BLUE * CHANNEL_SIZE);
+ CHECK(channels[2]->size(), CHANNEL_SIZE);
+ CHECK(channels[2]->channelType(), COLOR);
+
+ // Alpha
+ CHECK(channels[3]->pos(), PIXEL_ALPHA * CHANNEL_SIZE);
+ CHECK(channels[3]->size(), CHANNEL_SIZE);
+ CHECK(channels[3]->channelType(), ALPHA);
+
+ KisPaintDeviceSP pd = new KisPaintDevice(cs, "test");
+
+ KisRgbU16ColorSpace::Pixel defaultPixel;
+
+ memcpy(&defaultPixel, pd->dataManager()->defaultPixel(), sizeof(defaultPixel));
+
+ CHECK((int)defaultPixel.red, 0);
+ CHECK((int)defaultPixel.green, 0);
+ CHECK((int)defaultPixel.blue, 0);
+ CHECK((int)defaultPixel.alpha, 0);
+
+ Q_UINT16 pixel[NUM_CHANNELS];
+
+ cs->fromQColor(qRgb(255, 255, 255), reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK((uint)pixel[PIXEL_RED], MAX_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE);
+
+ cs->fromQColor(qRgb(0, 0, 0), reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK((uint)pixel[PIXEL_RED], MIN_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_GREEN], MIN_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_BLUE], MIN_CHANNEL_VALUE);
+
+ cs->fromQColor(qRgb(128, 64, 192), reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK((uint)pixel[PIXEL_RED], (uint)UINT8_TO_UINT16(128));
+ CHECK((uint)pixel[PIXEL_GREEN], (uint)UINT8_TO_UINT16(64));
+ CHECK((uint)pixel[PIXEL_BLUE], (uint)UINT8_TO_UINT16(192));
+
+ cs->fromQColor(qRgb(255, 255, 255), OPACITY_OPAQUE, reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK((uint)pixel[PIXEL_RED], MAX_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_ALPHA], MAX_CHANNEL_VALUE);
+
+ cs->fromQColor(qRgb(255, 255, 255), OPACITY_TRANSPARENT, reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK((uint)pixel[PIXEL_RED], MAX_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_ALPHA], MIN_CHANNEL_VALUE);
+
+ cs->fromQColor(qRgb(255, 255, 255), OPACITY_OPAQUE / 2, reinterpret_cast<Q_UINT8 *>(pixel));
+
+ CHECK((uint)pixel[PIXEL_RED], MAX_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_GREEN], MAX_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_BLUE], MAX_CHANNEL_VALUE);
+ CHECK((uint)pixel[PIXEL_ALPHA], UINT8_TO_UINT16(OPACITY_OPAQUE / 2));
+
+ pixel[PIXEL_RED] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE;
+
+ QColor c;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c);
+
+ CHECK(c.red(), 255);
+ CHECK(c.green(), 255);
+ CHECK(c.blue(), 255);
+
+ pixel[PIXEL_RED] = MIN_CHANNEL_VALUE;
+ pixel[PIXEL_GREEN] = MIN_CHANNEL_VALUE;
+ pixel[PIXEL_BLUE] = MIN_CHANNEL_VALUE;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c);
+
+ CHECK(c.red(), 0);
+ CHECK(c.green(), 0);
+ CHECK(c.blue(), 0);
+
+ pixel[PIXEL_RED] = MAX_CHANNEL_VALUE / 4;
+ pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2;
+ pixel[PIXEL_BLUE] = (3 * MAX_CHANNEL_VALUE) / 4;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c);
+
+ CHECK(c.red(), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 4));
+ CHECK(c.green(), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2));
+ CHECK(c.blue(), (int)UINT16_TO_UINT8((3 * MAX_CHANNEL_VALUE) / 4));
+
+ pixel[PIXEL_RED] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_ALPHA] = MAX_CHANNEL_VALUE;
+
+ Q_UINT8 opacity;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), 255);
+ CHECK(c.green(), 255);
+ CHECK(c.blue(), 255);
+ CHECK(opacity, OPACITY_OPAQUE);
+
+ pixel[PIXEL_ALPHA] = MAX_CHANNEL_VALUE;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), 255);
+ CHECK(c.green(), 255);
+ CHECK(c.blue(), 255);
+ CHECK(opacity, OPACITY_OPAQUE);
+
+ pixel[PIXEL_RED] = MIN_CHANNEL_VALUE;
+ pixel[PIXEL_GREEN] = MIN_CHANNEL_VALUE;
+ pixel[PIXEL_BLUE] = MIN_CHANNEL_VALUE;
+ pixel[PIXEL_ALPHA] = MIN_CHANNEL_VALUE;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), 0);
+ CHECK(c.green(), 0);
+ CHECK(c.blue(), 0);
+ CHECK(opacity, OPACITY_TRANSPARENT);
+
+ pixel[PIXEL_RED] = MAX_CHANNEL_VALUE / 4;
+ pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2;
+ pixel[PIXEL_BLUE] = (3 * MAX_CHANNEL_VALUE) / 4;
+ pixel[PIXEL_ALPHA] = MAX_CHANNEL_VALUE / 2;
+
+ cs->toQColor(reinterpret_cast<const Q_UINT8 *>(pixel), &c, &opacity);
+
+ CHECK(c.red(), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 4));
+ CHECK(c.green(), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2));
+ CHECK(c.blue(), (int)UINT16_TO_UINT8((3 * MAX_CHANNEL_VALUE) / 4));
+ CHECK((int)opacity, (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2));
+
+ #define NUM_PIXELS 4
+
+ KisRgbU16ColorSpace::Pixel pixels[NUM_PIXELS] = {
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4},
+ {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2},
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE},
+ {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE}
+ };
+
+ cs->setAlpha(reinterpret_cast<Q_UINT8 *>(pixels), OPACITY_OPAQUE / 2, NUM_PIXELS);
+
+ CHECK((uint)pixels[0].red, MAX_CHANNEL_VALUE);
+ CHECK((uint)pixels[0].green, MAX_CHANNEL_VALUE);
+ CHECK((uint)pixels[0].blue, MAX_CHANNEL_VALUE);
+ CHECK((uint)pixels[0].alpha, (uint)UINT8_TO_UINT16(OPACITY_OPAQUE / 2));
+
+ CHECK((uint)pixels[1].red, MAX_CHANNEL_VALUE / 3);
+ CHECK((uint)pixels[1].green, MAX_CHANNEL_VALUE / 2);
+ CHECK((uint)pixels[1].blue, MAX_CHANNEL_VALUE / 4);
+ CHECK((uint)pixels[1].alpha, (uint)UINT8_TO_UINT16(OPACITY_OPAQUE / 2));
+
+ CHECK((uint)pixels[2].red, MAX_CHANNEL_VALUE);
+ CHECK((uint)pixels[2].green, MAX_CHANNEL_VALUE);
+ CHECK((uint)pixels[2].blue, MAX_CHANNEL_VALUE);
+ CHECK((uint)pixels[2].alpha, (uint)UINT8_TO_UINT16(OPACITY_OPAQUE / 2));
+
+ CHECK((uint)pixels[3].red, MIN_CHANNEL_VALUE);
+ CHECK((uint)pixels[3].green, MIN_CHANNEL_VALUE);
+ CHECK((uint)pixels[3].blue, MIN_CHANNEL_VALUE);
+ CHECK((uint)pixels[3].alpha, (uint)UINT8_TO_UINT16(OPACITY_OPAQUE / 2));
+
+ pixel[PIXEL_RED] = MAX_CHANNEL_VALUE;
+ pixel[PIXEL_GREEN] = MAX_CHANNEL_VALUE / 2;
+ pixel[PIXEL_BLUE] = MAX_CHANNEL_VALUE / 4;
+ pixel[PIXEL_ALPHA] = MIN_CHANNEL_VALUE;
+
+ QString valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), RED_CHANNEL);
+ CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE));
+
+ valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), GREEN_CHANNEL);
+ CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 2));
+
+ valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), BLUE_CHANNEL);
+ CHECK(valueText, QString().setNum(MAX_CHANNEL_VALUE / 4));
+
+ valueText = cs->channelValueText(reinterpret_cast<Q_UINT8 *>(pixel), ALPHA_CHANNEL);
+ CHECK(valueText, QString().setNum(MIN_CHANNEL_VALUE));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), RED_CHANNEL);
+ CHECK(valueText, QString().setNum(static_cast<float>(MAX_CHANNEL_VALUE) / MAX_CHANNEL_VALUE));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), GREEN_CHANNEL);
+ CHECK(valueText, QString().setNum(static_cast<float>(MAX_CHANNEL_VALUE / 2) / MAX_CHANNEL_VALUE));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), BLUE_CHANNEL);
+ CHECK(valueText, QString().setNum(static_cast<float>(MAX_CHANNEL_VALUE / 4) / MAX_CHANNEL_VALUE));
+
+ valueText = cs->normalisedChannelValueText(reinterpret_cast<Q_UINT8 *>(pixel), ALPHA_CHANNEL);
+ CHECK(valueText, QString().setNum(static_cast<float>(MIN_CHANNEL_VALUE) / MAX_CHANNEL_VALUE));
+
+ cs->setPixel(reinterpret_cast<Q_UINT8 *>(pixel), 128, 192, 64, 99);
+ CHECK((uint)pixel[PIXEL_RED], 128u);
+ CHECK((uint)pixel[PIXEL_GREEN], 192u);
+ CHECK((uint)pixel[PIXEL_BLUE], 64u);
+ CHECK((uint)pixel[PIXEL_ALPHA], 99u);
+
+ Q_UINT16 red;
+ Q_UINT16 green;
+ Q_UINT16 blue;
+ Q_UINT16 alpha;
+
+ cs->getPixel(reinterpret_cast<const Q_UINT8 *>(pixel), &red, &green, &blue, &alpha);
+ CHECK((uint)red, 128u);
+ CHECK((uint)green, 192u);
+ CHECK((uint)blue, 64u);
+ CHECK((uint)alpha, 99u);
+}
+
+void KisRgbU16ColorSpaceTester::testMixColors()
+{
+ KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile());
+
+ KisAbstractColorSpace * cs = new KisRgbU16ColorSpace(defProfile);
+
+ // Test mixColors.
+ Q_UINT16 pixel1[NUM_CHANNELS];
+ Q_UINT16 pixel2[NUM_CHANNELS];
+ Q_UINT16 outputPixel[NUM_CHANNELS];
+
+ outputPixel[PIXEL_RED] = 0;
+ outputPixel[PIXEL_GREEN] = 0;
+ outputPixel[PIXEL_BLUE] = 0;
+ outputPixel[PIXEL_ALPHA] = 0;
+
+ pixel1[PIXEL_RED] = UINT16_MAX;
+ pixel1[PIXEL_GREEN] = UINT16_MAX;
+ pixel1[PIXEL_BLUE] = UINT16_MAX;
+ pixel1[PIXEL_ALPHA] = UINT16_MAX;
+
+ pixel2[PIXEL_RED] = 0;
+ pixel2[PIXEL_GREEN] = 0;
+ pixel2[PIXEL_BLUE] = 0;
+ pixel2[PIXEL_ALPHA] = 0;
+
+ const Q_UINT8 *pixelPtrs[2];
+ Q_UINT8 weights[2];
+
+ pixelPtrs[0] = reinterpret_cast<const Q_UINT8 *>(pixel1);
+ pixelPtrs[1] = reinterpret_cast<const Q_UINT8 *>(pixel2);
+
+ weights[0] = 255;
+ weights[1] = 0;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK((uint)outputPixel[PIXEL_RED], UINT16_MAX);
+ CHECK((uint)outputPixel[PIXEL_GREEN], UINT16_MAX);
+ CHECK((uint)outputPixel[PIXEL_BLUE], UINT16_MAX);
+ CHECK((uint)outputPixel[PIXEL_ALPHA], UINT16_MAX);
+
+ weights[0] = 0;
+ weights[1] = 255;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK((int)outputPixel[PIXEL_RED], 0);
+ CHECK((int)outputPixel[PIXEL_GREEN], 0);
+ CHECK((int)outputPixel[PIXEL_BLUE], 0);
+ CHECK((int)outputPixel[PIXEL_ALPHA], 0);
+
+ weights[0] = 128;
+ weights[1] = 127;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK((uint)outputPixel[PIXEL_RED], UINT16_MAX);
+ CHECK((uint)outputPixel[PIXEL_GREEN], UINT16_MAX);
+ CHECK((uint)outputPixel[PIXEL_BLUE], UINT16_MAX);
+ CHECK((uint)outputPixel[PIXEL_ALPHA], (128u * UINT16_MAX) / 255u);
+
+ pixel1[PIXEL_RED] = 20000;
+ pixel1[PIXEL_GREEN] = 10000;
+ pixel1[PIXEL_BLUE] = 5000;
+ pixel1[PIXEL_ALPHA] = UINT16_MAX;
+
+ pixel2[PIXEL_RED] = 10000;
+ pixel2[PIXEL_GREEN] = 20000;
+ pixel2[PIXEL_BLUE] = 2000;
+ pixel2[PIXEL_ALPHA] = UINT16_MAX;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK_TOLERANCE((uint)outputPixel[PIXEL_RED], (128u * 20000u + 127u * 10000u) / 255u, 5u);
+ CHECK_TOLERANCE((uint)outputPixel[PIXEL_GREEN], (128u * 10000u + 127u * 20000u) / 255u, 5u);
+ CHECK_TOLERANCE((uint)outputPixel[PIXEL_BLUE], (128u * 5000u + 127u * 2000u) / 255u, 5u);
+ CHECK((uint)outputPixel[PIXEL_ALPHA], UINT16_MAX);
+
+ pixel1[PIXEL_RED] = 0;
+ pixel1[PIXEL_GREEN] = 0;
+ pixel1[PIXEL_BLUE] = 0;
+ pixel1[PIXEL_ALPHA] = 0;
+
+ pixel2[PIXEL_RED] = UINT16_MAX;
+ pixel2[PIXEL_GREEN] = UINT16_MAX;
+ pixel2[PIXEL_BLUE] = UINT16_MAX;
+ pixel2[PIXEL_ALPHA] = UINT16_MAX;
+
+ weights[0] = 89;
+ weights[1] = 166;
+
+ cs->mixColors(pixelPtrs, weights, 2, reinterpret_cast<Q_UINT8 *>(outputPixel));
+
+ CHECK((uint)outputPixel[PIXEL_RED], UINT16_MAX);
+ CHECK((uint)outputPixel[PIXEL_GREEN], UINT16_MAX);
+ CHECK((uint)outputPixel[PIXEL_BLUE], UINT16_MAX);
+ CHECK_TOLERANCE((uint)outputPixel[PIXEL_ALPHA], (89u * 0u + 166u * UINT16_MAX) / 255u, 5u);
+}
+
+#define PIXELS_WIDTH 2
+#define PIXELS_HEIGHT 2
+
+void KisRgbU16ColorSpaceTester::testToQImage()
+{
+ KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile());
+
+ KisAbstractColorSpace * cs = new KisRgbU16ColorSpace(defProfile);
+
+ KisRgbU16ColorSpace::Pixel pixels[PIXELS_WIDTH * PIXELS_HEIGHT] = {
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4},
+ {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2},
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE},
+ {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE}
+ };
+
+ QImage image = cs->convertToQImage(reinterpret_cast<const Q_UINT8 *>(pixels), PIXELS_WIDTH, PIXELS_HEIGHT, 0, 0);
+
+ QRgb c = image.pixel(0, 0);
+
+ CHECK(qRed(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qGreen(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qBlue(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qAlpha(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 4));
+
+ c = image.pixel(1, 0);
+
+ CHECK(qRed(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 3));
+ CHECK(qGreen(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2));
+ CHECK_TOLERANCE(qBlue(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 4), 1u);
+ CHECK(qAlpha(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE / 2));
+
+ c = image.pixel(0, 1);
+
+ CHECK(qRed(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qGreen(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qBlue(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE));
+ CHECK(qAlpha(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE));
+
+ c = image.pixel(1, 1);
+
+ CHECK(qRed(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE));
+ CHECK(qGreen(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE));
+ CHECK(qBlue(c), (int)UINT16_TO_UINT8(MIN_CHANNEL_VALUE));
+ CHECK(qAlpha(c), (int)UINT16_TO_UINT8(MAX_CHANNEL_VALUE));
+}
+
+#define NUM_ROWS 2
+#define NUM_COLUMNS 2
+#define SRC_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE)
+#define DST_ROW_STRIDE (NUM_COLUMNS * CHANNEL_SIZE)
+#define MASK_ROW_STRIDE NUM_COLUMNS
+
+/*
+1 alpha 1 0 alpha 1
+1 alpha 0.5 0 alpha 1
+1 alpha 0.5 0 alpha 0.5
+1 alpha 0 0 alpha 0.5
+
+*/
+
+void KisRgbU16ColorSpaceTester::testCompositeOps()
+{
+ KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile());
+
+ KisRgbU16ColorSpace *cs = new KisRgbU16ColorSpace(defProfile);
+
+ KisRgbU16ColorSpace::Pixel srcPixel;
+ KisRgbU16ColorSpace::Pixel dstPixel;
+
+ srcPixel.red = UINT8_TO_UINT16(102);
+ srcPixel.green = UINT8_TO_UINT16(170);
+ srcPixel.blue = UINT8_TO_UINT16(238);
+ srcPixel.alpha = KisRgbU16ColorSpace::U16_OPACITY_OPAQUE;
+
+ dstPixel = srcPixel;
+
+ cs->compositeDivide(reinterpret_cast<Q_UINT8 *>(&dstPixel), 1, reinterpret_cast<const Q_UINT8 *>(&srcPixel),
+ 1, 0, 0, 1, 1, KisRgbU16ColorSpace::U16_OPACITY_OPAQUE);
+ /*
+ CHECK(dstPixel.red, (Q_UINT16)UINT8_TO_UINT16(253));
+ CHECK(dstPixel.green, (Q_UINT16)UINT8_TO_UINT16(254));
+ CHECK(dstPixel.blue, (Q_UINT16)UINT8_TO_UINT16(254));
+ CHECK(dstPixel.alpha, KisRgbU16ColorSpace::U16_OPACITY_OPAQUE);
+
+ Q_UINT16 srcColor = 43690;
+ Q_UINT16 dstColor = 43690;
+
+ srcColor = QMIN((dstColor * (65535u + 1u) + (srcColor / 2u)) / (1u + srcColor), 65535u);
+
+ CHECK((int)srcColor, 65534);
+
+ Q_UINT16 newColor = UINT16_BLEND(srcColor, dstColor, 65535u);
+
+ CHECK((int)newColor, 65534);
+ */
+
+ /*
+ KisRgbU16ColorSpace::Pixel srcPixels[NUM_ROWS * NUM_COLUMNS] = {
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4},
+ {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2},
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE},
+ {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE}
+ };
+
+ KisRgbU16ColorSpace::Pixel dstPixels[NUM_ROWS * NUM_COLUMNS] = {
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE / 4},
+ {MAX_CHANNEL_VALUE / 4, MAX_CHANNEL_VALUE / 2, MAX_CHANNEL_VALUE / 3, MAX_CHANNEL_VALUE / 2},
+ {MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MAX_CHANNEL_VALUE, MIN_CHANNEL_VALUE},
+ {MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MIN_CHANNEL_VALUE, MAX_CHANNEL_VALUE}
+ };
+
+ cs->compositeOver(reinterpret_cast<Q_UINT8 *>(dstPixels), DST_ROW_STRIDE, reinterpret_cast<const Q_UINT8 *>(srcPixels),
+ SRC_ROW_STRIDE, mask, MASK_ROW_STRIDE, NUM_ROWS, NUM_COLUMNS, opacity);
+ */
+
+ delete cs;
+}
+
diff --git a/krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.h b/krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.h
new file mode 100644
index 00000000..e80a7a43
--- /dev/null
+++ b/krita/colorspaces/rgb_u16/tests/kis_strategy_colorspace_rgb_u16_tester.h
@@ -0,0 +1,46 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_RGB_U16_TESTER_H
+#define KIS_STRATEGY_COLORSPACE_RGB_U16_TESTER_H
+
+#include <kunittest/tester.h>
+
+#define CHECK_TOLERANCE( x, y, tolerance ) \
+if ((x) <= (y) + (tolerance) && (x) >= (y) - (tolerance)) \
+{ \
+ success(QString(__FILE__) + "[" + QString::number(__LINE__) + "]: passed " + #x); \
+} \
+else \
+{ \
+ failure(QString(__FILE__) + "[" + QString::number(__LINE__) + QString("]: failed ") + #x + "\n Expected " + #y + ", Actual result " + QString::number(x)); \
+} \
+
+class KisRgbU16ColorSpaceTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+ void testBasics();
+ void testMixColors();
+ void testToQImage();
+ void testCompositeOps();
+};
+
+#endif
+
diff --git a/krita/colorspaces/rgb_u8/Makefile.am b/krita/colorspaces/rgb_u8/Makefile.am
new file mode 100644
index 00000000..4d8ab87c
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/Makefile.am
@@ -0,0 +1,33 @@
+# Install the desktop file needed to detect the plugin
+kde_services_DATA = kritargbplugin.desktop
+
+INCLUDES = -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../kritacolor/ \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+lib_LTLIBRARIES = libkritargb.la
+libkritargb_la_SOURCES = kis_rgb_colorspace.cc
+libkritargb_la_LDFLAGS = $(all_libraries)
+libkritargb_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = kritargbplugin.la
+
+# Srcs for the plugin
+kritargbplugin_la_SOURCES = rgb_plugin.cc
+noinst_HEADERS = rgb_plugin.h kis_rgb_colorspace.h
+
+kritargbplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kritargbplugin_la_LIBADD = libkritargb.la ../../kritacolor/libkritacolor.la
+
+kritargbplugin_la_METASOURCES = AUTO
+#METASOURCES = AUTO # XXX: which of the two?
+
+if include_kunittest_tests
+TESTSDIR = tests
+endif
+
+SUBDIRS = . templates $(TESTSDIR)
+
diff --git a/krita/colorspaces/rgb_u8/composite.h b/krita/colorspaces/rgb_u8/composite.h
new file mode 100644
index 00000000..961130ba
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/composite.h
@@ -0,0 +1,868 @@
+/*
+ * Copyright (c) 2004 Boudewijn Rempt <[email protected]>
+ *
+ * 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.
+ *
+
+ Some code is derived from GraphicsMagick/magick/composite.c and is
+ subject to the following license and copyright:
+
+ Copyright (C) 2002 GraphicsMagick Group, an organization dedicated
+ to making software imaging solutions freely available.
+
+ Permission is hereby granted, free of charge, to any person obtaining
+ a copy of this software and associated documentation files
+ ("GraphicsMagick"), to deal in GraphicsMagick without restriction,
+ including without limitation the rights to use, copy, modify, merge,
+ publish, distribute, sublicense, and/or sell copies of GraphicsMagick,
+ and to permit persons to whom GraphicsMagick is furnished to do so,
+ subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included
+ in all copies or substantial portions of GraphicsMagick.
+
+ The software is provided "as is", without warranty of any kind, express
+ or implied, including but not limited to the warranties of
+ merchantability, fitness for a particular purpose and noninfringement.
+ In no event shall GraphicsMagick Group be liable for any claim,
+ damages or other liability, whether in an action of contract, tort or
+ otherwise, arising from, out of or in connection with GraphicsMagick
+ or the use or other dealings in GraphicsMagick.
+
+ Except as contained in this notice, the name of the GraphicsMagick
+ Group shall not be used in advertising or otherwise to promote the
+ sale, use or other dealings in GraphicsMagick without prior written
+ authorization from the GraphicsMagick Group.
+
+ Other code is derived from gwenview/src/qxcfi.* - this is released under
+ the terms of the LGPL
+
+ */
+
+#ifndef COMPOSITE_H_
+#define COMPOSITE_H_
+
+#include <kdebug.h>
+
+#include <kis_global.h>
+
+/**
+ * Image composition functions that can be used by the colour strategies.
+ *
+ * XXX: perhaps each composition function ought to be a strategy of itself.
+ * Krita is still missing something like a capabilities database that ties
+ * together image formats, colour systems, composition functions etc., that
+ * determines which goes with which and defines user visible text for all this.
+ *
+ * For now, this is a quick hack; once things are working again, I'll investigate
+ * doing this nicely (famous last words...)
+ *
+ * XXX: Except for Over, none of the operators uses the opacity parameter
+ */
+
+
+// Straight from image.h
+
+#define PixelIntensity(pixel) ((unsigned int) \
+ (((double)306.0 * (pixel[PIXEL_RED]) + \
+ (double)601.0 * (pixel[PIXEL_GREEN]) + \
+ (double)117.0 * (pixel[PIXEL_BLUE)) \
+ / 1024.0))
+
+#define PixelIntensityToQuantum(pixel) ((Q_UINT8)PixelIntensity(pixel))
+
+#define PixelIntensityToDouble(pixel) ((double)PixelIntensity(pixel))
+
+#define RoundSignedToQuantum(value) ((Q_UINT8) (value < 0 ? 0 : \
+ (value > Q_UINT8_MAX) ? Q_UINT8_MAX : value + 0.5))
+
+#define RoundToQuantum(value) ((Q_UINT8) (value > Q_UINT8_MAX ? Q_UINT8_MAX : \
+ value + 0.5))
+
+// And from studio.h
+#define AbsoluteValue(x) ((x) < 0 ? -(x) : (x))
+
+void compositeIn(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double sAlpha, dAlpha;
+ double alpha;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+
+ if (s[PIXEL_ALPHA] == OPACITY_TRANSPARENT)
+ {
+ memcpy(d, s, pixelSize * sizeof(Q_UINT8));
+ continue;
+ }
+ if (d[PIXEL_ALPHA] == OPACITY_TRANSPARENT)
+ continue;
+
+ sAlpha = UINT8_MAX - s[PIXEL_ALPHA];
+ dAlpha = UINT8_MAX - d[PIXEL_ALPHA];
+
+ alpha=(double) (((double) UINT8_MAX - sAlpha) * (UINT8_MAX - dAlpha) / UINT8_MAX);
+ d[PIXEL_RED]=(Q_UINT8) (((double) UINT8_MAX - sAlpha) *
+ (UINT8_MAX-dAlpha) * s[PIXEL_RED] / UINT8_MAX / alpha + 0.5);
+ d[PIXEL_GREEN]=(Q_UINT8) (((double) UINT8_MAX - sAlpha)*
+ (UINT8_MAX-dAlpha) * s[PIXEL_GREEN] / UINT8_MAX / alpha + 0.5);
+ d[PIXEL_BLUE]=(Q_UINT8) (((double) UINT8_MAX - sAlpha)*
+ (UINT8_MAX - dAlpha) * s[PIXEL_BLUE] / UINT8_MAX / alpha + 0.5);
+ d[PIXEL_ALPHA]=(Q_UINT8) ((d[PIXEL_ALPHA] * (UINT8_MAX - alpha) / UINT8_MAX) + 0.5);
+
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+
+}
+
+void compositeOut(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double sAlpha, dAlpha;
+ double alpha;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+ if (s[PIXEL_ALPHA] == OPACITY_TRANSPARENT)
+ {
+ memcpy(d, s, pixelSize * sizeof(Q_UINT8));
+ break;
+ }
+ if (d[PIXEL_ALPHA] == OPACITY_OPAQUE)
+ {
+ d[PIXEL_ALPHA]=OPACITY_TRANSPARENT;
+ break;
+ }
+ sAlpha = UINT8_MAX - s[PIXEL_ALPHA];
+ dAlpha = UINT8_MAX - d[PIXEL_ALPHA];
+
+ alpha=(double) (UINT8_MAX - sAlpha) * d[PIXEL_ALPHA]/UINT8_MAX;
+ d[PIXEL_RED] = (Q_UINT8) (((double) UINT8_MAX - sAlpha) * dAlpha * s[PIXEL_RED] / UINT8_MAX / alpha + 0.5);
+ d[PIXEL_GREEN] = (Q_UINT8) (((double) UINT8_MAX - sAlpha) * dAlpha * s[PIXEL_GREEN] / UINT8_MAX / alpha + 0.5);
+ d[PIXEL_BLUE] = (Q_UINT8) (((double) UINT8_MAX - sAlpha) * dAlpha * s[PIXEL_BLUE] / UINT8_MAX / alpha + 0.5);
+ d[PIXEL_ALPHA]=(Q_UINT8) ((d[PIXEL_ALPHA] * (UINT8_MAX - alpha) / UINT8_MAX) + 0.5);
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+
+}
+
+void compositeAtop(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double sAlpha, dAlpha;
+ double alpha, red, green, blue;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+ sAlpha = UINT8_MAX - s[PIXEL_ALPHA];
+ dAlpha = UINT8_MAX - d[PIXEL_ALPHA];
+
+ alpha = ((double)(UINT8_MAX - sAlpha) *
+ (UINT8_MAX - dAlpha) + (double) sAlpha *
+ (UINT8_MAX - dAlpha)) / UINT8_MAX;
+
+ red = ((double)(UINT8_MAX - sAlpha) * (UINT8_MAX - dAlpha) * s[PIXEL_RED] / UINT8_MAX +
+ (double) sAlpha * (UINT8_MAX-dAlpha) * d[PIXEL_RED]/UINT8_MAX) / alpha;
+ d[PIXEL_RED] = (Q_UINT8) (red > UINT8_MAX ? UINT8_MAX : red + 0.5);
+
+ green = ((double) (UINT8_MAX - sAlpha) * (UINT8_MAX - dAlpha) * s[PIXEL_GREEN] / UINT8_MAX +
+ (double) sAlpha * (UINT8_MAX-dAlpha) * d[PIXEL_GREEN]/UINT8_MAX)/alpha;
+ d[PIXEL_GREEN] = (Q_UINT8) (green > UINT8_MAX ? UINT8_MAX : green + 0.5);
+
+ blue = ((double) (UINT8_MAX - sAlpha) * (UINT8_MAX- dAlpha) * s[PIXEL_BLUE] / UINT8_MAX +
+ (double) sAlpha * (UINT8_MAX - dAlpha) * d[PIXEL_BLUE]/UINT8_MAX) / alpha;
+ d[PIXEL_BLUE] = (Q_UINT8) (blue > UINT8_MAX ? UINT8_MAX : blue + 0.5);
+ d[PIXEL_ALPHA]=(Q_UINT8) (UINT8_MAX - (alpha > UINT8_MAX ? UINT8_MAX : alpha) + 0.5);
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+}
+
+
+void compositeXor(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double sAlpha, dAlpha;
+ double alpha, red, green, blue;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+ sAlpha = UINT8_MAX - s[PIXEL_ALPHA];
+ dAlpha = UINT8_MAX - d[PIXEL_ALPHA];
+
+ alpha =((double) (UINT8_MAX -sAlpha)*
+ dAlpha+(double) (UINT8_MAX -dAlpha)*
+ sAlpha)/UINT8_MAX ;
+ red=((double) (UINT8_MAX -sAlpha)*dAlpha*
+ s[PIXEL_RED]/UINT8_MAX +(double) (UINT8_MAX -dAlpha)*
+ sAlpha*d[PIXEL_RED]/UINT8_MAX )/alpha ;
+ d[PIXEL_RED]=RoundSignedToQuantum(red);
+ green=((double) (UINT8_MAX -sAlpha)*dAlpha*
+ s[PIXEL_GREEN]/UINT8_MAX +(double) (UINT8_MAX -dAlpha)*
+ sAlpha*d[PIXEL_GREEN]/UINT8_MAX )/alpha ;
+ d[PIXEL_GREEN]=RoundSignedToQuantum(green);
+ blue=((double) (UINT8_MAX -sAlpha)*dAlpha*
+ s[PIXEL_BLUE]/UINT8_MAX +(double) (UINT8_MAX -dAlpha)*
+ sAlpha*d[PIXEL_BLUE]/UINT8_MAX )/alpha ;
+ d[PIXEL_BLUE]=RoundSignedToQuantum(blue);
+ d[PIXEL_ALPHA]=UINT8_MAX -RoundSignedToQuantum(alpha );
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+
+}
+
+
+void compositePlus(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double sAlpha, dAlpha;
+ double alpha, red, green, blue;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+ sAlpha = UINT8_MAX - s[PIXEL_ALPHA];
+ dAlpha = UINT8_MAX - d[PIXEL_ALPHA];
+
+ red=((double) (UINT8_MAX -sAlpha)*s[PIXEL_RED]+(double)
+ (UINT8_MAX -dAlpha)*d[PIXEL_RED])/UINT8_MAX ;
+ d[PIXEL_RED]=RoundSignedToQuantum(red);
+ green=((double) (UINT8_MAX -sAlpha)*s[PIXEL_GREEN]+(double)
+ (UINT8_MAX -dAlpha)*d[PIXEL_GREEN])/UINT8_MAX ;
+ d[PIXEL_GREEN]=RoundSignedToQuantum(green);
+ blue=((double) (UINT8_MAX -sAlpha)*s[PIXEL_BLUE]+(double)
+ (UINT8_MAX -dAlpha)*d[PIXEL_BLUE])/UINT8_MAX ;
+ d[PIXEL_BLUE]=RoundSignedToQuantum(blue);
+ alpha =((double) (UINT8_MAX -sAlpha)+
+ (double) (UINT8_MAX -dAlpha))/UINT8_MAX ;
+ d[PIXEL_ALPHA]=UINT8_MAX -RoundSignedToQuantum(alpha );
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+}
+
+
+
+void compositeMinus(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double sAlpha, dAlpha;
+ double alpha, red, green, blue;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+ sAlpha = UINT8_MAX - s[PIXEL_ALPHA];
+ dAlpha = UINT8_MAX - d[PIXEL_ALPHA];
+
+ red=((double) (UINT8_MAX -dAlpha)*d[PIXEL_RED]-
+ (double) (UINT8_MAX -sAlpha)*s[PIXEL_RED])/UINT8_MAX ;
+ d[PIXEL_RED]=RoundSignedToQuantum(red);
+ green=((double) (UINT8_MAX -dAlpha)*d[PIXEL_GREEN]-
+ (double) (UINT8_MAX -sAlpha)*s[PIXEL_GREEN])/UINT8_MAX ;
+ d[PIXEL_GREEN]=RoundSignedToQuantum(green);
+ blue=((double) (UINT8_MAX -dAlpha)*d[PIXEL_BLUE]-
+ (double) (UINT8_MAX -sAlpha)*s[PIXEL_BLUE])/UINT8_MAX ;
+ d[PIXEL_BLUE]=RoundSignedToQuantum(blue);
+ alpha =((double) (UINT8_MAX -dAlpha)-
+ (double) (UINT8_MAX -sAlpha))/UINT8_MAX ;
+ d[PIXEL_ALPHA]=UINT8_MAX -RoundSignedToQuantum(alpha );
+
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+
+}
+
+void compositeAdd(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double sAlpha, dAlpha;
+ double red, green, blue;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+ sAlpha = UINT8_MAX - s[PIXEL_ALPHA];
+ dAlpha = UINT8_MAX - d[PIXEL_ALPHA];
+
+ red=(double) s[PIXEL_RED]+d[PIXEL_RED];
+ d[PIXEL_RED]=(Q_UINT8)
+ (red > UINT8_MAX ? red-=UINT8_MAX : red+0.5);
+ green=(double) s[PIXEL_GREEN]+d[PIXEL_GREEN];
+ d[PIXEL_GREEN]=(Q_UINT8)
+ (green > UINT8_MAX ? green-=UINT8_MAX : green+0.5);
+ blue=(double) s[PIXEL_BLUE]+d[PIXEL_BLUE];
+ d[PIXEL_BLUE]=(Q_UINT8)
+ (blue > UINT8_MAX ? blue-=UINT8_MAX : blue+0.5);
+ d[PIXEL_ALPHA]=OPACITY_OPAQUE;
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+
+}
+
+void compositeSubtract(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double red, green, blue;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+
+ red=(double) s[PIXEL_RED]-d[PIXEL_RED];
+ d[PIXEL_RED]=(Q_UINT8)
+ (red < 0 ? red+=UINT8_MAX : red+0.5);
+ green=(double) s[PIXEL_GREEN]-d[PIXEL_GREEN];
+ d[PIXEL_GREEN]=(Q_UINT8)
+ (green < 0 ? green+=UINT8_MAX : green+0.5);
+ blue=(double) s[PIXEL_BLUE]-d[PIXEL_BLUE];
+ d[PIXEL_BLUE]=(Q_UINT8)
+ (blue < 0 ? blue+=UINT8_MAX : blue+0.5);
+ d[PIXEL_ALPHA]=OPACITY_OPAQUE;
+
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+
+}
+
+void compositeDiff(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double sAlpha, dAlpha;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+ sAlpha = UINT8_MAX - s[PIXEL_ALPHA];
+ dAlpha = UINT8_MAX - d[PIXEL_ALPHA];
+
+ d[PIXEL_RED]=(Q_UINT8)
+ AbsoluteValue(s[PIXEL_RED]-(double) d[PIXEL_RED]);
+ d[PIXEL_GREEN]=(Q_UINT8)
+ AbsoluteValue(s[PIXEL_GREEN]-(double) d[PIXEL_GREEN]);
+ d[PIXEL_BLUE]=(Q_UINT8)
+ AbsoluteValue(s[PIXEL_BLUE]-(double) d[PIXEL_BLUE]);
+ d[PIXEL_ALPHA]=UINT8_MAX - (Q_UINT8)
+ AbsoluteValue(sAlpha-(double) dAlpha);
+
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+
+}
+
+void compositeBumpmap(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double intensity;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+ // Is this correct? It's not this way in GM.
+ if (s[PIXEL_ALPHA] == OPACITY_TRANSPARENT)
+ continue;
+
+ // And I'm not sure whether this is correct, either.
+ intensity = ((double)306.0 * s[PIXEL_RED] +
+ (double)601.0 * s[PIXEL_GREEN] +
+ (double)117.0 * s[PIXEL_BLUE]) / 1024.0;
+
+ d[PIXEL_RED]=(Q_UINT8) (((double)
+ intensity * d[PIXEL_RED])/UINT8_MAX +0.5);
+ d[PIXEL_GREEN]=(Q_UINT8) (((double)
+ intensity * d[PIXEL_GREEN])/UINT8_MAX +0.5);
+ d[PIXEL_BLUE]=(Q_UINT8) (((double)
+ intensity * d[PIXEL_BLUE])/UINT8_MAX +0.5);
+ d[PIXEL_ALPHA]= (Q_UINT8) (((double)
+ intensity * d[PIXEL_ALPHA])/UINT8_MAX +0.5);
+
+
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+
+}
+
+void compositeCopy(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 /*opacity*/ = OPACITY_OPAQUE)
+{
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+ d = dst;
+ s = src;
+ Q_UINT32 len = cols * pixelSize;
+
+ while (rows-- > 0) {
+ memcpy(d, s, len);
+ d += dstRowSize;
+ s += srcRowSize;
+ }
+}
+
+void compositeCopyChannel(Q_UINT8 pixel,
+ Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 /*opacity*/ = OPACITY_OPAQUE)
+{
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+ Q_INT32 i;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+ d[pixel] = s[pixel];
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+
+}
+
+void compositeCopyRed(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ compositeCopyChannel(PIXEL_RED, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity);
+}
+
+void compositeCopyGreen(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ compositeCopyChannel(PIXEL_GREEN, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity);
+}
+
+void compositeCopyBlue(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ compositeCopyChannel(PIXEL_BLUE, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity);
+}
+
+
+void compositeCopyOpacity(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+
+ // XXX: mess with intensity if there isn't an alpha channel, according to GM.
+ compositeCopyChannel(PIXEL_ALPHA, pixelSize, dst, dstRowSize, src, srcRowSize, rows, cols, opacity);
+
+}
+
+
+void compositeClear(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 /*srcRowSize*/,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 /*opacity*/ = OPACITY_OPAQUE)
+{
+
+ Q_INT32 linesize = pixelSize * sizeof(Q_UINT8) * cols;
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ d = dst;
+ s = src;
+
+ while (rows-- > 0) {
+ memset(d, 0, linesize);
+ d += dstRowSize;
+ }
+
+}
+
+
+void compositeDissolve(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double sAlpha, dAlpha;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+ // XXX: correct?
+ if (s[PIXEL_ALPHA] == OPACITY_TRANSPARENT) continue;
+
+ sAlpha = UINT8_MAX - s[PIXEL_ALPHA];
+ dAlpha = UINT8_MAX - d[PIXEL_ALPHA];
+
+ d[PIXEL_RED]=(Q_UINT8) (((double) sAlpha*s[PIXEL_RED]+
+ (UINT8_MAX -sAlpha)*d[PIXEL_RED])/UINT8_MAX +0.5);
+ d[PIXEL_GREEN]= (Q_UINT8) (((double) sAlpha*s[PIXEL_GREEN]+
+ (UINT8_MAX -sAlpha)*d[PIXEL_GREEN])/UINT8_MAX +0.5);
+ d[PIXEL_BLUE] = (Q_UINT8) (((double) sAlpha*s[PIXEL_BLUE]+
+ (UINT8_MAX -sAlpha)*d[PIXEL_BLUE])/UINT8_MAX +0.5);
+ d[PIXEL_ALPHA] = OPACITY_OPAQUE;
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+
+}
+
+
+void compositeDisplace(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 /*opacity*/ = OPACITY_OPAQUE)
+{
+ Q_INT32 linesize = pixelSize * sizeof(Q_UINT8) * cols;
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+ d = dst;
+ s = src;
+
+ while (rows-- > 0) {
+ memcpy(d, s, linesize);
+ d += dstRowSize;
+ s += srcRowSize;
+ }
+
+}
+
+#if 0
+void compositeModulate(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ if (opacity == OPACITY_TRANSPARENT)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 i;
+
+ double sAlpha, dAlpha;
+ long offset;
+
+ while (rows-- > 0) {
+ d = dst;
+ s = src;
+ for (i = cols; i > 0; i--, d += pixelSize, s += pixelSize) {
+ // XXX: correct?
+ if (s[PIXEL_ALPHA] == OPACITY_TRANSPARENT) continue;
+
+ sAlpha = UINT8_MAX - s[PIXEL_ALPHA];
+ dAlpha = UINT8_MAX - d[PIXEL_ALPHA];
+
+
+ offset=(long) (PixelIntensityToQuantum(&source)-midpoint);
+ if (offset == 0)
+ continue;
+ TransformHSL(d[PIXEL_RED],d[PIXEL_GREEN],d[PIXEL_BLUE],
+ &hue,&saturation,&brightness);
+ brightness+=(percent_brightness*offset)/midpoint;
+ if (brightness < 0.0)
+ brightness=0.0;
+ else
+ if (brightness > 1.0)
+ brightness=1.0;
+ HSLTransform(hue,saturation,brightness,&d[PIXEL_RED],
+ &d[PIXEL_GREEN],&d[PIXEL_BLUE]);
+
+
+ }
+ dst += dstRowSize;
+ src += srcRowSize;
+ }
+
+
+}
+
+
+void compositeThreshold(Q_INT32 pixelSize,
+ Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 opacity = OPACITY_OPAQUE)
+{
+ Q_INT32 linesize = pixelSize * sizeof(Q_UINT8) * cols;
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+ Q_UINT8 alpha;
+ Q_UINT8 invAlpha;
+ Q_INT32 i;
+
+}
+
+#endif
+
+void compositeColorize(Q_INT32,
+ Q_UINT8 *,
+ Q_INT32 ,
+ const Q_UINT8 *,
+ Q_INT32 ,
+ Q_INT32 ,
+ Q_INT32 ,
+ Q_UINT8 )
+{
+}
+
+
+void compositeLuminize(Q_INT32 ,
+ Q_UINT8 *,
+ Q_INT32 ,
+ const Q_UINT8 *,
+ Q_INT32 ,
+ Q_INT32 ,
+ Q_INT32 ,
+ Q_UINT8 )
+{
+
+}
+
+#endif
+
diff --git a/krita/colorspaces/rgb_u8/kis_rgb_colorspace.cc b/krita/colorspaces/rgb_u8/kis_rgb_colorspace.cc
new file mode 100644
index 00000000..61272e36
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/kis_rgb_colorspace.cc
@@ -0,0 +1,1501 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <[email protected]>
+ * Copyright (c) 2004 Boudewijn Rempt <[email protected]>
+ *
+ * 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 <qimage.h>
+#include <qcolor.h>
+
+#include <kdebug.h>
+#include <klocale.h>
+
+#include "kis_rgb_colorspace.h"
+#include "kis_u8_base_colorspace.h"
+#include "kis_color_conversions.h"
+#include "kis_integer_maths.h"
+#include "kis_colorspace_factory_registry.h"
+
+#include "composite.h"
+
+#define downscale(quantum) (quantum) //((unsigned char) ((quantum)/257UL))
+#define upscale(value) (value) // ((Q_UINT8) (257UL*(value)))
+
+namespace {
+ const Q_INT32 MAX_CHANNEL_RGB = 3;
+ const Q_INT32 MAX_CHANNEL_RGBA = 4;
+}
+
+KisRgbColorSpace::KisRgbColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) :
+ KisU8BaseColorSpace(KisID("RGBA", i18n("RGB (8-bit integer/channel)")), TYPE_BGRA_8, icSigRgbData, parent, p)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Red"), i18n("R"), 2, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(255,0,0)));
+ m_channels.push_back(new KisChannelInfo(i18n("Green"), i18n("G"), 1, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(0,255,0)));
+ m_channels.push_back(new KisChannelInfo(i18n("Blue"), i18n("B"), 0, KisChannelInfo::COLOR, KisChannelInfo::UINT8, 1, QColor(0,0,255)));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), i18n("A"), 3, KisChannelInfo::ALPHA, KisChannelInfo::UINT8));
+
+ m_alphaPos = PIXEL_ALPHA;
+ init();
+}
+
+KisRgbColorSpace::~KisRgbColorSpace()
+{
+}
+
+void KisRgbColorSpace::setPixel(Q_UINT8 *pixel, Q_UINT8 red, Q_UINT8 green, Q_UINT8 blue, Q_UINT8 alpha) const
+{
+ pixel[PIXEL_RED] = red;
+ pixel[PIXEL_GREEN] = green;
+ pixel[PIXEL_BLUE] = blue;
+ pixel[PIXEL_ALPHA] = alpha;
+}
+
+void KisRgbColorSpace::getPixel(const Q_UINT8 *pixel, Q_UINT8 *red, Q_UINT8 *green, Q_UINT8 *blue, Q_UINT8 *alpha) const
+{
+ *red = pixel[PIXEL_RED];
+ *green = pixel[PIXEL_GREEN];
+ *blue = pixel[PIXEL_BLUE];
+ *alpha = pixel[PIXEL_ALPHA];
+}
+
+void KisRgbColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+ Q_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0;
+
+ while (nColors--)
+ {
+ Q_UINT32 alpha = (*colors)[PIXEL_ALPHA];
+ // although we only mult by weight and not by weight*256/255
+ // we divide by the same amount later, so there is no need
+ Q_UINT32 alphaTimesWeight = alpha * *weights;
+
+ totalRed += (*colors)[PIXEL_RED] * alphaTimesWeight;
+ totalGreen += (*colors)[PIXEL_GREEN] * alphaTimesWeight;
+ totalBlue += (*colors)[PIXEL_BLUE] * alphaTimesWeight;
+ totalAlpha += alphaTimesWeight;
+
+ weights++;
+ colors++;
+ }
+
+ // note this is correct - if you look at the above calculation
+ if (totalAlpha > 255*255) totalAlpha = 255*255;
+
+ // Divide by 255.
+ dst[PIXEL_ALPHA] =(((totalAlpha + 0x80)>>8)+totalAlpha + 0x80) >>8;
+
+ if (totalAlpha > 0) {
+ totalRed = totalRed / totalAlpha;
+ totalGreen = totalGreen / totalAlpha;
+ totalBlue = totalBlue / totalAlpha;
+ } // else the values are already 0 too
+
+ Q_UINT32 dstRed = totalRed;
+ //Q_ASSERT(dstRed <= 255);
+ if (dstRed > 255) dstRed = 255;
+ dst[PIXEL_RED] = dstRed;
+
+ Q_UINT32 dstGreen = totalGreen;
+ //Q_ASSERT(dstGreen <= 255);
+ if (dstGreen > 255) dstGreen = 255;
+ dst[PIXEL_GREEN] = dstGreen;
+
+ Q_UINT32 dstBlue = totalBlue;
+ //Q_ASSERT(dstBlue <= 255);
+ if (dstBlue > 255) dstBlue = 255;
+ dst[PIXEL_BLUE] = dstBlue;
+}
+
+void KisRgbColorSpace::convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const
+{
+ Q_INT64 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0;
+ Q_INT32 totalWeight = 0, totalWeightTransparent = 0;
+ while (nColors--)
+ {
+ Q_INT32 weight = *kernelValues;
+
+ if (weight != 0) {
+ if((*colors)[PIXEL_ALPHA] == 0)
+ {
+ totalWeightTransparent += weight;
+ } else {
+ totalRed += (*colors)[PIXEL_RED] * weight;
+ totalGreen += (*colors)[PIXEL_GREEN] * weight;
+ totalBlue += (*colors)[PIXEL_BLUE] * weight;
+ }
+ totalAlpha += (*colors)[PIXEL_ALPHA] * weight;
+ totalWeight += weight;
+ }
+ colors++;
+ kernelValues++;
+ }
+ if(totalWeightTransparent == 0)
+ {
+ if (channelFlags & KisChannelInfo::FLAG_COLOR) {
+ dst[PIXEL_RED] = CLAMP((totalRed / factor) + offset, 0, Q_UINT8_MAX);
+ dst[PIXEL_GREEN] = CLAMP((totalGreen / factor) + offset, 0, Q_UINT8_MAX);
+ dst[PIXEL_BLUE] = CLAMP((totalBlue / factor) + offset, 0, Q_UINT8_MAX);
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ dst[PIXEL_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT8_MAX);
+ }
+ } else if(totalWeightTransparent != totalWeight && (channelFlags & KisChannelInfo::FLAG_COLOR)) {
+ if(totalWeight == factor)
+ {
+ Q_INT64 a = ( totalWeight - totalWeightTransparent );
+ dst[PIXEL_RED] = CLAMP((totalRed / a) + offset, 0, Q_UINT8_MAX);
+ dst[PIXEL_GREEN] = CLAMP((totalGreen / a) + offset, 0, Q_UINT8_MAX);
+ dst[PIXEL_BLUE] = CLAMP((totalBlue / a) + offset, 0, Q_UINT8_MAX);
+ } else {
+ double a = totalWeight / ( factor * ( totalWeight - totalWeightTransparent ) ); // use double as it can saturate
+ dst[PIXEL_RED] = CLAMP( (Q_UINT8)(totalRed * a) + offset, 0, Q_UINT8_MAX);
+ dst[PIXEL_GREEN] = CLAMP( (Q_UINT8)(totalGreen * a) + offset, 0, Q_UINT8_MAX);
+ dst[PIXEL_BLUE] = CLAMP( (Q_UINT8)(totalBlue * a) + offset, 0, Q_UINT8_MAX);
+ }
+ }
+ if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
+ dst[PIXEL_ALPHA] = CLAMP((totalAlpha/ factor) + offset, 0, Q_UINT8_MAX);
+ }
+}
+
+
+void KisRgbColorSpace::invertColor(Q_UINT8 * src, Q_INT32 nPixels)
+{
+ Q_UINT32 psize = pixelSize();
+
+ while (nPixels--)
+ {
+ src[PIXEL_RED] = Q_UINT8_MAX - src[PIXEL_RED];
+ src[PIXEL_GREEN] = Q_UINT8_MAX - src[PIXEL_GREEN];
+ src[PIXEL_BLUE] = Q_UINT8_MAX - src[PIXEL_BLUE];
+
+ src += psize;
+ }
+}
+
+
+void KisRgbColorSpace::darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const
+{
+ Q_UINT32 pSize = pixelSize();
+
+ while (nPixels--) {
+ if (compensate) {
+ dst[PIXEL_RED] = (Q_INT8) QMIN(255,((src[PIXEL_RED] * shade) / (compensation * 255)));
+ dst[PIXEL_GREEN] = (Q_INT8) QMIN(255,((src[PIXEL_GREEN] * shade) / (compensation * 255)));
+ dst[PIXEL_BLUE] = (Q_INT8) QMIN(255,((src[PIXEL_BLUE] * shade) / (compensation * 255)));
+ }
+ else {
+ dst[PIXEL_RED] = (Q_INT8) QMIN(255, (src[PIXEL_RED] * shade / 255));
+ dst[PIXEL_BLUE] = (Q_INT8) QMIN(255, (src[PIXEL_BLUE] * shade / 255));
+ dst[PIXEL_GREEN] = (Q_INT8) QMIN(255, (src[PIXEL_GREEN] * shade / 255));
+ }
+ dst += pSize;
+ src += pSize;
+ }
+}
+
+Q_UINT8 KisRgbColorSpace::intensity8(const Q_UINT8 * src) const
+{
+ return (Q_UINT8)((src[PIXEL_RED] * 0.30 + src[PIXEL_GREEN] * 0.59 + src[PIXEL_BLUE] * 0.11) + 0.5);
+}
+
+QValueVector<KisChannelInfo *> KisRgbColorSpace::channels() const
+{
+ return m_channels;
+}
+
+Q_UINT32 KisRgbColorSpace::nChannels() const
+{
+ return MAX_CHANNEL_RGBA;
+}
+
+Q_UINT32 KisRgbColorSpace::nColorChannels() const
+{
+ return MAX_CHANNEL_RGB;
+}
+
+Q_UINT32 KisRgbColorSpace::pixelSize() const
+{
+ return MAX_CHANNEL_RGBA;
+}
+
+QImage KisRgbColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
+ KisProfile * dstProfile,
+ Q_INT32 renderingIntent, float /*exposure*/)
+
+{
+ Q_ASSERT(data);
+ QImage img = QImage(const_cast<Q_UINT8 *>(data), width, height, 32, 0, 0, QImage::LittleEndian);
+ img.setAlphaBuffer(true);
+ // XXX: The previous version of this code used the quantum data directly
+ // as an optimisation. We're introducing a copy overhead here which could
+ // be factored out again if needed.
+ img = img.copy();
+
+ if (dstProfile != 0) {
+ KisColorSpace *dstCS = m_parent->getColorSpace(KisID("RGBA",""), dstProfile->productName());
+ convertPixelsTo(img.bits(),
+ img.bits(), dstCS,
+ width * height, renderingIntent);
+ }
+
+ return img;
+}
+
+
+
+
+void KisRgbColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride,
+ const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride,
+ const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride,
+ Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(srcAlpha, opacity);
+ }
+
+ if (srcAlpha == OPACITY_OPAQUE) {
+ memcpy(dst, src, MAX_CHANNEL_RGBA * sizeof(Q_UINT8));
+ } else {
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ if (srcBlend == OPACITY_OPAQUE) {
+ memcpy(dst, src, MAX_CHANNEL_RGB * sizeof(Q_UINT8));
+ } else {
+ dst[PIXEL_RED] = UINT8_BLEND(src[PIXEL_RED], dst[PIXEL_RED], srcBlend);
+ dst[PIXEL_GREEN] = UINT8_BLEND(src[PIXEL_GREEN], dst[PIXEL_GREEN], srcBlend);
+ dst[PIXEL_BLUE] = UINT8_BLEND(src[PIXEL_BLUE], dst[PIXEL_BLUE], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+
+void KisRgbColorSpace::compositeAlphaDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride,
+ const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride,
+ const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride,
+ Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(srcAlpha, opacity);
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT && srcAlpha >= dstAlpha) {
+ dst[PIXEL_ALPHA] = srcAlpha;
+ memcpy(dst, src, MAX_CHANNEL_RGB * sizeof(Q_UINT8));
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+
+void KisRgbColorSpace::compositeMultiply(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ Q_UINT8 srcColor = src[PIXEL_RED];
+ Q_UINT8 dstColor = dst[PIXEL_RED];
+
+ srcColor = UINT8_MULT(srcColor, dstColor);
+
+ dst[PIXEL_RED] = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ srcColor = src[PIXEL_GREEN];
+ dstColor = dst[PIXEL_GREEN];
+
+ srcColor = UINT8_MULT(srcColor, dstColor);
+
+ dst[PIXEL_GREEN] = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ srcColor = src[PIXEL_BLUE];
+ dstColor = dst[PIXEL_BLUE];
+
+ srcColor = UINT8_MULT(srcColor, dstColor);
+
+ dst[PIXEL_BLUE] = UINT8_BLEND(srcColor, dstColor, srcBlend);
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeDivide(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT8_MAX + 1u) + (srcColor / 2u)) / (1u + srcColor), UINT8_MAX);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeScreen(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = UINT8_MAX - UINT8_MULT(UINT8_MAX - dstColor, UINT8_MAX - srcColor);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeOverlay(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = UINT8_MULT(dstColor, dstColor + UINT8_MULT(2 * srcColor, UINT8_MAX - dstColor));
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeDodge(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMIN((dstColor * (UINT8_MAX + 1)) / (UINT8_MAX + 1 - srcColor), UINT8_MAX);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeBurn(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMIN(((UINT8_MAX - dstColor) * (UINT8_MAX + 1)) / (srcColor + 1), UINT8_MAX);
+ if (UINT8_MAX - srcColor > UINT8_MAX) srcColor = UINT8_MAX;
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeDarken(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMIN(srcColor, dstColor);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeLighten(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ for (int channel = 0; channel < MAX_CHANNEL_RGB; channel++) {
+
+ Q_UINT8 srcColor = src[channel];
+ Q_UINT8 dstColor = dst[channel];
+
+ srcColor = QMAX(srcColor, dstColor);
+
+ Q_UINT8 newColor = UINT8_BLEND(srcColor, dstColor, srcBlend);
+
+ dst[channel] = newColor;
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeHue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ int dstRed = dst[PIXEL_RED];
+ int dstGreen = dst[PIXEL_GREEN];
+ int dstBlue = dst[PIXEL_BLUE];
+
+ int srcHue;
+ int srcSaturation;
+ int srcValue;
+ int dstHue;
+ int dstSaturation;
+ int dstValue;
+
+ rgb_to_hsv(src[PIXEL_RED], src[PIXEL_GREEN], src[PIXEL_BLUE], &srcHue, &srcSaturation, &srcValue);
+ rgb_to_hsv(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ int srcRed;
+ int srcGreen;
+ int srcBlue;
+
+ hsv_to_rgb(srcHue, dstSaturation, dstValue, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = UINT8_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = UINT8_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = UINT8_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeSaturation(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ int dstRed = dst[PIXEL_RED];
+ int dstGreen = dst[PIXEL_GREEN];
+ int dstBlue = dst[PIXEL_BLUE];
+
+ int srcHue;
+ int srcSaturation;
+ int srcValue;
+ int dstHue;
+ int dstSaturation;
+ int dstValue;
+
+ rgb_to_hsv(src[PIXEL_RED], src[PIXEL_GREEN], src[PIXEL_BLUE], &srcHue, &srcSaturation, &srcValue);
+ rgb_to_hsv(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ int srcRed;
+ int srcGreen;
+ int srcBlue;
+
+ hsv_to_rgb(dstHue, srcSaturation, dstValue, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = UINT8_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = UINT8_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = UINT8_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeValue(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ int dstRed = dst[PIXEL_RED];
+ int dstGreen = dst[PIXEL_GREEN];
+ int dstBlue = dst[PIXEL_BLUE];
+
+ int srcHue;
+ int srcSaturation;
+ int srcValue;
+ int dstHue;
+ int dstSaturation;
+ int dstValue;
+
+ rgb_to_hsv(src[PIXEL_RED], src[PIXEL_GREEN], src[PIXEL_BLUE], &srcHue, &srcSaturation, &srcValue);
+ rgb_to_hsv(dstRed, dstGreen, dstBlue, &dstHue, &dstSaturation, &dstValue);
+
+ int srcRed;
+ int srcGreen;
+ int srcBlue;
+
+ hsv_to_rgb(dstHue, dstSaturation, srcValue, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = UINT8_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = UINT8_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = UINT8_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeColor(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ Q_INT32 columns = numColumns;
+ const Q_UINT8 *mask = maskRowStart;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ srcAlpha = QMIN(srcAlpha, dstAlpha);
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(src[PIXEL_ALPHA], opacity);
+ }
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ int dstRed = dst[PIXEL_RED];
+ int dstGreen = dst[PIXEL_GREEN];
+ int dstBlue = dst[PIXEL_BLUE];
+
+ int srcHue;
+ int srcSaturation;
+ int srcLightness;
+ int dstHue;
+ int dstSaturation;
+ int dstLightness;
+
+ rgb_to_hls(src[PIXEL_RED], src[PIXEL_GREEN], src[PIXEL_BLUE], &srcHue, &srcLightness, &srcSaturation);
+ rgb_to_hls(dstRed, dstGreen, dstBlue, &dstHue, &dstLightness, &dstSaturation);
+
+ Q_UINT8 srcRed;
+ Q_UINT8 srcGreen;
+ Q_UINT8 srcBlue;
+
+ hls_to_rgb(srcHue, dstLightness, srcSaturation, &srcRed, &srcGreen, &srcBlue);
+
+ dst[PIXEL_RED] = UINT8_BLEND(srcRed, dstRed, srcBlend);
+ dst[PIXEL_GREEN] = UINT8_BLEND(srcGreen, dstGreen, srcBlend);
+ dst[PIXEL_BLUE] = UINT8_BLEND(srcBlue, dstBlue, srcBlend);
+ }
+
+ columns--;
+ src += MAX_CHANNEL_RGBA;
+ dst += MAX_CHANNEL_RGBA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+}
+
+void KisRgbColorSpace::compositeErase(Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowSize,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ Q_UINT8 /*opacity*/)
+{
+ Q_INT32 i;
+ Q_UINT8 srcAlpha;
+
+ while (rows-- > 0)
+ {
+ const Q_UINT8 *s = src;
+ Q_UINT8 *d = dst;
+ const Q_UINT8 *mask = srcAlphaMask;
+
+ for (i = cols; i > 0; i--, s+=MAX_CHANNEL_RGBA, d+=MAX_CHANNEL_RGBA)
+ {
+ srcAlpha = s[PIXEL_ALPHA];
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_BLEND(srcAlpha, OPACITY_OPAQUE, *mask);
+ mask++;
+ }
+ d[PIXEL_ALPHA] = UINT8_MULT(srcAlpha, d[PIXEL_ALPHA]);
+ }
+
+ dst += dstRowSize;
+ if(srcAlphaMask)
+ srcAlphaMask += maskRowStride;
+ src += srcRowSize;
+ }
+}
+
+void KisRgbColorSpace::bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *mask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op)
+{
+
+ switch (op.op()) {
+ case COMPOSITE_UNDEF:
+ // Undefined == no composition
+ break;
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ALPHA_DARKEN:
+ compositeAlphaDarken(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DIVIDE:
+ compositeDivide(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_LIGHTEN:
+ compositeLighten(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_HUE:
+ compositeHue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_SATURATION:
+ compositeSaturation(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_VALUE:
+ compositeValue(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COLOR:
+ compositeColor(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, 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, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_OVERLAY:
+ compositeOverlay(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_DODGE:
+ compositeDodge(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_BURN:
+ compositeBurn(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ default:
+ break;
+ }
+}
+
+KisCompositeOpList KisRgbColorSpace::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));
+ list.append(KisCompositeOp(COMPOSITE_HUE));
+ list.append(KisCompositeOp(COMPOSITE_SATURATION));
+ list.append(KisCompositeOp(COMPOSITE_VALUE));
+ list.append(KisCompositeOp(COMPOSITE_COLOR));
+ list.append(KisCompositeOp(COMPOSITE_PLUS));
+ list.append(KisCompositeOp(COMPOSITE_MINUS));
+ list.append(KisCompositeOp(COMPOSITE_SUBTRACT));
+ list.append(KisCompositeOp(COMPOSITE_ADD));
+
+ return list;
+}
diff --git a/krita/colorspaces/rgb_u8/kis_rgb_colorspace.h b/krita/colorspaces/rgb_u8/kis_rgb_colorspace.h
new file mode 100644
index 00000000..40718251
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/kis_rgb_colorspace.h
@@ -0,0 +1,116 @@
+/*
+ * Copyright (c) 2002 Patrick Julien <[email protected]>
+ *
+ * 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_RGB_H_
+#define KIS_STRATEGY_COLORSPACE_RGB_H_
+
+#include "klocale.h"
+
+#include "kis_global.h"
+#include "kis_u8_base_colorspace.h"
+#include "koffice_export.h"
+
+const Q_UINT8 PIXEL_BLUE = 0;
+const Q_UINT8 PIXEL_GREEN = 1;
+const Q_UINT8 PIXEL_RED = 2;
+const Q_UINT8 PIXEL_ALPHA = 3;
+
+class KRITATOOL_EXPORT KisRgbColorSpace : public KisU8BaseColorSpace {
+public:
+ KisRgbColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p);
+ virtual ~KisRgbColorSpace();
+
+ virtual bool willDegrade(ColorSpaceIndependence)
+ {
+ return false;
+ };
+
+
+public:
+ void setPixel(Q_UINT8 *pixel, Q_UINT8 red, Q_UINT8 green, Q_UINT8 blue, Q_UINT8 alpha) const;
+ void getPixel(const Q_UINT8 *pixel, Q_UINT8 *red, Q_UINT8 *green, Q_UINT8 *blue, Q_UINT8 *alpha) const;
+
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+ virtual void convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const;
+ virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels);
+ virtual void darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const;
+ virtual Q_UINT8 intensity8(const Q_UINT8 * src) const;
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+
+ virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
+ KisProfile * dstProfile = 0,
+ Q_INT32 renderingIntent = INTENT_PERCEPTUAL,
+ float exposure = 0.0f);
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+protected:
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeAlphaDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeMultiply(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeDivide(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeScreen(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeOverlay(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeDodge(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeBurn(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeDarken(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeLighten(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeHue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeSaturation(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeValue(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeColor(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+};
+
+class KisRgbColorSpaceFactory : public KisColorSpaceFactory
+{
+public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("RGBA", i18n("RGB (8-bit integer/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return TYPE_BGRA_8; };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icSigRgbData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile * p) { return new KisRgbColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return "sRGB built-in - (lcms internal)"; };
+};
+
+#endif // KIS_STRATEGY_COLORSPACE_RGB_H_
diff --git a/krita/colorspaces/rgb_u8/kritargbplugin.desktop b/krita/colorspaces/rgb_u8/kritargbplugin.desktop
new file mode 100644
index 00000000..a8f5c30d
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/kritargbplugin.desktop
@@ -0,0 +1,99 @@
+[Desktop Entry]
+Name=RGB Color Model
+Name[bg]=Цветови модел RGB
+Name[br]=Gobari al livioù RGB
+Name[ca]=Model de color RGB
+Name[cy]=Model Lliw RGB
+Name[da]=RGB-farvemodel
+Name[de]=RGB-Farbmodell
+Name[el]=Χρωματικό μοντέλο RGB
+Name[en_GB]=RGB Colour Model
+Name[eo]=RGB-kolormodelo
+Name[es]=Modelo de color RGB
+Name[et]=RGB värvimudel
+Name[eu]=RGB kolore-eredua
+Name[fa]=مدل رنگ RGB
+Name[fi]=RGB-värimalli
+Name[fr]=Modèle de couleurs RVB
+Name[fy]=RGB-kleurmodel
+Name[gl]=Modelo de Cores RGB
+Name[he]=מודל צבעים RGB
+Name[hi]=आरजीबी रंग नमूना
+Name[hu]=RGB színmodell
+Name[is]=RGB litategund
+Name[it]=Modello di colore RGB
+Name[ja]=RGB カラーモデル
+Name[km]=គំរូ​ពណ៌ RGB
+Name[lt]=RGB spalvų modelis
+Name[lv]=RGB krāsu modelis
+Name[ms]=Model Warna RGB
+Name[nb]=RGB-fargemodell
+Name[nds]=RGB-Klöörmodell
+Name[ne]=RGB रङ मोडेल
+Name[nl]=RGB-kleurmodel
+Name[nn]=RGB-fargemodell
+Name[pl]=Przestrzeń barw RGB
+Name[pt]=Modelo de Cor RGB
+Name[pt_BR]=Modelo de Cor RGB
+Name[ru]=RGB
+Name[se]=RGB-ivdnemálle
+Name[sk]=Model farieb RGB
+Name[sl]=Barvni model RGB
+Name[sr]=RGB модел боја
+Name[sr@Latn]=RGB model boja
+Name[sv]=RGB-färgmodell
+Name[ta]=RGB வண்ண மாதிரி
+Name[tr]=RGB Renk Modeli
+Name[uk]=Модель кольору RGB
+Name[uz]=RGB rang usuli
+Name[uz@cyrillic]=RGB ранг усули
+Name[zh_CN]=RGB 色彩模型
+Name[zh_TW]=RGB 色彩模型
+Comment=Color model for 8-bit/channel RGB images
+Comment[bg]=Цветови модел за 8 битови изображения RGB
+Comment[ca]=Model de color per a 8 bits/canal d'imatges RGB
+Comment[cy]=Model lliw ar gyfer delweddau RGB 8-did/sianel
+Comment[da]=Farvemodel for 8-bit/kanal RGB-billeder
+Comment[de]=Farbmodell für 8-bit pro Kanal RGB-Bilder
+Comment[el]=Χρωματικό μοντέλο για 8-bit/κανάλι RGB εικόνες
+Comment[en_GB]=Colour model for 8-bit/channel RGB images
+Comment[es]=Modelo de color para imágenes de 8 bits/canal RGB
+Comment[et]=8-bitiste kanalitega RGB-piltide värvimudel
+Comment[eu]=8-bit/kanaleko RGB irudien kolore-eredua
+Comment[fa]=مدل رنگ برای تصاویر ۸ بیتی/RGB مجرا
+Comment[fi]=Värimalli 8-bittisille/kanavaisille RGB-kuville
+Comment[fr]=Modèle de couleurs pour des images RVB en 8 bits/plage
+Comment[fy]=Kleurmodel foar 8-bit/kanaal RGB-ôfbyldings
+Comment[gl]=Modelo de Cores para imaxe RGB de 8-bit/canal
+Comment[he]=מודל צבעים עבור תמונות RGB של 8 סיביות/ערוצים
+Comment[hi]=8-बिट/चैनल आरजीबी छवियों के लिए रंग नमूना
+Comment[hu]=Színmodell 8 bit/csatorna RGB képekhez
+Comment[is]=Litategund fyrir 8-bita/rás RGB myndir
+Comment[it]=Modello di colore per immagini RGB a canale di 8 bit
+Comment[ja]=8 ビット/チャンネル RGB 画像のためのカラーモデル
+Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព RGB ៨ ប៊ីត/មួយ​ឆានែល
+Comment[ms]=Model warna imej RGB 8-bit/saluran
+Comment[nb]=Fargemodell for RGB-bilde med 8 bit per kanal
+Comment[nds]=Klöörmodell för RGB-Biller mit 8-Bit per Kanaal
+Comment[ne]=८-बिट/च्यानल RGB छविहरूका लागि रङ मोडेल
+Comment[nl]=Kleurmodel voor 8-bit/kanaal RGB-afbeeldingen
+Comment[nn]=Fargemodell for RGB-bilete med 8 bit per kanal
+Comment[pl]=Przestrzeń barw dla obrazków RGB 8-bitów/kanał
+Comment[pt]=Modelo de cor para imagens RGB com 8 bits por canal
+Comment[pt_BR]=Modelo de cor para imagens com 8-bits de canal RGB
+Comment[ru]=Цветовое пространство RGB (8-бит/канал)
+Comment[sk]=Model farieb pre RGB obrázky s 8-bitovými číslami na kanál
+Comment[sl]=Barvni model za slike RGB z 8 biti/kanal
+Comment[sr]=Модел боја за RGB слике са 8 битова/каналу
+Comment[sr@Latn]=Model boja za RGB slike sa 8 bitova/kanalu
+Comment[sv]=Färgmodell för 8-bitar/kanal RGB-bilder
+Comment[ta]=8/பிட்/வழி RGB பிம்பங்களுக்கான வண்ண முறை
+Comment[tg]=Mодели ранга барои 8-бит /канал тасвирҳои RGB
+Comment[tr]=8-bit/kanal RGB görüntüler için renk modeli.
+Comment[uk]=Модель кольорів для зображень RGB з 8-бітами/канал
+Comment[zh_CN]=8 位/通道 RGB 图像的色彩模型
+Comment[zh_TW]=8-bit/色頻 RGB 圖片的色彩模型
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-KDE-Library=kritargbplugin
+X-Krita-Version=2
diff --git a/krita/colorspaces/rgb_u8/rgb_plugin.cc b/krita/colorspaces/rgb_u8/rgb_plugin.cc
new file mode 100644
index 00000000..018c1491
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/rgb_plugin.cc
@@ -0,0 +1,74 @@
+/*
+* rgb_plugin.cc -- Part of Krita
+*
+* Copyright (c) 2004 Boudewijn Rempt ([email protected])
+*
+* 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 <stdlib.h>
+#include <vector>
+
+#include <qpoint.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <kis_debug_areas.h>
+
+#include <kis_debug_areas.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_basic_histogram_producers.h>
+
+#include "rgb_plugin.h"
+#include "kis_rgb_colorspace.h"
+
+typedef KGenericFactory<RGBPlugin> RGBPluginFactory;
+K_EXPORT_COMPONENT_FACTORY( kritargbplugin, RGBPluginFactory( "krita" ) )
+
+
+RGBPlugin::RGBPlugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(RGBPluginFactory::instance());
+
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") )
+ {
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry*>(parent);
+
+ KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile());
+ f->addProfile(defProfile);
+
+
+ KisColorSpaceFactory * csFactory = new KisRgbColorSpaceFactory();
+ f->add(csFactory);
+
+ KisColorSpace * colorSpaceRGBA = new KisRgbColorSpace(f, 0);
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicU8HistogramProducer>
+ (KisID("RGB8HISTO", i18n("RGB8")), colorSpaceRGBA) );
+ }
+
+}
+
+RGBPlugin::~RGBPlugin()
+{
+}
+
+#include "rgb_plugin.moc"
diff --git a/krita/colorspaces/rgb_u8/rgb_plugin.h b/krita/colorspaces/rgb_u8/rgb_plugin.h
new file mode 100644
index 00000000..262d0bb4
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/rgb_plugin.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2003 Boudewijn Rempt ([email protected])
+ *
+ * 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 RGB_PLUGIN_H_
+#define RGB_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the RGB colour space strategy.
+ */
+class RGBPlugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ RGBPlugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~RGBPlugin();
+
+};
+
+
+#endif // RGB_PLUGIN_H_
diff --git a/krita/colorspaces/rgb_u8/rgbplugin.rc b/krita/colorspaces/rgb_u8/rgbplugin.rc
new file mode 100644
index 00000000..cc618164
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/rgbplugin.rc
@@ -0,0 +1,9 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui library="kritargbplugin" version="1">
+<Menu name="Image"><text>&amp;Image</text>
+ <Menu name="Mode"><text>&amp;Mode</text>
+ <Action name="convert to RGB(A)"/>
+ </Menu>
+</Menu>
+
+</kpartgui>
diff --git a/krita/colorspaces/rgb_u8/templates/.directory b/krita/colorspaces/rgb_u8/templates/.directory
new file mode 100644
index 00000000..4b475643
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/.directory
@@ -0,0 +1,6 @@
+[Desktop Entry]
+Name=RGB
+Name[cy]=CGwGl (RGB)
+Name[fr]=RVB
+Name[hi]=आरजीबी
+X-KDE-DefaultTab=true
diff --git a/krita/colorspaces/rgb_u8/templates/Makefile.am b/krita/colorspaces/rgb_u8/templates/Makefile.am
new file mode 100644
index 00000000..29c87939
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/Makefile.am
@@ -0,0 +1,8 @@
+templates_DATA = .directory transparent_1024x768.desktop transparent_1280x1024.desktop transparent_1600x1200.desktop transparent_640x480.desktop white_1024x768.desktop white_1280x1024.desktop white_1600x1200.desktop white_640x480.desktop
+templatesdir = $(kde_datadir)/krita/templates/rgb
+
+templatesrc_DATA = transparent_1024x768.kra transparent_1280x1024.kra transparent_1600x1200.kra transparent_640x480.kra white_1024x768.kra white_1280x1024.kra white_1600x1200.kra white_640x480.kra
+templatesrcdir = $(kde_datadir)/krita/templates/rgb/.source
+
+templatesicon_ICON = AUTO
+templatesicondir = $(kde_datadir)/krita/icons
diff --git a/krita/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png b/krita/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png
new file mode 100644
index 00000000..ec4d6ddc
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png
Binary files differ
diff --git a/krita/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz b/krita/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz
new file mode 100644
index 00000000..3ea7b854
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz
Binary files differ
diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1024x768.desktop b/krita/colorspaces/rgb_u8/templates/transparent_1024x768.desktop
new file mode 100644
index 00000000..d22ad3e3
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/transparent_1024x768.desktop
@@ -0,0 +1,91 @@
+[Desktop Entry]
+Type=Link
+URL=.source/transparent_1024x768.kra
+Icon=template_rgb_empty
+Name=Transparent 1024 x 768
+Name[bg]=Прозрачно 1024x768
+Name[br]=Treuzwelus 1024 x 768
+Name[cy]=Tryloyw 1024 x 768
+Name[da]=Gennemsigtig 1024 x 768
+Name[el]=Διαφανής 1024 x 768
+Name[es]=1024 x 768 transparente
+Name[et]=Läbipaistev 1024 x 768
+Name[eu]=Gardena 1024 x 768
+Name[fa]=شفاف ۷۶۸ × ۱۰۲۴
+Name[fi]=Läpinäkyvä 1024x768
+Name[fr]=Image transparente 1024 x 768
+Name[fy]=Trochsichtich 1024 x 768
+Name[gl]=Transparente 1024 x 768
+Name[he]=‏1024‎ x 768 שקוף
+Name[hu]=Áttetsző 1024 x 768
+Name[is]=Gegnsæ 1024 x 768
+Name[it]=Trasparente 1024 × 768
+Name[ja]=透明 1024 x 768
+Name[km]=ថ្លា 1024 x 768
+Name[lt]=Permatomas 1024 x 768
+Name[lv]=Caurspīdīgs 1024 x 768
+Name[ms]=Lutsinar 1024 x 768
+Name[nb]=Gjennomsiktig 1024 × 768
+Name[nds]=Dörsichtig 1024 x 768
+Name[ne]=पारदर्शी १०२४ x ७६८
+Name[nn]=Gjennomsiktig 1024 × 768
+Name[pl]=Przezroczysty 1024 x 768
+Name[pt]=Transparente 1024 x 768
+Name[pt_BR]=Transparente de 1024 x 768
+Name[ru]=Рисунок 1024x768, прозрачный фон
+Name[se]=Čađačuovgi 1024 × 768
+Name[sk]=Priehľadný 1024 x 768
+Name[sl]=Prosojna 1024 x 768
+Name[sr]=Провидна 1024 x 768
+Name[sr@Latn]=Providna 1024 x 768
+Name[sv]=Genomskinlig 1024 x 768
+Name[uk]=Прозоре 1024 x 768
+Name[uz]=Shaffof 1024 x 768
+Name[uz@cyrillic]=Шаффоф 1024 x 768
+Name[zh_CN]=透明 1024 x 768
+Name[zh_TW]=透明 1024 x 768
+Comment=Creates a transparent image of 1024 x 768 pixels.
+Comment[bg]=Създава прозрачно изображение с размери 1024x768 пиксела.
+Comment[ca]=Crea una imatge transparent de 1024 x 768 píxels.
+Comment[cy]=Creu delwedd dryloyw o 1024 x 768 picsel.
+Comment[da]=Laver et gennemsigtigt billede på 1024 x 768 billedpunkter.
+Comment[de]=Erstellt ein transparentes Bild mit 1024 x 768 Pixeln.
+Comment[el]=Δημιουργεί μία διαφανή εικόνα μεγέθους 1024 x 768 εικονοστοιχείων.
+Comment[eo]=Kreas travideblan bildon el 1024 x 768 rastrumeroj.
+Comment[es]=Crea una imagen transparente de 1024 x 768 píxeles.
+Comment[et]=Loob läbipaistva pildi mõõtmetega 1024 x 768 pikslit.
+Comment[eu]=1024 x 768 pixeleko irudi garden bat sortzen du.
+Comment[fa]=یک تصویر شفاف ۷۶۸ × ۱۰۲۴ تصویردانه‌ای ایجاد می‌کند.
+Comment[fi]=Luo läpinäkyvän 1024x768 pikselin kuvan.
+Comment[fr]=Crée une image transparente de 1024 x 768 pixels.
+Comment[fy]=Makket in trochsichtige ôfbylding oan fan 1024 x 768 byldpunten.
+Comment[gl]=Cria unha imaxe transparente de 1024 x 768 pixels.
+Comment[he]=יצירת תמונה שקופה בגודל ‎1024 x 768 פיקסלים
+Comment[hu]=Létrehoz egy 1024 x 768 képpontos áttetsző képet.
+Comment[is]=Býr til gegnsæja mynd í hlutföllunum 1024 x 768 punktar.
+Comment[it]=Crea un'immagine trasparente di 1024 × 768 pixel.
+Comment[ja]=1024 x 768 ピクセルの透視画像を作成
+Comment[km]=បង្កើត​រូបភាព​ថ្លា​ទំហំ 1024 x 768 ភីកសែល ។
+Comment[lt]=Sukuria permatomą 1024 x 768 pikselių paveiksliuką.
+Comment[ms]=Cipta imej lutsinar 1024 x 768 piksel.
+Comment[nb]=Lager et gjennomsiktig bilde på 1024 x 768 piksler.
+Comment[nds]=Stellt en dörsichtig Bild mit 1024 x 768 Pixels op.
+Comment[ne]=१०२४ x ७६८ पिक्सेलको पारदर्शी छवि सिर्जना गर्दछ ।
+Comment[nl]=Maakt een transparante afbeelding aan van 1024 x 768 pixels.
+Comment[nn]=Lagar eit gjennomsiktig bilete på 1024 × 768 pikslar.
+Comment[pl]=Tworzy przezroczysty obrazek o rozmiarach 1024 x 768 pikseli.
+Comment[pt]=Cria uma imagem transparente com 1024 x 768 pontos.
+Comment[pt_BR]=Cria uma imagem transparente de 1024 x 768 pixels.
+Comment[ru]=Рисунок 1024x768, прозрачный фон
+Comment[se]=Ráhkada čađačuovgi gova mas t 1024 × 768 govvačuoggá
+Comment[sk]=Vytvorí obrázok s rozmermi 1024 x 768 pixelov a priehľadným pozadím.
+Comment[sl]=Ustvari prosojno sliko velikosti 1024 x 768 pik.
+Comment[sr]=Прави провидну слику са 1024 x 768 пиксела.
+Comment[sr@Latn]=Pravi providnu sliku sa 1024 x 768 piksela.
+Comment[sv]=Skapar en genomskinlig bild med 1024 x 768 bildpunkter.
+Comment[uk]=Створює прозоре зображення 1024 x 768 пікселів.
+Comment[uz]=Oʻlchami 1024 x 768 nuqta boʻlgan shaffof rasmni yaratish.
+Comment[uz@cyrillic]=Ўлчами 1024 x 768 нуқта бўлган шаффоф расмни яратиш.
+Comment[zh_CN]=创建 1024 x 768 像素的透明图像。
+Comment[zh_TW]=建立一個 1024 x 768 像素的透明圖片。
+X-Krita-Version=2
diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1024x768.kra b/krita/colorspaces/rgb_u8/templates/transparent_1024x768.kra
new file mode 100644
index 00000000..eb026588
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/transparent_1024x768.kra
Binary files differ
diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.desktop b/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.desktop
new file mode 100644
index 00000000..58469cc6
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+Type=Link
+URL=.source/transparent_1280x1024.kra
+Icon=template_rgb_empty
+Name=Transparent 1280 x 1024
+Name[bg]=Прозрачно 1280x1204
+Name[br]=Treuzwelus 1280 x 1024
+Name[cy]=Tryloyw 1280 x 1024
+Name[da]=Gennemsigtig 1280 x 1024
+Name[el]=Διαφανής 1280 x 1024
+Name[eo]=Travidebla 1280 x 1024
+Name[es]=1280 x 1024 transparente
+Name[et]=Läbipaistev 1280 x 1024
+Name[eu]=Gardena 1280 x 1024
+Name[fa]=شفاف ۱۰۲۴ × ۱۲۸۰
+Name[fi]=Läpinäkyvä 1280x1024
+Name[fr]=Image transparente 1280 x 1024
+Name[fy]=Trochsichtich 1280 x 1024
+Name[gl]=Transparente 1280 x 1024
+Name[he]=‏1280‎ x 1024 שקוף
+Name[hu]=Áttetsző 1280 x 1024
+Name[is]=Gegnsæ 1280 x 1024
+Name[it]=Trasparente 1280 × 1024
+Name[ja]=透明 1280 x 1024
+Name[km]=ថ្លា 1280 x 1024
+Name[lt]=Permatomas 1280 x 1024
+Name[lv]=Caurspīdīgs 1280 x 1024
+Name[ms]=Lutsinar 1280 x 1024
+Name[nb]=Gjennomsiktig 1280 x 1024
+Name[nds]=Dörsichtig 1280 x 1024
+Name[ne]=पारदर्शी १२८० x १०२४
+Name[nn]=Gjennomsiktig 1280 × 1024
+Name[pl]=Przezroczysty 1280 x 1024
+Name[pt]=Transparente 1280 x 1024
+Name[pt_BR]=Transparente de 1280 x 1024
+Name[ru]=Рисунок 1280x1024, прозрачный фон
+Name[se]=Čađačuovgi 1280 × 1024
+Name[sk]=Priehľadný 1280 x 1024
+Name[sl]=Prosojna 1280 x 1024
+Name[sr]=Провидна 1280 x 1024
+Name[sr@Latn]=Providna 1280 x 1024
+Name[sv]=Genomskinlig 1280 x 1024
+Name[uk]=Прозоре 1280 x 1024
+Name[uz]=Shaffof 1280 x 1024
+Name[uz@cyrillic]=Шаффоф 1280 x 1024
+Name[zh_CN]=透明 1280 x 1024
+Name[zh_TW]=透明 1280 x 1024
+Comment=Creates a transparent image of 1280 x 1024 pixels.
+Comment[bg]=Създава прозрачно изображение с размери 1280x1024 пиксела.
+Comment[ca]=Crea una imatge transparent de 1280 x 1024 píxels.
+Comment[cy]=Creu delwedd dryloyw o 1280 x 1024 picsel.
+Comment[da]=Laver et gennemsigtigt billede på 1280 x 1024 billedpunkter.
+Comment[de]=Erstellt ein transparentes Bild mit 1280 x 1024 Pixeln.
+Comment[el]=Δημιουργεί μία διαφανή εικόνα μεγέθους 1280 x 1024 εικονοστοιχείων.
+Comment[eo]=Kreas travideblan bildon el 1280 x 1024 rastrumeroj.
+Comment[es]=Crea una imagen transparente de 1280 x 1024 píxeles.
+Comment[et]=Loob läbipaistva pildi mõõtmetega 1280 x 1024 pikslit.
+Comment[eu]=1280 x 1024 pixeleko irudi garden bat sortzen du.
+Comment[fa]=یک تصویر شفاف ۱۰۲۴ × ۱۲۸۰ تصویردانه‌ای ایجاد می‌کند.
+Comment[fi]=Luo läpinäkyvän 1280x1024 pikselin kuvan.
+Comment[fr]=Crée une image transparente de 1280 x 1024 pixels.
+Comment[fy]=Makket in trochsichtige ôfbylding oan fan 1280 x 1024 byldpunten.
+Comment[gl]=Cria unha imaxe transparente de 1280 x 1024 pixels.
+Comment[he]=יצירת תמונה שקופה בגודל ‎1280 x 1024 פיקסלים
+Comment[hu]=Létrehoz egy 1280 x 1024 képpontos áttetsző képet.
+Comment[is]=Býr til gegnsæja mynd í hlutföllunum 1280 x 1024 punktar.
+Comment[it]=Crea un'immagine trasparente di 1280 × 1024 pixel.
+Comment[ja]=1280 x 1024 ピクセルの透視画像を作成
+Comment[km]=បង្កើត​រូបភាព​ថ្លា​ទំហំ 1280 x 1024 ភីកសែល ។
+Comment[lt]=Sukuria permatomą 1280 x 1024 pikselių paveiksliuką.
+Comment[ms]=Cipta imej lutsinar 1280 x 1024 piksel.
+Comment[nb]=Lager et gjennomsiktig bilde på 1280 x 1024 piksler.
+Comment[nds]=Stellt en dörsichtig Bild mit 1280 x 1024 Pixels op.
+Comment[ne]=१२८० x १०२४ पिक्सेलको पारदर्शी छवि सिर्जना गर्दछ ।
+Comment[nl]=Maakt een transparante afbeelding aan van 1280 x 1024 pixels.
+Comment[nn]=Lagar eit gjennomsiktig bilete på 1280 × 1024 pikslar.
+Comment[pl]=Tworzy przezroczysty obrazek o rozmiarach 1280 x 1024 pikseli.
+Comment[pt]=Cria uma imagem transparente com 1280 x 1024 pontos.
+Comment[pt_BR]=Cria uma imagem transparente de 1280 x 1024 pixels.
+Comment[ru]=Рисунок 1280x1024, прозрачный фон
+Comment[se]=Ráhkada čađačuovgi gova mas lea 1280 × 1024 govvačuoggá
+Comment[sk]=Vytvorí obrázok s rozmermi 1280 x 1024 pixelov a priehľadným pozadím.
+Comment[sl]=Ustvari prosojno sliko velikosti 1280 x 1024 pik.
+Comment[sr]=Прави провидну слику са 1280 x 1024 пиксела.
+Comment[sr@Latn]=Pravi providnu sliku sa 1280 x 1024 piksela.
+Comment[sv]=Skapar en genomskinlig bild med 1280 x 1024 bildpunkter.
+Comment[uk]=Створює прозоре зображення 1280 x 1024 пікселів.
+Comment[uz]=Oʻlchami 1280 x 1024 nuqta boʻlgan shaffof rasmni yaratish.
+Comment[uz@cyrillic]=Ўлчами 1280 x 1024 нуқта бўлган шаффоф расмни яратиш.
+Comment[zh_CN]=创建 1280x 1024 像素的透明图像。
+Comment[zh_TW]=建立一個 1280 x 1024 像素的透明圖片。
+X-Krita-Version=2
diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.kra b/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.kra
new file mode 100644
index 00000000..be96fb23
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.kra
Binary files differ
diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.desktop b/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.desktop
new file mode 100644
index 00000000..c4937805
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.desktop
@@ -0,0 +1,97 @@
+[Desktop Entry]
+Type=Link
+URL=.source/transparent_1600x1200.kra
+Icon=template_rgb_empty
+Name=Transparent 1600 x 1200
+Name[bg]=Прозрачно 1600x1200
+Name[br]=Treuzwelus 1600 x 1200
+Name[cy]=Tryloyw 1600 x 1200
+Name[da]=Gennemsigtig 1600 x 1200
+Name[el]=Διαφανής 1600 x 1200
+Name[es]=1600 x 1200 transparente
+Name[et]=Läbipaistev 1600 x 1200
+Name[eu]=Gardena 1600 x 1200
+Name[fa]=شفاف ۱۲۰۰ × ۱۶۰۰
+Name[fi]=Läpinäkyvä 1600x1200
+Name[fr]=Image transparente 1600 x 1200
+Name[fy]=Trochsichtich 1600 x 1200
+Name[gl]=Transparente 1600 x 1200
+Name[he]=‏1600‎ x 1200 שקוף
+Name[hi]=पारदर्शी 1600 x 1200
+Name[hu]=Áttetsző 1600 x 1200
+Name[is]=Gegnsæ 1600 x 1200
+Name[it]=Trasparente 1600 × 1200
+Name[ja]=透明 1600 x 1200
+Name[km]=ថ្លា 1600 x 1200
+Name[lt]=Permatomas 1600 x 1200
+Name[lv]=Caurspīdīgs 1600 x 1200
+Name[ms]=Lutsinar 1600 x 1200
+Name[nb]=Gjennomsiktig 1600 × 1200
+Name[nds]=Dörsichtig 1600 x 1200
+Name[ne]=पारदर्शी १६०० x १२००
+Name[nl]=Transparant 1600 x 1200
+Name[nn]=Gjennomsiktig 1600 × 1200
+Name[pl]=Przezroczysty 1600 x 1200
+Name[pt]=Transparente 1600 x 1200
+Name[pt_BR]=Transparente de 1600 x 1200
+Name[ru]=Рисунок 1600x1200, прозрачный фон
+Name[se]=Čađačuovgi 1600 × 1200
+Name[sk]=Priehľadný 1600 x 1200
+Name[sl]=Prosojna 1600 x 1200
+Name[sr]=Провидна 1600 x 1200
+Name[sr@Latn]=Providna 1600 x 1200
+Name[sv]=Genomskinlig 1600 x 1200
+Name[ta]=தெரியக்கூடிய 1600 x 1200
+Name[tr]=Saydam 1600 x 1200
+Name[uk]=Прозоре 1600 x 1200
+Name[uz]=Shaffof 1600 x 1200
+Name[uz@cyrillic]=Шаффоф 1600 x 1200
+Name[zh_CN]=透明 1600 x 1200
+Name[zh_TW]=透明 1600 x 1200
+Comment=Creates a transparent image of 1600 x 1200 pixels.
+Comment[bg]=Създаване на прозрачно изображение с размери 1600x1200 пиксела.
+Comment[ca]=Crea una imatge transparent de 1600 x 1200 píxels.
+Comment[cy]=Creu delwedd dryloyw o 1600 x 1200 picsel.
+Comment[da]=Laver et gennemsigtigt billede på 1600 x 1200 billedpunkter.
+Comment[de]=Erstellt ein transparentes Bild mit 1600 x 1200 Pixeln.
+Comment[el]=Δημιουργεί μία διαφανή εικόνα μεγέθους 1600 x 1200 εικονοστοιχείων.
+Comment[es]=Crea una imagen transparente de 1600 x 1200 píxeles.
+Comment[et]=Loob läbipaistva pildi mõõtmetega 1600 x 1200 pikslit.
+Comment[eu]=1600 x 1200 pixeleko irudi garden bat sortzen du.
+Comment[fa]=یک تصویر شفاف ۱۲۰۰ × ۱۶۰۰ تصویردانه‌ای ایجاد می‌کند.
+Comment[fi]=Luo läpinäkyvän 1600x1200 pikselin kuvan.
+Comment[fr]=Crée une image transparente de 1600 x 1200 pixels.
+Comment[fy]=Makket in trochsichtige ôfbylding oan fan 11600 x 1200 byldpunten.
+Comment[gl]=Cria unha imaxe transparente de 1600 x 1200 pixels.
+Comment[he]=יצירת תמונה שקופה בגודל ‎1600 x 1200 פיקסלים
+Comment[hi]=1600 x 1200 पिक्सेल की पारदर्शी छवि बनाता है.
+Comment[hu]=Létrehoz egy 1600 x 1200 képpontos áttetsző képet.
+Comment[is]=Býr til gegnsæja mynd í hlutföllunum 1600 x 1200 punktar.
+Comment[it]=Crea un'immagine trasparente di 1600 × 1200 pixel.
+Comment[ja]=1600 x 1200 ピクセルの透視画像を作成
+Comment[km]=បង្កើត​រូបភាព​ថ្លា​ទំហំ 1600 x 1200 ភីកសែល ។
+Comment[lt]=Sukuria permatomą 1600 x 1200 pikselių paveiksliuką.
+Comment[ms]=Cipta imej lutsinar 1600 x 1200 piksel.
+Comment[nb]=Lager et gjennomsiktig bilde på 1600 x 1200 piksler.
+Comment[nds]=Stellt en dörsichtig Bild mit 1600 x 1200 Pixels op.
+Comment[ne]=१६०० x १२०० पिक्सेलको पारदर्शी छवि सिर्जना गर्दछ।
+Comment[nl]=Maakt een transparante afbeelding aan van 1600 x 1200 pixels.
+Comment[nn]=Lagar eit gjennomsiktig bilete på 1600 × 1200 pikslar.
+Comment[pl]=Tworzy przezroczysty obrazek o rozmiarach 1600 x 1200 pikseli.
+Comment[pt]=Cria uma imagem transparente com 1600 x 1200 pontos.
+Comment[pt_BR]=Cria uma imagem transparente de 1600 x 1200 pixéis.
+Comment[ru]=Рисунок 1600x1200, прозрачный фон
+Comment[se]=Ráhkada čađačuovgi gova mas lea 1600 × 1200 govvačuoggá.
+Comment[sk]=Vytvorí obrázok s rozmermi 1600 x 1200 pixelov a priehľadným pozadím.
+Comment[sl]=Ustvari prosojno sliko velikosti 1600 x 1200 pik.
+Comment[sr]=Прави провидну слику са 1600 x 1200 пиксела.
+Comment[sr@Latn]=Pravi providnu sliku sa 1600 x 1200 piksela.
+Comment[sv]=Skapar en genomskinlig bild med 1600 x 1200 bildpunkter.
+Comment[ta]=1600 x 1200 படத்துணுக்குகளில் ஒரு தெரியக்கூடிய பிம்பத்தை உருவாக்குகிறது.
+Comment[tr]=1600 x 1200 piksel ebadında transparan bir görüntü oluşturur.
+Comment[uk]=Створює прозоре зображення 1600 x 1200 пікселів.
+Comment[uz]=Oʻlchami 1600 x 1200 nuqta boʻlgan shaffof rasmni yaratish.
+Comment[uz@cyrillic]=Ўлчами 1600 x 1200 нуқта бўлган шаффоф расмни яратиш.
+Comment[zh_CN]=创建 1600 x 1200 像素的透明图像。
+Comment[zh_TW]=建立一個 1600 x 1200 像素的透明圖片。
+X-Krita-Version=2
diff --git a/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.kra b/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.kra
new file mode 100644
index 00000000..b01685a9
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.kra
Binary files differ
diff --git a/krita/colorspaces/rgb_u8/templates/transparent_640x480.desktop b/krita/colorspaces/rgb_u8/templates/transparent_640x480.desktop
new file mode 100644
index 00000000..7dec238a
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/transparent_640x480.desktop
@@ -0,0 +1,92 @@
+[Desktop Entry]
+Type=Link
+URL=.source/transparent_640x480.kra
+Icon=template_rgb_empty
+Name=Transparent 640 x 480
+Name[bg]=Прозрачно 640x480
+Name[br]=Treuzwelus 640 x 480
+Name[cy]=Tryloyw 640 x 480
+Name[da]=Gennemsigtig 640 x 480
+Name[el]=Διαφανής 640 x 480
+Name[eo]=Travidebla 640 x 480
+Name[es]=640 x 480 transparente
+Name[et]=Läbipaistev 640 x 480
+Name[eu]=Gardena 640 x 480
+Name[fa]=شفاف ۴۸۰ × ۶۴۰
+Name[fi]=Läpinäkyvä 640x480
+Name[fr]=Image transparente 640 x 480
+Name[fy]=Trochsichtich 640 x 480
+Name[gl]=Transparente 640 x 480
+Name[he]=‏640 x 480 שקוף
+Name[hu]=Áttetsző 640 x 480
+Name[is]=Gegnsæ 640 x 480
+Name[it]=Trasparente 640 × 480
+Name[ja]=透明 640 x 480
+Name[km]=ថ្លា 640 x 480
+Name[lt]=Permatomas 640 x 480
+Name[lv]=Caurspīdīgs 640 x 480
+Name[ms]=Lutsinar 640 x 480
+Name[nb]=Gjennomsiktig 640 x 480
+Name[nds]=Dörsichtig 640 x 480
+Name[ne]=पारदर्शी ६४० x ४८०
+Name[nn]=Gjennomsiktig 640 × 480
+Name[pl]=Przezroczysty 640 x 480
+Name[pt]=Transparente 640 x 480
+Name[pt_BR]=Transparente de 640 x 480
+Name[ru]=Рисунок 640x480, прозрачный фон
+Name[se]=Čađačuovgi 640 × 480
+Name[sk]=Priehľadný 640 x 480
+Name[sl]=Prosojna 640 x 480
+Name[sr]=Провидна 640 x 480
+Name[sr@Latn]=Providna 640 x 480
+Name[sv]=Genomskinlig 640 x 480
+Name[uk]=Прозоре 640 x 480
+Name[uz]=Shaffof 640 x 480
+Name[uz@cyrillic]=Шаффоф 640 x 480
+Name[zh_CN]=透明 640 x 480
+Name[zh_TW]=透明 640 x 480
+Comment=Creates a transparent image of 640 x 480 pixels.
+Comment[bg]=Създаване на прозрачно изображение с размери 640x480 пиксела.
+Comment[ca]=Crea una imatge transparent de 640 x 480 píxels.
+Comment[cy]=Creu delwedd dryloyw o 640 x 480 picsel.
+Comment[da]=Laver et gennemsigtigt billede på 640 x 480 billedpunkter.
+Comment[de]=Erstellt ein transparentes Bild mit 640 x 480 Pixeln.
+Comment[el]=Δημιουργεί μία διαφανή εικόνα μεγέθους 640 x 480 εικονοστοιχείων.
+Comment[eo]=Kreas travideblan bildon el 640 x 480 rastrumeroj.
+Comment[es]=Crea una imagen transparente de 640 x 480 píxeles.
+Comment[et]=Loob läbipaistva pildi mõõtmetega 640 x 480 pikslit.
+Comment[eu]=640 x 480 pixeleko irudi garden bat sortzen du.
+Comment[fa]=یک تصویر شفاف ۴۸۰ × ۶۴۰ تصویردانه‌ای ایجاد می‌کند.
+Comment[fi]=Luo läpinäkyvän 640x480 pikselin kuvan.
+Comment[fr]=Crée une image transparente de 640 x 480 pixels.
+Comment[fy]=Makket in trochsichtige ôfbylding oan fan 640 x 480 byldpunten.
+Comment[gl]=Cria unha imaxe transparente de 640 x 480 pixels.
+Comment[he]=יצירת תמונה שקופה בגודל ‎640 x 480 פיקסלים
+Comment[hu]=Létrehoz egy 640 x 480 képpontos áttetsző képet.
+Comment[is]=Býr til gegnsæja mynd í hlutföllunum 640 x 480 punktar.
+Comment[it]=Crea un'immagine trasparente di 640 × 480 pixel.
+Comment[ja]=640 x 480 ピクセルの透視画像を作成
+Comment[km]=បង្កើត​រូបភាព​ថ្លា​ទំហំ 640 x 480 ភីកសែល ។
+Comment[lt]=Sukuria permatomą 640 x 480 pikselių paveiksliuką.
+Comment[ms]=Cipta imej lutsinar 640 x 480 piksel.
+Comment[nb]=Lager et gjennomsiktig bilde på 640 x 480 piksler.
+Comment[nds]=Stellt en dörsichtig Bild mit 640 x 480 Pixels op.
+Comment[ne]=६४० x ४८० पिक्सेलको पारदर्शी सिर्जना गर्दछ ।
+Comment[nl]=Maakt een transparante afbeelding aan van 640 x 480 pixels.
+Comment[nn]=Lagar eit gjennomsiktig bilete på 640 × 480 pikslar.
+Comment[pl]=Tworzy przezroczysty obrazek o rozmiarach 640 x 480 pikseli.
+Comment[pt]=Cria uma imagem transparente com 640 x 480 pontos.
+Comment[pt_BR]=Cria uma imagem transparente de 640 x 480 pixels.
+Comment[ru]=Рисунок 640x480, прозрачный фон
+Comment[se]=Ráhkada čađačuovgi gova mas lea 640 × 480 govvačuoggá.
+Comment[sk]=Vytvorí obrázok s rozmermi 640 x 480 pixelov a priehľadným pozadím.
+Comment[sl]=Ustvari prosojno sliko velikosti 640 x 480 pik.
+Comment[sr]=Прави провидну слику са 640 x 480 пиксела.
+Comment[sr@Latn]=Pravi providnu sliku sa 640 x 480 piksela.
+Comment[sv]=Skapar en genomskinlig bild med 640 x 480 bildpunkter.
+Comment[uk]=Створює прозоре зображення 640 x 480 пікселів.
+Comment[uz]=Oʻlchami 640 x 480 nuqta boʻlgan shaffof rasmni yaratish.
+Comment[uz@cyrillic]=Ўлчами 640 x 480 нуқта бўлган шаффоф расмни яратиш.
+Comment[zh_CN]=创建 640 x 480 像素的透明图像。
+Comment[zh_TW]=建立一個 640 x 480 像素的透明圖片。
+X-Krita-Version=2
diff --git a/krita/colorspaces/rgb_u8/templates/transparent_640x480.kra b/krita/colorspaces/rgb_u8/templates/transparent_640x480.kra
new file mode 100644
index 00000000..59777c92
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/transparent_640x480.kra
Binary files differ
diff --git a/krita/colorspaces/rgb_u8/templates/white_1024x768.desktop b/krita/colorspaces/rgb_u8/templates/white_1024x768.desktop
new file mode 100644
index 00000000..57f097bf
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/white_1024x768.desktop
@@ -0,0 +1,102 @@
+[Desktop Entry]
+Type=Link
+URL=.source/white_1024x768.kra
+Icon=template_rgb_empty
+Name=White 1024 x 768
+Name[bg]=Бяло 1024x768
+Name[br]=Gwenn 1024 x 768
+Name[ca]=Blanc 1024 x 768
+Name[cy]=Gwyn 1024 x 768
+Name[da]=Hvidt 1024 x 768
+Name[de]=Weiß 1024 x 768
+Name[el]=Λευκή 1024 x 768
+Name[eo]=Blanka 1024 x 768
+Name[es]=1024 x 768 blanco
+Name[et]=Valge 1024 x 768
+Name[eu]=Zuria 1024 x 768
+Name[fa]=سفید ۷۶۸ × ۱۰۲۴
+Name[fi]=Valkoinen 1024x768
+Name[fr]=Image blanche 1024 x 768
+Name[fy]=Wyt 1024 x 768
+Name[ga]=Bán 1024×768
+Name[gl]=Branca 1024 x 768
+Name[he]=לבן ‎1024 x 768
+Name[hi]=सफेद 1024 x 768
+Name[hu]=Fehér 1024 x 768
+Name[is]=Hvít 1024 x 768
+Name[it]=Bianco 1024 × 768
+Name[ja]=白 1024 x 768
+Name[km]=ពណ៌ស 1024 x 768
+Name[lt]=Baltas 1024 x 768
+Name[lv]=Balts 1024 x 768
+Name[ms]=Putih 1024 x 768
+Name[nb]=Hvitt 1024 x 768
+Name[nds]=Witt 1024 x 768
+Name[ne]=सेतो १०२४ x ७६८
+Name[nl]=Wit 1024 x 768
+Name[nn]=Kvitt 1024 × 768
+Name[pl]=Biały 1024 x 768
+Name[pt]=Branca 1024 x 768
+Name[pt_BR]=1024 x 768 em Branco
+Name[ru]=Рисунок 1024x768, белый фон
+Name[se]=Vilges 1024 × 768
+Name[sk]=Biely 1024 x 768
+Name[sl]=Bela 1024 x 768
+Name[sr]=Бела 1024 x 768
+Name[sr@Latn]=Bela 1024 x 768
+Name[sv]=Vit 1024 x 768
+Name[ta]=வெள்ளை 1024 x 768
+Name[tr]=Beyaz 1024 x 768
+Name[uk]=Біле 1024 x 768
+Name[uz]=Oq 1024 x 768
+Name[uz@cyrillic]=Оқ 1024 x 768
+Name[zh_CN]=白色 1024 x 768
+Name[zh_TW]=白色 1024 x 768
+Comment=Creates a white RGB image of 1024 x 768 pixels.
+Comment[bg]=Създаване на бяло изображение RGB с размери 1024x768 пиксела.
+Comment[ca]=Crea una imatge blanca RGB de 1024 x 768 píxels.
+Comment[cy]=Creu delwedd RGB wen o 1024 x 768 picsel.
+Comment[da]=Laver et hvidt RGB-billede på 1024 x 768 billedpunkter.
+Comment[de]=Erstellt ein weißes RGB-Bild mit 1024 x 768 Pixeln.
+Comment[el]=Δημιουργεί μία λευκή RGB εικόνα μεγέθους 1024 x 768 εικονοστοιχείων.
+Comment[eo]=Kreas blankan RGB-bildon el 1024 x 768 rastrumeroj.
+Comment[es]=Crea una imagen RGB de 1024 x 768 píxeles.
+Comment[et]=Loob valge RGB-pildi mõõtmetega 1024 x 768 pikslit.
+Comment[eu]=1024 x 768 pixeleko RGB irudi zuri bat sortzen du.
+Comment[fa]=یک تصویر RGB سفید ۷۶۸ × ۱۰۲۴ تصویردانه‌ای ایجاد می‌کند.
+Comment[fi]=Luo valkoisen 1024x768 pikselin RGB-kuvan.
+Comment[fr]=Crée une image blanche RVB de 1024 x 768 pixels.
+Comment[fy]=Makket in wite RGB-ôfbylding oan fan 1024 x 768 byldpunten.
+Comment[gl]=Cria unha imaxe RGB branca de 1024 x 768 pixels.
+Comment[he]=יצירת תמונת RGB לבנה בגודל ‎1024 x 768 פיקסלים
+Comment[hi]=1024 x 768 पिक्सेल की सफेद आरजीबी छवि बनाता है.
+Comment[hu]=Létrehoz egy 1024 x 768 képpontos fehér RGB képet.
+Comment[is]=Býr til hvíta RGB mynd í hlutföllunum 1024 x 768 punktar.
+Comment[it]=Crea un'immagine RGB bianca di 1024 × 768 pixel.
+Comment[ja]=1024 x 768 ピクセルの RGB 画像を作成
+Comment[km]=បង្កើត​រូបភាព RGB ពណ៌​ស​ទំហំ 1024 x 768 ភីកសែល ។
+Comment[lt]=Sukuria baltą 1024 x 768 pikselių RGB paveiksliuką.
+Comment[ms]=Cipta imej RGB putih 1024 x 768 piksel.
+Comment[nb]=Lager et hvitt RGB-bilde på 1024 x 768 piksler.
+Comment[nds]=Stellt en witt RGB-Bild mit 1024 x 768 Pixels op.
+Comment[ne]=१०२४ x ७६८ पिक्सेलको सेतो RGB छवि सिर्जना गर्दछ ।
+Comment[nl]=Maakt een witte RGB-afbeelding aan van 1024 x 768 pixels.
+Comment[nn]=Lagar eit kvitt RGB-bilete på 1024 × 768 pikslar.
+Comment[pl]=Tworzy biały obrazek RGB o rozmiarach 1024 x 768 pikseli.
+Comment[pt]=Cria uma imagem RGB branca com 1024 x 768 pontos.
+Comment[pt_BR]=Cria uma imagem RGB em branco de 1024 x 768 pixéis.
+Comment[ru]=Рисунок RGB 1024x768, белый фон
+Comment[se]=Ráhkada vilges RGB-gova mas lea 1024 × 768 govvačuoggá.
+Comment[sk]=Vytvorí RGB obrázok s rozmermi 1024 x 768 pixelov a bielym pozadím.
+Comment[sl]=Ustvari belo sliko RGB velikosti 1024 x 768 pik.
+Comment[sr]=Прави белу RGB слику са 1024 x 768 пиксела.
+Comment[sr@Latn]=Pravi belu RGB sliku sa 1024 x 768 piksela.
+Comment[sv]=Skapar en vit RGB-bild med 1024 x 768 bildpunkter.
+Comment[ta]=1024 x 768 படத்துணுக்குகளில் ஒரு வெள்ளை RGB பிம்பத்தை உருவாக்குகிறது.
+Comment[tr]=1024 x 768 piksel ebadında beyaz bir RGB görüntü oluşturur.
+Comment[uk]=Створює біле зображення у форматі RGB, 640 x 480 пікселів.
+Comment[uz]=Oʻlchami 1024 x 768 nuqta boʻlgan oq RGB rasmni yaratish.
+Comment[uz@cyrillic]=Ўлчами 1024 x 768 нуқта бўлган оқ RGB расмни яратиш.
+Comment[zh_CN]=创建 1024 x 768 像素的 RGB 白色背景图像。
+Comment[zh_TW]=建立一個 1024 x 768 像素的白色 RGB 圖片。
+X-Krita-Version=2
diff --git a/krita/colorspaces/rgb_u8/templates/white_1024x768.kra b/krita/colorspaces/rgb_u8/templates/white_1024x768.kra
new file mode 100644
index 00000000..0a7702ad
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/white_1024x768.kra
Binary files differ
diff --git a/krita/colorspaces/rgb_u8/templates/white_1280x1024.desktop b/krita/colorspaces/rgb_u8/templates/white_1280x1024.desktop
new file mode 100644
index 00000000..a6363424
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/white_1280x1024.desktop
@@ -0,0 +1,95 @@
+[Desktop Entry]
+Type=Link
+URL=.source/white_1280x1024.kra
+Icon=template_rgb_empty
+Name=White 1280 x 1024
+Name[bg]=Бяло 1280x1024
+Name[br]=Gwenn 1280 x 1024
+Name[ca]=Blanc 1280 x 1024
+Name[cy]=Gwyn 1280 x 1024
+Name[da]=Hvidt 1280 x 1024
+Name[de]=Weiß 1280 x 1024
+Name[el]=Λευκή 1280 x 1024
+Name[eo]=Blanka 1280 x 1024
+Name[es]=1280 x 1024 blanco
+Name[et]=Valge 1280 x 1024
+Name[eu]=Zuria 1280 x 1024
+Name[fa]=سفید ۱۰۲۴ × ۱۲۸۰
+Name[fi]=Valkoinen 1280x1024
+Name[fr]=Image blanche 1280 x 1024
+Name[fy]=Wyt 1280 x 1024
+Name[ga]=Bán 1280×1024
+Name[gl]=Branca 1280 x 1024
+Name[he]=לבן ‎1280 x 1024
+Name[hu]=Fehér 1280 x 1024
+Name[is]=Hvít 1280 x 1024
+Name[it]=Bianco 1280 × 1024
+Name[ja]=白 1280 x 1024
+Name[km]=ពណ៌ស 1280 x 1024
+Name[lt]=Baltas 1280 x 1024
+Name[lv]=Balts 1280 x 1024
+Name[ms]=Putih 1280 x 1024
+Name[nb]=Hvit 1280 x 1024
+Name[nds]=Witt 1280 x 1024
+Name[ne]=सेतो १२८० x १०२४
+Name[nn]=Kvitt 1280 × 1024
+Name[pl]=Biały 1280 x 1024
+Name[pt]=Branca 1280 x 1024
+Name[pt_BR]=1280 x 1024 em Branco
+Name[ru]=Рисунок 1280x1024, белый фон
+Name[se]=Vilges 1280 × 1024
+Name[sk]=Biely 1280 x 1024
+Name[sl]=Bela 1280 x 1024
+Name[sr]=Бела 1280 x 1024
+Name[sr@Latn]=Bela 1280 x 1024
+Name[sv]=Vit 1280 x 1024
+Name[uk]=Біле 1280 x 1024
+Name[uz]=Oq 1280 x 1024
+Name[uz@cyrillic]=Оқ 1280 x 1024
+Name[zh_CN]=白色 1280 x 1024
+Name[zh_TW]=白色 1280 x 1024
+Comment=Creates a white RGB image of 1280 x 1024 pixels.
+Comment[bg]=Създаване на бяло изображение RGB с размери 1280x1024 пиксела.
+Comment[ca]=Crea una imatge blanca RGB de 1280 x 1024 píxels.
+Comment[cy]=Creu delwedd RGB wen o 1280 x 1024 picsel.
+Comment[da]=Laver et hvidt RGB-billede på 1280 x 1024 billedpunkter.
+Comment[de]=Erstellt ein weißes RGB-Bild mit 1280 x 1024 Pixeln.
+Comment[el]=Δημιουργεί μία λευκή RGB εικόνα μεγέθους 1280 x 1024 εικονοστοιχείων.
+Comment[eo]=Kreas blankan RGB-bildon el 1280 x 1024 rastrumeroj.
+Comment[es]=Crea una imagen RGB de 1280 x 1024 píxeles.
+Comment[et]=Loob valge RGB-pildi mõõtmetega 61280 x 1024 pikslit.
+Comment[eu]=1280 x 1024 pixeleko RGB irudi zuri bat sortzen du.
+Comment[fa]=یک تصویر RGB سفید ۱۰۲۴ × ۱۲۸۰ تصویردانه‌ای ایجاد می‌کند.
+Comment[fi]=Luo valkoisen 1280x1024 pikselin RGB-kuvan.
+Comment[fr]=Crée une image blanche RVB de 1280 x 1024 pixels.
+Comment[fy]=Makket in wite RGB-ôfbylding oan fan 1280 x 768 byldpunten.
+Comment[gl]=Cria unha imaxe RGB branca de 1280 x 1024 pixels.
+Comment[he]=יצירת תמונת RGB לבנה בגודל ‎1280 x 1024 פיקסלים
+Comment[hu]=Létrehoz egy 1280 x 1024 képpontos fehér RGB képet.
+Comment[is]=Býr til hvíta RGB mynd í hlutföllunum 1280 x 1024 punktar.
+Comment[it]=Crea un'immagine RGB bianca di 1280 × 1024 pixel.
+Comment[ja]=1280 x 1024 ピクセルの RGB 画像を作成
+Comment[km]=បង្កើត​រូបភាព RGB ពណ៌ស​ទំហំ 1280 x 1024 ភីកសែល ។
+Comment[lt]=Sukuria baltą 1280 x 1024 pikselių RGB paveiksliuką.
+Comment[ms]=Cipta imej RGB putih 1280 x 1024 piksel.
+Comment[nb]=Lager et hvitt bilde på 1280 x 1024 piksler.
+Comment[nds]=Stellt en witt RGB-Bild mit 1280 x 1024 Pixels op.
+Comment[ne]=१२८० x १०२४ पिक्सेलको सेतो RGB छवि सिर्जना गर्दछ ।
+Comment[nl]=Maakt een witte RGB-afbeelding aan van 1280 x 1024 pixels.
+Comment[nn]=Lagar eit kvitt RGB-bilete på 1280 × 1024 pikslar.
+Comment[pl]=Tworzy biały obrazek RGB o rozmiarach 1280 x 1024 pikseli.
+Comment[pt]=Cria uma imagem RGB branca com 1280 x 1024 pontos.
+Comment[pt_BR]=Cria uma imagem RGB em branco de 1280 x 1024 pixels.
+Comment[ru]=Рисунок RGB 1280x1024, белый фон
+Comment[se]=Ráhkada vilges RGB-gova mas lea 1280 × 1024 govvačuoggá.
+Comment[sk]=Vytvorí RGB obrázok s rozmermi 1280 x 1024 pixelov a bielym pozadím.
+Comment[sl]=Ustvari belo sliko RGB velikosti 1280 x 1024 pik.
+Comment[sr]=Прави белу RGB слику са 1280 x 1024 пиксела.
+Comment[sr@Latn]=Pravi belu RGB sliku sa 1280 x 1024 piksela.
+Comment[sv]=Skapar en vit RGB-bild med 1280 x 1024 bildpunkter.
+Comment[uk]=Створює біле зображення у форматі RGB, 1280 x 1024 пікселів.
+Comment[uz]=Oʻlchami 1280 x 1024 nuqta boʻlgan oq RGB rasmni yaratish.
+Comment[uz@cyrillic]=Ўлчами 1280 x 1024 нуқта бўлган оқ RGB расмни яратиш.
+Comment[zh_CN]=创建 1080 x 1024 像素的 RGB 白色背景图像。
+Comment[zh_TW]=建立一個 1280 x 1024 像素的白色 RGB 圖片。
+X-Krita-Version=2
diff --git a/krita/colorspaces/rgb_u8/templates/white_1280x1024.kra b/krita/colorspaces/rgb_u8/templates/white_1280x1024.kra
new file mode 100644
index 00000000..8d552419
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/white_1280x1024.kra
Binary files differ
diff --git a/krita/colorspaces/rgb_u8/templates/white_1600x1200.desktop b/krita/colorspaces/rgb_u8/templates/white_1600x1200.desktop
new file mode 100644
index 00000000..bb43573f
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/white_1600x1200.desktop
@@ -0,0 +1,95 @@
+[Desktop Entry]
+Type=Link
+URL=.source/white_1600x1200.kra
+Icon=template_rgb_empty
+Name=White 1600 x 1200
+Name[bg]=Бяло 1600x1200
+Name[br]=Gwenn 1600 x 1200
+Name[ca]=Blanc 1600 x 1200
+Name[cy]=Gwyn 1600 x 1200
+Name[da]=Hvidt 1600 x 1200
+Name[de]=Weiß 1600 x 1200
+Name[el]=Λευκή 1600 x 1200
+Name[eo]=Blanka 1600 x 1200
+Name[es]=1600 x 1200 blanco
+Name[et]=Valge 1600 x 1200
+Name[eu]=Zuria 1600 x 1200
+Name[fa]=سفید ۱۲۰۰ × ۱۶۰۰
+Name[fi]=Valkoinen 1600x1200
+Name[fr]=Image blanche 1600 x 1200
+Name[fy]=Wyt 1600 x 1200
+Name[ga]=Bán 1600×1200
+Name[gl]=Branca 1600 x 1200
+Name[he]=לבן ‎1600 x 1200
+Name[hu]=Fehér 1600 x 1200
+Name[is]=Hvít 1600 x 1200
+Name[it]=Bianco 1600 × 1200
+Name[ja]=白 1600 x 1200
+Name[km]=ពណ៌ស 1600 x 1200
+Name[lt]=Baltas 1600 x 1200
+Name[lv]=Balts 1600 x 1200
+Name[ms]=Putih 1600 x 1200
+Name[nb]=Hvit 1600 x 1200
+Name[nds]=Witt 1600 x 1200
+Name[ne]=सेतो १६०० x १२००
+Name[nn]=Kvitt 1600 × 1200
+Name[pl]=Biały 1600 x 1200
+Name[pt]=Branca 1600 x 1200
+Name[pt_BR]=1600 x 1200 em Branco
+Name[ru]=Рисунок 1600x1200, белый фон
+Name[se]=Vilges 1600 × 1200
+Name[sk]=Biely 1600 x 1200
+Name[sl]=Bela 1600 x 1200
+Name[sr]=Бела 1600 x 1200
+Name[sr@Latn]=Bela 1600 x 1200
+Name[sv]=Vit 1600 x 1200
+Name[uk]=Біле 1600 x 1200
+Name[uz]=Oq 1600 x 1200
+Name[uz@cyrillic]=Оқ 1600 x 1200
+Name[zh_CN]=白色 1600 x 1200
+Name[zh_TW]=白色 1600 x 1200
+Comment=Creates a white RGB image of 1600 x 1200 pixels.
+Comment[bg]=Създаване на бяло изображение RGB с размери 1600x1200 пиксела.
+Comment[ca]=Crea una imatge blanca RGB de 1600 x 1200 píxels.
+Comment[cy]=Creu delwedd RGB wen o 1600 x 1200 picsel.
+Comment[da]=Laver et hvidt RGB-billede på 1600 x 1200 billedpunkter.
+Comment[de]=Erstellt ein weißes RGB-Bild mit 1600 x 1200 Pixeln.
+Comment[el]=Δημιουργεί μία λευκή RGB εικόνα μεγέθους 1600 x 1200 εικονοστοιχείων.
+Comment[eo]=Kreas blankan RGB-bildon el 1600 x 1200 rastrumeroj.
+Comment[es]=Crea una imagen RGB de 1600 x 1200 píxeles.
+Comment[et]=Loob valge RGB-pildi mõõtmetega 1600 x 1200 pikslit.
+Comment[eu]=1600 x 1200 pixeleko RGB irudi zuri bat sortzen du.
+Comment[fa]=یک تصویر RGB سفید ۱۲۰۰ × ۱۶۰۰ تصویردانه‌ای ایجاد می‌کند.
+Comment[fi]=Luo valkoisen 1600x1200 pikselin RGB-kuvan.
+Comment[fr]=Crée une image blanche RVB de 1600 x 1200 pixels.
+Comment[fy]=Makket in wite RGB-ôfbylding oan fan 1600 x 1200 byldpunten.
+Comment[gl]=Cria unha imaxe RGB branca de 1600 x 1200 pixels.
+Comment[he]=יצירת תמונת RGB לבנה בגודל ‎1600 x 1200 פיקסלים
+Comment[hu]=Létrehoz egy 1600 x 1200 képpontos fehér RGB képet.
+Comment[is]=Býr til hvíta RGB mynd í hlutföllunum 1600 x 1200 punktar.
+Comment[it]=Crea un'immagine RGB bianca di 1600 × 1200 pixel.
+Comment[ja]=1600 x 1200 ピクセルの RGB 画像を作成
+Comment[km]=បង្កើត​រូបភាព RGB ពណ៌ស​ទំហំ 1600 x 1200 ភីកសែល ។
+Comment[lt]=Sukuria baltą 1600 x 1200 pikselių RGB paveiksliuką.
+Comment[ms]=Cipta imej RGB putih 1600 x 1200 piksel.
+Comment[nb]=Lager et hvitt bilde på 1600 x 1200 piksler.
+Comment[nds]=Stellt en witt RGB-Bild mit 1600 x 1200 Pixels op
+Comment[ne]=१६०० x १२०० पिक्सेलको सेतो RGB छवि सिर्जना गर्दछ ।
+Comment[nl]=Maakt een witte RGB-afbeelding aan van 1600 x 1200 pixels.
+Comment[nn]=Lagar eit kvitt RGB-bilete på 1600 × 1200 pikslar.
+Comment[pl]=Tworzy biały obrazek RGB o rozmiarach 1600 x1200 pikseli.
+Comment[pt]=Cria uma imagem RGB branca com 1600 x 1200 pontos.
+Comment[pt_BR]=Cria uma imagem RGB em branco de 1600 x 1200 pixels.
+Comment[ru]=Рисунок RGB 1600x1200, белый фон
+Comment[se]=Ráhkada vilges RGB-gova mas lea 1600 × 1200 govvačuoggá.
+Comment[sk]=Vytvorí RGB obrázok s rozmermi 1600 x 1200 pixelov a bielym pozadím.
+Comment[sl]=Ustvari belo sliko RGB velikosti 1600 x 1200 pik.
+Comment[sr]=Прави белу RGB слику са 1600 x 1200 пиксела.
+Comment[sr@Latn]=Pravi belu RGB sliku sa 1600 x 1200 piksela.
+Comment[sv]=Skapar en vit RGB-bild med 1600 x 1200 bildpunkter.
+Comment[uk]=Створює біле зображення у форматі RGB, 1600 x 1200 пікселів.
+Comment[uz]=Oʻlchami 1600 x 1200 nuqta boʻlgan oq RGB rasmni yaratish.
+Comment[uz@cyrillic]=Ўлчами 1600 x 1200 нуқта бўлган оқ RGB расмни яратиш.
+Comment[zh_CN]=创建 1600 x 1200 像素的 RGB 白色背景图像。
+Comment[zh_TW]=建立一個 1600 x 1200 像素的白色 RGB 圖片。
+X-Krita-Version=2
diff --git a/krita/colorspaces/rgb_u8/templates/white_1600x1200.kra b/krita/colorspaces/rgb_u8/templates/white_1600x1200.kra
new file mode 100644
index 00000000..7c037d9e
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/white_1600x1200.kra
Binary files differ
diff --git a/krita/colorspaces/rgb_u8/templates/white_640x480.desktop b/krita/colorspaces/rgb_u8/templates/white_640x480.desktop
new file mode 100644
index 00000000..2babefbf
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/white_640x480.desktop
@@ -0,0 +1,102 @@
+[Desktop Entry]
+Type=Link
+URL=.source/white_640x480.kra
+Icon=template_rgb_empty
+Name=White 640x480
+Name[bg]=Бяло 640x480
+Name[br]=Gwenn 640x480
+Name[ca]=Blanc 640x480
+Name[cy]=Gwyn 640 x 480
+Name[da]=Hvidt 640x480
+Name[de]=Weiß 640x480
+Name[el]=Λευκή 640x480
+Name[eo]=Blanka 640x480
+Name[es]=640x480 blanco
+Name[et]=Valge 640x480
+Name[eu]=Zuria 640x480
+Name[fa]=سفید ۴۸۰ × ۶۴۰
+Name[fi]=Valkoinen 640x480
+Name[fr]=Image blanche 640 x 480
+Name[fy]=Wyt 640x480
+Name[ga]=Bán 640×480
+Name[gl]=Branca 640x480
+Name[he]=לבן 640x480
+Name[hi]=सफेद 640x480
+Name[hu]=Fehér 640 x 480
+Name[is]=Hvít 640x480
+Name[it]=Bianco 640×480
+Name[ja]=白 640 x 480
+Name[km]=ពណ៌​ស​640 x 480
+Name[lt]=Baltas 640x480
+Name[lv]=Balts 640x480
+Name[ms]=Putih 640x480
+Name[nb]=Hvitt 640 x 480
+Name[nds]=Witt 640x480
+Name[ne]=सेतो ६४०x४८०
+Name[nl]=Wit 640 x 480
+Name[nn]=Kvitt 640 × 480
+Name[pl]=Biały 640x480
+Name[pt]=Branca 640x480
+Name[pt_BR]=640x480 em Branco
+Name[ru]=Рисунок 640x480, белый фон
+Name[se]=Vilges 640 × 480
+Name[sk]=Biely 640x480
+Name[sl]=Bela 640x480
+Name[sr]=Бела 640x480
+Name[sr@Latn]=Bela 640x480
+Name[sv]=Vit 640x480
+Name[ta]=வெள்ளை 640x480
+Name[tr]=Beyaz 640x480
+Name[uk]=Біле 640x480
+Name[uz]=Oq 640 x 480
+Name[uz@cyrillic]=Оқ 640 x 480
+Name[zh_CN]=白色 640 x 480
+Name[zh_TW]=白色 640x480
+Comment=Creates a white RGB image of 640 x 480 pixels.
+Comment[bg]=Създаване на бяло изображение RGB с размери 640x480 пиксела.
+Comment[ca]=Crea una imatge blanca RGB de 640 x 480 píxels.
+Comment[cy]=Creu delwedd RGB wen o 640 x 480 picsel.
+Comment[da]=Laver et hvidt RGB-billede på 640 x 480 billedpunkter.
+Comment[de]=Erstellt ein weißes RGB-Bild mit 640 x 480 Pixeln.
+Comment[el]=Δημιουργεί μία λευκή RGB εικόνα μεγέθους 640 x 480 εικονοστοιχείων.
+Comment[eo]=Kreas blankan RGB-bildon el 640 x 480 rastrumeroj.
+Comment[es]=Crea una imagen RGB de 640 x 480 píxeles.
+Comment[et]=Loob valge RGB pildi mõõtmetega 640 x 480 pikslit.
+Comment[eu]=640 x 480 pixeleko RGB irudi zuri bat sortzen du.
+Comment[fa]=یک تصویر RGB سفید ۴۸۰ × ۶۴۰ تصویردانه‌ای ایجاد می‌کند.
+Comment[fi]=Luo valkoisen 640x480 pikselin RGB-kuvan.
+Comment[fr]=Crée une image blanche RVB de 640 x 480 pixels.
+Comment[fy]=Makket in wite RGB-ôfbylding oan fan 640 x 480 byldpunten.
+Comment[gl]=Cria unha imaxe RGB branca de 640 x 480 pixels.
+Comment[he]=יצירת תמונת RGB לבנה בגודל ‎640 x 480 פיקסלים
+Comment[hi]=640 x 480 पिक्सेल का, सफेद आरजीबी छवि बनाता है
+Comment[hu]=Létrehoz egy 640 x 480 képpontos fehér RGB képet.
+Comment[is]=Býr til hvíta RGB mynd í hlutföllunum 640 x 480 punktar.
+Comment[it]=Crea un'immagine RGB bianca di 640 × 480 pixel.
+Comment[ja]=640 x 480 ピクセルの RGB 画像を作成
+Comment[km]=បង្កើត​រូបភាព RGB ពណ៌ស​ទំហំ 640 x 480 ភីកសែល ។
+Comment[lt]=Sukuria baltą 640 x 480 pikselių RGB paveiksliuką.
+Comment[ms]=Cipta imej RGB putih 640 x 480 piksel.
+Comment[nb]=Lager et hvitt bilde på 640 x 480 piksler.
+Comment[nds]=Stellt en witt RGB-Bild mit 640 x 480 Pixels op.
+Comment[ne]=६४० x ४८० पिक्सेलको सेतो RGB छवि सिर्जना गर्दछ ।
+Comment[nl]=Maakt een witte RGB-afbeelding aan van 640 x 480 pixels.
+Comment[nn]=Lagar eit kvitt RGB-bilete på 640 × 480 pikslar.
+Comment[pl]=Tworzy biały obrazek RGB o rozmiarach 640 x 480 pikseli.
+Comment[pt]=Cria uma imagem RGB branca com 640 x 480 pontos.
+Comment[pt_BR]=Cria uma imagem RGB em branco de 640 x 480 pixéis.
+Comment[ru]=Рисунок RGB 640x480, белый фон
+Comment[se]=Ráhkada vilges RGB-gova mas lea 640 × 480 govvačuoggá.
+Comment[sk]=Vytvorí RGB obrázok s rozmermi 640 x 480 pixelov a bielym pozadím.
+Comment[sl]=Ustvari belo sliko RGB velikosti 640 x 480 pik.
+Comment[sr]=Прави белу RGB слику са 640 x 480 пиксела.
+Comment[sr@Latn]=Pravi belu RGB sliku sa 640 x 480 piksela.
+Comment[sv]=Skapar en vit RGB-bild med 640 x 480 bildpunkter.
+Comment[ta]=640 x 480 படத்துணுக்குகளில் ஒரு வெள்ளை RGB பிம்பத்தை உருவாக்குகிறது.
+Comment[tr]=640 x 480 piksel ebadında beyaz bir RGB görüntü oluşturur.
+Comment[uk]=Створює біле зображення у форматі RGB, 640 x 480 пікселів.
+Comment[uz]=Oʻlchami 640 x 480 nuqta boʻlgan oq RGB rasmni yaratish.
+Comment[uz@cyrillic]=Ўлчами 640 x 480 нуқта бўлган оқ RGB расмни яратиш.
+Comment[zh_CN]=创建 640 x 480 像素的 RGB 白色背景图像。
+Comment[zh_TW]=建立一個 640 x 480 像素的白色 RGB 圖片。
+X-Krita-Version=2
diff --git a/krita/colorspaces/rgb_u8/templates/white_640x480.kra b/krita/colorspaces/rgb_u8/templates/white_640x480.kra
new file mode 100644
index 00000000..2a0265d0
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/templates/white_640x480.kra
Binary files differ
diff --git a/krita/colorspaces/rgb_u8/tests/Makefile.am b/krita/colorspaces/rgb_u8/tests/Makefile.am
new file mode 100644
index 00000000..65832896
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/tests/Makefile.am
@@ -0,0 +1,17 @@
+AM_CPPFLAGS = -I$(srcdir)/../../../sdk \
+ -I$(srcdir)/.. \
+ -I$(srcdir)/../../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../../color_strategy/ \
+ $(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_strategy_colorspace_rgb_tester.la
+
+kunittest_kis_strategy_colorspace_rgb_tester_la_SOURCES = kis_strategy_colorspace_rgb_tester.cpp
+kunittest_kis_strategy_colorspace_rgb_tester_la_LIBADD = -lkunittest ../libkritargb.la
+kunittest_kis_strategy_colorspace_rgb_tester_la_LDFLAGS = -module $(KDE_CHECK_PLUGIN) $(all_libraries)
+
+check-local: kunittest_kis_strategy_colorspace_rgb_tester.la
+ kunittestmodrunner
+
diff --git a/krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.cpp b/krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.cpp
new file mode 100644
index 00000000..7ad4cfae
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.cpp
@@ -0,0 +1,197 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_factory.h"
+#include "kis_strategy_colorspace_rgb_tester.h"
+#include "kis_rgb_colorspace.h"
+
+using namespace KUnitTest;
+
+KUNITTEST_MODULE( kunittest_kis_strategy_colorspace_rgb_tester, "RGB ColorSpace Tester" );
+KUNITTEST_MODULE_REGISTER_TESTER( KisRgbColorSpaceTester );
+
+void KisRgbColorSpaceTester::allTests()
+{
+ // We need this so that the colour profile loading can operate without crashing.
+ KisFactory *factory = new KisFactory();
+
+ testBasics();
+ testMixColors();
+
+ delete factory;
+}
+
+#define NUM_CHANNELS 4
+
+#define RED_CHANNEL 0
+#define GREEN_CHANNEL 1
+#define BLUE_CHANNEL 2
+#define ALPHA_CHANNEL 3
+
+void KisRgbColorSpaceTester::testBasics()
+{
+ KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile());
+ KisRgbColorSpace *cs = new KisRgbColorSpace(defProfile);
+
+ Q_UINT8 pixel[NUM_CHANNELS];
+
+ pixel[PIXEL_RED] = 255;
+ pixel[PIXEL_GREEN] = 128;
+ pixel[PIXEL_BLUE] = 64;
+ pixel[PIXEL_ALPHA] = 0;
+
+ QString valueText = cs->channelValueText(pixel, RED_CHANNEL);
+ CHECK(valueText, QString("255"));
+
+ valueText = cs->channelValueText(pixel, GREEN_CHANNEL);
+ CHECK(valueText, QString("128"));
+
+ valueText = cs->channelValueText(pixel, BLUE_CHANNEL);
+ CHECK(valueText, QString("64"));
+
+ valueText = cs->channelValueText(pixel, ALPHA_CHANNEL);
+ CHECK(valueText, QString("0"));
+
+ valueText = cs->normalisedChannelValueText(pixel, RED_CHANNEL);
+ CHECK(valueText, QString().setNum(1.0));
+
+ valueText = cs->normalisedChannelValueText(pixel, GREEN_CHANNEL);
+ CHECK(valueText, QString().setNum(128.0 / 255.0));
+
+ valueText = cs->normalisedChannelValueText(pixel, BLUE_CHANNEL);
+ CHECK(valueText, QString().setNum(64.0 / 255.0));
+
+ valueText = cs->normalisedChannelValueText(pixel, ALPHA_CHANNEL);
+ CHECK(valueText, QString().setNum(0.0));
+
+ cs->setPixel(pixel, 128, 192, 64, 99);
+ CHECK((uint)pixel[PIXEL_RED], 128u);
+ CHECK((uint)pixel[PIXEL_GREEN], 192u);
+ CHECK((uint)pixel[PIXEL_BLUE], 64u);
+ CHECK((uint)pixel[PIXEL_ALPHA], 99u);
+
+ Q_UINT8 red;
+ Q_UINT8 green;
+ Q_UINT8 blue;
+ Q_UINT8 alpha;
+
+ cs->getPixel(pixel, &red, &green, &blue, &alpha);
+ CHECK((uint)red, 128u);
+ CHECK((uint)green, 192u);
+ CHECK((uint)blue, 64u);
+ CHECK((uint)alpha, 99u);
+}
+
+void KisRgbColorSpaceTester::testMixColors()
+{
+ KisProfile *defProfile = new KisProfile(cmsCreate_sRGBProfile());
+ KisRgbColorSpace *cs = new KisRgbColorSpace(defProfile);
+
+
+ // Test mixColors.
+ Q_UINT8 pixel1[4];
+ Q_UINT8 pixel2[4];
+ Q_UINT8 outputPixel[4];
+
+ pixel1[PIXEL_RED] = 255;
+ pixel1[PIXEL_GREEN] = 255;
+ pixel1[PIXEL_BLUE] = 255;
+ pixel1[PIXEL_ALPHA] = 255;
+
+ pixel2[PIXEL_RED] = 0;
+ pixel2[PIXEL_GREEN] = 0;
+ pixel2[PIXEL_BLUE] = 0;
+ pixel2[PIXEL_ALPHA] = 0;
+
+ const Q_UINT8 *pixelPtrs[2];
+ Q_UINT8 weights[2];
+
+ pixelPtrs[0] = pixel1;
+ pixelPtrs[1] = pixel2;
+
+ weights[0] = 255;
+ weights[1] = 0;
+
+ cs->mixColors(pixelPtrs, weights, 2, outputPixel);
+
+ CHECK((int)outputPixel[PIXEL_RED], 255);
+ CHECK((int)outputPixel[PIXEL_GREEN], 255);
+ CHECK((int)outputPixel[PIXEL_BLUE], 255);
+ CHECK((int)outputPixel[PIXEL_ALPHA], 255);
+
+ weights[0] = 0;
+ weights[1] = 255;
+
+ cs->mixColors(pixelPtrs, weights, 2, outputPixel);
+
+ CHECK((int)outputPixel[PIXEL_RED], 0);
+ CHECK((int)outputPixel[PIXEL_GREEN], 0);
+ CHECK((int)outputPixel[PIXEL_BLUE], 0);
+ CHECK((int)outputPixel[PIXEL_ALPHA], 0);
+
+ weights[0] = 128;
+ weights[1] = 127;
+
+ cs->mixColors(pixelPtrs, weights, 2, outputPixel);
+
+ CHECK((int)outputPixel[PIXEL_RED], 255);
+ CHECK((int)outputPixel[PIXEL_GREEN], 255);
+ CHECK((int)outputPixel[PIXEL_BLUE], 255);
+ CHECK((int)outputPixel[PIXEL_ALPHA], 128);
+
+ pixel1[PIXEL_RED] = 200;
+ pixel1[PIXEL_GREEN] = 100;
+ pixel1[PIXEL_BLUE] = 50;
+ pixel1[PIXEL_ALPHA] = 255;
+
+ pixel2[PIXEL_RED] = 100;
+ pixel2[PIXEL_GREEN] = 200;
+ pixel2[PIXEL_BLUE] = 20;
+ pixel2[PIXEL_ALPHA] = 255;
+
+ cs->mixColors(pixelPtrs, weights, 2, outputPixel);
+
+ CHECK((int)outputPixel[PIXEL_RED], 150);
+ CHECK((int)outputPixel[PIXEL_GREEN], 150);
+ CHECK((int)outputPixel[PIXEL_BLUE], 35);
+ CHECK((int)outputPixel[PIXEL_ALPHA], 255);
+
+ pixel1[PIXEL_RED] = 0;
+ pixel1[PIXEL_GREEN] = 0;
+ pixel1[PIXEL_BLUE] = 0;
+ pixel1[PIXEL_ALPHA] = 0;
+
+ pixel2[PIXEL_RED] = 255;
+ pixel2[PIXEL_GREEN] = 255;
+ pixel2[PIXEL_BLUE] = 255;
+ pixel2[PIXEL_ALPHA] = 254;
+
+ weights[0] = 89;
+ weights[1] = 166;
+
+ cs->mixColors(pixelPtrs, weights, 2, outputPixel);
+
+ CHECK((int)outputPixel[PIXEL_RED], 255);
+ CHECK((int)outputPixel[PIXEL_GREEN], 255);
+ CHECK((int)outputPixel[PIXEL_BLUE], 255);
+ CHECK((int)outputPixel[PIXEL_ALPHA], 165);
+}
+
diff --git a/krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.h b/krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.h
new file mode 100644
index 00000000..16fc4e83
--- /dev/null
+++ b/krita/colorspaces/rgb_u8/tests/kis_strategy_colorspace_rgb_tester.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright (c) 2005 Adrian Page <[email protected]>
+ *
+ * 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_RGB_TESTER_H
+#define KIS_STRATEGY_COLORSPACE_RGB_TESTER_H
+
+#include <kunittest/tester.h>
+
+class KisRgbColorSpaceTester : public KUnitTest::Tester
+{
+public:
+ void allTests();
+ void testBasics();
+ void testMixColors();
+};
+
+#endif
+
diff --git a/krita/colorspaces/wet/Makefile.am b/krita/colorspaces/wet/Makefile.am
new file mode 100644
index 00000000..aaf561b0
--- /dev/null
+++ b/krita/colorspaces/wet/Makefile.am
@@ -0,0 +1,27 @@
+kritarcdir = $(kde_datadir)/kritaplugins
+kritarc_DATA = wetplugin.rc
+kde_services_DATA = kritawetplugin.desktop
+
+EXTRA_DIST = $(kritarc_DATA)
+
+INCLUDES = -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../core \
+ -I$(srcdir)/../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../kritacolor/ \
+ -I$(srcdir)/../../ui \
+ -I$(srcdir)/../../kopalette \
+ $(KOFFICE_INCLUDES) \
+ -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) \
+ $(all_includes)
+
+kde_module_LTLIBRARIES = kritawetplugin.la
+
+kritawetplugin_la_SOURCES = kis_wet_colorspace.cc wet_plugin.cc kis_wetop.cc kis_wet_palette_widget.cc kis_wetness_visualisation_filter.cc kis_texture_painter.cc kis_texture_filter.cc wetphysicsfilter.cc wdgpressure.ui
+noinst_HEADERS = kis_wet_colorspace.h wet_plugin.h wetphysicsfilter.h kis_wetop.cc kis_wet_palette_widget.h kis_texture_painter.h kis_wetness_visualisation_filter.h kis_texture_filter.h wetphysicsfilter.h
+
+kritawetplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kritawetplugin_la_LIBADD = ../../libkritacommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE)
+
+kritawetplugin_la_METASOURCES = AUTO
+
diff --git a/krita/colorspaces/wet/kis_texture_filter.cc b/krita/colorspaces/wet/kis_texture_filter.cc
new file mode 100644
index 00000000..1fc2e4d3
--- /dev/null
+++ b/krita/colorspaces/wet/kis_texture_filter.cc
@@ -0,0 +1,43 @@
+/*
+ * kis_texture_filter.cc -- Part of Krita
+ *
+ * Copyright (c) 2005 Bart Coppens <[email protected]>
+ *
+ * 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_view.h>
+#include <kis_image.h>
+#include <kis_debug_areas.h>
+#include "kis_texture_painter.h"
+#include "kis_texture_filter.h"
+
+void WetPaintDevAction::act(KisPaintDeviceSP device, Q_INT32 w, Q_INT32 h) const {
+ KisColorSpace * cs = device->colorSpace();
+
+ if (cs->id() != KisID("WET","")) {
+ kdDebug(DBG_AREA_CMS) << "You set this kind of texture on non-wet layers!.\n";
+ return;
+ } else {
+ kdDebug(DBG_AREA_CMS) << "Wet Paint Action activated!\n";
+ }
+
+ // XXX if params of the painter get configurable, make them here configurable as well?
+ KisTexturePainter painter(device);
+ painter.createTexture(0, 0, w, h);
+ painter.end();
+}
+
diff --git a/krita/colorspaces/wet/kis_texture_filter.h b/krita/colorspaces/wet/kis_texture_filter.h
new file mode 100644
index 00000000..fb2ef021
--- /dev/null
+++ b/krita/colorspaces/wet/kis_texture_filter.h
@@ -0,0 +1,38 @@
+/*
+ * kis_texture_filter.h -- Part of Krita
+ *
+ * Copyright (c) 2004 Boudewijn Rempt ([email protected])
+ *
+ * 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 _TEXTURE_FILTER_H
+#define _TEXTURE_FILTER_H
+
+#include <qstring.h>
+#include <klocale.h>
+#include <kis_paint_device_action.h>
+
+/// Initializes a wet paint device with a texture
+class WetPaintDevAction : public KisPaintDeviceAction {
+public:
+ virtual ~WetPaintDevAction() {}
+
+ virtual void act(KisPaintDeviceSP device, Q_INT32 w = 0, Q_INT32 h = 0) const;
+ virtual QString name() const { return i18n("Wet Texture"); }
+ virtual QString description() const { return i18n("Add a texture to the wet canvas"); }
+};
+
+#endif // _TEXTURE_FILTER_H
diff --git a/krita/colorspaces/wet/kis_texture_painter.cc b/krita/colorspaces/wet/kis_texture_painter.cc
new file mode 100644
index 00000000..a98038e6
--- /dev/null
+++ b/krita/colorspaces/wet/kis_texture_painter.cc
@@ -0,0 +1,92 @@
+/*
+ * Copyright (c) 2004 Cyrille Berger <[email protected]>
+ *
+ * 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 <math.h>
+
+#include <kdebug.h>
+
+#include <kis_global.h>
+#include <kis_image.h>
+#include <kis_iterators_pixel.h>
+#include <kis_layer.h>
+#include <kis_paint_device.h>
+#include <kis_painter.h>
+#include <kis_types.h>
+
+#include "kis_wet_colorspace.h"
+#include "kis_texture_painter.h"
+
+KisTexturePainter::KisTexturePainter()
+ : super()
+{
+ // XXX make at least one of these configurable, probably blurh
+ m_height = 1;
+ m_blurh = 0.7;
+}
+
+KisTexturePainter::KisTexturePainter(KisPaintDeviceSP device) : super(device)
+{
+ m_height = 1;
+ m_blurh = 0.7;
+}
+
+void KisTexturePainter::createTexture( Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h)
+{
+ double hscale = 128 * m_height / RAND_MAX;
+
+ int ibh = (int) floor(256 * m_blurh + 0.5);
+
+ // initialize with random data
+ for (int y2 = 0; y2 < h; y2++) {
+ KisHLineIterator i = m_device->createHLineIterator(x, y + y2, w, true);
+ while (!i.isDone()) {
+ WetPack* pack = reinterpret_cast<WetPack*>(i.rawData());
+ WetPix* w = &(pack->adsorb);
+ w->h = ( Q_UINT16)floor(128 + hscale * rand());
+ ++i;
+ }
+ }
+
+ int lh;
+
+ // Blur horizontally
+ for (int y2 = 0; y2 < h; y2++) {
+ KisHLineIterator i = m_device->createHLineIterator(x, y + y2, w, true);
+
+ WetPack* pack = reinterpret_cast<WetPack*>(i.rawData());
+ WetPix* w = &(pack->adsorb);
+ lh = w->h;
+ ++i;
+
+ while (!i.isDone()) {
+ pack = reinterpret_cast<WetPack*>(i.rawData());
+ w = &(pack->adsorb);
+ w->h += ((lh - w->h) * ibh + 128) >> 8;
+ lh = w->h;
+ // XXX to make it easier for us later on, we store the height data in paint
+ // as well!
+ w = &(pack->paint);
+ w->h = lh;
+ ++i;
+ }
+ }
+
+ // Vertical blurring was commented out in wetdreams, the effect seems to be achievable
+ // without this.
+ // I think this is because with blur in one direction, you get more the effect of
+ // having 'fibers' in your paper
+}
diff --git a/krita/colorspaces/wet/kis_texture_painter.h b/krita/colorspaces/wet/kis_texture_painter.h
new file mode 100644
index 00000000..a3323492
--- /dev/null
+++ b/krita/colorspaces/wet/kis_texture_painter.h
@@ -0,0 +1,40 @@
+/*
+ * Copyright (c) 2004 Cyrille Berger <[email protected]>
+ *
+ * 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_TEXTURE_PAINTER_H_
+#define KIS_TEXTURE_PAINTER_H_
+
+#include "kis_types.h"
+#include "kis_painter.h"
+
+class KisTexturePainter : public KisPainter
+{
+
+ typedef KisPainter super;
+
+public:
+
+ KisTexturePainter();
+ KisTexturePainter(KisPaintDeviceSP device);
+
+ void createTexture( Q_INT32 x, Q_INT32 y, Q_INT32 w, Q_INT32 h);
+
+private:
+ double m_blurh, m_height;
+
+};
+#endif //KIS_TEXTURE_PAINTER_H_
diff --git a/krita/colorspaces/wet/kis_wet_colorspace.cc b/krita/colorspaces/wet/kis_wet_colorspace.cc
new file mode 100644
index 00000000..4ca96eb5
--- /dev/null
+++ b/krita/colorspaces/wet/kis_wet_colorspace.cc
@@ -0,0 +1,514 @@
+/*
+ * Copyright (c) 2004 Boudewijn Rempt <[email protected]>
+ *
+ * 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 <qimage.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+#include <kis_debug_areas.h>
+#include "kis_abstract_colorspace.h"
+#include "kis_colorspace_factory_registry.h"
+#include "kis_image.h"
+#include "kis_wet_colorspace.h"
+#include "wetphysicsfilter.h"
+#include "kis_integer_maths.h"
+
+namespace {
+ static const WetPix m_paint = { 707, 0, 707, 0, 707, 0, 240, 0 };
+
+ /* colors from Curtis et al, Siggraph 97 */
+
+ static const WetPix m_paintbox[] = {
+ {496, 0, 16992, 0, 3808, 0, 0, 0},
+ {16992, 9744, 21712, 6400, 25024, 3296, 0, 0},
+ {6512, 6512, 6512, 4880, 11312, 0, 0, 0},
+ {16002, 0, 2848, 0, 16992, 0, 0, 0},
+ {22672, 0, 5328, 2272, 4288, 2640, 0, 0},
+ {8000, 0, 16992, 0, 28352, 0, 0, 0},
+ {5696, 5696, 12416, 2496, 28352, 0, 0, 0},
+ {0, 0, 5136, 0, 28352, 0, 0, 0},
+ {2320, 1760, 7344, 4656, 28352, 0, 0, 0},
+ {8000, 0, 3312, 0, 5504, 0, 0, 0},
+ {13680, 0, 16992, 0, 3312, 0, 0, 0},
+ {5264, 5136, 1056, 544, 6448, 6304, 0, 0},
+ {11440, 11440, 11440, 11440, 11440, 11440, 0, 0},
+ {11312, 0, 11312, 0, 11312, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0} };
+
+ static const int m_nPaints = 15;
+}
+
+void wetPixToDouble(WetPixDbl * dst, WetPix *src)
+{
+ dst->rd = (1.0 / 8192.0) * src->rd;
+ dst->rw = (1.0 / 8192.0) * src->rw;
+ dst->gd = (1.0 / 8192.0) * src->gd;
+ dst->gw = (1.0 / 8192.0) * src->gw;
+ dst->bd = (1.0 / 8192.0) * src->bd;
+ dst->bw = (1.0 / 8192.0) * src->bw;
+ dst->w = (1.0 / 8192.0) * src->w;
+ dst->h = (1.0 / 8192.0) * src->h;
+}
+
+void wetPixFromDouble(WetPix * dst, WetPixDbl *src)
+{
+ int v;
+
+ v = (int)floor (8192.0 * src->rd + 0.5);
+ dst->rd = CLAMP(v, 0, 65535);
+
+ v = (int)floor (8192.0 * src->rw + 0.5);
+ dst->rw = CLAMP(v, 0, 65535);
+
+ v = (int)floor (8192.0 * src->gd + 0.5);
+ dst->gd = CLAMP(v, 0, 65535);
+
+ v = (int)floor (8192.0 * src->gw + 0.5);
+ dst->gw = CLAMP(v, 0, 65535);
+
+ v = (int)floor (8192.0 * src->bd + 0.5);
+ dst->bd = CLAMP(v, 0, 65535);
+
+ v = (int)floor (8192.0 * src->bw + 0.5);
+ dst->bw = CLAMP(v, 0, 65535);
+
+ v = (int)floor (8192.0 * src->w + 0.5);
+ dst->w = CLAMP(v, 0, 511);
+
+ v = (int)floor (8192.0 * src->h + 0.5);
+ dst->h = CLAMP(v, 0, 511);
+
+}
+
+int getH(int r, int g, int b)
+{
+ int h, s, v;
+ QColor c(r,g, b);
+ c.getHsv(&h, &s, &v);
+ return h;
+}
+
+KisWetColorSpace::KisWetColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) :
+ KisAbstractColorSpace(KisID("WET", i18n("Watercolors")), 0, icMaxEnumData, parent, p)
+{
+ wet_init_render_tab();
+
+ m_paintNames << i18n("Quinacridone Rose")
+ << i18n("Indian Red")
+ << i18n("Cadmium Yellow")
+ << i18n("Hookers Green")
+ << i18n("Cerulean Blue")
+ << i18n("Burnt Umber")
+ << i18n("Cadmium Red")
+ << i18n("Brilliant Orange")
+ << i18n("Hansa Yellow")
+ << i18n("Phthalo Green")
+ << i18n("French Ultramarine")
+ << i18n("Interference Lilac")
+ << i18n("Titanium White")
+ << i18n("Ivory Black")
+ << i18n("Pure Water");
+
+ m_channels.push_back(new KisChannelInfo(i18n("Red Concentration"), "Rc", 0, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Myth Red"), "Rm", 1, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Green Concentration"), "Gc", 2, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Myth Green"), "Gm", 3, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Blue Concentration"), "Bc", 4, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Myth Blue"), "Bm", 5, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Water Volume"), "W", 6, KisChannelInfo::SUBSTANCE, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Paper Height"), "H", 7, KisChannelInfo::SUBSTANCE, KisChannelInfo::UINT16));
+
+ m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Red Concentration"), "Rc", 8, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Myth Red"), "Rm", 9, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Green Concentration"), "Gc", 10, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Myth Green"), "Gm", 11, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Blue Concentration"), "Bc", 12, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Myth Blue"), "Bm", 13, KisChannelInfo::COLOR, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Water Volume"), "W", 14, KisChannelInfo::SUBSTANCE, KisChannelInfo::UINT16));
+ m_channels.push_back(new KisChannelInfo(i18n("Adsorbed Paper Height"), "H", 15, KisChannelInfo::SUBSTANCE, KisChannelInfo::UINT16));
+
+ // Store the hue; we'll pick the paintbox color that closest to the given QColor's hue.
+ m_conversionMap[getH(240, 32, 160)] = m_paintbox[0]; // Quinacridone Rose
+ m_conversionMap[getH(159, 88, 43)] = m_paintbox[1]; // Indian Red
+ m_conversionMap[getH(254, 220, 64)] = m_paintbox[2]; // Cadmium Yellow
+ m_conversionMap[getH(36, 180, 32)] = m_paintbox[3]; // Hookers Green
+ m_conversionMap[getH(16, 185, 215)] = m_paintbox[4]; // Cerulean Blue
+ m_conversionMap[getH(96, 32, 8)] = m_paintbox[5]; // Burnt Umber
+ m_conversionMap[getH(254, 96, 8)] = m_paintbox[6]; // Cadmium Red
+ m_conversionMap[getH(255, 136, 8)] = m_paintbox[7]; // Brilliant Orange
+ m_conversionMap[getH(240, 199, 8)] = m_paintbox[8]; // Hansa Yellow
+ m_conversionMap[getH(96, 170, 130)] = m_paintbox[9]; // Phthalo Green
+ m_conversionMap[getH(48, 32, 170)] = m_paintbox[10]; // French Ultramarine
+ m_conversionMap[getH(118, 16, 135)] = m_paintbox[11]; // Interference Lilac
+ m_conversionMap[getH(254, 254, 254)] = m_paintbox[12]; // Titanium White
+ m_conversionMap[getH(64, 64, 74)] = m_paintbox[13]; // Ivory Black
+
+ m_paintwetness = false;
+ phasebig = 0;
+}
+
+
+KisWetColorSpace::~KisWetColorSpace()
+{
+}
+
+void KisWetColorSpace::fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * /*profile*/)
+{
+ WetPack* p = reinterpret_cast<WetPack*>(dst);
+
+ int h = getH(c.red(), c.green(), c.blue());
+ int delta = 256;
+ int key = 0;
+ QMap<int, WetPix>::Iterator it;
+ QMap<int, WetPix>::Iterator end = m_conversionMap.end();
+ for (it = m_conversionMap.begin(); it != end; ++it) {
+ if (abs(it.key() - h) < delta) {
+ delta = abs(it.key() - h);
+ key = it.key();
+ }
+ }
+
+ // Translate the special QCOlors from our paintbox to wetpaint paints.
+ if (m_conversionMap.contains(key)) {
+ (*p).paint = m_conversionMap[key];
+ (*p).adsorb = m_conversionMap[key]; // or maybe best add water here?
+ } else {
+ // water
+ (*p).paint = m_paintbox[14];
+ (*p).adsorb = m_paintbox[14];
+ }
+}
+
+void KisWetColorSpace::fromQColor(const QColor& c, Q_UINT8 /*opacity*/, Q_UINT8 *dst, KisProfile * /*profile*/)
+{
+ fromQColor(c, dst);
+}
+
+ Q_UINT8 KisWetColorSpace::getAlpha(const Q_UINT8 */*pixel*/) const
+{
+ return OPACITY_OPAQUE;
+}
+
+void KisWetColorSpace::setAlpha( Q_UINT8 * /*pixels*/, Q_UINT8 /*alpha*/, Q_INT32 /*nPixels*/) const
+{
+}
+
+void KisWetColorSpace::multiplyAlpha( Q_UINT8 * /*pixels*/, Q_UINT8 /*alpha*/, Q_INT32 /*nPixels*/)
+{
+}
+
+void KisWetColorSpace::applyAlphaU8Mask( Q_UINT8 * /*pixels*/, Q_UINT8 * /*alpha*/, Q_INT32 /*nPixels*/)
+{
+}
+
+void KisWetColorSpace::applyInverseAlphaU8Mask( Q_UINT8 * /*pixels*/, Q_UINT8 * /*alpha*/, Q_INT32 /*nPixels*/)
+{
+}
+
+ Q_UINT8 KisWetColorSpace::scaleToU8(const Q_UINT8 * /*srcPixel*/, Q_INT32 /*channelPos*/)
+{
+ return 0;
+}
+
+Q_UINT16 KisWetColorSpace::scaleToU16(const Q_UINT8 * /*srcPixel*/, Q_INT32 /*channelPos*/)
+{
+ return 0;
+}
+
+
+void KisWetColorSpace::toQColor(const Q_UINT8 *src, QColor *c, KisProfile * /*profile*/)
+{
+ Q_UINT8 * rgb = new Q_UINT8[3];
+ Q_CHECK_PTR(rgb);
+
+ memset(rgb, 255, 3);
+
+ // Composite the two layers in each pixelSize
+
+ WetPack * wp = (WetPack*)src;
+
+ // First the adsorption layer
+ wet_composite(RGB, rgb, &wp->adsorb);
+
+ // Then the paint layer (which comes first in our double-packed pixel)
+ wet_composite(RGB, rgb, &wp->paint);
+
+ c->setRgb(rgb[0], rgb[1], rgb[2]);
+
+ delete[]rgb;
+}
+
+void KisWetColorSpace::toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 */*opacity*/, KisProfile * /*profile*/)
+{
+ toQColor(src, c);
+}
+
+void KisWetColorSpace::mixColors(const Q_UINT8 **/*colors*/, const Q_UINT8 */*weights*/, Q_UINT32 /*nColors*/, Q_UINT8 */*dst*/) const
+{
+}
+
+QValueVector<KisChannelInfo *> KisWetColorSpace::channels() const
+{
+ return m_channels;
+}
+
+ Q_UINT32 KisWetColorSpace::nChannels() const
+{
+ return 16;
+}
+
+ Q_UINT32 KisWetColorSpace::nColorChannels() const
+{
+ return 12;
+}
+
+ Q_UINT32 KisWetColorSpace::nSubstanceChannels() const
+{
+ return 4;
+}
+
+
+ Q_UINT32 KisWetColorSpace::pixelSize() const
+{
+ return 32; // This color strategy wants an unsigned short for each
+ // channel, and every pixel consists of two wetpix structs
+ // -- even though for many purposes we need only one wetpix
+ // struct.
+}
+
+
+
+// XXX: use profiles to display correctly on calibrated displays.
+QImage KisWetColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
+ KisProfile * /*dstProfile*/,
+ Q_INT32 /*renderingIntent*/, float /*exposure*/)
+{
+
+ QImage img(width, height, 32);
+
+ Q_UINT8 *rgb = (Q_UINT8*) img.bits();
+ const WetPack* wetData = reinterpret_cast<const WetPack*>(data);
+
+ // Clear to white -- the following code actually composits the contents of the
+ // wet pixels with the contents of the image buffer, so they need to be
+ // prepared
+ memset(rgb, 255, width * height * 4);
+ // Composite the two layers in each pixelSize
+
+ Q_INT32 i = 0;
+ while ( i < width * height) {
+ // First the adsorption layers
+ WetPack* wp = const_cast<WetPack*>(&wetData[i]); // XXX don't do these things!
+ // XXX Probably won't work on MSB archs!
+ wet_composite(BGR, rgb, &(wp->adsorb));
+ // Then the paint layer (which comes first in our double-packed pixel)
+ wet_composite(BGR, rgb, &(wp->paint));
+
+ // XXX pay attention to this comment!!
+ // Display the wet stripes -- this only works if we have at least three scanlines in height,
+ // because otherwise the phase trick won't work.
+
+ // Because we work in a stateless thing, and we can't just draw this wetness
+ // indication AFTER this (e.g. like the selection), we have to do un nice things:
+ // Because we (hopefully atm!) don't use the height of the paint wetpix, we abuse
+ // that to store a state. It's not perfect, but it works for now...
+ if (m_paintwetness) {
+ wet_render_wetness(rgb, wp);
+ }
+
+ i++;
+ rgb += sizeof( Q_UINT32); // Because the QImage is 4 bytes deep.
+
+ }
+
+ return img;
+}
+
+void KisWetColorSpace::bitBlt( Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 */*srcAlphaMask*/,
+ Q_INT32 /*maskRowStride*/,
+ Q_UINT8 /*opacity*/,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op)
+{
+ if (rows <= 0 || cols <= 0)
+ return;
+
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+
+ Q_INT32 linesize = pixelSize() * cols;
+ d = dst;
+ s = src;
+
+ // Do as if we 'stack' them atop of each other
+ if (op == COMPOSITE_OVER) {
+ while (rows-- > 0) {
+ for (int i = 0; i < cols; i++) {
+ WetPack* dstPack = &(reinterpret_cast<WetPack*>(d))[i];
+ const WetPack* srcPack = &(reinterpret_cast<const WetPack*>(s))[i];
+ combinePixels(&(dstPack->paint), &(dstPack->paint), &(srcPack->paint));
+ combinePixels(&(dstPack->adsorb), &(dstPack->adsorb), &(srcPack->adsorb));
+ }
+ d += dstRowSize; // size??
+ s += srcRowStride;
+ }
+
+ return;
+ }
+
+ // Just copy the src onto the dst, we don't do fancy things here,
+ // we do those in the paint op, because we need pressure to determine
+ // paint deposition.
+
+ while (rows-- > 0) {
+ memcpy(d, s, linesize);
+ d += dstRowSize; // size??
+ s += srcRowStride;
+ }
+}
+
+void KisWetColorSpace::wet_init_render_tab()
+{
+ int i;
+
+ double d;
+ int a, b;
+
+ wet_render_tab = new Q_UINT32[4096];
+ Q_CHECK_PTR(wet_render_tab);
+
+ for (i = 0; i < 4096; i++)
+ {
+ d = i * (1.0 / 512.0);
+
+ if (i == 0)
+ a = 0;
+ else
+ a = (int) floor (0xff00 / i + 0.5);
+
+ b = (int) floor (0x8000 * exp (-d) + 0.5);
+ wet_render_tab[i] = (a << 16) | b;
+ }
+
+}
+
+void KisWetColorSpace::wet_composite(RGBMode m, Q_UINT8 *rgb, WetPix * wet)
+{
+ int r, g, b;
+ int d, w;
+ int ab;
+ int wa;
+
+ if (m == RGB)
+ r = rgb[0];
+ else
+ r = rgb[2];
+ w = wet[0].rw >> 4;
+ d = wet[0].rd >> 4;
+
+ ab = wet_render_tab[d];
+
+ wa = (w * (ab >> 16) + 0x80) >> 8;
+ r = wa + (((r - wa) * (ab & 0xffff) + 0x4000) >> 15);
+ if (m == RGB)
+ rgb[0] = r;
+ else
+ rgb[2] = r;
+
+ // Green is 1 both in RGB as BGR
+ g = rgb[1];
+ w = wet[0].gw >> 4;
+ d = wet[0].gd >> 4;
+ d = d >= 4096 ? 4095 : d;
+ ab = wet_render_tab[d];
+ wa = (w * (ab >> 16) + 0x80) >> 8;
+ g = wa + (((g - wa) * (ab & 0xffff) + 0x4000) >> 15);
+ rgb[1] = g;
+
+ if (m == RGB)
+ b = rgb[2];
+ else
+ b = rgb[0];
+ w = wet[0].bw >> 4;
+ d = wet[0].bd >> 4;
+ d = d >= 4096 ? 4095 : d;
+ ab = wet_render_tab[d];
+ wa = (w * (ab >> 16) + 0x80) >> 8;
+ b = wa + (((b - wa) * (ab & 0xffff) + 0x4000) >> 15);
+ if (m == RGB)
+ rgb[2] = b;
+ else
+ rgb[0] = b;
+}
+
+void KisWetColorSpace::wet_render_wetness( Q_UINT8 * rgb, WetPack * pack)
+{
+ int highlight = 255 - (pack->paint.w >> 1);
+
+ if (highlight < 255 && ((phase++) % 3 == 0)) {
+ for (int i = 0; i < 3; i++)
+ rgb[i] = 255 - (((255 - rgb[i]) * highlight) >> 8);
+ }
+ phase &= 3;
+}
+
+KisCompositeOpList KisWetColorSpace::userVisiblecompositeOps() const
+{
+ KisCompositeOpList list;
+
+ list.append(KisCompositeOp(COMPOSITE_OVER));
+
+ return list;
+}
+
+QString KisWetColorSpace::channelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < nChannels());
+ const Q_UINT16 *pixel = reinterpret_cast<const Q_UINT16 *>(U8_pixel);
+ Q_UINT32 channelPosition = m_channels[channelIndex]->pos();
+
+ return QString().setNum(pixel[channelPosition]);
+}
+
+QString KisWetColorSpace::normalisedChannelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < nChannels());
+ const Q_UINT16 *pixel = reinterpret_cast<const Q_UINT16 *>(U8_pixel);
+ Q_UINT32 channelPosition = m_channels[channelIndex]->pos();
+
+ return QString().setNum(static_cast<float>(pixel[channelPosition]) / UINT16_MAX);
+}
+
+QValueList<KisFilter *> KisWetColorSpace::createBackgroundFilters()
+{
+ QValueList<KisFilter *> filterList;
+ KisFilter * f = new WetPhysicsFilter();
+ filterList << f;
+ return filterList;
+}
diff --git a/krita/colorspaces/wet/kis_wet_colorspace.h b/krita/colorspaces/wet/kis_wet_colorspace.h
new file mode 100644
index 00000000..9c66c52e
--- /dev/null
+++ b/krita/colorspaces/wet/kis_wet_colorspace.h
@@ -0,0 +1,219 @@
+/*
+ * Copyright (c) 2004 Cyrille Berger <[email protected]>
+ *
+ * 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_WET_H_
+#define KIS_STRATEGY_COLORSPACE_WET_H_
+
+#include <qcolor.h>
+#include <qstringlist.h>
+#include <qvaluelist.h>
+#include <qmap.h>
+
+#include "kis_global.h"
+#include "kis_abstract_colorspace.h"
+
+class KisFilter;
+
+/**
+ * The wet colourspace is one of the more complicated colour spaces. Every
+ * pixel actually consists of two pixels: the paint pixel and the adsorbtion
+ * pixel. This corresponds to the two layers of the wetpack structure in the
+ * original wetdreams code by Raph Levien.
+ */
+
+// XXX: This should really be in a namespace.
+
+typedef struct _WetPix WetPix;
+typedef struct _WetPixDbl WetPixDbl;
+typedef struct _WetPack WetPack;
+
+/*
+ * White is made up of myth-red, myth-green, and myth-blue. Myth-red
+ * looks red when viewed reflectively, but cyan when viewed
+ * transmissively (thus, it vaguely resembles a dichroic
+ * filter). Myth-red over black is red, and myth-red over white is
+ * white.
+ *
+ * Total red channel concentration is myth-red concentration plus
+ * cyan concentration.
+ */
+
+struct _WetPix {
+ Q_UINT16 rd; /* Total red channel concentration */
+ Q_UINT16 rw; /* Myth-red concentration */
+
+ Q_UINT16 gd; /* Total green channel concentration */
+ Q_UINT16 gw; /* Myth-green concentration */
+
+ Q_UINT16 bd; /* Total blue channel concentration */
+ Q_UINT16 bw; /* Myth-blue concentration */
+
+ Q_UINT16 w; /* Water volume */
+ Q_UINT16 h; /* Height of paper surface XXX: This might just as well be a single
+ channel in our colour model that has two of
+ these wetpix structs for every paint device pixels*/
+};
+
+struct _WetPack {
+ WetPix paint; /* Paint layer */
+ WetPix adsorb; /* Adsorbtion layer */
+};
+
+struct _WetPixDbl {
+ double rd; /* Total red channel concentration */
+ double rw; /* Myth-red concentration */
+ double gd; /* Total green channel concentration */
+ double gw; /* Myth-green concentration */
+ double bd; /* Total blue channel concentration */
+ double bw; /* Myth-blue concentration */
+ double w; /* Water volume */
+ double h; /* Height of paper surface */
+};
+
+
+
+void wetPixToDouble(WetPixDbl * dst, WetPix *src);
+void wetPixFromDouble(WetPix * dst, WetPixDbl *src);
+
+
+class KisWetColorSpace : public KisAbstractColorSpace {
+public:
+ KisWetColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p);
+ virtual ~KisWetColorSpace();
+
+
+ virtual bool willDegrade(ColorSpaceIndependence independence)
+ {
+ if (independence == TO_RGBA8 || independence == TO_LAB16)
+ return true;
+ else
+ return false;
+ };
+
+
+
+
+public:
+
+ // Semi-clever: we have only fifteen wet paint colors that are mapped to the
+ // qcolors that are put in the painter by the special wet paint palette. Other
+ // QColors are mapped to plain water...
+ virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0);
+ virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0);
+
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0);
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0);
+
+ virtual Q_UINT8 getAlpha(const Q_UINT8 * pixel) const;
+ virtual void setAlpha( Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const;
+ virtual void multiplyAlpha( Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels);
+
+ virtual void applyAlphaU8Mask( Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels);
+ virtual void applyInverseAlphaU8Mask( Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels);
+
+ virtual Q_UINT8 scaleToU8(const Q_UINT8 * srcPixel, Q_INT32 channelPos);
+ virtual Q_UINT16 scaleToU16(const Q_UINT8 * srcPixel, Q_INT32 channelPos);
+
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 nSubstanceChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+
+ virtual QString channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const;
+ virtual QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const;
+
+ virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
+ KisProfile * dstProfile,
+ Q_INT32 renderingIntent = INTENT_PERCEPTUAL,
+ float exposure = 0.0f);
+
+ virtual QValueList<KisFilter*> createBackgroundFilters();
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+ void setPaintWetness(bool b) { m_paintwetness = b; } // XXX this needs better design!
+ bool paintWetness() { return m_paintwetness; }
+ void resetPhase() { phase = phasebig++; phasebig &= 3; }
+
+ void combinePixels(WetPix* dst, WetPix const* src1, WetPix const* src2) const {
+ dst->rd = src1->rd + src2->rd;
+ dst->rw = src1->rw + src2->rw;
+ dst->gd = src1->gd + src2->gd;
+ dst->gw = src1->gw + src2->gw;
+ dst->bd = src1->bd + src2->bd;
+ dst->bw = src1->bw + src2->bw;
+ dst->w = src1->w + src2->w;
+ }
+protected:
+ virtual void bitBlt( Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+private:
+
+ // This was static, but since we have only one instance of the color strategy,
+ // it can be just as well a private member variable.
+ void wet_init_render_tab();
+
+ /// Convert a single pixel from its wet representation to rgb: internal rgb: rgb[0] = R, etc
+ typedef enum { RGB, BGR } RGBMode;
+ void wet_composite(RGBMode m, Q_UINT8 *rgb, WetPix * wet);
+
+ void wet_render_wetness( Q_UINT8 * rgb, WetPack * pack);
+
+private:
+ Q_UINT32 * wet_render_tab;
+
+ QStringList m_paintNames;
+ QMap<int, WetPix> m_conversionMap;
+
+ bool m_paintwetness;
+ int phase, phasebig;
+
+};
+
+class KisWetColorSpaceFactory : public KisColorSpaceFactory
+{
+public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("WET", i18n("Watercolors")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return 0; };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icMaxEnumData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisWetColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return ""; };
+};
+
+#endif // KIS_STRATEGY_COLORSPACE_WET_H_
diff --git a/krita/colorspaces/wet/kis_wet_palette_widget.cc b/krita/colorspaces/wet/kis_wet_palette_widget.cc
new file mode 100644
index 00000000..ae405f94
--- /dev/null
+++ b/krita/colorspaces/wet/kis_wet_palette_widget.cc
@@ -0,0 +1,245 @@
+/*
+ * This file is part of Krita
+ *
+ * Copyright (c) 1999 Matthias Elter ([email protected])
+ * Copyright (c) 2001-2002 Igor Jansen ([email protected])
+ *
+ * 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 <qpushbutton.h>
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qcolor.h>
+#include <qdrawutil.h>
+#include <qhbox.h>
+#include <qlabel.h>
+#include <qlayout.h>
+#include <qpainter.h>
+#include <qspinbox.h>
+#include <qstyle.h>
+#include <qtooltip.h>
+
+#include <klocale.h>
+#include <knuminput.h>
+#include <koFrameButton.h>
+
+#include <kis_meta_registry.h>
+#include <kis_factory.h>
+#include <kis_canvas_subject.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_color.h>
+#include <kis_color_cup.h>
+
+#include "kis_wet_colorspace.h"
+#include "kis_wet_palette_widget.h"
+
+KisWetPaletteWidget::KisWetPaletteWidget(QWidget *parent, const char *name) : super(parent, name)
+{
+ m_subject = 0;
+
+ QVBoxLayout * vl = new QVBoxLayout(this, 0, -1, "main layout");
+
+ QGridLayout * l = new QGridLayout(vl, 2, 8, 2, "color wells grid");
+
+ KisColorCup * b;
+ int WIDTH = 24;
+ int HEIGHT = 24;
+
+ b = new KisColorCup(this);
+ b->setColor( QColor(240, 32, 160) );
+ l->addWidget(b, 0, 0);
+ QToolTip::add(b, i18n("Quinacridone Rose"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(159, 88, 43));
+ l->addWidget(b, 0, 1);
+ QToolTip::add(b,i18n("Indian Red"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor( QColor(254, 220, 64) );
+ l->addWidget(b, 0, 2);
+ QToolTip::add(b,i18n("Cadmium Yellow"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(36, 180, 32));
+ l->addWidget(b, 0, 3);
+ QToolTip::add(b,i18n("Hookers Green"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(16, 185, 215));
+ l->addWidget(b, 0, 4);
+ QToolTip::add(b,i18n("Cerulean Blue"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(96, 32, 8));
+ l->addWidget(b, 0, 5);
+ QToolTip::add(b,i18n("Burnt Umber"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(254, 96, 8));
+ l->addWidget(b, 0, 6);
+ QToolTip::add(b,i18n("Cadmium Red"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(255, 136, 8));
+ l->addWidget(b, 0, 7);
+ QToolTip::add(b,i18n("Brilliant Orange"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(240, 199, 8));
+ l->addWidget(b, 1, 0);
+ QToolTip::add(b,i18n("Hansa Yellow"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(96, 170, 130));
+ l->addWidget(b, 1, 1);
+ QToolTip::add(b,i18n("Phthalo Green"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(48, 32, 170));
+ l->addWidget(b, 1, 2);
+ QToolTip::add(b,i18n("French Ultramarine"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(118, 16, 135));
+ l->addWidget(b, 1, 3);
+ QToolTip::add(b,i18n("Interference Lilac"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(254, 254, 254));
+ l->addWidget(b, 1, 4);
+ QToolTip::add(b,i18n("Titanium White"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(64, 64, 74));
+ l->addWidget(b, 1, 5);
+ QToolTip::add(b,i18n("Ivory Black"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ b = new KisColorCup(this);
+ b->setColor(QColor(255, 255, 255));
+ l->addWidget(b, 1, 6);
+ QToolTip::add(b,i18n("Pure Water"));
+ b->setFixedSize(WIDTH, HEIGHT);
+ connect(b, SIGNAL(changed(const QColor &)), SLOT(slotFGColorSelected(const QColor &)));
+
+ QGridLayout * g2 = new QGridLayout(vl, 2, 2);
+
+ QLabel * label = new QLabel(i18n("Paint strength:"), this);
+ g2->addWidget(label, 0, 0);
+ m_strength = new KDoubleNumInput(0.0, 2.0, 1.0, 0.1, 1, this);
+ m_strength->setRange(0.0, 2.0, 0.1, true);
+ connect(m_strength, SIGNAL(valueChanged(double)), this, SLOT(slotStrengthChanged(double)));
+ g2->addWidget(m_strength, 0, 1);
+
+ label = new QLabel(i18n("Wetness:"), this);
+ g2->addWidget(label, 1, 0);
+ m_wetness = new KIntNumInput(16, this);
+ connect(m_wetness, SIGNAL(valueChanged(int)), this, SLOT(slotWetnessChanged(int)));
+ m_wetness->setRange(0, 16, true);
+ g2->addWidget(m_wetness, 1, 1);
+
+ g2->addItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
+
+}
+
+void KisWetPaletteWidget::update(KisCanvasSubject *subject)
+{
+ m_subject = subject;
+
+}
+
+void KisWetPaletteWidget::slotFGColorSelected(const QColor& c)
+{
+ KisWetColorSpace* cs = dynamic_cast<KisWetColorSpace*>(KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""), ""));
+ Q_ASSERT(cs);
+
+ WetPack pack;
+ Q_UINT8* data = reinterpret_cast< Q_UINT8*>(&pack);
+ cs->fromQColor(c, data);
+ pack.paint.w = 15 * m_wetness->value();
+ // upscale from double to uint16:
+ pack.paint.h = static_cast< Q_UINT16>(m_strength->value() * (double)(0xffff/2));
+ KisColor color(data, cs);
+
+ if(m_subject)
+ m_subject->setFGColor(color);
+}
+
+void KisWetPaletteWidget::slotWetnessChanged(int n)
+{
+ if (!m_subject)
+ return;
+
+ KisWetColorSpace* cs = dynamic_cast<KisWetColorSpace*>(KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""), ""));
+ Q_ASSERT(cs);
+
+ KisColor color = m_subject->fgColor();
+ color.convertTo(cs);
+ WetPack pack = *(reinterpret_cast<WetPack*>(color.data()));
+ pack.paint.w = 15 * n;
+
+ color.setColor(reinterpret_cast< Q_UINT8*>(&pack), cs);
+ m_subject->setFGColor(color);
+}
+
+void KisWetPaletteWidget::slotStrengthChanged(double n)
+{
+ if (!m_subject)
+ return;
+
+ KisWetColorSpace* cs = dynamic_cast<KisWetColorSpace*>(
+ KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""), ""));
+ Q_ASSERT(cs);
+
+ KisColor color = m_subject->fgColor();
+ color.convertTo(cs);
+ WetPack pack = *(reinterpret_cast<WetPack*>(color.data()));
+ pack.paint.h = static_cast< Q_UINT16>(n * (double)(0xffff/2)); // upscale from double to uint16
+
+ color.setColor(reinterpret_cast< Q_UINT8*>(&pack), cs);
+ m_subject->setFGColor(color);
+}
+
+
+#include "kis_wet_palette_widget.moc"
diff --git a/krita/colorspaces/wet/kis_wet_palette_widget.h b/krita/colorspaces/wet/kis_wet_palette_widget.h
new file mode 100644
index 00000000..fb2800d3
--- /dev/null
+++ b/krita/colorspaces/wet/kis_wet_palette_widget.h
@@ -0,0 +1,67 @@
+/* This file is part of the KDE project
+ *
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * 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_WET_PALETTE_WIDGET_H
+#define KIS_WET_PALETTE_WIDGET_H
+
+#include "qwidget.h"
+#include "qpushbutton.h"
+
+#include "kis_canvas_subject.h"
+#include "kis_canvas_observer.h"
+
+#include <koffice_export.h>
+
+class KoFrameButton;
+class QGridLayout;
+class QColor;
+class QLabel;
+class QSpinBox;
+class QColor;
+class KIntNumInput;
+class KDoubleNumInput;
+
+class KRITAUI_EXPORT KisWetPaletteWidget
+ : public QWidget,
+ public KisCanvasObserver
+{
+ Q_OBJECT
+ typedef QWidget super;
+
+public:
+ KisWetPaletteWidget(QWidget *parent = 0L, const char *name = 0);
+ virtual ~KisWetPaletteWidget() {}
+
+protected slots:
+
+ void slotFGColorSelected(const QColor& c);
+ void slotWetnessChanged(int);
+ void slotStrengthChanged(double);
+
+private:
+ void update(KisCanvasSubject*);
+
+private:
+ KisCanvasSubject *m_subject;
+ KDoubleNumInput* m_strength;
+ KIntNumInput* m_wetness;
+
+
+};
+
+#endif
diff --git a/krita/colorspaces/wet/kis_wetness_visualisation_filter.cc b/krita/colorspaces/wet/kis_wetness_visualisation_filter.cc
new file mode 100644
index 00000000..411a3495
--- /dev/null
+++ b/krita/colorspaces/wet/kis_wetness_visualisation_filter.cc
@@ -0,0 +1,77 @@
+/*
+ * kis_wetness_visualisation_filter.cc -- Part of Krita
+ *
+ * Copyright (c) 2005 Bart Coppens <[email protected]>
+ *
+ * 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 <klocale.h>
+#include "kis_meta_registry.h"
+#include <kis_view.h>
+#include <kis_image.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_factory.h>
+#include "kis_wet_colorspace.h"
+#include <kis_debug_areas.h>
+#include "kis_wetness_visualisation_filter.h"
+
+WetnessVisualisationFilter::WetnessVisualisationFilter(KisView* view)
+ : m_view(view), m_action(0) {
+ connect(&m_timer, SIGNAL(timeout()), this, SLOT(slotTimeout()));
+}
+
+// XXX this needs to work on a per-layer basis!
+
+void WetnessVisualisationFilter::setAction(KToggleAction* action) {
+ m_action = action;
+ if (!m_action)
+ return;
+ KisWetColorSpace* cs = dynamic_cast<KisWetColorSpace*>(
+ KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""),"") );
+ Q_ASSERT(cs);
+ m_action->setChecked(cs->paintWetness());
+}
+
+void WetnessVisualisationFilter::slotActivated() {
+ kdDebug(DBG_AREA_CMS) << "activated" << endl;
+ if (!m_action) {
+ kdDebug(DBG_AREA_CMS) << "no action" << endl;
+ return;
+ }
+ KisWetColorSpace* cs = dynamic_cast<KisWetColorSpace*>(
+ KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""),"") );
+ Q_ASSERT(cs);
+ if (!m_action->isChecked()) {
+ m_timer.stop();
+ cs->setPaintWetness(false);
+ } else {
+ m_timer.start(500);
+ cs->setPaintWetness(true);
+ }
+}
+
+void WetnessVisualisationFilter::slotTimeout() {
+ KisWetColorSpace* cs = dynamic_cast<KisWetColorSpace*>(
+ KisMetaRegistry::instance()->csRegistry()->getColorSpace(KisID("WET", ""),"") );
+ Q_ASSERT(cs);
+ if (!cs) return;
+ cs->resetPhase();
+
+}
+
+#include "kis_wetness_visualisation_filter.moc"
diff --git a/krita/colorspaces/wet/kis_wetness_visualisation_filter.h b/krita/colorspaces/wet/kis_wetness_visualisation_filter.h
new file mode 100644
index 00000000..ad5da5d3
--- /dev/null
+++ b/krita/colorspaces/wet/kis_wetness_visualisation_filter.h
@@ -0,0 +1,50 @@
+/*
+ * kis_wetness_visualisation_filter.h -- Part of Krita
+ *
+ * Copyright (c) 2004 Boudewijn Rempt ([email protected])
+ *
+ * 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 _WETNESS_VISUALISATION_FILTER_H
+#define _WETNESS_VISUALISATION_FILTER_H
+
+#include <qobject.h>
+#include <qtimer.h>
+#include <kactionclasses.h>
+
+class KisView;
+
+class WetnessVisualisationFilter : public QObject
+{
+ Q_OBJECT
+public:
+ WetnessVisualisationFilter(KisView* view);
+ virtual ~WetnessVisualisationFilter() {}
+ void setAction(KToggleAction* action);
+ // XXX: Figure out a way to match a filter exactly to a colorspace
+ virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; };
+ virtual bool workWith(KisColorSpace* cs) { return (cs->id() == KisID("WET")); };
+private slots:
+ void slotActivated();
+ void slotTimeout();
+
+private:
+ KisView * m_view;
+ KToggleAction * m_action;
+ QTimer m_timer;
+};
+
+#endif // _WETNESS_VISUALISATION_FILTER_H
diff --git a/krita/colorspaces/wet/kis_wetop.cc b/krita/colorspaces/wet/kis_wetop.cc
new file mode 100644
index 00000000..cff3ac1e
--- /dev/null
+++ b/krita/colorspaces/wet/kis_wetop.cc
@@ -0,0 +1,230 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * 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 <qrect.h>
+#include <qcheckbox.h>
+
+#include <kdebug.h>
+
+#include <kis_brush.h>
+#include <kis_debug_areas.h>
+#include <kis_paint_device.h>
+#include <kis_painter.h>
+#include <kis_types.h>
+#include <kis_paintop.h>
+#include <kis_iterators_pixel.h>
+#include <kis_layer.h>
+#include <kis_meta_registry.h>
+#include <kis_colorspace_factory_registry.h>
+#include "kis_input_device.h"
+
+#include "kis_wetop.h"
+#include "kis_wet_colorspace.h"
+
+KisWetOpSettings::KisWetOpSettings(QWidget *parent)
+ : super(parent)
+{
+ m_options = new WetPaintOptions(parent, "wet option widget");
+}
+
+bool KisWetOpSettings::varySize() const
+{
+ return m_options->checkSize->isChecked();
+}
+
+bool KisWetOpSettings::varyWetness() const
+{
+ return m_options->checkWetness->isChecked();
+}
+
+bool KisWetOpSettings::varyStrength() const
+{
+ return m_options->checkStrength->isChecked();
+}
+
+KisPaintOp * KisWetOpFactory::createOp(const KisPaintOpSettings *settings, KisPainter * painter)
+{
+ const KisWetOpSettings *wetopSettings = dynamic_cast<const KisWetOpSettings *>(settings);
+ Q_ASSERT(settings == 0 || wetopSettings != 0);
+
+ KisPaintOp * op = new KisWetOp(wetopSettings, painter);
+ Q_CHECK_PTR(op);
+ return op;
+}
+
+KisPaintOpSettings* KisWetOpFactory::settings(QWidget * parent, const KisInputDevice& inputDevice)
+{
+ if (inputDevice == KisInputDevice::mouse()) {
+ // No options for mouse, only tablet devices
+ return 0;
+ } else {
+ return new KisWetOpSettings(parent);
+ }
+}
+
+KisWetOp::KisWetOp(const KisWetOpSettings * settings, KisPainter * painter)
+ : super(painter)
+{
+ if (settings) {
+ m_size = settings->varySize();
+ m_wetness = settings->varyWetness();
+ m_strength = settings->varyStrength();
+ } else {
+ m_size = false;
+ m_wetness = false;
+ m_strength = false;
+ }
+}
+
+KisWetOp::~KisWetOp()
+{
+}
+
+void KisWetOp::paintAt(const KisPoint &pos, const KisPaintInformation& info)
+{
+ if (!m_painter) return;
+
+ if (!m_painter->device()) return;
+ KisPaintDeviceSP device = m_painter->device();
+ if (!m_painter->device()) return;
+
+ KisBrush *brush = m_painter->brush();
+ Q_ASSERT(brush);
+
+ if (! brush->canPaintFor(info) )
+ return;
+
+ KisPaintInformation inf(info);
+
+ if (!m_size)
+ inf.pressure = PRESSURE_DEFAULT;
+
+ KisPaintDeviceSP dab = 0;
+
+ if (brush->brushType() == IMAGE || brush->brushType() == PIPE_IMAGE) {
+ dab = brush->image(KisMetaRegistry::instance()->csRegistry()->getAlpha8(), inf);
+ }
+ else {
+ KisAlphaMaskSP mask = brush->mask(inf);
+ dab = computeDab(mask, KisMetaRegistry::instance()->csRegistry()->getAlpha8());
+ }
+
+ KisColorSpace * cs = device->colorSpace();
+
+ if (cs->id() != KisID("WET","")) {
+ kdDebug(DBG_AREA_CMS) << "You cannot paint wet paint on dry pixels.\n";
+ return;
+ }
+
+ KisColor paintColor = m_painter->paintColor();
+ paintColor.convertTo(cs);
+ // hopefully this does
+ // nothing, conversions are bad ( wet->rgb->wet gives horrible mismatches, due to
+ // the conversion to rgb actually rendering the paint above white
+
+ WetPack* paintPack = reinterpret_cast<WetPack*>(paintColor.data());
+ WetPix paint = paintPack->paint;
+
+ // Get the paint info (we store the strength in the otherwise unused (?) height field of
+ // the paint
+ // double wetness = paint.w; // XXX: Was unused
+ // strength is a double in the 0 - 2 range, but upscaled to Q_UINT16:
+ //kdDebug() << "Original strength as in paint.h: " << paint.h << endl;
+
+ double strength = 2.0 * static_cast<double>(paint.h) / (double)(0xffff);
+
+ //kdDebug() << "Before strength: " << strength << endl;
+
+ if (m_strength)
+ strength = strength * (strength + info.pressure) * 0.5;
+ else
+ strength = strength * (strength + PRESSURE_DEFAULT) * 0.5;
+
+ double pressure = 0.75 + 0.25 * info.pressure;
+
+ //kdDebug() << "info.pressure " << info.pressure << ", local pressure: " << pressure << ", strength: " << strength << endl;
+
+ WetPack currentPack;
+ WetPix currentPix;
+ double eff_height;
+ double press, contact;
+
+ int maskW = brush->maskWidth(inf);
+ int maskH = brush->maskHeight(inf);
+ KoPoint dest = (pos - (brush->hotSpot(inf)));
+ int xStart = (int)dest.x();
+ int yStart = (int)dest.y();
+
+ for (int y = 0; y < maskH; y++) {
+ KisHLineIteratorPixel dabIt = dab->createHLineIterator(0, y, maskW, false);
+ KisHLineIteratorPixel it = device->createHLineIterator(xStart, yStart+y, maskW, true);
+
+ while (!dabIt.isDone()) {
+ // This only does something with .paint, and not with adsorb.
+ currentPack = *(reinterpret_cast<WetPack*>(it.rawData()));
+ WetPix currentData = currentPack.adsorb;
+ currentPix = currentPack.paint;
+
+ // Hardcoded threshold for the dab 'strength': above it, it will get painted
+ if (*dabIt.rawData() > 125)
+ press = pressure * 0.25;
+ else
+ press = -1;
+ //kdDebug() << "After mysterious line, press becomes: " << press << ", this is the same as in the orignal. Good" << endl;
+ // XXX - 192 is probably only useful for paper with a texture...
+ eff_height = (currentData.h + currentData.w - 192.0) * (1.0 / 255.0);
+ contact = (press + eff_height) * 0.2;
+ double old_contact = contact;
+ if (contact > 0.5)
+ contact = 1.0 - 0.5 * exp(-2.0 * contact - 1.0);
+
+ //kdDebug() << "Contact was " << old_contact << " and has become: " << contact << endl;
+ if (contact > 0.0001) {
+ int v;
+ double rnd = rand() * (1.0 / RAND_MAX);
+
+ v = currentPix.rd;
+ currentPix.rd = floor(v + (paint.rd * strength - v) * contact + rnd);
+ //kdDebug() << "Rd was " << v << " and has become " << currentPix.rd << endl;
+ v = currentPix.rw;
+ currentPix.rw = floor(v + (paint.rw * strength - v) * contact + rnd);
+ v = currentPix.gd;
+ currentPix.gd = floor(v + (paint.gd * strength - v) * contact + rnd);
+ v = currentPix.gw;
+ currentPix.gw = floor(v + (paint.gw * strength - v) * contact + rnd);
+ v = currentPix.bd;
+ currentPix.bd = floor(v + (paint.bd * strength - v) * contact + rnd);
+ v = currentPix.bw;
+ currentPix.bw = floor(v + (paint.bw * strength - v) * contact + rnd);
+ v = currentPix.w;
+ if (m_wetness)
+ currentPix.w = (CLAMP(floor(
+ v + (paint.w * (0.5 + pressure) - v) * contact + rnd), 0, 512));
+ else
+ currentPix.w = floor(v + (paint.w - v) * contact + rnd);
+
+ currentPack.paint = currentPix;
+ *(reinterpret_cast<WetPack*>(it.rawData())) = currentPack;
+ }
+ ++dabIt;
+ ++it;
+ }
+ }
+
+ m_painter->addDirtyRect(QRect(xStart, yStart, maskW, maskH));
+}
diff --git a/krita/colorspaces/wet/kis_wetop.h b/krita/colorspaces/wet/kis_wetop.h
new file mode 100644
index 00000000..cc488bf9
--- /dev/null
+++ b/krita/colorspaces/wet/kis_wetop.h
@@ -0,0 +1,73 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * 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_WETOP_H_
+#define KIS_WETOP_H_
+
+#include "kis_paintop.h"
+#include "kis_types.h"
+#include "kis_colorspace.h"
+#include "wdgpressure.h"
+
+class KisPoint;
+class KisPainter;
+class KisInputDevice;
+
+class KisWetOpFactory : public KisPaintOpFactory {
+public:
+ KisWetOpFactory() {}
+ virtual ~KisWetOpFactory() {}
+
+ virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter);
+ virtual KisID id() { return KisID("wetbrush", i18n("Watercolor Brush")); }
+ virtual bool userVisible(KisColorSpace* cs) { return cs->id() == KisID("WET", ""); }
+ virtual KisPaintOpSettings *settings(QWidget * parent, const KisInputDevice& inputDevice);
+};
+
+class KisWetOpSettings : public KisPaintOpSettings {
+ typedef KisPaintOpSettings super;
+public:
+ KisWetOpSettings(QWidget *parent);
+
+ bool varySize() const;
+ bool varyWetness() const;
+ bool varyStrength() const;
+
+ virtual QWidget *widget() const { return m_options; }
+
+private:
+ WetPaintOptions *m_options;
+};
+
+class KisWetOp : public KisPaintOp {
+
+ typedef KisPaintOp super;
+ bool m_size;
+ bool m_wetness;
+ bool m_strength;
+
+public:
+
+ KisWetOp(const KisWetOpSettings *settings, KisPainter * painter);
+ virtual ~KisWetOp();
+
+ void paintAt(const KisPoint &pos, const KisPaintInformation& info);
+
+};
+
+#endif // KIS_WETOP_H_
diff --git a/krita/colorspaces/wet/kritawetplugin.desktop b/krita/colorspaces/wet/kritawetplugin.desktop
new file mode 100644
index 00000000..b6b20e84
--- /dev/null
+++ b/krita/colorspaces/wet/kritawetplugin.desktop
@@ -0,0 +1,86 @@
+[Desktop Entry]
+Name=Watercolor Paint Plugin
+Name[bg]=Приставка акварелни бои
+Name[ca]=Connector de pintura aquarel·la
+Name[cy]=Ategyn Paent Dyfrlliw
+Name[da]=Plugin for vandfarvemaling
+Name[de]=Modul für Wasserfarben-Effekte
+Name[el]=Πρόσθετο υδατογραφίας
+Name[eo]=Akvokolorpentrada kromaĵo
+Name[es]=Complemento de pintura de acuarela
+Name[et]=Vesivärvijoonistuse plugin
+Name[eu]=Akuarelazko margoen plugina
+Name[fa]=وصلۀ رنگ‌آمیزی آبرنگ
+Name[fi]=Vesivärikuvaliitännäinen
+Name[fr]=Module de dessin à l'aquarelle
+Name[fy]=Wetter skilderplugin
+Name[gl]=Plugin de Pintura con Cores de Auga
+Name[he]=תוסף צביעה בצבעי מים
+Name[hu]=Vízfesték modul
+Name[is]=Vatnslita íforrit
+Name[it]=Plugin per la pittura ad acquerello
+Name[ja]=水彩プラグイン
+Name[km]=កម្មវិធី​ជំនួយ​សម្រាប់​គូរ​គំនូរ​ពណ៌​ទឹក
+Name[lv]=Zīmēšanas ar ūdenskrāsām spraudnis
+Name[ms]=Plugin Warna Cat Air
+Name[nb]=Paint-programtillegg for vannfarger
+Name[nds]=Waterklöör-Effektmoduul
+Name[ne]=पानी रङ पेन्ट प्लगइन
+Name[nl]=Waterkleur schilderplugin
+Name[nn]=Programtillegg for vassfargar
+Name[pl]=Wtyczka malowania akwarelami
+Name[pt]='Plugin' de Pintura a Água
+Name[pt_BR]=Plug-in de Marca D'água
+Name[ru]=Акварель
+Name[sk]=Modul pre vodové farby
+Name[sl]=Vstavek za slikanje z vodnimi barvami
+Name[sr]=Прикључак за сликање воденим бојама
+Name[sr@Latn]=Priključak za slikanje vodenim bojama
+Name[sv]=Insticksprogram för vattenfärgsmålning
+Name[uk]=Втулок малювання акварельними фарбами
+Name[zh_CN]=水彩绘画插件
+Name[zh_TW]=水色繪畫外掛程式
+Comment=Color model and tools for painting with simulated watercolors
+Comment[bg]=Цветови модел и инструменти за рисуване със симулирани акварелни бои
+Comment[ca]=Model de color i eines per a pintar amb aquarel·les simulades
+Comment[cy]=Model lliw ac offer ar gyfer paentio efo dyfrliwiau wedi'u hefelychu
+Comment[da]=Farvemodel og værktøjer til at male med simulerede vandfarver
+Comment[de]=Farbmodell und Werkzeuge zum Malen mit simulierten Wasserfarben
+Comment[el]=Χρωματικό μοντέλο και εργαλεία για τη ζωγραφική με εξομοίωση χρωμάτων υδατογραφίας
+Comment[en_GB]=Colour model and tools for painting with simulated watercolours
+Comment[es]=Modelo de color y herramientas para pintar con acuarelas simuladas
+Comment[et]=Vesivärvijoonistuse simulatsiooni värvimudel ja tööriistad
+Comment[eu]=Akuarelen itxuraz margotzeko tresnak eta kolore-eredua
+Comment[fa]=مدل رنگ و ابزارها برای رنگ‌آمیزی با آبرنگهای شبیه‌سازی شده
+Comment[fi]=Värimalli ja työkalut simuloiduille vesiväreille
+Comment[fr]=Modèle de couleurs et outils pour dessiner avec des couleurs simulées d'aquarelle
+Comment[fy]=Kleurmodel en -ark foar it skilderjen mei simulearre wetterkleuren
+Comment[gl]=Modelo de cores e ferramentas para pintar con cores de auga simulados
+Comment[he]=מודל צבעים וכלים לצביעה תוך הדמיה של צבעי מים
+Comment[hu]=Színmodell és eszközök szimulált vízfestékes képekhez
+Comment[is]=Litategundir og tól til að teikna með vatnslitum
+Comment[it]=Modello di colore e strumenti per il disegno con acquerelli simulati
+Comment[ja]=水彩画をシミュレートして描画するためのカラーモデルとツール
+Comment[km]=គំរូពណ៌ និង​ឧបករណ៍​សម្រាប់​គូរ​គំនូរ​ដែល​មាន​ពណ៌​ស្រដៀង​ទឹក
+Comment[ms]=Model warna dan alat lukisan dengan cat air tiruan
+Comment[nb]=Fargemodell og verktøy for maling med simulerte vannfarger
+Comment[nds]=Klöörmodell un Warktüüch för't Malen mit Waterklöreneffekten
+Comment[ne]=बनावटी पानीरङहरू सँग पेन्टीङ्गका लागि रङ मोडेल
+Comment[nl]=Kleurmodel en -gereedschappen voor het schilderen met gesimuleerde waterkleuren
+Comment[nn]=Fargemodell og verktøy for måling med simulerte vassfargar
+Comment[pl]=Przestrzeń barw oraz narzędzia do symulacji malowania farbami akwarelowymi
+Comment[pt]=Modelo de cor e ferramentas para pintar com cores aquosas simuladas
+Comment[pt_BR]=Modelo de cor e ferramentas para pintura de cores simuladas de água
+Comment[ru]=Цветовое пространство и инструменты рисования акварелью
+Comment[sk]=Model farieb a nástroje na kreslenie vodovými farbami
+Comment[sl]=Barvni model in orodja za slikanje s similiranimi vodnimi barvami
+Comment[sr]=Модел боја и алати за сликање симулираним воденим бојама
+Comment[sr@Latn]=Model boja i alati za slikanje simuliranim vodenim bojama
+Comment[sv]=Färgmodell och verktyg för att måla med simulerade vattenfärger
+Comment[uk]=Модель кольорів та засобів для малювання з симулюванням акварелі
+Comment[zh_CN]=模拟水彩绘画的色彩模型和工具
+Comment[zh_TW]=以模擬水色繪製的色彩模型與工具
+ServiceTypes=Krita/ColorSpace,Krita/ViewPlugin
+Type=Service
+X-KDE-Library=kritawetplugin
+X-Krita-Version=2
diff --git a/krita/colorspaces/wet/todo b/krita/colorspaces/wet/todo
new file mode 100644
index 00000000..2f6d358b
--- /dev/null
+++ b/krita/colorspaces/wet/todo
@@ -0,0 +1,24 @@
+* Implement wet model
+* Implement wet paintop
+* Implement dry filter
+* Enable/disable all relevant gui bits on switching to/from a wet layer
+* Create something that can periodically call the dry filter
+* A palette with the special colour for wet painting: a docker tab for the colour docker.
+
+Perhaps: a special layer type or paint device, with an extensible option widget.
+
+When to create the height field? Ideally, the height field should be visualized in subtle shades
+of grey before painting.
+
+How to hack into the creation of paint devices? We need initializers, extra options, status
+widgets and thread or timer based continuous running filters.
+
+-> Maybe add an initializePaintDevice(rect) method to the color strategy that is called with the image
+rect on creation. Then, for uninitialized rects (because of autolayers extension) call the method again.
+
+A wet layer is equivalent to the wetpack; two layers, i.e., stacked pixels, per pixel.
+
+The filter will contain the physics model: paint flow, drying and adsorbing onto the lower "layer"
+
+
+
diff --git a/krita/colorspaces/wet/wdgpressure.ui b/krita/colorspaces/wet/wdgpressure.ui
new file mode 100644
index 00000000..92161294
--- /dev/null
+++ b/krita/colorspaces/wet/wdgpressure.ui
@@ -0,0 +1,60 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>WetPaintOptions</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>WetPaintOptions</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>382</width>
+ <height>31</height>
+ </rect>
+ </property>
+ <hbox>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <property name="margin">
+ <number>0</number>
+ </property>
+ <widget class="QLabel">
+ <property name="name">
+ <cstring>textLabel1</cstring>
+ </property>
+ <property name="text">
+ <string>Pressure effects:</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkSize</cstring>
+ </property>
+ <property name="text">
+ <string>Size</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkWetness</cstring>
+ </property>
+ <property name="text">
+ <string>Wetness</string>
+ </property>
+ </widget>
+ <widget class="QCheckBox">
+ <property name="name">
+ <cstring>checkStrength</cstring>
+ </property>
+ <property name="text">
+ <string>Strength</string>
+ </property>
+ </widget>
+ </hbox>
+</widget>
+<layoutdefaults spacing="6" margin="11"/>
+</UI>
diff --git a/krita/colorspaces/wet/wet_plugin.cc b/krita/colorspaces/wet/wet_plugin.cc
new file mode 100644
index 00000000..cbb4787b
--- /dev/null
+++ b/krita/colorspaces/wet/wet_plugin.cc
@@ -0,0 +1,128 @@
+/*
+ * wet_plugin.cc -- Part of Krita
+ *
+ * Copyright (c) 2004 Boudewijn Rempt ([email protected])
+ *
+ * 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 <stdlib.h>
+#include <vector>
+
+#include <qobject.h>
+#include <qapplication.h>
+#include <qclipboard.h>
+#include <qdockwindow.h>
+#include <qpoint.h>
+#include <qlabel.h>
+#include <qwidget.h>
+
+#include <kactionclasses.h>
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+#include <kopalettemanager.h>
+#include <KoMainWindow.h>
+
+#include <kis_debug_areas.h>
+#include "kis_meta_registry.h"
+#include <kis_factory.h>
+#include <kis_image.h>
+#include <kis_debug_areas.h>
+#include <kis_types.h>
+#include <kis_view.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_tool_registry.h>
+#include <kis_paintop_registry.h>
+#include <kis_canvas_subject.h>
+#include <kis_basic_histogram_producers.h>
+
+#include "wet_plugin.h"
+#include "kis_wet_palette_widget.h"
+#include "kis_wet_colorspace.h"
+#include "kis_wetop.h"
+#include "kis_wetness_visualisation_filter.h"
+#include "kis_texture_filter.h"
+#include "wetphysicsfilter.h"
+
+typedef KGenericFactory<WetPlugin> WetPluginFactory;
+K_EXPORT_COMPONENT_FACTORY( kritawetplugin, WetPluginFactory( "kritacore" ) )
+
+
+WetPlugin::WetPlugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(WetPluginFactory::instance());
+
+ // This is not a gui plugin; only load it when the doc is created.
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") ) {
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry*>(parent);
+
+ KisColorSpace* colorSpaceWet = new KisWetColorSpace(f, 0);
+
+ KisColorSpaceFactory * csf = new KisWetColorSpaceFactory();
+ Q_CHECK_PTR(colorSpaceWet);
+
+ // colorspace
+ f->add(csf);
+
+ // histogram producer
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicU16HistogramProducer>
+ (KisID("WETHISTO", i18n("Wet")), colorSpaceWet) );
+
+ // wet brush op
+ KisPaintOpRegistry::instance()->add(new KisWetOpFactory);
+
+ // Dry filter
+ KisFilterRegistry::instance()->add( new WetPhysicsFilter() );
+
+ // Texture Action:
+ f->addPaintDeviceAction(colorSpaceWet, new WetPaintDevAction);
+ }
+ else if (parent->inherits("KisView"))
+ {
+ setInstance(WetPluginFactory::instance());
+ setXMLFile(locate("data","kritaplugins/wetplugin.rc"), true);
+
+ m_view = dynamic_cast<KisView*>(parent);
+ // Wetness visualisation
+ WetnessVisualisationFilter * wf = new WetnessVisualisationFilter(m_view);
+ wf->setAction(new KToggleAction(i18n("Wetness Visualisation"), 0, 0, wf,
+ SLOT(slotActivated()), actionCollection(), "wetnessvisualisation"));
+
+ // Create the wet palette
+ KisWetPaletteWidget * w = new KisWetPaletteWidget(m_view);
+ Q_CHECK_PTR(w);
+
+ w->setCaption(i18n("Watercolors"));
+
+ m_view->canvasSubject()->paletteManager()->addWidget(w, "watercolor docker", krita::COLORBOX, INT_MAX, PALETTE_DOCKER, false);
+ m_view->canvasSubject()->attach(w);
+ }
+
+
+}
+
+WetPlugin::~WetPlugin()
+{
+}
+
+#include "wet_plugin.moc"
diff --git a/krita/colorspaces/wet/wet_plugin.h b/krita/colorspaces/wet/wet_plugin.h
new file mode 100644
index 00000000..117ee253
--- /dev/null
+++ b/krita/colorspaces/wet/wet_plugin.h
@@ -0,0 +1,45 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * 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 WET_PLUGIN_H_
+#define WET_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+#include "kis_types.h"
+
+class KisView;
+class KisWetColorSpace;
+
+/**
+ * A plugin wrapper around the WET colour space strategy.
+ */
+class WetPlugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ WetPlugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~WetPlugin();
+
+private:
+
+ KisView* m_view;
+
+};
+
+#endif // WET_PLUGIN_H_
diff --git a/krita/colorspaces/wet/wetdreams/Makefile b/krita/colorspaces/wet/wetdreams/Makefile
new file mode 100644
index 00000000..3daf4d76
--- /dev/null
+++ b/krita/colorspaces/wet/wetdreams/Makefile
@@ -0,0 +1,6 @@
+CFLAGS = -O3 `gtk-config --cflags` -Wall -ansi -pedantic
+LDFLAGS = -O3 `gtk-config --libs` -Wall -ansi -pedantic
+
+all: wetmain
+
+wetmain: wetmain.o wetpix.o wetpaint.o wettexture.o wetphysics.o
diff --git a/krita/colorspaces/wet/wetdreams/wetmain.c b/krita/colorspaces/wet/wetdreams/wetmain.c
new file mode 100644
index 00000000..151385f5
--- /dev/null
+++ b/krita/colorspaces/wet/wetdreams/wetmain.c
@@ -0,0 +1,517 @@
+#include <gtk/gtk.h>
+#include <stdlib.h>
+#include <math.h>
+#include "wetpix.h"
+#include "wetpaint.h"
+#include "wettexture.h"
+#include "wetphysics.h"
+WetPack *pack; /* The global wet pack */
+
+double lastx, lasty;
+double dist;
+double spacing = 2;
+
+WetPix paint = { 707, 0, 707, 0, 707, 0, 240, 0 };
+
+/* colors from Curtis et al, Siggraph 97 */
+
+WetPix paintbox[] = {
+ {496, 0, 16992, 0, 3808, 0, 0, 0},
+ {16992, 9744, 21712, 6400, 25024, 3296, 0, 0},
+ {6512, 6512, 6512, 4880, 11312, 0, 0, 0},
+ {16002, 0, 2848, 0, 16992, 0, 0, 0},
+ {22672, 0, 5328, 2272, 4288, 2640, 0, 0},
+ {8000, 0, 16992, 0, 28352, 0, 0, 0},
+ {5696, 5696, 12416, 2496, 28352, 0, 0, 0},
+ {0, 0, 5136, 0, 28352, 0, 0, 0},
+ {2320, 1760, 7344, 4656, 28352, 0, 0, 0},
+ {8000, 0, 3312, 0, 5504, 0, 0, 0},
+ {13680, 0, 16992, 0, 3312, 0, 0, 0},
+ {5264, 5136, 1056, 544, 6448, 6304, 0, 0},
+ {11440, 11440, 11440, 11440, 11440, 11440, 0, 0},
+ {11312, 0, 11312, 0, 11312, 0, 0, 0},
+ {0, 0, 0, 0, 0, 0, 0, 0}
+};
+
+int n_paints = 15;
+
+char *paintstr = "select paint";
+
+GtkWidget *paintname;
+
+char *paintnames[] = {
+ "Quinacridone Rose",
+ "Indian Red",
+ "Cadmium Yellow",
+ "Hookers Green",
+ "Cerulean Blue",
+ "Burnt Umber",
+ "Cadmium Red",
+ "Brilliant Orange",
+ "Hansa Yellow",
+ "Phthalo Green",
+ "French Ultramarine",
+ "Interference Lilac",
+ "Titanium White",
+ "Ivory Black",
+ "Pure Water"
+};
+
+GtkWidget *autodryb;
+int timo = 0;
+int adsorb_cnt;
+
+GtkObject *brushsize_adjust;
+
+GtkObject *wetness_adjust;
+
+GtkObject *strength_adjust;
+
+static void stop_drying(void)
+{
+ timo = 0;
+ gtk_label_set_text(GTK_LABEL(paintname), paintstr);
+}
+
+static double strength_func(double strength, double pressure)
+{
+ return strength * (strength + pressure) * 0.5;
+}
+
+static gint wet_button_press(GtkWidget * widget, GdkEventButton * event)
+{
+#define noVERBOSE
+#ifdef VERBOSE
+ g_print("button press %f %f %f\n", event->x, event->y,
+ event->pressure);
+
+#endif
+ wet_dab(pack->layers[1],
+ &paint,
+ event->x,
+ event->y,
+ ((GtkAdjustment *) brushsize_adjust)->value *
+ event->pressure, 0.75 + 0.25 * event->pressure,
+ strength_func(((GtkAdjustment *) strength_adjust)->value,
+ event->pressure));
+
+ lastx = event->x;
+ lasty = event->y;
+ dist = 0;
+
+ stop_drying();
+
+ gtk_widget_queue_draw(widget);
+ return TRUE;
+}
+
+static gint wet_motion(GtkWidget * widget, GdkEventMotion * event)
+{
+ double delta;
+#ifdef VERBOSE
+ g_print("motion %f %f %f %d\n", event->x, event->y,
+ event->pressure, event->state);
+
+#endif
+ stop_drying();
+
+ if (!(event->state & 256))
+ return TRUE;
+
+ delta = sqrt((event->x - lastx) * (event->x - lastx) +
+ (event->y - lasty) * (event->y - lasty));
+
+ dist += delta;
+
+ if (dist >= spacing) {
+ /* todo: interpolate position and pressure of the dab */
+ wet_dab(pack->layers[1],
+ &paint,
+ event->x,
+ event->y,
+ ((GtkAdjustment *) brushsize_adjust)->value *
+ event->pressure, 0.75 + 0.25 * event->pressure,
+ strength_func(((GtkAdjustment *) strength_adjust)->
+ value, event->pressure));
+ gtk_widget_queue_draw(widget);
+ dist -= spacing;
+ }
+
+ lastx = event->x;
+ lasty = event->y;
+
+ return TRUE;
+}
+
+static void dry(GtkWidget * da)
+{
+ g_print("drying...");
+ gtk_label_set_text(GTK_LABEL(paintname), "drying...");
+ gtk_widget_draw(paintname, NULL);
+ gdk_flush();
+ wet_flow(pack->layers[1]);
+ adsorb_cnt++;
+ if (adsorb_cnt == 2) {
+ wet_adsorb(pack->layers[1], pack->layers[0]);
+ wet_dry(pack->layers[1]);
+ adsorb_cnt = 0;
+ }
+
+ gtk_widget_draw(da, NULL);
+#if 0
+ gtk_label_set_text(GTK_LABEL(paintname), paintstr);
+#endif
+ g_print("done\n");
+}
+
+static gint wet_dry_button_press(GtkWidget * widget, GtkWidget * da)
+{
+ dry(da);
+
+ timo = 0;
+
+ return TRUE;
+}
+
+static gint clear_button_press(GtkWidget * widget, GtkWidget * da)
+{
+ wet_layer_clear(pack->layers[0]);
+ wet_layer_clone_texture(pack->layers[0], pack->layers[1]);
+ wet_layer_clear(pack->layers[1]);
+ wet_layer_clone_texture(pack->layers[1], pack->layers[0]);
+
+ gtk_widget_draw(da, NULL);
+
+ stop_drying();
+
+ return TRUE;
+}
+
+static gint dry_timer(gpointer * dummy)
+{
+ GtkWidget *da = (GtkWidget *) dummy;
+
+ timo++;
+ if (timo >= 10) {
+ if (gtk_toggle_button_get_active
+ (GTK_TOGGLE_BUTTON(autodryb))) {
+ dry(da);
+ }
+
+ timo -= 2;
+ }
+ return TRUE;
+}
+
+static gint
+wet_expose(GtkWidget * widget, GdkEventExpose * event, WetPack * pack)
+{
+ byte *rgb;
+ int rowstride;
+
+#ifdef VERBOSE
+ g_print("expose: %d layers\n", pack->n_layers);
+#endif
+
+ rowstride = event->area.width * 3;
+ rowstride = (rowstride + 3) & -4; /* align to 4-byte boundary */
+ rgb = g_new(byte, event->area.height * rowstride);
+
+ wet_pack_render(rgb, rowstride,
+ pack,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height);
+
+ gdk_draw_rgb_image(widget->window,
+ widget->style->black_gc,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height,
+ GDK_RGB_DITHER_MAX, rgb, rowstride);
+
+ g_free(rgb);
+ return FALSE;
+}
+
+
+static void init_input(void)
+{
+ GList *tmp_list;
+ GdkDeviceInfo *info;
+
+ tmp_list = gdk_input_list_devices();
+
+ info = NULL;
+ while (tmp_list) {
+ info = (GdkDeviceInfo *) tmp_list->data;
+#ifdef VERBOSE
+ g_print("device: %s\n", info->name);
+#endif
+ if (!g_strcasecmp(info->name, "wacom") ||
+ !g_strcasecmp(info->name, "stylus") ||
+ !g_strcasecmp(info->name, "eraser")) {
+ gdk_input_set_mode(info->deviceid,
+ GDK_MODE_SCREEN);
+ }
+ tmp_list = tmp_list->next;
+ }
+ if (!info)
+ return;
+}
+
+static gint
+pselect_expose(GtkWidget * widget, GdkEventExpose * event, WetPack * pack)
+{
+ byte *rgb;
+ int x;
+ int paint_quad, paint_num;
+ int last_pn;
+ int bg;
+
+#ifdef VERBOSE
+ g_print("expose: %d layers\n", pack->n_layers);
+#endif
+
+ rgb = g_new(byte, pack->layers[0]->width * 3);
+
+ last_pn = 0;
+ for (x = 0; x < pack->layers[0]->width; x++) {
+ paint_quad =
+ floor(4 * x * n_paints / pack->layers[0]->width + 0.5);
+ paint_num = paint_quad >> 2;
+ if (last_pn != paint_num) {
+ rgb[x * 3] = 255;
+ rgb[x * 3 + 1] = 255;
+ rgb[x * 3 + 2] = 255;
+ last_pn = paint_num;
+ } else {
+ if ((paint_quad & 3) > 0 && (paint_quad & 3) < 3)
+ bg = 0;
+ else
+ bg = 255;
+ rgb[x * 3] = bg;
+ rgb[x * 3 + 1] = bg;
+ rgb[x * 3 + 2] = bg;
+ wet_composite(&rgb[x * 3], 0, &paintbox[paint_num],
+ 0, 1, 1);
+ }
+ }
+
+ gdk_draw_rgb_image(widget->window,
+ widget->style->black_gc,
+ event->area.x, event->area.y,
+ event->area.width, event->area.height,
+ GDK_RGB_DITHER_MAX,
+ rgb + (event->area.x) * 3, 0);
+
+ g_free(rgb);
+ return FALSE;
+}
+
+static gint
+pselect_button_press(GtkWidget * widget, GdkEventButton * event)
+{
+ int paint_num;
+ int wet;
+
+#ifdef VERBOSE
+ g_print("pselect button press %f %f %f\n", event->x, event->y,
+ event->pressure);
+
+#endif
+ paint_num = floor((event->x * n_paints) / pack->layers[0]->width);
+
+ /* preserve wetness */
+ wet = paint.w;
+ paint = paintbox[paint_num];
+ paint.w = wet;
+ paintstr = paintnames[paint_num];
+ /*
+ gtk_adjustment_set_value (GTK_ADJUSTMENT (wetness_adjust), paint.w);
+ */
+ gtk_label_set_text(GTK_LABEL(paintname), paintstr);
+
+ stop_drying();
+
+ return TRUE;
+}
+
+static void wetness_update(GtkAdjustment * adj, gpointer data)
+{
+ paint.w = floor(15 * adj->value + 0.5);
+}
+
+int main(int argc, char **argv)
+{
+ GtkWidget *w;
+ GtkWidget *v;
+ GtkWidget *eb;
+ GtkWidget *da;
+ GtkWidget *peb;
+ GtkWidget *pda;
+ GtkWidget *h;
+ GtkWidget *b;
+ GtkWidget *db;
+ GtkWidget *h2;
+ GtkWidget *l;
+ GtkWidget *brushsize;
+ GtkWidget *wetness;
+ GtkWidget *strength;
+ int xs = 512;
+ int ys = 512;
+
+ gtk_init(&argc, &argv);
+
+ if (argc >= 3) {
+ xs = atoi(argv[1]);
+ ys = atoi(argv[2]);
+ if (xs == 0)
+ xs = 512;
+ if (ys == 0)
+ ys = 512;
+ }
+
+
+ init_input();
+
+ gdk_rgb_init();
+
+ gtk_widget_set_default_colormap(gdk_rgb_get_cmap());
+ gtk_widget_set_default_visual(gdk_rgb_get_visual());
+
+ pack = wet_pack_new(xs, ys);
+
+ wet_pack_maketexture(pack, 1, 0.7, 0.5);
+
+ w = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_signal_connect(GTK_OBJECT(w), "destroy",
+ (GtkSignalFunc) gtk_main_quit, NULL);
+
+ v = gtk_vbox_new(FALSE, 2);
+ gtk_container_add(GTK_CONTAINER(w), v);
+ gtk_widget_show(v);
+
+ eb = gtk_event_box_new();
+ gtk_container_add(GTK_CONTAINER(v), eb);
+ gtk_widget_show(eb);
+
+ gtk_widget_set_extension_events(eb, GDK_EXTENSION_EVENTS_ALL);
+
+ gtk_widget_set_events(eb, GDK_EXPOSURE_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_KEY_PRESS_MASK
+ | GDK_POINTER_MOTION_MASK
+ | GDK_PROXIMITY_OUT_MASK);
+
+ gtk_signal_connect(GTK_OBJECT(eb), "button_press_event",
+ (GtkSignalFunc) wet_button_press, NULL);
+ gtk_signal_connect(GTK_OBJECT(eb), "motion_notify_event",
+ (GtkSignalFunc) wet_motion, NULL);
+
+ da = gtk_drawing_area_new();
+ gtk_drawing_area_size(GTK_DRAWING_AREA(da), xs, ys);
+ gtk_container_add(GTK_CONTAINER(eb), da);
+ gtk_widget_show(da);
+
+ gtk_signal_connect(GTK_OBJECT(da), "expose_event",
+ (GtkSignalFunc) wet_expose, pack);
+
+ peb = gtk_event_box_new();
+ gtk_container_add(GTK_CONTAINER(v), peb);
+ gtk_widget_show(peb);
+
+ gtk_widget_set_extension_events(peb, GDK_EXTENSION_EVENTS_ALL);
+
+ gtk_widget_set_events(peb, GDK_EXPOSURE_MASK
+ | GDK_LEAVE_NOTIFY_MASK
+ | GDK_BUTTON_PRESS_MASK
+ | GDK_KEY_PRESS_MASK
+ | GDK_PROXIMITY_OUT_MASK);
+
+ gtk_signal_connect(GTK_OBJECT(peb), "button_press_event",
+ (GtkSignalFunc) pselect_button_press, NULL);
+
+ pda = gtk_drawing_area_new();
+ gtk_drawing_area_size(GTK_DRAWING_AREA(pda), xs, 16);
+ gtk_container_add(GTK_CONTAINER(peb), pda);
+ gtk_widget_show(pda);
+
+ gtk_signal_connect(GTK_OBJECT(pda), "expose_event",
+ (GtkSignalFunc) pselect_expose, pack);
+
+ paintname = gtk_label_new(paintstr);
+ gtk_container_add(GTK_CONTAINER(v), paintname);
+ gtk_widget_show(paintname);
+
+ h = gtk_hbox_new(TRUE, 5);
+ gtk_container_add(GTK_CONTAINER(v), h);
+ gtk_widget_show(h);
+
+ b = gtk_button_new_with_label("Dry");
+ gtk_container_add(GTK_CONTAINER(h), b);
+ gtk_widget_show(b);
+
+ gtk_signal_connect(GTK_OBJECT(b), "clicked",
+ (GtkSignalFunc) wet_dry_button_press, da);
+
+ autodryb = gtk_toggle_button_new_with_label("Auto Dry");
+ gtk_container_add(GTK_CONTAINER(h), autodryb);
+ gtk_widget_show(autodryb);
+
+ db = gtk_button_new_with_label("Clear");
+ gtk_container_add(GTK_CONTAINER(h), db);
+ gtk_widget_show(db);
+
+ gtk_signal_connect(GTK_OBJECT(db), "clicked",
+ (GtkSignalFunc) clear_button_press, da);
+
+ h2 = gtk_hbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(v), h2);
+ gtk_widget_show(h2);
+
+ l = gtk_label_new("Brush size: ");
+ gtk_container_add(GTK_CONTAINER(h2), l);
+ gtk_widget_show(l);
+
+ brushsize_adjust = gtk_adjustment_new(10, 0, 32, 0.1, 0.1, 0);
+ brushsize = gtk_hscale_new(GTK_ADJUSTMENT(brushsize_adjust));
+ gtk_container_add(GTK_CONTAINER(h2), brushsize);
+ gtk_widget_show(brushsize);
+
+ h2 = gtk_hbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(v), h2);
+ gtk_widget_show(h2);
+
+ l = gtk_label_new("Wetness: ");
+ gtk_container_add(GTK_CONTAINER(h2), l);
+ gtk_widget_show(l);
+
+ wetness_adjust = gtk_adjustment_new(16, 0, 16, 1.0, 1.0, 0);
+ wetness = gtk_hscale_new(GTK_ADJUSTMENT(wetness_adjust));
+ gtk_container_add(GTK_CONTAINER(h2), wetness);
+ gtk_widget_show(wetness);
+ gtk_signal_connect(GTK_OBJECT(wetness_adjust), "value_changed",
+ (GtkSignalFunc) wetness_update, NULL);
+
+ h2 = gtk_hbox_new(FALSE, 5);
+ gtk_container_add(GTK_CONTAINER(v), h2);
+ gtk_widget_show(h2);
+
+ l = gtk_label_new("Strength: ");
+ gtk_container_add(GTK_CONTAINER(h2), l);
+ gtk_widget_show(l);
+
+ strength_adjust = gtk_adjustment_new(1, 0, 2, 0.1, 0.1, 0);
+ strength = gtk_hscale_new(GTK_ADJUSTMENT(strength_adjust));
+ gtk_scale_set_digits(GTK_SCALE(strength), 2);
+ gtk_container_add(GTK_CONTAINER(h2), strength);
+ gtk_widget_show(strength);
+
+ gtk_widget_show(w);
+
+ gtk_timeout_add(50, (GtkFunction) dry_timer, da);
+
+ gtk_main();
+
+ return 0;
+}
diff --git a/krita/colorspaces/wet/wetdreams/wetpaint.c b/krita/colorspaces/wet/wetdreams/wetpaint.c
new file mode 100644
index 00000000..c1ac0d0c
--- /dev/null
+++ b/krita/colorspaces/wet/wetdreams/wetpaint.c
@@ -0,0 +1,101 @@
+
+#include <stdlib.h>
+#include <math.h>
+#include "wetpix.h"
+#include "wetphysics.h"
+#include "wetpaint.h"
+
+/* This function is not entirely satisfactory - the compositing is basically
+ opaque, and it really should do wet compositing. */
+void
+wet_dab(WetLayer * layer,
+ WetPix * paint,
+ double x, double y, double r, double pressure, double strength)
+{
+ double r_fringe;
+ int x0, y0;
+ int x1, y1;
+ WetPix *wet_line;
+ int xp, yp;
+ double xx, yy, rr;
+ double eff_height;
+ double press, contact;
+ WetPixDbl wet_tmp, wet_tmp2;
+
+ r_fringe = r + 1;
+ x0 = floor(x - r_fringe);
+ y0 = floor(y - r_fringe);
+ x1 = ceil(x + r_fringe);
+ y1 = ceil(y + r_fringe);
+ if (x0 < 0)
+ x0 = 0;
+ if (y0 < 0)
+ y0 = 0;
+ if (x1 >= layer->width)
+ x1 = layer->width;
+ if (y1 >= layer->height)
+ y1 = layer->height;
+
+ wet_line = layer->buf + y0 * layer->rowstride;
+ for (yp = y0; yp < y1; yp++) {
+ yy = (yp + 0.5 - y);
+ yy *= yy;
+ for (xp = x0; xp < x1; xp++) {
+ xx = (xp + 0.5 - x);
+ xx *= xx;
+ rr = yy + xx;
+ if (rr < r * r)
+ press = pressure * 0.25;
+ else
+ press = -1;
+ eff_height =
+ (wet_line[xp].h + wet_line[xp].w -
+ 192) * (1.0 / 255);
+ contact = (press + eff_height) * 0.2;
+ if (contact > 0.5)
+ contact =
+ 1 - 0.5 * exp(-2.0 * contact - 1);
+ if (contact > 0.0001) {
+ int v;
+ double rnd = rand() * (1.0 / RAND_MAX);
+
+ v = wet_line[xp].rd;
+ wet_line[xp].rd =
+ floor(v +
+ (paint->rd * strength -
+ v) * contact + rnd);
+ v = wet_line[xp].rw;
+ wet_line[xp].rw =
+ floor(v +
+ (paint->rw * strength -
+ v) * contact + rnd);
+ v = wet_line[xp].gd;
+ wet_line[xp].gd =
+ floor(v +
+ (paint->gd * strength -
+ v) * contact + rnd);
+ v = wet_line[xp].gw;
+ wet_line[xp].gw =
+ floor(v +
+ (paint->gw * strength -
+ v) * contact + rnd);
+ v = wet_line[xp].bd;
+ wet_line[xp].bd =
+ floor(v +
+ (paint->bd * strength -
+ v) * contact + rnd);
+ v = wet_line[xp].bw;
+ wet_line[xp].bw =
+ floor(v +
+ (paint->bw * strength -
+ v) * contact + rnd);
+ v = wet_line[xp].w;
+ wet_line[xp].w =
+ floor(v + (paint->w - v) * contact +
+ rnd);
+
+ }
+ }
+ wet_line += layer->rowstride;
+ }
+}
diff --git a/krita/colorspaces/wet/wetdreams/wetpaint.h b/krita/colorspaces/wet/wetdreams/wetpaint.h
new file mode 100644
index 00000000..5cec2659
--- /dev/null
+++ b/krita/colorspaces/wet/wetdreams/wetpaint.h
@@ -0,0 +1,4 @@
+void wet_dab(WetLayer * layer,
+ WetPix * paint,
+ double x, double y,
+ double r, double pressure, double strength);
diff --git a/krita/colorspaces/wet/wetdreams/wetphysics.c b/krita/colorspaces/wet/wetdreams/wetphysics.c
new file mode 100644
index 00000000..d8b321a8
--- /dev/null
+++ b/krita/colorspaces/wet/wetdreams/wetphysics.c
@@ -0,0 +1,334 @@
+/* Cool physics functions for wet paint */
+
+#include <gtk/gtk.h>
+#include <math.h>
+#include "wetpix.h"
+#include "wetphysics.h"
+
+/* symmetric combine, i.e. wet mixing.
+
+ This does not set the dst h field.
+*/
+void wet_pix_combine(WetPixDbl * dst, WetPixDbl * src1, WetPixDbl * src2)
+{
+ dst->rd = src1->rd + src2->rd;
+ dst->rw = src1->rw + src2->rw;
+#if 0
+ g_print("rd %f rw %f\n", dst->rd, dst->rw);
+#endif
+ dst->gd = src1->gd + src2->gd;
+ dst->gw = src1->gw + src2->gw;
+ dst->bd = src1->bd + src2->bd;
+ dst->bw = src1->bw + src2->bw;
+ dst->w = src1->w + src2->w;
+#if 0
+ g_print("%f + %f -> %f\n", src1->w, src2->w, dst->w);
+#endif
+}
+
+void wet_pix_dilute(WetPixDbl * dst, WetPix * src, double dilution)
+{
+ double scale = dilution * (1.0 / 8192.0);
+
+
+ dst->rd = src->rd * scale;
+#if 0
+ g_print("dilution %f scale %f rd %f\n", dilution, scale, dst->rd);
+#endif
+ dst->rw = src->rw * scale;
+ dst->gd = src->gd * scale;
+ dst->gw = src->gw * scale;
+ dst->bd = src->bd * scale;
+ dst->bw = src->bw * scale;
+ dst->w = src->w * (1.0 / 8192.0);
+ dst->h = src->h * (1.0 / 8192.0);
+}
+
+void wet_pix_reduce(WetPixDbl * dst, WetPix * src, double dilution)
+{
+ wet_pix_dilute(dst, src, dilution);
+ dst->w *= dilution;
+}
+
+/* allows visualization of adsorption by rotating the hue 120 degrees */
+/* layer-merge combining. src1 is the top layer
+
+ This does not set the dst h or w fields.
+*/
+void
+wet_pix_merge(WetPixDbl * dst, WetPixDbl * src1, double dilution1,
+ WetPixDbl * src2)
+{
+ double d1, w1, d2, w2;
+ double ed1, ed2;
+
+ if (src1->rd < 1e-4) {
+ dst->rd = src2->rd;
+ dst->rw = src2->rw;
+ } else if (src2->rd < 1e-4) {
+ dst->rd = src1->rd * dilution1;
+ dst->rw = src1->rw * dilution1;
+ } else {
+ d1 = src1->rd;
+ w1 = src1->rw;
+ d2 = src2->rd;
+ w2 = src2->rw;
+ dst->rd = d1 * dilution1 + d2;
+ ed1 = exp(-d1 * dilution1);
+ ed2 = exp(-d2);
+ dst->rw = dst->rd * ((1 - ed1) * w1 / d1 +
+ ed1 * (1 - ed2) * w2 / d2) /
+ (1 - ed1 * ed2);
+ }
+
+ if (src1->gd < 1e-4) {
+ dst->gd = src2->gd;
+ dst->gw = src2->gw;
+ } else if (src2->gd < 1e-4) {
+ dst->gd = src1->gd * dilution1;
+ dst->gw = src1->gw * dilution1;
+ } else {
+ d1 = src1->gd;
+ w1 = src1->gw;
+ d2 = src2->gd;
+ w2 = src2->gw;
+ dst->gd = d1 * dilution1 + d2;
+ ed1 = exp(-d1 * dilution1);
+ ed2 = exp(-d2);
+ dst->gw = dst->gd * ((1 - ed1) * w1 / d1 +
+ ed1 * (1 - ed2) * w2 / d2) /
+ (1 - ed1 * ed2);
+ }
+
+ if (src1->bd < 1e-4) {
+ dst->bd = src2->bd;
+ dst->bw = src2->bw;
+ } else if (src2->bd < 1e-4) {
+ dst->bd = src1->bd * dilution1;
+ dst->bw = src1->bw * dilution1;
+ } else {
+ d1 = src1->bd;
+ w1 = src1->bw;
+ d2 = src2->bd;
+ w2 = src2->bw;
+ dst->bd = d1 * dilution1 + d2;
+ ed1 = exp(-d1 * dilution1);
+ ed2 = exp(-d2);
+ dst->bw = dst->bd * ((1 - ed1) * w1 / d1 +
+ ed1 * (1 - ed2) * w2 / d2) /
+ (1 - ed1 * ed2);
+ }
+
+}
+
+void wet_flow(WetLayer * layer)
+{
+ /* XXX: Is this like a convolution operation? BSAR */
+ int x, y;
+ int width = layer->width;
+ int height = layer->height;
+ int rs = layer->rowstride;
+ double *flow_t, *flow_b, *flow_l, *flow_r;
+ double *fluid, *outflow;
+ WetPix *wet_line = layer->buf;
+ WetPix *wet_old;
+ int my_height;
+ int ix;
+ double ft, fb, fl, fr; /* top, bottom, left, right */
+ WetPixDbl wet_mix, wet_tmp;
+
+ flow_t = g_new(double, width * height);
+ flow_b = g_new(double, width * height);
+ flow_l = g_new(double, width * height);
+ flow_r = g_new(double, width * height);
+ fluid = g_new(double, width * height);
+ outflow = g_new(double, width * height);
+ wet_old = g_new(WetPix, width * height);
+
+ /* assumes rowstride == width */
+ memcpy(wet_old, layer->buf, sizeof(WetPix) * width * height);
+
+ ix = width + 1;
+ for (y = 1; y < height - 1; y++) {
+ wet_line += rs;
+ for (x = 1; x < width - 1; x++) {
+ if (wet_line[x].w > 0) {
+ my_height = wet_line[x].h + wet_line[x].w;
+ ft = (wet_line[x - rs].h +
+ wet_line[x - rs].w) - my_height;
+ fb = (wet_line[x + rs].h +
+ wet_line[x + rs].w) - my_height;
+ fl = (wet_line[x - 1].h +
+ wet_line[x - 1].w) - my_height;
+ fr = (wet_line[x + 1].h +
+ wet_line[x + 1].w) - my_height;
+
+ fluid[ix] =
+ 0.4 * sqrt(wet_line[x].w * 1.0 /
+ 255.0);
+
+ /* smooth out the flow a bit */
+ flow_t[ix] =
+ 0.1 * (10 + ft * 0.75 - fb * 0.25);
+ if (flow_t[ix] > 1)
+ flow_t[ix] = 1;
+ if (flow_t[ix] < 0)
+ flow_t[ix] = 0;
+ flow_b[ix] =
+ 0.1 * (10 + fb * 0.75 - ft * 0.25);
+ if (flow_b[ix] > 1)
+ flow_b[ix] = 1;
+ if (flow_b[ix] < 0)
+ flow_b[ix] = 0;
+ flow_l[ix] =
+ 0.1 * (10 + fl * 0.75 - fr * 0.25);
+ if (flow_l[ix] > 1)
+ flow_l[ix] = 1;
+ if (flow_l[ix] < 0)
+ flow_l[ix] = 0;
+ flow_r[ix] =
+ 0.1 * (10 + fr * 0.75 - fl * 0.25);
+ if (flow_r[ix] > 1)
+ flow_r[ix] = 1;
+ if (flow_r[ix] < 0)
+ flow_r[ix] = 0;
+
+ outflow[ix] = 0;
+ }
+ ix++;
+ }
+ ix += 2;
+ }
+
+ ix = width + 1;
+ wet_line = layer->buf;
+ for (y = 1; y < height - 1; y++) {
+ wet_line += rs;
+ for (x = 1; x < width - 1; x++) {
+ if (wet_line[x].w > 0) {
+ /* reduce flow in dry areas */
+ flow_t[ix] *= fluid[ix] * fluid[ix - rs];
+ outflow[ix - rs] += flow_t[ix];
+ flow_b[ix] *= fluid[ix] * fluid[ix + rs];
+ outflow[ix + rs] += flow_b[ix];
+ flow_l[ix] *= fluid[ix] * fluid[ix - 1];
+ outflow[ix - 1] += flow_l[ix];
+ flow_r[ix] *= fluid[ix] * fluid[ix + 1];
+ outflow[ix + 1] += flow_r[ix];
+ }
+ ix++;
+ }
+ ix += 2;
+ }
+
+ wet_line = layer->buf;
+ ix = width + 1;
+ for (y = 1; y < height - 1; y++) {
+ wet_line += rs;
+ for (x = 1; x < width - 1; x++) {
+ if (wet_line[x].w > 0) {
+ wet_pix_reduce(&wet_mix, &wet_old[ix],
+ 1 - outflow[ix]);
+
+ wet_pix_reduce(&wet_tmp, &wet_old[ix - rs],
+ flow_t[ix]);
+ wet_pix_combine(&wet_mix, &wet_mix,
+ &wet_tmp);
+ wet_pix_reduce(&wet_tmp, &wet_old[ix + rs],
+ flow_b[ix]);
+ wet_pix_combine(&wet_mix, &wet_mix,
+ &wet_tmp);
+ wet_pix_reduce(&wet_tmp, &wet_old[ix - 1],
+ flow_l[ix]);
+ wet_pix_combine(&wet_mix, &wet_mix,
+ &wet_tmp);
+ wet_pix_reduce(&wet_tmp, &wet_old[ix + 1],
+ flow_r[ix]);
+ wet_pix_combine(&wet_mix, &wet_mix,
+ &wet_tmp);
+
+ wet_pix_from_double(&wet_line[x],
+ &wet_mix);
+
+#if 0
+ if (ix % 3201 == 0)
+ g_print("%f %f %f %f %f %f\n",
+ outflow[ix],
+ flow_t[ix],
+ flow_b[ix],
+ flow_l[ix],
+ flow_r[ix], fluid[ix]);
+#endif
+ }
+ ix++;
+ }
+ ix += 2;
+ }
+
+ g_free(flow_t);
+ g_free(flow_b);
+ g_free(flow_l);
+ g_free(flow_r);
+ g_free(fluid);
+ g_free(outflow);
+ g_free(wet_old);
+}
+
+void wet_dry(WetLayer * layer)
+{
+ int x, y;
+ WetPix *wet_line = layer->buf;
+ int width = layer->width;
+ int height = layer->height;
+ int rs = layer->rowstride;
+ int w;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ w = wet_line[x].w;
+ w -= 1;
+ if (w > 0)
+ wet_line[x].w = w;
+ else
+ wet_line[x].w = 0;
+
+ }
+ wet_line += rs;
+ }
+}
+
+/* Move stuff from the upperlayer to the lower layer. This is filter-level stuff*/
+void wet_adsorb(WetLayer * layer, WetLayer * adsorb)
+{
+ int x, y;
+ WetPix *wet_line = layer->buf;
+ WetPix *ads_line = adsorb->buf;
+ int width = layer->width;
+ int height = layer->height;
+ int rs = layer->rowstride;
+ double ads;
+ WetPixDbl wet_top;
+ WetPixDbl wet_bot;
+
+ for (y = 0; y < height; y++) {
+ for (x = 0; x < width; x++) {
+ /* do adsorption */
+ if (wet_line[x].w == 0)
+ continue;
+ ads = 0.5 / MAX(wet_line[x].w, 1);
+
+ wet_pix_to_double(&wet_top, &wet_line[x]);
+ wet_pix_to_double(&wet_bot, &ads_line[x]);
+ wet_pix_merge(&wet_bot, &wet_top, ads, &wet_bot);
+ wet_pix_from_double(&ads_line[x], &wet_bot);
+ wet_line[x].rd = wet_line[x].rd * (1 - ads);
+ wet_line[x].rw = wet_line[x].rw * (1 - ads);
+ wet_line[x].gd = wet_line[x].gd * (1 - ads);
+ wet_line[x].gw = wet_line[x].gw * (1 - ads);
+ wet_line[x].bd = wet_line[x].bd * (1 - ads);
+ wet_line[x].bw = wet_line[x].bw * (1 - ads);
+ }
+ wet_line += rs;
+ ads_line += rs;
+ }
+}
diff --git a/krita/colorspaces/wet/wetdreams/wetphysics.h b/krita/colorspaces/wet/wetdreams/wetphysics.h
new file mode 100644
index 00000000..25140956
--- /dev/null
+++ b/krita/colorspaces/wet/wetdreams/wetphysics.h
@@ -0,0 +1,9 @@
+void wet_pix_combine(WetPixDbl * dst, WetPixDbl * src1, WetPixDbl * src2);
+
+void wet_pix_dilute(WetPixDbl * dst, WetPix * src, double dilution);
+
+void wet_flow(WetLayer * layer);
+
+void wet_dry(WetLayer * layer);
+
+void wet_adsorb(WetLayer * layer, WetLayer * adsorb);
diff --git a/krita/colorspaces/wet/wetdreams/wetpix.c b/krita/colorspaces/wet/wetdreams/wetpix.c
new file mode 100644
index 00000000..812a038d
--- /dev/null
+++ b/krita/colorspaces/wet/wetdreams/wetpix.c
@@ -0,0 +1,332 @@
+/* Routines for manipulating wet pixels.
+
+ Copyright 1999 Raph Levien <[email protected]>
+
+ Released under GPL.
+
+ A wet pixel is a sequence of eight bytes, arranged as follows:
+
+ Red value when composited over black
+ Green value when composited over black
+ Blue value when composited over black
+ Volume of water
+ Red value when composited over white
+ Green value when composited over white
+ Blue value when composited over white
+ Height of paper surface
+
+*/
+
+#include <gtk/gtk.h>
+#include <string.h>
+#include <math.h>
+#include "wetpix.h"
+
+u32 *wet_render_tab = NULL;
+
+static void wet_init_render_tab(void)
+{
+ int i;
+ double d;
+ int a, b;
+
+ wet_render_tab = g_new(u32, 4096);
+ for (i = 0; i < 4096; i++) {
+ d = i * (1.0 / 512.0);
+ if (i == 0)
+ a = 0;
+ else
+ a = floor(0xff00 / i + 0.5);
+ b = floor(0x8000 * exp(-d) + 0.5);
+#if 0
+ g_print("%d: %x %x\n", i, a, b);
+#endif
+ wet_render_tab[i] = (a << 16) | b;
+ }
+}
+
+void
+wet_composite(byte * rgb, int rgb_rowstride,
+ WetPix * wet, int wet_rowstride,
+ int width, int height)
+{
+ int x, y;
+ byte *rgb_line = rgb;
+ WetPix *wet_line = wet;
+
+ if (wet_render_tab == NULL)
+ wet_init_render_tab();
+
+ for (y = 0; y < height; y++) {
+ byte *rgb_ptr = rgb_line;
+ WetPix *wet_ptr = wet_line;
+ for (x = 0; x < width; x++) {
+ int r, g, b;
+ int d, w;
+ int ab;
+ int wa;
+
+ r = rgb_ptr[0];
+ w = wet_ptr[0].rw >> 4;
+ d = wet_ptr[0].rd >> 4;
+ /*
+ d = d >= 4096 ? 4095 : d;
+ */
+ ab = wet_render_tab[d];
+ wa = (w * (ab >> 16) + 0x80) >> 8;
+ r = wa +
+ (((r - wa) * (ab & 0xffff) + 0x4000) >> 15);
+ rgb_ptr[0] = r;
+
+#if 0
+ if (x == 128 && y == 128) {
+ g_print("w %d d %d r %d\n", w, d, r);
+ }
+#endif
+
+ g = rgb_ptr[1];
+ w = wet_ptr[0].gw >> 4;
+ d = wet_ptr[0].gd >> 4;
+ d = d >= 4096 ? 4095 : d;
+ ab = wet_render_tab[d];
+ wa = (w * (ab >> 16) + 0x80) >> 8;
+ g = wa +
+ (((g - wa) * (ab & 0xffff) + 0x4000) >> 15);
+ rgb_ptr[1] = g;
+
+ b = rgb_ptr[2];
+ w = wet_ptr[0].bw >> 4;
+ d = wet_ptr[0].bd >> 4;
+ d = d >= 4096 ? 4095 : d;
+ ab = wet_render_tab[d];
+ wa = (w * (ab >> 16) + 0x80) >> 8;
+ b = wa +
+ (((b - wa) * (ab & 0xffff) + 0x4000) >> 15);
+ rgb_ptr[2] = b;
+
+ rgb_ptr += 3;
+ wet_ptr++;
+ }
+ rgb_line += rgb_rowstride;
+ wet_line += wet_rowstride;
+ }
+}
+
+void
+wet_render_wetness(byte * rgb, int rgb_rowstride,
+ WetLayer * layer, int x0, int y0, int width, int height)
+{
+ static int wet_phase = 0;
+ int x, y;
+ byte *rgb_line = rgb;
+ WetPix *wet_line = layer->buf + (y0 * layer->rowstride) + x0;
+ int highlight;
+
+ for (y = 0; y < height; y++) {
+ byte *rgb_ptr = rgb_line;
+ WetPix *wet_ptr = wet_line;
+ for (x = 0; x < width; x++) {
+ if (((x + y) & 3) == wet_phase) {
+ highlight = 255 - (wet_ptr[0].w >> 1);
+ if (highlight < 255) {
+ rgb_ptr[0] =
+ 255 -
+ (((255 -
+ rgb_ptr[0]) *
+ highlight) >> 8);
+ rgb_ptr[1] =
+ 255 -
+ (((255 -
+ rgb_ptr[1]) *
+ highlight) >> 8);
+ rgb_ptr[2] =
+ 255 -
+ (((255 -
+ rgb_ptr[2]) *
+ highlight) >> 8);
+ }
+ }
+ rgb_ptr += 3;
+ wet_ptr++;
+ }
+ rgb_line += rgb_rowstride;
+ wet_line += layer->rowstride;
+ }
+ wet_phase += 1;
+ wet_phase &= 3;
+}
+
+void
+wet_composite_layer(byte * rgb, int rgb_rowstride,
+ WetLayer * layer,
+ int x0, int y0, int width, int height)
+{
+ /* todo: sanitycheck bounds */
+ wet_composite(rgb, rgb_rowstride,
+ layer->buf + (y0 * layer->rowstride) + x0,
+ layer->rowstride, width, height);
+}
+
+void
+wet_pack_render(byte * rgb, int rgb_rowstride,
+ WetPack * pack, int x0, int y0, int width, int height)
+{
+ int y;
+ byte *rgb_line = rgb;
+ int i;
+
+ /* clear rgb buffer to white */
+ for (y = 0; y < height; y++) {
+ memset(rgb_line, 255, width * 3);
+ rgb_line += rgb_rowstride;
+ }
+
+ /* black stripe */
+/* rgb_line = rgb;
+ for (y = y0; y < 8 && y < y0 + height; y++)
+ {
+ memset (rgb_line, 0, width * 3);
+ rgb_line += rgb_rowstride;
+ }
+*/
+
+ for (i = 0; i < pack->n_layers; i++)
+ wet_composite_layer(rgb, rgb_rowstride,
+ pack->layers[i],
+ x0, y0, width, height);
+
+ wet_render_wetness(rgb, rgb_rowstride,
+ pack->layers[pack->n_layers - 1],
+ x0, y0, width, height);
+}
+
+WetLayer *wet_layer_new(int width, int height)
+{
+ WetLayer *layer;
+
+ layer = g_new(WetLayer, 1);
+
+ layer->buf = g_new(WetPix, width * height);
+ layer->width = width;
+ layer->height = height;
+ layer->rowstride = width;
+
+ return layer;
+}
+
+void wet_layer_clear(WetLayer * layer)
+{
+ int x, y;
+ WetPix *wet_line = layer->buf;
+ int width = layer->width;
+
+ for (y = 0; y < layer->height; y++) {
+ for (x = 0; x < width; x++) {
+ /* transparent, dry, smooth */
+ wet_line[x].rd = 0;
+ wet_line[x].rw = 0;
+ wet_line[x].gd = 0;
+ wet_line[x].gw = 0;
+ wet_line[x].bd = 0;
+ wet_line[x].bw = 0;
+ wet_line[x].w = 0;
+ wet_line[x].h = 128;
+ }
+ wet_line += layer->rowstride;
+ }
+}
+
+WetPack *wet_pack_new(int width, int height)
+{
+ WetPack *pack;
+
+ pack = g_new(WetPack, 1);
+
+ pack->n_layers = 2;
+ pack->layers = g_new(WetLayer *, pack->n_layers);
+ pack->layers[0] = wet_layer_new(width, height);
+ wet_layer_clear(pack->layers[0]);
+ pack->layers[1] = wet_layer_new(width, height);
+ wet_layer_clear(pack->layers[1]);
+
+ return pack;
+}
+
+void wet_pix_to_double(WetPixDbl * dst, WetPix * src)
+{
+ dst->rd = (1.0 / 8192.0) * src->rd;
+ dst->rw = (1.0 / 8192.0) * src->rw;
+ dst->gd = (1.0 / 8192.0) * src->gd;
+ dst->gw = (1.0 / 8192.0) * src->gw;
+ dst->bd = (1.0 / 8192.0) * src->bd;
+ dst->bw = (1.0 / 8192.0) * src->bw;
+ dst->w = (1.0 / 8192.0) * src->w;
+ dst->h = (1.0 / 8192.0) * src->h;
+}
+
+void wet_pix_from_double(WetPix * dst, WetPixDbl * src)
+{
+ int v;
+
+ v = floor(8192.0 * src->rd + 0.5);
+ if (v < 0)
+ v = 0;
+ if (v > 65535)
+ v = 65535;
+ dst->rd = v;
+
+ g_print("src->rd = %f, dst->rd = %d\n", src->rd, dst->rd);
+
+ v = floor(8192.0 * src->rw + 0.5);
+ if (v < 0)
+ v = 0;
+ if (v > 65535)
+ v = 65535;
+ dst->rw = v;
+
+ v = floor(8192.0 * src->gd + 0.5);
+ if (v < 0)
+ v = 0;
+ if (v > 65535)
+ v = 65535;
+ dst->gd = v;
+
+ v = floor(8192.0 * src->gw + 0.5);
+ if (v < 0)
+ v = 0;
+ if (v > 65535)
+ v = 65535;
+ dst->gw = v;
+
+ v = floor(8192.0 * src->bd + 0.5);
+ if (v < 0)
+ v = 0;
+ if (v > 65535)
+ v = 65535;
+ dst->bd = v;
+
+ v = floor(8192.0 * src->bw + 0.5);
+ if (v < 0)
+ v = 0;
+ if (v > 65535)
+ v = 65535;
+ dst->bw = v;
+
+ v = floor(8192.0 * src->w + 0.5);
+ if (v < 0)
+ v = 0;
+ if (v > 511)
+ v = 511;
+ dst->w = v;
+#if 0
+ g_print("src->w = %f, dst->w = %d\n", src->w, dst->w);
+#endif
+
+ v = floor(8192.0 * src->h + 0.5);
+ if (v < 0)
+ v = 0;
+ if (v > 511)
+ v = 511;
+ dst->h = v;
+
+}
diff --git a/krita/colorspaces/wet/wetdreams/wetpix.h b/krita/colorspaces/wet/wetdreams/wetpix.h
new file mode 100644
index 00000000..3dc7913f
--- /dev/null
+++ b/krita/colorspaces/wet/wetdreams/wetpix.h
@@ -0,0 +1,87 @@
+/* Routines for manipulating wet pixels.
+
+ Copyright 1999 Raph Levien <[email protected]>
+
+ Released under GPL.
+
+ A wet pixel is an eight word sequence, representing partially
+ transparent wet paint on a paper surface.
+
+*/
+
+typedef unsigned char byte;
+typedef unsigned short u16;
+typedef unsigned int u32;
+
+typedef struct _WetPix WetPix;
+typedef struct _WetLayer WetLayer;
+typedef struct _WetPack WetPack;
+
+typedef struct _WetPixDbl WetPixDbl;
+
+/* White is made up of myth-red, myth-green, and myth-blue. Myth-red
+ looks red when viewed reflectively, but cyan when viewed
+ transmissively (thus, it vaguely resembles a dichroic
+ filter). Myth-red over black is red, and myth-red over white is
+ white.
+
+ Total red channel concentration is myth-red concentration plus
+ cyan concentration.
+
+*/
+
+struct _WetPix {
+ u16 rd; /* Total red channel concentration */
+ u16 rw; /* Myth-red concentration */
+ u16 gd; /* Total green channel concentration */
+ u16 gw; /* Myth-green concentration */
+ u16 bd; /* Total blue channel concentration */
+ u16 bw; /* Myth-blue concentration */
+ u16 w; /* Water volume */
+ u16 h; /* Height of paper surface */
+};
+
+struct _WetLayer {
+ WetPix *buf;
+ int width;
+ int height;
+ int rowstride;
+};
+
+struct _WetPack {
+ int n_layers;
+ WetLayer **layers;
+};
+
+struct _WetPixDbl {
+ double rd; /* Total red channel concentration */
+ double rw; /* Myth-red concentration */
+ double gd; /* Total green channel concentration */
+ double gw; /* Myth-green concentration */
+ double bd; /* Total blue channel concentration */
+ double bw; /* Myth-blue concentration */
+ double w; /* Water volume */
+ double h; /* Height of paper surface */
+};
+
+void wet_composite(byte * rgb, int rgb_rowstride,
+ WetPix * wet, int wet_rowstride,
+ int width, int height);
+
+void wet_composite_layer(byte * rgb, int rgb_rowstride,
+ WetLayer * layer,
+ int x0, int y0, int width, int height);
+
+void wet_pack_render(byte * rgb, int rgb_rowstride,
+ WetPack * pack,
+ int x0, int y0, int width, int height);
+
+WetLayer *wet_layer_new(int width, int height);
+
+void wet_layer_clear(WetLayer * layer);
+
+WetPack *wet_pack_new(int width, int height);
+
+void wet_pix_to_double(WetPixDbl * dst, WetPix * src);
+
+void wet_pix_from_double(WetPix * dst, WetPixDbl * src);
diff --git a/krita/colorspaces/wet/wetdreams/wettexture.c b/krita/colorspaces/wet/wetdreams/wettexture.c
new file mode 100644
index 00000000..620ad8b5
--- /dev/null
+++ b/krita/colorspaces/wet/wetdreams/wettexture.c
@@ -0,0 +1,84 @@
+/* synthesize a surface texture */
+
+#include <stdlib.h>
+#include <math.h>
+#include "wetpix.h"
+
+void
+wet_layer_maketexture(WetLayer * layer,
+ double height, double blurh, double blurv)
+{
+ int x, y;
+ int width = layer->width;
+ int lheight = layer->height;
+ int rowstride = layer->rowstride;
+ WetPix *wet_line = layer->buf;
+ double hscale = 128 * height / RAND_MAX;
+ int lh;
+ int ibh, ibv;
+
+ ibh = floor(256 * blurh + 0.5);
+#ifdef VERBOSE
+ g_print("ibh = %d\n", ibh);
+#endif
+ ibv = floor(256 * blurv + 0.5);
+
+ for (y = 0; y < lheight; y++) {
+ for (x = 0; x < width; x++) {
+ wet_line[x].h = floor(128 + hscale * rand());
+ }
+ /* g_print ("%d\n", wet_line[0].h); */
+ wet_line += rowstride;
+ }
+
+ wet_line = layer->buf;
+ for (y = 0; y < lheight; y++) {
+ lh = wet_line[0].h;
+ for (x = 1; x < width; x++) {
+ wet_line[x].h +=
+ ((lh - wet_line[x].h) * ibh + 128) >> 8;
+ lh = wet_line[x].h;
+ }
+ wet_line += rowstride;
+ }
+
+#if 0
+ for (x = 0; x < width; x++) {
+ wet_line = layer->buf + x;
+ lh = wet_line[0].h;
+ for (y = 1; y < lheight; y++) {
+ wet_line += rowstride;
+ wet_line[0].h +=
+ ((lh - wet_line[0].h) * ibv + 128) >> 8;
+ lh = wet_line[0].h;
+ }
+ }
+#endif
+}
+
+void wet_layer_clone_texture(WetLayer * dst, WetLayer * src)
+{
+ int x, y;
+ int width = src->width;
+ WetPix *dst_line = dst->buf;
+ WetPix *src_line = src->buf;
+
+ for (y = 0; y < src->height; y++) {
+ for (x = 0; x < width; x++) {
+ dst_line[x].h = src_line[x].h;
+ }
+ dst_line += dst->rowstride;
+ src_line += src->rowstride;
+ }
+}
+
+void
+wet_pack_maketexture(WetPack * pack,
+ double height, double blurh, double blurv)
+{
+ int i;
+
+ wet_layer_maketexture(pack->layers[0], height, blurh, blurv);
+ for (i = 1; i < pack->n_layers; i++)
+ wet_layer_clone_texture(pack->layers[i], pack->layers[0]);
+}
diff --git a/krita/colorspaces/wet/wetdreams/wettexture.h b/krita/colorspaces/wet/wetdreams/wettexture.h
new file mode 100644
index 00000000..c3cbc0d2
--- /dev/null
+++ b/krita/colorspaces/wet/wetdreams/wettexture.h
@@ -0,0 +1,9 @@
+/* synthesize a surface texture */
+
+void wet_layer_maketexture(WetLayer * layer,
+ double height, double blurh, double blurv);
+
+void wet_layer_clone_texture(WetLayer * dst, WetLayer * src);
+
+void wet_pack_maketexture(WetPack * pack,
+ double height, double blurh, double blurv);
diff --git a/krita/colorspaces/wet/wetphysicsfilter.cc b/krita/colorspaces/wet/wetphysicsfilter.cc
new file mode 100644
index 00000000..195a17be
--- /dev/null
+++ b/krita/colorspaces/wet/wetphysicsfilter.cc
@@ -0,0 +1,424 @@
+/*
+ * This file is part of the KDE project
+ *
+ * Copyright (c) 2004 Cyrille Berger <[email protected]>
+ * 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 <stdlib.h>
+#include <vector>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include <kis_iterators_pixel.h>
+#include <kis_filter_registry.h>
+#include <kis_debug_areas.h>
+#include <kis_types.h>
+#include <kis_paint_device.h>
+#include <kis_debug_areas.h>
+#include "wetphysicsfilter.h"
+
+/*
+ * [11:14] <boud> CyrilleB: I think I know why watercolor drying creates that funny pattern (you can see it if you have a very wet canvas with lots of paint and leave it drying for a while): our dry filter must have an off-by-one error to the right and bottom, which is also why the buggy drying didn't remove all of previously applied paint but left a fringe.
+ * [11:14] <pippin> does the drying behave kind of like an error diffusion?
+ * [11:14] <pippin> (it sounds like error diffusion artifacts,.)
+ * [11:15] <boud> pippin: not sure what error diffusion is...
+ * [11:15] <pippin> used for digital halftoning
+ * [11:15] <pippin> take a greyscale image,.. you want to end up with binary (could be less, but let's use 1bit result)
+ * [11:15] <CyrilleB> boud: the funny pattern is also in wetdreams when you disable wetness visualisation
+ * [11:15] <boud> CyrilleB: I don't mean the checkerboard pattern
+ * [11:16] <pippin> then for each pixel you calculate the difference between the current value and the desired value (0 or 255)
+ * [11:16] <CyrilleB> boud: which one then ?
+ * [11:16] <pippin> the error is distributed to the neighbour pixels (to the right, down and down to the left in pixels which have not yet been processed
+ * [11:16] <pippin> )
+ * [11:16] <boud> CyrilleB: it's only apparent when you let something dry for some time, it looks like meandering snakes (like the old game "snake")
+ * [11:16] <CyrilleB> pippin: somehow yes
+ * [11:16] <boud> pippin: that is possible
+ * [11:17] <pippin> boud: this leads to "bleeding" of data to the right and down,..
+ * [11:17] <boud> pippin: but on the other hand, when the filter worked on the old tiles (empty ones) it also left a fringe of color.
+ * [11:17] <pippin> having the "error" spread in different directions on each iteration might fix something like this,.
+ * [11:18] <boud> Which leads me to think it's an off-by one.
+ * [11:25] <boud> No, it isn't off by one. Then pippin must be right.
+ * [11:26] <pippin> if I am, this is a fun debug session, not even having the code or the visual results available,. just hanging around on irc :)
+ * [11:27] <boud> Well, I don't have time to investigate right now, but it sounds very plausible.
+ * [11:27] <CyrilleB> pippin: :)
+ * [11:28] <boud> of course, the code _is_ available :-)
+ * [11:28] <pippin> if there is some form of diffusion matrix that is directional around the current pixel,. having that mask rotate depending on the modulus of the current iteration # should cancel such an effect out
+ */
+WetPhysicsFilter::WetPhysicsFilter()
+ : KisFilter(id(), "artistic", i18n("Dry the Paint"))
+{
+ m_adsorbCount = 0;
+}
+
+void WetPhysicsFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* /*config*/, const QRect& rect)
+{
+ kdDebug() << "Physics processing " << src->name() << m_adsorbCount << endl;
+ // XXX: It would be nice be able to interleave this, instead of
+ // having the same loop over our pixels three times.
+ flow(src, dst, rect);
+ if (m_adsorbCount++ == 2) {
+// XXX I think we could combine dry and adsorb, yes
+ adsorb(src, dst, rect);
+ dry(src, dst, rect);
+ m_adsorbCount = 0;
+ }
+ setProgressDone(); // Must be called even if you don't really support progression
+}
+
+
+void WetPhysicsFilter::flow(KisPaintDeviceSP src, KisPaintDeviceSP /*dst*/, const QRect & r)
+{
+ /* XXX: Is this like a convolution operation? BSAR */
+ int width = r.width();
+ int height = r.height();
+
+ kdDebug() << "Flowing: " << r << endl;
+
+ /* width of a line in a layer in pixel units, not in bytes -- used to move to the next
+ line in the fluid masks below */
+ int rs = width; // rowstride
+
+ double * flow_t = new double[width * height];
+ Q_CHECK_PTR(flow_t);
+
+ double * flow_b = new double[width * height];
+ Q_CHECK_PTR(flow_b);
+
+ double * flow_l = new double[width * height];
+ Q_CHECK_PTR(flow_l);
+
+ double * flow_r = new double[width * height];
+ Q_CHECK_PTR(flow_r);
+
+ double * fluid = new double[width * height];
+ Q_CHECK_PTR(fluid);
+
+ double * outflow = new double[width * height];
+ Q_CHECK_PTR(outflow);
+
+ // Height of the paper surface. Do we also increase height because of paint deposits?
+ int my_height;
+
+ // Flow to the top, bottom, left, right of the currentpixel
+ double ft, fb, fl, fr;
+
+ // Temporary pixel constructs
+ WetPixDbl wet_mix, wet_tmp;
+
+ // XXX If the flow touches areas that have not been initialized with a height field yet,
+ // create a heigth field.
+
+ // We need three iterators, because we're working on a five-point convolution kernel (no corner pixels are being used)
+
+ // First iteration: compute fluid deposits around the paper.
+ Q_INT32 dx, dy;
+ dx = r.x();
+ dy = r.y();
+
+ int ix = width + 1; // keeps track where we are in the one-dimensional arrays
+
+ for (Q_INT32 y2 = 1; y2 < height - 1; ++y2) {
+ KisHLineIteratorPixel srcIt = src->createHLineIterator(dx, dy + y2, width, false);
+ KisHLineIteratorPixel upIt = src->createHLineIterator(dx + 1, dy + y2 - 1, width - 2, false);
+ KisHLineIteratorPixel downIt = src->createHLineIterator(dx + 1, dy + y2 + 1, width - 2, false);
+
+ // .paint is the first field in our wetpack, so this is ok (even though not nice)
+ WetPix left = *(reinterpret_cast<WetPix*>(srcIt.rawData()));
+ ++srcIt;
+ WetPix current = *(reinterpret_cast<WetPix*>(srcIt.rawData()));
+ ++srcIt;
+ WetPix right = *(reinterpret_cast<WetPix*>(srcIt.rawData()));
+ WetPix up, down;
+
+ while (!srcIt.isDone()) {
+ up = *(reinterpret_cast<WetPix*>(upIt.rawData()));
+ down = *(reinterpret_cast<WetPix*>(downIt.rawData()));
+
+ if (current.w > 0) {
+ my_height = current.h + current.w;
+ ft = (up.h + up.w) - my_height;
+ fb = (down.h + down.w) - my_height;
+ fl = (left.h + left.w) - my_height;
+ fr = (right.h + right.w) - my_height;
+
+ fluid[ix] = 0.4 * sqrt(current.w * 1.0 / 255.0);
+
+ /* smooth out the flow a bit */
+ flow_t[ix] = CLAMP(0.1 * (10 + ft * 0.75 - fb * 0.25), 0, 1);
+
+ flow_b[ix] = CLAMP(0.1 * (10 + fb * 0.75 - ft * 0.25), 0, 1);
+
+ flow_l[ix] = CLAMP(0.1 * (10 + fl * 0.75 - fr * 0.25), 0, 1);
+
+ flow_r[ix] = CLAMP(0.1 * (10 + fr * 0.75 - fl * 0.25), 0, 1);
+
+ outflow[ix] = 0;
+ }
+
+ ++srcIt;
+ ++upIt;
+ ++downIt;
+ ix++;
+ left = current;
+ current = right;
+ right = *(reinterpret_cast<WetPix*>(srcIt.rawData()));
+ }
+ ix+=2; // one for the last pixel on the line, and one for the first of the next line
+ }
+ // Second iteration: Reduce flow in dry areas
+ ix = width + 1;
+
+ for (Q_INT32 y2 = 1; y2 < height - 1; ++y2) {
+ KisHLineIteratorPixel srcIt = src->createHLineIterator(dx + 1, dy + y2, width - 2, false);
+ while (!srcIt.isDone()) {
+ if ((reinterpret_cast<WetPix*>(srcIt.rawData()))->w > 0) {
+ /* reduce flow in dry areas */
+ flow_t[ix] *= fluid[ix] * fluid[ix - rs];
+ outflow[ix - rs] += flow_t[ix];
+ flow_b[ix] *= fluid[ix] * fluid[ix + rs];
+ outflow[ix + rs] += flow_b[ix];
+ flow_l[ix] *= fluid[ix] * fluid[ix - 1];
+ outflow[ix - 1] += flow_l[ix];
+ flow_r[ix] *= fluid[ix] * fluid[ix + 1];
+ outflow[ix + 1] += flow_r[ix];
+ }
+ ++srcIt;
+ ix++;
+ }
+ ix += 2;
+ }
+
+ // Third iteration: Combine the paint from the flow areas.
+ ix = width + 1;
+ for (Q_INT32 y2 = 1; y2 < height - 1; ++y2) {
+ KisHLineIteratorPixel srcIt = src->createHLineIterator(dx, dy + y2, width, false);
+ KisHLineIteratorPixel upIt = src->createHLineIterator(dx + 1, dy + y2 - 1, width - 2, false);
+ KisHLineIteratorPixel downIt = src->createHLineIterator(dx + 1, dy + y2 + 1, width - 2, false);
+
+ KisHLineIteratorPixel dstIt = src->createHLineIterator(dx + 1, dy + y2, width - 2, true);
+
+ WetPix left = *(reinterpret_cast<const WetPix*>(srcIt.oldRawData()));
+ ++srcIt;
+ WetPix current = *(reinterpret_cast<const WetPix*>(srcIt.oldRawData()));
+ ++srcIt;
+ WetPix right = *(reinterpret_cast<const WetPix*>(srcIt.oldRawData()));
+ WetPix up, down;
+
+ while (!srcIt.isDone()) {
+ up = *(reinterpret_cast<const WetPix*>(upIt.oldRawData()));
+ down = *(reinterpret_cast<const WetPix*>(downIt.oldRawData()));
+
+ if ((reinterpret_cast<WetPix*>(srcIt.rawData()))->w > 0) {
+ reducePixel(&wet_mix, &current, 1 - outflow[ix]);
+ reducePixel(&wet_tmp, &up, flow_t[ix]);
+ combinePixels(&wet_mix, &wet_mix, &wet_tmp);
+ reducePixel(&wet_tmp, &down, flow_b[ix]);
+ combinePixels(&wet_mix, &wet_mix, &wet_tmp);
+ reducePixel(&wet_tmp, &left, flow_l[ix]);
+ combinePixels(&wet_mix, &wet_mix, &wet_tmp);
+ reducePixel(&wet_tmp, &right, flow_r[ix]);
+ combinePixels(&wet_mix, &wet_mix, &wet_tmp);
+ WetPix* target = reinterpret_cast<WetPix*>(dstIt.rawData());
+ wetPixFromDouble(target, &wet_mix);
+ }
+ ++srcIt;
+ ++dstIt;
+ ++upIt;
+ ++downIt;
+ ix++;
+
+ left = current;
+ current = right;
+ right = *(reinterpret_cast<const WetPix*>(srcIt.oldRawData()));
+ }
+ ix += 2;
+ }
+
+ delete[] flow_t;
+ delete[] flow_b;
+ delete[] flow_l;
+ delete[] flow_r;
+ delete[] fluid;
+ delete[] outflow;
+}
+
+void WetPhysicsFilter::dry(KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect & r)
+{
+ kdDebug () << "Drying " << r << endl;
+ for (Q_INT32 y = 0; y < r.height(); y++) {
+ KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), r.y() + y, r.width(), false);
+ KisHLineIteratorPixel dstIt = dst->createHLineIterator(r.x(), r.y() + y, r.width(), true);
+
+ Q_UINT16 w;
+ while (!srcIt.isDone()) {
+ // Two wet pixels in one KisWetColorSpace pixels.
+
+ WetPack pack = *(reinterpret_cast<WetPack*>(srcIt.rawData()));
+ WetPix* p = &(pack.paint);
+
+ w = p->w; // no -1 here because we work on unsigned ints!
+
+ if (w > 0)
+ p->w = w - 1;
+ else
+ p->w = 0;
+
+ *(reinterpret_cast<WetPack*>(dstIt.rawData())) = pack;
+
+ ++dstIt;
+ ++srcIt;
+ }
+ }
+}
+
+void WetPhysicsFilter::adsorb(KisPaintDeviceSP src, KisPaintDeviceSP /*dst*/, const QRect & r)
+{
+ kdDebug() << "Adsorbing " << r << endl;
+ for (Q_INT32 y = 0; y < r.height(); y++) {
+ KisHLineIteratorPixel srcIt = src->createHLineIterator(r.x(), r.y() + y, r.width(), true);
+
+ double ads;
+
+ WetPixDbl wet_top;
+ WetPixDbl wet_bot;
+
+ WetPack * pack;
+ Q_UINT16 w;
+
+ while (!srcIt.isDone()) {
+ // Two wet pixels in one KisWetColorSpace pixels.
+ pack = reinterpret_cast<WetPack*>(srcIt.rawData());
+ WetPix* paint = &pack->paint;
+ WetPix* adsorb = &pack->adsorb;
+
+ /* do adsorption */
+ w = paint->w;
+
+ if (w == 0) {
+ ++srcIt;
+ }
+ else {
+
+ ads = 0.5 / QMAX(w, 1);
+
+ wetPixToDouble(&wet_top, paint);
+ wetPixToDouble(&wet_bot, adsorb);
+
+ mergePixel(&wet_bot, &wet_top, ads, &wet_bot);
+ wetPixFromDouble(adsorb, &wet_bot);
+
+ paint->rd = (Q_UINT16) (paint->rd*(1 - ads));
+ paint->rw = (Q_UINT16) (paint->rw*(1 - ads));
+ paint->gd = (Q_UINT16) (paint->gd*(1 - ads));
+ paint->gw = (Q_UINT16) (paint->gw*(1 - ads));
+ paint->bd = (Q_UINT16) (paint->bd*(1 - ads));
+ paint->bw = (Q_UINT16) (paint->bw*(1 - ads));
+
+ ++srcIt;
+ }
+ }
+ }
+}
+
+void WetPhysicsFilter::combinePixels (WetPixDbl *dst, WetPixDbl *src1, WetPixDbl *src2)
+{
+ dst->rd = src1->rd + src2->rd;
+ dst->rw = src1->rw + src2->rw;
+ dst->gd = src1->gd + src2->gd;
+ dst->gw = src1->gw + src2->gw;
+ dst->bd = src1->bd + src2->bd;
+ dst->bw = src1->bw + src2->bw;
+ dst->w = src1->w + src2->w;
+}
+
+void WetPhysicsFilter::dilutePixel (WetPixDbl *dst, WetPix *src, double dilution)
+{
+ double scale = dilution * (1.0 / 8192.0);
+
+ dst->rd = src->rd * scale;
+ dst->rw = src->rw * scale;
+ dst->gd = src->gd * scale;
+ dst->gw = src->gw * scale;
+ dst->bd = src->bd * scale;
+ dst->bw = src->bw * scale;
+ dst->w = src->w * (1.0 / 8192.0);
+ dst->h = src->h * (1.0 / 8192.0);
+}
+
+
+void WetPhysicsFilter::reducePixel (WetPixDbl *dst, WetPix *src, double dilution)
+{
+ dilutePixel(dst, src, dilution);
+ dst->w *= dilution;
+}
+
+void WetPhysicsFilter::mergePixel (WetPixDbl *dst, WetPixDbl *src1, double dilution1,
+ WetPixDbl *src2)
+{
+ double d1, w1, d2, w2;
+ double ed1, ed2;
+
+ if (src1->rd < 1e-4) {
+ dst->rd = src2->rd;
+ dst->rw = src2->rw;
+ } else if (src2->rd < 1e-4) {
+ dst->rd = src1->rd * dilution1;
+ dst->rw = src1->rw * dilution1;
+ } else {
+ d1 = src1->rd;
+ w1 = src1->rw;
+ d2 = src2->rd;
+ w2 = src2->rw;
+ dst->rd = d1 * dilution1 + d2;
+ ed1 = exp(-d1 * dilution1);
+ ed2 = exp(-d2);
+ dst->rw = dst->rd * ((1 - ed1) * w1 / d1 + ed1 * (1 - ed2) * w2 / d2) / (1 - ed1 * ed2);
+ }
+
+ if (src1->gd < 1e-4) {
+ dst->gd = src2->gd;
+ dst->gw = src2->gw;
+ } else if (src2->gd < 1e-4) {
+ dst->gd = src1->gd * dilution1;
+ dst->gw = src1->gw * dilution1;
+ } else {
+ d1 = src1->gd;
+ w1 = src1->gw;
+ d2 = src2->gd;
+ w2 = src2->gw;
+ dst->gd = d1 * dilution1 + d2;
+ ed1 = exp(-d1 * dilution1);
+ ed2 = exp(-d2);
+ dst->gw = dst->gd * ((1 - ed1) * w1 / d1 + ed1 * (1 - ed2) * w2 / d2) / (1 - ed1 * ed2);
+ }
+
+ if (src1->bd < 1e-4) {
+ dst->bd = src2->bd;
+ dst->bw = src2->bw;
+ } else if (src2->bd < 1e-4) {
+ dst->bd = src1->bd * dilution1;
+ dst->bw = src1->bw * dilution1;
+ } else {
+ d1 = src1->bd;
+ w1 = src1->bw;
+ d2 = src2->bd;
+ w2 = src2->bw;
+ dst->bd = d1 * dilution1 + d2;
+ ed1 = exp(-d1 * dilution1);
+ ed2 = exp(-d2);
+ dst->bw = dst->bd * ((1 - ed1) * w1 / d1 + ed1 * (1 - ed2) * w2 / d2) / (1 - ed1 * ed2);
+ }
+}
diff --git a/krita/colorspaces/wet/wetphysicsfilter.h b/krita/colorspaces/wet/wetphysicsfilter.h
new file mode 100644
index 00000000..a02f8402
--- /dev/null
+++ b/krita/colorspaces/wet/wetphysicsfilter.h
@@ -0,0 +1,87 @@
+/*
+ * This file is part of Krita
+ *
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * 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 WET_PHYSICS_FILTER_H
+#define WET_PHYSICS_FILTER_H
+
+#include <klocale.h>
+
+#include <kis_filter.h>
+#include <kis_types.h>
+
+#include "kis_wet_colorspace.h"
+
+class KisID;
+class QRect;
+
+
+/**
+ * The wet physics filter must be run regularly from a timer
+ * or preferably from a thread. Every time the filter is processed
+ * the paint flows; every third time, the paint is adsorbed unto the
+ * lower pixel and dried.
+ *
+ * Note: this might also be implemented as three separate filters.
+ * That might even be better.
+ */
+class WetPhysicsFilter: public KisFilter
+{
+public:
+ WetPhysicsFilter();
+public:
+ virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration*, const QRect& r);
+
+ static inline KisID id() { return KisID("wetphysics", i18n("Watercolor Physics Simulation Filter")); };
+
+ virtual bool supportsPainting() { return false; }
+ virtual bool supportsPreview() { return false; }
+ virtual ColorSpaceIndependence colorSpaceIndependence() { return FULLY_INDEPENDENT; };
+ virtual bool workWith(KisColorSpace* cs) { return (cs->id() == KisID("WET")); };
+
+private:
+
+ void flow(KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect & r);
+ void dry(KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect & r);
+
+ // Move stuff from the upperlayer to the lower layer. This is filter-level stuff.
+ void adsorb(KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect & r);
+
+ // NOTE: this does not set the height fields
+ void combinePixels (WetPixDbl *dst, WetPixDbl *src1, WetPixDbl *src2);
+ void dilutePixel (WetPixDbl *dst, WetPix *src, double dilution);
+ void reducePixel (WetPixDbl *dst, WetPix *src, double dilution);
+
+ /*
+ * Allows visualization of adsorption by rotating the hue 120 degrees
+ * layer-merge combining. src1 is the top layer
+ *
+ * This does not set the dst h or w fields.
+ */
+ void mergePixel (WetPixDbl *dst, WetPixDbl *src1, double dilution1, WetPixDbl *src2);
+
+
+private:
+
+ Q_INT32 m_adsorbCount;
+
+
+};
+
+#endif
diff --git a/krita/colorspaces/wet/wetplugin.rc b/krita/colorspaces/wet/wetplugin.rc
new file mode 100644
index 00000000..39cb6f81
--- /dev/null
+++ b/krita/colorspaces/wet/wetplugin.rc
@@ -0,0 +1,8 @@
+<!DOCTYPE kpartgui SYSTEM "kpartgui.dtd">
+<kpartgui library="kritawetplugin" version="1">
+<MenuBar>
+<Menu name="View"><text>&amp;View</text>
+ <Action name="wetnessvisualisation"/>
+</Menu>
+</MenuBar>
+</kpartgui>
diff --git a/krita/colorspaces/wetsticky/Makefile.am b/krita/colorspaces/wetsticky/Makefile.am
new file mode 100644
index 00000000..70eeb06d
--- /dev/null
+++ b/krita/colorspaces/wetsticky/Makefile.am
@@ -0,0 +1,25 @@
+kde_services_DATA = kritawsplugin.desktop
+INCLUDES = -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../core \
+ -I$(srcdir)/../../core/color_strategy \
+ -I$(srcdir)/../../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../../color_strategy/ \
+ -I$(srcdir)/../../ui \
+ $(KOFFICE_INCLUDES) \
+ -I$(interfacedir) \
+ $(KOPAINTER_INCLUDES) \
+ $(all_includes)
+
+kde_module_LTLIBRARIES = kritawsplugin.la
+
+kritawsplugin_la_SOURCES = wet_sticky_plugin.cc kis_wet_sticky_colorspace.cc kis_ws_engine_filter.cc
+noinst_HEADERS = wet_sticky_plugin.h kis_wet_sticky_colorspace.h kis_ws_engine_filter.h
+
+kritawsplugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kritawsplugin_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+kritawsplugin_la_METASOURCES = AUTO
+
+SUBDIRS=brushop
+
+
diff --git a/krita/colorspaces/wetsticky/README b/krita/colorspaces/wetsticky/README
new file mode 100644
index 00000000..79a105d4
--- /dev/null
+++ b/krita/colorspaces/wetsticky/README
@@ -0,0 +1,42 @@
+Wet & Sticky
+
+The Krita Wet & Sticky module is derived from the seminal dissertation
+"Wet & Stick: A Novel Model for Computer-Based Painting" by Malcom Tunde
+Cockshott, and the implementation of that model by Tunde Cockshott,
+David England and Kevin Waite. The complete source code to the first
+implementation is included in the module_ws/ws and is released under
+the terms of the GPL.
+
+The W&S model is implemented in the following components:
+
+* A color strategy
+* A paint op
+* A filter
+
+The color strategy implements the canvas; the paint op implements the
+application of paint and the filter implements the paint simulation
+engine.
+
+This system adds the following interesting capabilities to Krita:
+
+* Extending the tool options dialog with a widget describing the
+ paint op.
+
+* Extending the paint op class with properties beyond opacity and
+ color to a more generic structure with can contain the many different
+ properties needed by more complex color models to calculate bitBlt's.
+
+ All the ordinary paint ops still work, but they act as if they are
+ applying dry, thin paint, conforming to Cockshott's analysis of the
+ Shoup model (which Krita implemented in the first instance) as a subset
+ of the W&S model.
+
+* Adding continuously running filters (either in separate threads or
+ called by a timer) to a particular paint device.
+
+* Adding a new way to mix colour; the older colour selection widgets
+ still work, but only give completely dry, infinitely thin paint.
+
+* Creating a layer with a fill of 'substrate' cells -- i.e, filling not just
+ with colour, but also with certain calculated amounts of height,
+ gravity and absorbency.
diff --git a/krita/colorspaces/wetsticky/TODO b/krita/colorspaces/wetsticky/TODO
new file mode 100644
index 00000000..513df2ff
--- /dev/null
+++ b/krita/colorspaces/wetsticky/TODO
@@ -0,0 +1,7 @@
+* Add paintopbox to toolbox
+* Make all paint tools use the paintop from the paintop box
+* Add paintop properties palette
+* Add continuously running filters
+* Add filler objects that can fill a given area computationally
+* Add extensible properties for paint devices (to control things like drying)
+* Add default fill hook dependent on colorspace
diff --git a/krita/colorspaces/wetsticky/brushop/Makefile.am b/krita/colorspaces/wetsticky/brushop/Makefile.am
new file mode 100644
index 00000000..48edd999
--- /dev/null
+++ b/krita/colorspaces/wetsticky/brushop/Makefile.am
@@ -0,0 +1,28 @@
+kde_services_DATA = kritawsbrushpaintop.desktop
+
+kritaimagesdir = $(prefix)/share/apps/krita/images
+kritaimages_DATA = wetpaintbrush.png
+
+# all_includes must remain last!
+INCLUDES = -I$(srcdir)/../../../sdk \
+ -I$(srcdir)/../../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../../color_strategy/ \
+ -I$(srcdir)/../../../core/ \
+ -I$(srcdir)/../../../ui \
+ $(KOFFICE_INCLUDES) $(KOPAINTER_INCLUDES) $(all_includes)
+
+
+kritawsbrushpaintop_la_SOURCES = \
+ wsbrushpaintop_plugin.cc \
+ kis_wsbrushop.cc
+
+noinst_HEADERS= \
+ wsbrushpaintop_plugin.h \
+ kis_wsbrushop.h
+
+kde_module_LTLIBRARIES = kritawsbrushpaintop.la
+
+kritawsbrushpaintop_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+kritawsbrushpaintop_la_LIBADD = ../../..//libkritacommon.la $(LIB_KOPAINTER) $(LIB_KOFFICECORE)
+
+kritawsbrushpaintop_la_METASOURCES = AUTO
diff --git a/krita/colorspaces/wetsticky/brushop/README b/krita/colorspaces/wetsticky/brushop/README
new file mode 100644
index 00000000..81156a89
--- /dev/null
+++ b/krita/colorspaces/wetsticky/brushop/README
@@ -0,0 +1,2 @@
+Template for plugin paintops. Paint tools use the paintop to determine how
+to deposit their paint on the canvas, exactly.
diff --git a/krita/colorspaces/wetsticky/brushop/kis_wsbrushop.cc b/krita/colorspaces/wetsticky/brushop/kis_wsbrushop.cc
new file mode 100644
index 00000000..50b8b4ca
--- /dev/null
+++ b/krita/colorspaces/wetsticky/brushop/kis_wsbrushop.cc
@@ -0,0 +1,117 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * 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 <qrect.h>
+
+#include <kdebug.h>
+
+#include "kis_brush.h"
+#include "kis_global.h"
+#include "kis_paint_device.h"
+#include "kis_painter.h"
+#include "kis_types.h"
+#include "kis_paintop.h"
+
+#include "kis_wsbrushop.h"
+
+KisPaintOp * KisWSBrushOpFactory::createOp(const KisPaintOpSettings */*settings*/, KisPainter * painter)
+{
+ KisPaintOp * op = new KisWSBrushOp(painter);
+ Q_CHECK_PTR(op);
+ return op;
+}
+
+KisWSBrushOp::KisWSBrushOp(KisPainter * painter)
+ : super(painter)
+{
+}
+
+KisWSBrushOp::~KisWSBrushOp()
+{
+}
+
+void KisWSBrushOp::paintAt(const KisPoint &pos,
+ const double pressure,
+ const double /*xTilt*/,
+ const double /*yTilt*/)
+{
+ // Painting should be implemented according to the following algorithm:
+ // retrieve brush
+ // if brush == mask
+ // retrieve mask
+ // else if brush == image
+ // retrieve image
+ // subsample (mask | image) for position -- pos should be double!
+ // apply filters to mask (colour | gradient | pattern | etc.
+ // composite filtered mask into temporary layer
+ // composite temporary layer into target layer
+ // @see: doc/brush.txt
+
+ if (!m_painter -> device()) return;
+
+ KisBrush *brush = m_painter -> brush();
+
+ Q_ASSERT(brush);
+ if (!brush) return;
+
+ KisPaintDeviceSP device = m_painter -> device();
+
+ KisPoint hotSpot = brush -> hotSpot(pressure);
+ KisPoint pt = pos - hotSpot;
+
+ // Split the coordinates into integer plus fractional parts. The integer
+ // is where the dab will be positioned and the fractional part determines
+ // the sub-pixel positioning.
+ Q_INT32 x;
+ double xFraction;
+ Q_INT32 y;
+ double yFraction;
+
+ splitCoordinate(pt.x(), &x, &xFraction);
+ splitCoordinate(pt.y(), &y, &yFraction);
+
+ KisLayerSP dab = 0;
+
+ if (brush -> brushType() == IMAGE || brush -> brushType() == PIPE_IMAGE) {
+ dab = brush -> image(device -> colorSpace(), pressure, xFraction, yFraction);
+ }
+ else {
+ KisAlphaMaskSP mask = brush -> mask(pressure, xFraction, yFraction);
+ dab = computeDab(mask);
+ }
+ m_painter -> setPressure(pressure);
+
+ QRect dabRect = QRect(0, 0, brush -> maskWidth(pressure), brush -> maskHeight(pressure));
+ QRect dstRect = QRect(x, y, dabRect.width(), dabRect.height());
+
+ KisImage * image = device -> image();
+
+ if (image != 0) {
+ dstRect &= image -> bounds();
+ }
+
+ if (dstRect.isNull() || dstRect.isEmpty() || !dstRect.isValid()) return;
+
+ Q_INT32 sx = dstRect.x() - x;
+ Q_INT32 sy = dstRect.y() - y;
+ Q_INT32 sw = dstRect.width();
+ Q_INT32 sh = dstRect.height();
+
+ m_painter -> bltSelection(dstRect.x(), dstRect.y(), m_painter -> compositeOp(), dab.data(), m_painter -> opacity(), sx, sy, sw, sh);
+ m_painter -> addDirtyRect(dstRect);
+}
diff --git a/krita/colorspaces/wetsticky/brushop/kis_wsbrushop.h b/krita/colorspaces/wetsticky/brushop/kis_wsbrushop.h
new file mode 100644
index 00000000..34f50207
--- /dev/null
+++ b/krita/colorspaces/wetsticky/brushop/kis_wsbrushop.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * 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_WSBRUSHOP_H_
+#define KIS_WSBRUSHOP_H_
+
+#include "kis_paintop.h"
+#include "kis_types.h"
+
+class KisPoint;
+class KisPainter;
+
+
+class KisWSBrushOpFactory : public KisPaintOpFactory {
+
+public:
+ KisWSBrushOpFactory() {}
+ virtual ~KisWSBrushOpFactory() {}
+
+ virtual KisPaintOp * createOp(const KisPaintOpSettings *settings, KisPainter * painter);
+ virtual KisID id() { return KisID("wsbrush", i18n("Wet & Sticky Paintbrush")); }
+ virtual QString pixmap() { return "wetpaintbrush.png"; }
+};
+
+class KisWSBrushOp : public KisPaintOp {
+
+ typedef KisPaintOp super;
+
+public:
+
+ KisWSBrushOp(KisPainter * painter);
+ virtual ~KisWSBrushOp();
+
+ void paintAt(const KisPoint &pos,
+ const double pressure,
+ const double /*xTilt*/,
+ const double /*yTilt*/);
+
+};
+
+#endif // KIS_WSBRUSHOP_H_
diff --git a/krita/colorspaces/wetsticky/brushop/kritawsbrushpaintop.desktop b/krita/colorspaces/wetsticky/brushop/kritawsbrushpaintop.desktop
new file mode 100644
index 00000000..d8afc3ed
--- /dev/null
+++ b/krita/colorspaces/wetsticky/brushop/kritawsbrushpaintop.desktop
@@ -0,0 +1,73 @@
+[Desktop Entry]
+Name=Wet & Sticky Paintbrush Paintop
+Name[bg]=Мокра и лепкава четка
+Name[ca]=Pinzell humit i viscós de Paintop
+Name[cy]=Brws paent gwlyb gludiog
+Name[da]=Maleoperation med våd og klæbrig malerpensel
+Name[de]=Maloperation mit feuchtem & klebrigem Farbpinsel
+Name[el]=Βούρτσα υγρής και κολλώδους μπογιάς
+Name[eo]=KDED-testmodulo
+Name[es]=Pincel mojado y pegajoso para pintar
+Name[et]=Märja lõuendi joonistamistoiming
+Name[fa]=Paintop قلم‌موی چسبناک و مرطوب
+Name[fr]=Pinceau paintop mouillé et gluant
+Name[fy]=Kwasten foar wiete en kliemske ferfhannelings
+Name[gl]=Pintado Mollado e Pegoñento
+Name[hu]=Nedves és ragadós ecset
+Name[is]=Blautur & klístraður pensill
+Name[it]=Operazione con pennello bagnato e appiccicoso
+Name[km]=ជក់​ទឹក & ស្អិត Paintop
+Name[nb]=Fargemodell for våt og klissete pensel
+Name[nds]=Malen mit en natten backigen Pinsel
+Name[ne]=ओसिलो र टाँसिने पेन्टब्रस पेन्टप
+Name[nl]=Kwasten voor natte en kleverige verfverrichtingen
+Name[pl]=Mokre i lepkie włosie pędzla
+Name[pt]=Modelo de Cores Molhado e Pegajoso
+Name[pt_BR]=Modelo de Cores Molhado e Pegajoso
+Name[ru]=Кисть с параметрами влажности и прилипания
+Name[sk]=Mokrý a lepkavý štetec Paintop
+Name[sl]=Slikanje z mokrim in lepljivim čopičem
+Name[sr]=Модел боја мокре и лепљиве четкице
+Name[sr@Latn]=Model boja mokre i lepljive četkice
+Name[sv]=Målningsoperation med våt och klibbig målarpensel
+Name[uk]=Пензель з параметрами вогкості і клейкості
+Name[zh_CN]=湿性和粘性画布
+Name[zh_TW]=濕 & 黏的筆刷頭
+Comment=Wet & Sticky paintbrush
+Comment[bg]=Мокра и лепкава четка
+Comment[ca]=Pinzell humit i viscós
+Comment[cy]=Brws paent gwlyb gludiog
+Comment[da]=Våd og klæbrig malerpensel
+Comment[de]=Feuchter & klebriger Farbpinsel
+Comment[el]=Βούρτσα υγρής και κολλώδους μπογιάς
+Comment[eo]=Malseka & Glueca peniko
+Comment[es]=Pincel mojado y pegajoso
+Comment[et]=Märja lõuendi pintsel
+Comment[fa]=قلم‌موی چسبناک و مرطوب
+Comment[fr]=Pinceau mouillé et gluant
+Comment[fy]=Kwast foar wiete en kliemske ferfhannelings
+Comment[gl]=Un pincel mollado e pegaxoso
+Comment[hu]=Nedves és ragadós ecset
+Comment[is]=Blautur og klístraður pensill
+Comment[it]=Pennello bagnato e appiccicoso
+Comment[ja]=Wet & Sticky ペイントブラシ
+Comment[km]=ជក់​ទឹក & ស្អិត
+Comment[nb]=Våt og klissete pensel
+Comment[nds]=Natt un backig Pinsel
+Comment[ne]=ओसिलो र टाँसिने पेन्टब्रस
+Comment[nl]=Kwast voor nat en kleverige verfverichtingen
+Comment[pl]=Mokry i lepki pędzel
+Comment[pt]=Um pincel molhado e pegajoso
+Comment[pt_BR]=Modelo de cores de tela Molhada & Pegajosa
+Comment[ru]=Кисть с параметрами влажности и прилипания
+Comment[sk]=Mokrý a lepkavý štetec
+Comment[sl]=Moker in lepljiv čopič
+Comment[sr]=Мокра и лепљива четкица
+Comment[sr@Latn]=Mokra i lepljiva četkica
+Comment[sv]=Våt och klibbig målarpensel
+Comment[uk]=Пензель з параметрами вогкості і клейкості
+Comment[zh_TW]=濕 & 黏的筆刷
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-KDE-Library=kritawsbrushpaintop
+X-Krita-Version=2
diff --git a/krita/colorspaces/wetsticky/brushop/wetpaintbrush.png b/krita/colorspaces/wetsticky/brushop/wetpaintbrush.png
new file mode 100644
index 00000000..b1b6317d
--- /dev/null
+++ b/krita/colorspaces/wetsticky/brushop/wetpaintbrush.png
Binary files differ
diff --git a/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc b/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc
new file mode 100644
index 00000000..fe0e1eb4
--- /dev/null
+++ b/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.cc
@@ -0,0 +1,56 @@
+/*
+ * wsbrushpaintop_plugin.cc -- Part of Krita
+ *
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * 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 <kiconloader.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+#include <kis_paintop_registry.h>
+#include <kis_debug_areas.h>
+#include "kis_wsbrushop.h"
+
+#include "wsbrushpaintop_plugin.h"
+
+typedef KGenericFactory<WSBrushPaintOpPlugin> WSBrushPaintOpPluginFactory;
+K_EXPORT_COMPONENT_FACTORY( kritawsbrushpaintop, WSBrushPaintOpPluginFactory( "kritacore" ) )
+
+
+WSBrushPaintOpPlugin::WSBrushPaintOpPlugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(WSBrushPaintOpPluginFactory::instance());
+
+ // This is not a gui plugin; only load it when the doc is created.
+ if ( parent->inherits("KisFactory") )
+ {
+ KisPaintOpRegistry::instance() -> add ( new KisWSBrushOpFactory );
+ }
+
+}
+
+WSBrushPaintOpPlugin::~WSBrushPaintOpPlugin()
+{
+}
+
+#include "wsbrushpaintop_plugin.moc"
diff --git a/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h b/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h
new file mode 100644
index 00000000..f668aabf
--- /dev/null
+++ b/krita/colorspaces/wetsticky/brushop/wsbrushpaintop_plugin.h
@@ -0,0 +1,43 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * 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 WSBRUSH_PAINTOP_PLUGIN_H_
+#define WSBRUSH_PAINTOP_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+#include "kis_types.h"
+
+class KisView;
+
+/**
+ * A plugin wrapper that adds the paintop factories to the paintop registry.
+ */
+class WSBrushPaintOpPlugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ WSBrushPaintOpPlugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~WSBrushPaintOpPlugin();
+
+private:
+
+ KisView* m_view;
+};
+
+#endif // WSBRUSH_PAINTOP_PLUGIN_H_
diff --git a/krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc b/krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc
new file mode 100644
index 00000000..c837a558
--- /dev/null
+++ b/krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.cc
@@ -0,0 +1,605 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * 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 <qimage.h>
+
+#include <klocale.h>
+#include <kdebug.h>
+
+#include "kis_color_conversions.h"
+#include "kis_abstract_colorspace.h"
+#include "kis_colorspace_registry.h"
+#include "kis_image.h"
+#include "kis_wet_sticky_colorspace.h"
+#include "kis_integer_maths.h"
+#include "kis_types.h"
+#include "kis_channelinfo.h"
+
+#define NOWSDEBUG
+
+using namespace WetAndSticky;
+
+enum WetStickyChannelIndex {
+ BLUE_CHANNEL_INDEX,
+ GREEN_CHANNEL_INDEX,
+ RED_CHANNEL_INDEX,
+ ALPHA_CHANNEL_INDEX,
+ HUE_CHANNEL_INDEX,
+ SATURATION_CHANNEL_INDEX,
+ LIGHTNESS_CHANNEL_INDEX,
+ LIQUID_CONTENT_CHANNEL_INDEX,
+ DRYING_RATE_CHANNEL_INDEX,
+ MISCIBILITY_CHANNEL_INDEX,
+ GRAVITATIONAL_DIRECTION_INDEX,
+ GRAVITATIONAL_STRENGTH_CHANNEL_INDEX,
+ ABSORBANCY_CHANNEL_INDEX,
+ PAINT_VOLUME_CHANNEL_INDEX
+};
+
+KisWetStickyColorSpace::KisWetStickyColorSpace() :
+ KisAbstractColorSpace(KisID("W&S", i18n("Wet & Sticky")), 0, icMaxEnumData)
+{
+ Q_INT32 pos = 0;
+
+ // Basic representational definition
+ m_channels.push_back(new KisChannelInfo(i18n("Blue"), "B", pos, COLOR, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Green"), "G", ++pos, COLOR, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Red"), "R", ++pos, COLOR, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), "A", ++pos, ALPHA, 1));
+
+ // Paint definition
+ m_channels.push_back(new KisChannelInfo(i18n("Hue"), "H", ++pos, COLOR, sizeof(float)));
+ m_channels.push_back(new KisChannelInfo(i18n("Saturation"), "S", pos+=sizeof(float) , COLOR, sizeof(float)));
+ m_channels.push_back(new KisChannelInfo(i18n("Lightness"), "L", pos+=sizeof(float), COLOR, sizeof(float)));
+
+ m_channels.push_back(new KisChannelInfo(i18n("Liquid Content"), "Q", pos+=sizeof(float), SUBSTANCE, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Drying Rate"), "D", ++pos, SUBSTANCE, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Miscibility"), "M", ++pos, SUBSTANCE, 1));
+
+ // Substrate definition
+ m_channels.push_back(new KisChannelInfo(i18n("Gravitational Direction"), "Gd", ++pos, SUBSTRATE, sizeof(enumDirection)));
+ m_channels.push_back(new KisChannelInfo(i18n("Gravitational Strength"), "Gs", pos+=sizeof(enumDirection), SUBSTRATE, 1));
+
+ m_channels.push_back(new KisChannelInfo(i18n("Absorbency"), "Ad", ++pos, SUBSTRATE, 1));
+ m_channels.push_back(new KisChannelInfo(i18n("Paint Volume"), "V", ++pos, SUBSTANCE, 1));
+
+ m_alphaPos = 3;
+ m_alphaSize = 1;
+ setDefaultProfile( 0 );
+
+#ifdef WSDEBUG
+ QValueVector<KisChannelInfo *>_it it;
+ int i = 0;
+ for (it = m_channels.begin(); it != m_channels.end(); ++it)
+ {
+ KisChannelInfo * ch = (*it);
+ kdDebug(DBG_AREA_CMS) << "Channel: " << ch->name() << ", " << ch->pos() << ", " << i << "\n";
+ ++i;
+ }
+
+ kdDebug(DBG_AREA_CMS) << "Size of cell: " << sizeof(CELL) << "\n";
+#endif
+}
+
+
+KisWetStickyColorSpace::~KisWetStickyColorSpace()
+{
+}
+
+void KisWetStickyColorSpace::fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile)
+{
+ CELL_PTR p = (CELL_PTR) dst;
+ Q_UINT8 r, g, b;
+
+ r = c.red();
+ g = c.green();
+ b = c.blue();
+
+ p -> red = r;
+ p -> green = g;
+ p -> blue = b;
+ p -> alpha = OPACITY_OPAQUE;
+
+ rgb_to_hls(r, g, b, &p->hue, &p->lightness, &p->saturation);
+
+ p -> liquid_content = 0;
+ p -> drying_rate = 0;
+ p -> miscibility = 0;
+
+ p -> direction = DOWN;
+ p -> strength = 10;
+
+ p -> absorbancy = 10;
+ p -> volume = 0;
+
+#ifdef WSDEBUG
+ kdDebug(DBG_AREA_CMS) << "qcolor: "
+ << " r: " << c.red() << " b: " << c.blue() << " g: " << c.red()
+ << " native color: (" << QString().setNum(p->red) << ", "
+ << QString().setNum(p->green) << ", "
+ << QString().setNum(p->blue) << ", "
+ << QString().setNum(p->alpha) << ") "
+ << ", hls: (" << p->hue << ", "
+ << p->lightness << ", "
+ << p->saturation << ")\n";
+#endif
+}
+
+void KisWetStickyColorSpace::fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile)
+{
+ CELL_PTR p = (CELL_PTR) dst;
+ Q_UINT8 r, g, b;
+
+ r = c.red();
+ g = c.green();
+ b = c.blue();
+
+ p -> red = r;
+ p -> green = g;
+ p -> blue = b;
+ p -> alpha = opacity;
+ rgb_to_hls(r, g, b, &p -> hue, &p -> lightness, &p -> saturation);
+
+ p ->liquid_content = 0;
+ p ->drying_rate = 0;
+ p ->miscibility = 0;
+
+ p -> direction = DOWN;
+ p -> strength = 10;
+
+ p -> absorbancy = 10;
+ p -> volume = 0;
+
+#ifdef WSDEBUG
+ kdDebug(DBG_AREA_CMS) << "qcolor: "
+ << " r: " << c.red() << " b: " << c.blue() << " g: " << c.red() << " opacity: " << opacity
+ << " native color: (" << QString().setNum(p->red) << ", "
+ << QString().setNum(p->green) << ", "
+ << QString().setNum(p->blue) << ", "
+ << QString().setNum(p->alpha) << ") "
+ << ", hls: (" << p->hue << ", "
+ << p->lightness << ", "
+ << p->saturation << ")\n";
+#endif
+}
+
+void KisWetStickyColorSpace::toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile)
+{
+ CELL_PTR p = (CELL_PTR) src;
+
+ c -> setRgb(p -> red,
+ p -> green,
+ p -> blue);
+#ifdef WSDEBUG
+ kdDebug(DBG_AREA_CMS) << "Created qcolor from wet & sticky: " << " r: " << c->red() << " b: " << c->blue() << " g: " << c->red() << "\n";
+#endif
+}
+
+void KisWetStickyColorSpace::toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile)
+{
+
+ CELL_PTR p = (CELL_PTR) src;
+
+ c -> setRgb(p -> red,
+ p -> green,
+ p -> blue);
+
+ *opacity = p -> alpha;
+#ifdef WSDEBUG
+ kdDebug(DBG_AREA_CMS) << "Created qcolor from wet & sticky: " << " r: " << c->red() << " b: " << c->blue() << " g: " << c->red() << "\n";
+#endif
+}
+
+
+
+KisPixelRO KisWetStickyColorSpace::toKisPixelRO(const Q_UINT8 *src, KisProfile * profile)
+{
+ return KisPixelRO (src, src, this, profile);
+}
+
+KisPixel KisWetStickyColorSpace::toKisPixel(Q_UINT8 *src, KisProfile * profile)
+{
+ return KisPixel (src, src, this, profile);
+}
+
+void KisWetStickyColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+}
+
+Q_UINT8 KisWetStickyColorSpace::getAlpha(const Q_UINT8 *pixel) const
+{
+ return ((CELL_PTR)pixel)->alpha;
+}
+
+void KisWetStickyColorSpace::setAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const
+{
+ while (nPixels > 0) {
+ ((CELL_PTR)pixels)->alpha = alpha;
+ --nPixels;
+ pixels+=pixelSize();
+ }
+}
+
+void KisWetStickyColorSpace::applyAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels)
+{
+}
+
+void KisWetStickyColorSpace::applyInverseAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels)
+{
+}
+
+Q_UINT8 KisWetStickyColorSpace::scaleToU8(const Q_UINT8 * srcPixel, Q_INT32 channelPos)
+{
+ return 0;
+}
+
+Q_UINT16 KisWetStickyColorSpace::scaleToU16(const Q_UINT8 * srcPixel, Q_INT32 channelPos)
+{
+ return 0;
+}
+
+
+QValueVector<KisChannelInfo *> KisWetStickyColorSpace::channels() const
+{
+ return m_channels;
+}
+
+bool KisWetStickyColorSpace::hasAlpha() const
+{
+ return true;
+}
+
+Q_INT32 KisWetStickyColorSpace::nChannels() const
+{
+ return 14;
+}
+
+Q_INT32 KisWetStickyColorSpace::nColorChannels() const
+{
+ return 3;
+}
+
+Q_INT32 KisWetStickyColorSpace::nSubstanceChannels() const
+{
+ return 4;
+
+}
+
+Q_INT32 KisWetStickyColorSpace::pixelSize() const
+{
+ return sizeof(CELL);
+}
+
+
+QImage KisWetStickyColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
+ KisProfile * /*srcProfile*/, KisProfile * /*dstProfile*/,
+ Q_INT32 /*renderingIntent*/, float /*exposure*/)
+{
+
+ QImage img(width, height, 32, 0, QImage::LittleEndian);
+
+ Q_INT32 i = 0;
+ uchar *j = img.bits();
+
+ CELL_PTR p = (CELL_PTR) data;
+
+ while ( i < width * height) {
+
+ const Q_UINT8 PIXEL_BLUE = 0;
+ const Q_UINT8 PIXEL_GREEN = 1;
+ const Q_UINT8 PIXEL_RED = 2;
+ const Q_UINT8 PIXEL_ALPHA = 3;
+
+ *( j + PIXEL_ALPHA ) = p -> alpha;
+ *( j + PIXEL_RED ) = p -> red;
+ *( j + PIXEL_GREEN ) = p -> green;
+ *( j + PIXEL_BLUE ) = p -> blue;
+
+ p++;
+ i++;
+ j += 4; // Because we're hard-coded 32 bits deep, 4 bytes
+ }
+ return img;
+}
+
+bool KisWetStickyColorSpace::convertPixelsTo(const Q_UINT8 * src, KisProfile * /*srcProfile*/,
+ Q_UINT8 * dst, KisAbstractColorSpace * dstColorSpace, KisProfile * dstProfile,
+ Q_UINT32 numPixels,
+ Q_INT32 /*renderingIntent*/)
+{
+ Q_INT32 dSize = dstColorSpace -> pixelSize();
+ Q_INT32 sSize = pixelSize();
+
+ Q_UINT32 j = 0;
+ Q_UINT32 i = 0;
+ QColor c;
+ CELL_PTR cp;
+ while ( i < numPixels ) {
+ cp = (CELL_PTR) (src + i);
+
+ c.setRgb(cp -> red,
+ cp -> green,
+ cp -> blue);
+
+ dstColorSpace -> fromQColor(c, cp -> alpha, (dst + j), dstProfile);
+
+ i += sSize;
+ j += dSize;
+
+ }
+ return true;
+
+}
+
+void KisWetStickyColorSpace::bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *mask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op)
+{
+ switch (op.op()) {
+ case COMPOSITE_UNDEF:
+ // Undefined == no composition
+ break;
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY:
+ default:
+ compositeCopy(dst, dstRowStride, src, srcRowStride, mask, maskRowStride, rows, cols, opacity);
+ break;
+ }
+
+}
+
+
+void KisWetStickyColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ // XXX: This is basically the same as with rgb and used to composite layers for Composition for
+ // painting works differently
+
+
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ const Q_UINT8 *mask = maskRowStart;
+
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ CELL_PTR dstCell = (CELL_PTR) dst;
+ CELL_PTR srcCell = (CELL_PTR) src;
+
+#ifdef WSDEBUG
+ kdDebug(DBG_AREA_CMS) << "Source: " << rows << ", " << columns << " color: " <<
+ srcCell->red << ", " << srcCell->blue << ", " << srcCell->green << ", " << srcCell->alpha << ", " << srcCell->volume << "\n";
+
+
+ kdDebug(DBG_AREA_CMS) << "Destination: " << rows << ", " << columns << " color: " <<
+ dstCell->red << ", " << dstCell->blue << ", " << dstCell->green << ", " << dstCell->alpha << ", " << dstCell->volume << "\n";
+
+#endif
+
+ Q_UINT8 srcAlpha = srcCell->alpha;
+
+ // apply the alphamask
+ if(mask != 0)
+ {
+ if(*mask != OPACITY_OPAQUE)
+ srcAlpha = UINT8_MULT(srcAlpha, *mask);
+ mask++;
+ }
+
+ if (srcAlpha != OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT8_MULT(srcCell->alpha, opacity);
+ }
+
+ if (srcAlpha == OPACITY_OPAQUE) {
+ memcpy(dst, src, 3); // XXX: First three bytes for rgb?
+ } else {
+ Q_UINT8 dstAlpha = dstCell->alpha;
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + UINT8_MULT(OPACITY_OPAQUE - dstAlpha, srcAlpha);
+ dstCell->alpha = newAlpha;
+
+ if (newAlpha != 0) {
+ srcBlend = UINT8_DIVIDE(srcAlpha, newAlpha);
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ if (srcBlend == OPACITY_OPAQUE) {
+ memcpy(dst, src, 3); //XXX: First three bytes for rgb?
+ } else {
+ dstCell->red = UINT8_BLEND(srcCell->red, dstCell->red, srcBlend);
+ dstCell->green = UINT8_BLEND(srcCell->green, dstCell->green, srcBlend);
+ dstCell->blue = UINT8_BLEND(srcCell->blue, dstCell->blue, srcBlend);
+ }
+ }
+ }
+ columns--;
+ src += sizeof(CELL);
+ dst += sizeof(CELL);
+ }
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+
+ if(maskRowStart)
+ maskRowStart += maskRowStride;
+ }
+
+}
+
+void KisWetStickyColorSpace::compositeCopy(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity)
+{
+ Q_INT32 linesize = sizeof(CELL) * columns;
+ Q_UINT8 *d;
+ const Q_UINT8 *s;
+ d = dst;
+ s = src;
+
+ while (rows-- > 0) {
+ memcpy(d, s, linesize);
+ d += dstRowStride;
+ s += srcRowStride;
+ }
+
+}
+
+
+KisCompositeOpList KisWetStickyColorSpace::userVisiblecompositeOps() const
+{
+ KisCompositeOpList list;
+
+ list.append(KisCompositeOp(COMPOSITE_OVER));
+
+ return list;
+}
+
+QString KisWetStickyColorSpace::channelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < nChannels());
+ const CELL *pixel = reinterpret_cast<const CELL *>(U8_pixel);
+
+ switch (channelIndex) {
+ case BLUE_CHANNEL_INDEX:
+ return QString().setNum(pixel -> blue);
+ case GREEN_CHANNEL_INDEX:
+ return QString().setNum(pixel -> green);
+ case RED_CHANNEL_INDEX:
+ return QString().setNum(pixel -> red);
+ case ALPHA_CHANNEL_INDEX:
+ return QString().setNum(pixel -> alpha);
+ case HUE_CHANNEL_INDEX:
+ return QString().setNum(pixel -> hue);
+ case SATURATION_CHANNEL_INDEX:
+ return QString().setNum(pixel -> saturation);
+ case LIGHTNESS_CHANNEL_INDEX:
+ return QString().setNum(pixel -> lightness);
+ case LIQUID_CONTENT_CHANNEL_INDEX:
+ return QString().setNum(pixel -> liquid_content);
+ case DRYING_RATE_CHANNEL_INDEX:
+ return QString().setNum(pixel -> drying_rate);
+ case MISCIBILITY_CHANNEL_INDEX:
+ return QString().setNum(pixel -> miscibility);
+ case GRAVITATIONAL_DIRECTION_INDEX:
+ {
+ switch (pixel -> direction) {
+ case UP:
+ return i18n("Up");
+ case DOWN:
+ return i18n("Down");
+ case LEFT:
+ return i18n("Left");
+ case RIGHT:
+ return i18n("Right");
+ default:
+ Q_ASSERT(false);
+ return QString();
+ }
+ }
+ case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX:
+ return QString().setNum(pixel -> strength);
+ case ABSORBANCY_CHANNEL_INDEX:
+ return QString().setNum(pixel -> absorbancy);
+ case PAINT_VOLUME_CHANNEL_INDEX:
+ return QString().setNum(pixel -> volume);
+ default:
+ Q_ASSERT(false);
+ return QString();
+ }
+}
+
+QString KisWetStickyColorSpace::normalisedChannelValueText(const Q_UINT8 *U8_pixel, Q_UINT32 channelIndex) const
+{
+ Q_ASSERT(channelIndex < nChannels());
+ const CELL *pixel = reinterpret_cast<const CELL *>(U8_pixel);
+
+ //XXX: Are these right?
+
+ switch (channelIndex) {
+ case BLUE_CHANNEL_INDEX:
+ return QString().setNum(static_cast<float>(pixel -> blue) / UINT8_MAX);
+ case GREEN_CHANNEL_INDEX:
+ return QString().setNum(static_cast<float>(pixel -> green) / UINT8_MAX);
+ case RED_CHANNEL_INDEX:
+ return QString().setNum(static_cast<float>(pixel -> red) / UINT8_MAX);
+ case ALPHA_CHANNEL_INDEX:
+ return QString().setNum(static_cast<float>(pixel -> alpha) / UINT8_MAX);
+ case HUE_CHANNEL_INDEX:
+ return QString().setNum(pixel -> hue);
+ case SATURATION_CHANNEL_INDEX:
+ return QString().setNum(pixel -> saturation);
+ case LIGHTNESS_CHANNEL_INDEX:
+ return QString().setNum(pixel -> lightness);
+ case LIQUID_CONTENT_CHANNEL_INDEX:
+ return QString().setNum(static_cast<float>(pixel -> liquid_content) / UINT8_MAX);
+ case DRYING_RATE_CHANNEL_INDEX:
+ return QString().setNum(static_cast<float>(pixel -> drying_rate) / UINT8_MAX);
+ case MISCIBILITY_CHANNEL_INDEX:
+ return QString().setNum(static_cast<float>(pixel -> miscibility) / UINT8_MAX);
+ case GRAVITATIONAL_DIRECTION_INDEX:
+ {
+ switch (pixel -> direction) {
+ case UP:
+ return i18n("Up");
+ case DOWN:
+ return i18n("Down");
+ case LEFT:
+ return i18n("Left");
+ case RIGHT:
+ return i18n("Right");
+ default:
+ Q_ASSERT(false);
+ return QString();
+ }
+ }
+ case GRAVITATIONAL_STRENGTH_CHANNEL_INDEX:
+ return QString().setNum(static_cast<float>(pixel -> strength) / UINT8_MAX);
+ case ABSORBANCY_CHANNEL_INDEX:
+ return QString().setNum(static_cast<float>(pixel -> absorbancy) / UINT8_MAX);
+ case PAINT_VOLUME_CHANNEL_INDEX:
+ return QString().setNum(static_cast<float>(pixel -> volume) / UINT8_MAX);
+ default:
+ Q_ASSERT(false);
+ return QString();
+ }
+}
+
diff --git a/krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.h b/krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.h
new file mode 100644
index 00000000..758cb57e
--- /dev/null
+++ b/krita/colorspaces/wetsticky/kis_wet_sticky_colorspace.h
@@ -0,0 +1,148 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt <[email protected]>
+ *
+ * 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_WET_STICKY_H_
+#define KIS_COLORSPACE_WET_STICKY_H_
+
+#include <qcolor.h>
+
+#include "kis_global.h"
+#include "kis_abstract_colorspace.h"
+
+namespace WetAndSticky {
+
+ /**
+ * A color is specified as a vector in HLS space. Hue is a value
+ * in the range 0..360 degrees with 0 degrees being red. Saturation
+ * and Lightness are both in the range [0,1]. A lightness of 0 means
+ * black, with 1 being white. A totally saturated color has saturation
+ * of 1.
+ */
+
+ enum enumDirection {
+ UP,
+ DOWN,
+ LEFT,
+ RIGHT
+ };
+
+ /**
+ * Defines the contents and attributes of a cell on the canvas.
+ */
+ typedef struct cell {
+ Q_UINT8 blue;
+ Q_UINT8 green;
+ Q_UINT8 red;
+ Q_UINT8 alpha;
+
+ float hue;
+ float saturation;
+ float lightness;
+
+ Q_UINT8 liquid_content;
+ Q_UINT8 drying_rate;
+ Q_UINT8 miscibility;
+
+ enumDirection direction;
+ Q_UINT8 strength;
+
+ Q_UINT8 absorbancy; /* How much paint can this cell hold? */
+ Q_UINT8 volume; /* The volume of paint. */
+
+ } CELL, *CELL_PTR;
+
+
+}
+
+
+
+class KisWetStickyColorSpace : public KisAbstractColorSpace {
+public:
+ KisWetStickyColorSpace();
+ virtual ~KisWetStickyColorSpace();
+
+public:
+
+
+
+ virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0);
+ virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0);
+
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0);
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0);
+
+ virtual Q_UINT8 getAlpha(const Q_UINT8 *pixel) const;
+ virtual void setAlpha(Q_UINT8 * pixels, Q_UINT8 alpha, Q_INT32 nPixels) const;
+
+ virtual void applyAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels);
+ virtual void applyInverseAlphaU8Mask(Q_UINT8 * pixels, Q_UINT8 * alpha, Q_INT32 nPixels);
+
+ virtual Q_UINT8 scaleToU8(const Q_UINT8 * srcPixel, Q_INT32 channelPos);
+ virtual Q_UINT16 scaleToU16(const Q_UINT8 * srcPixel, Q_INT32 channelPos);
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual bool hasAlpha() const;
+ virtual Q_INT32 nChannels() const;
+ virtual Q_INT32 nColorChannels() const;
+ virtual Q_INT32 nSubstanceChannels() const;
+ virtual Q_INT32 pixelSize() const;
+
+ virtual QString channelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const;
+ virtual QString normalisedChannelValueText(const Q_UINT8 *pixel, Q_UINT32 channelIndex) const;
+
+ virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
+ KisProfile * srcProfile, KisProfile * dstProfile,
+ Q_INT32 renderingIntent = INTENT_PERCEPTUAL,
+ float exposure = 0.0f);
+
+
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+ virtual void convolveColors(Q_UINT8** colors, Q_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, Q_UINT8 *dst, Q_INT32 factor, Q_INT32 offset, Q_INT32 nColors) const;
+ virtual void invertColor(Q_UINT8 * src, Q_INT32 nPixels);
+ virtual void darken(const Q_UINT8 * src, Q_UINT8 * dst, Q_INT32 shade, bool compensate, double compensation, Q_INT32 nPixels) const;
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+protected:
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowSize,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+
+ virtual bool convertPixelsTo(const Q_UINT8 * src, KisProfile * srcProfile,
+ Q_UINT8 * dst, KisAbstractColorSpace * dstColorSpace, KisProfile * dstProfile,
+ Q_UINT32 numPixels,
+ Q_INT32 renderingIntent = INTENT_PERCEPTUAL);
+
+
+private:
+
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeClear(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeCopy(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+
+};
+
+#endif // KIS_COLORSPACE_WET_STICKY_H_
diff --git a/krita/colorspaces/wetsticky/kis_ws_engine_filter.cc b/krita/colorspaces/wetsticky/kis_ws_engine_filter.cc
new file mode 100644
index 00000000..365b5f2a
--- /dev/null
+++ b/krita/colorspaces/wetsticky/kis_ws_engine_filter.cc
@@ -0,0 +1,180 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * 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 <stdlib.h>
+#include <vector>
+#include <math.h>
+
+#include <qpoint.h>
+#include <qspinbox.h>
+#include <qrect.h>
+#include <qcolor.h>
+
+#include <klocale.h>
+#include <kiconloader.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+#include <knuminput.h>
+
+#include <kis_debug_areas.h>
+#include <kis_image.h>
+#include <kis_iterators_pixel.h>
+#include <kis_layer.h>
+#include <kis_filter_registry.h>
+#include <kis_debug_areas.h>
+#include <kis_types.h>
+#include <kis_paint_device.h>
+#include <kis_colorspace_registry.h>
+
+#include "kis_ws_engine_filter.h"
+#include "kis_wet_sticky_colorspace.h"
+
+/**
+ * The Wet & Sticky Engine filter is based on the wet & sticky model
+ * for computer painting designed by Tunde Cockshott and implemented
+ * by David England and Kevin Waite.
+ *
+ * The filter implements the engine that moves the paint according to
+ * gravity, viscosity and absorbency.
+ *
+ */
+KisWSEngineFilter::KisWSEngineFilter() : KisFilter(id(), "", i18n("&Wet & Sticky paint engine..."))
+{
+}
+
+
+/**
+ * Sets the POINT giving the coordinate location of the next
+ * cell on the canvas to be visited. There is an even probability
+ * of each cell being visited.
+ */
+QPoint next_cell(Q_UINT32 width, Q_UINT32 height)
+{
+ return QPoint(random() * width, random() * height);
+}
+
+void single_step(KisColorSpace * cs, KisPaintDeviceSP src, KisPaintDeviceSP dst, const QRect & rect, bool native)
+{
+ using namespace WetAndSticky;
+
+
+ QPoint p = next_cell( rect.width(), rect.height() );
+
+ // XXX: We could optimize by randomly doing lines of 64 pixels
+ // -- maybe that would be enough to avoid the windscreen wiper
+ // effect.
+ KisHLineIterator iter = src -> createHLineIterator(p.x(), p.y(), 1, false);
+
+ Q_UINT8 *orig = iter.rawData();
+ Q_UINT8 *pix = orig;
+
+ if (!orig) return;
+
+ if (!native ) {
+ QColor c;
+ Q_UINT8 opacity;
+
+ src -> colorSpace() -> toQColor(pix, &c, &opacity);
+ Q_UINT8 *pix = new Q_UINT8[sizeof( cell )];
+ Q_CHECK_PTR(pix);
+
+ cs -> fromQColor(c, opacity, pix);
+ }
+
+ // Process
+
+ CELL_PTR c = ( CELL_PTR )pix;
+
+
+ if ( !native ) {
+ // Set RGBA back
+ }
+
+}
+
+void KisWSEngineFilter::process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* configuration, const QRect& rect)
+{
+
+ m_src = src;
+ m_dst = dst;
+ m_cfg = ( KisWSEngineFilterConfiguration * )configuration;
+ m_rect = rect;
+
+
+ kdDebug(DBG_AREA_FILTERS) << "WSEnginefilter called!\n";
+ QTime t;
+ t.restart();
+
+ // Two possibilities: we have our own, cool w&s pixel, and
+ // then we have real data to mess with, or we're filtering a
+ // boring shoup-model paint device and we can only work by
+ // synthesizing w&s pixels.
+ bool native = false;
+ // XXX: We need a better way to ID color strategies
+ if ( src -> colorSpace() -> id() == KisID("W&S","") ) native = true;
+
+ // XXX: We need a better way to ID color strategies
+ KisColorSpace * cs = KisColorSpaceRegistry::instance()->get("W&S");
+
+ Q_UINT32 pixels = 400; //m_cfg -> pixels();
+
+ kdDebug(DBG_AREA_FILTERS) << "Going to singlestep " << pixels << " pixels.\n";
+
+ // Determine whether we want an infinite loop
+ if ( pixels == 0 ) {
+ while ( true )
+ single_step (cs, src, dst, rect, native);
+ }
+ // Or not.
+ else {
+ for ( Q_UINT32 i = 0; i < pixels; ++i ) {
+ single_step (cs, src, dst, rect, native);
+ }
+ }
+ kdDebug(DBG_AREA_FILTERS) << "Done in " << t.elapsed() << " ms\n";
+
+}
+
+KisFilterConfigWidget * KisWSEngineFilter::createConfigurationWidget(QWidget* parent, KisPaintDeviceSP dev)
+{
+// KisWSEngineFilterConfigurationWidget* kefcw = new KisWSEngineFilterConfigurationWidget(this,parent, "");
+// kdDebug(DBG_AREA_FILTERS) << kefcw << endl;
+// return kefcw ;
+ return 0;
+}
+
+KisFilterConfiguration* KisWSEngineFilter::configuration(QWidget* nwidget, KisPaintDeviceSP dev)
+{
+// KisWSEngineFilterConfigurationWidget* widget = (KisWSEngineFilterConfigurationWidget*) nwidget;
+
+// if( widget == 0 )
+// {
+// return new KisWSEngineFilterConfiguration(30);
+// } else {
+// Q_UINT32 depth = widget -> baseWidget() -> depthSpinBox -> value();
+
+// return new KisWSEngineFilterConfiguration(depth);
+// }
+
+
+ return new KisWSEngineFilterConfiguration( m_rect.height() * m_rect.width() );
+}
+
diff --git a/krita/colorspaces/wetsticky/kis_ws_engine_filter.h b/krita/colorspaces/wetsticky/kis_ws_engine_filter.h
new file mode 100644
index 00000000..5eb8ca81
--- /dev/null
+++ b/krita/colorspaces/wetsticky/kis_ws_engine_filter.h
@@ -0,0 +1,77 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * 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_WS_ENGINE_FILTER_H_
+#define _KIS_WS_ENGINE_FILTER_H_
+
+#include <kdebug.h>
+
+#include <kis_view.h>
+#include <kis_filter.h>
+#include <kis_id.h>
+
+class KisWSEngineFilterConfiguration : public KisFilterConfiguration
+{
+
+public:
+
+ KisWSEngineFilterConfiguration() { m_pixels = 10000; }
+
+ KisWSEngineFilterConfiguration(Q_UINT32 pixels = 0) { m_pixels = pixels; }
+
+ Q_UINT32 pixels() { return m_pixels; }
+
+private:
+
+ Q_UINT32 m_pixels; // The number of pixels the filter should
+ // move. 0 means keep running indefinitely
+
+
+
+};
+
+class KisWSEngineFilter : public KisFilter
+{
+
+public:
+
+ KisWSEngineFilter();
+
+ virtual void process(KisPaintDeviceSP src, KisPaintDeviceSP dst, KisFilterConfiguration* cfg, const QRect& rc);
+
+ static inline KisID id() { return KisID("Wet & Sticky Engine", i18n("Wet & Sticky")); };
+ virtual bool supportsPainting() { return false; }
+ virtual bool supportsPreview() { return false; }
+ virtual bool supportsIncrementalPainting() { return false; }
+
+public:
+ virtual KisFilterConfigWidget * createConfigurationWidget(QWidget* parent, KisPaintDeviceSP dev);
+ virtual KisFilterConfiguration* configuration(QWidget*, KisPaintDeviceSP dev);
+
+
+private:
+
+private:
+
+ KisWSEngineFilterConfiguration * m_cfg;
+ KisPaintDeviceSP m_src;
+ KisPaintDeviceSP m_dst;
+ QRect m_rect;
+
+};
+
+#endif // _KIS_WS_ENGINE_FILTER_H_
diff --git a/krita/colorspaces/wetsticky/kritawsplugin.desktop b/krita/colorspaces/wetsticky/kritawsplugin.desktop
new file mode 100644
index 00000000..0f6b6791
--- /dev/null
+++ b/krita/colorspaces/wetsticky/kritawsplugin.desktop
@@ -0,0 +1,46 @@
+[Desktop Entry]
+Name=Wet & Sticky Canvas Color Model
+Name[bg]=Цветови модел за мокро и лепкаво платно
+Name[ca]=Model de color de llenç humit i viscós
+Name[cy]=Model Lliw Cynfas Gwlyb a Gludiog
+Name[da]=Våd & klæbrig kanvasfarve-model
+Name[de]=Farbmodell feuchte & klebrige Leinwand
+Name[el]=Μοντέλο καμβά υγρής και κολλώδους μπογιάς
+Name[en_GB]=Wet & Sticky Canvas Colour Model
+Name[eo]=Kolormodelo por Malseka & Glueca Kanvaso
+Name[es]=Modelo de color de lienzo mojado y pegajoso
+Name[et]=Märja lõuendi värvimudel
+Name[eu]=Oihal heze eta itsaskorraren kolore-eredua
+Name[fa]=مدل رنگ صفحه مجازی چسبناک و مرطوب
+Name[fi]=Märkä ja tahmea kangasvärimalli
+Name[fr]=Modèle de couleurs gluantes et mouillées
+Name[fy]=wiete en kliemske canvasmodel
+Name[gl]=Modelo de Cores de Tea Mollado e Pegoñento
+Name[hu]=Nedves és ragadós vászon színmodell
+Name[is]=Blaut & klístruð litategund
+Name[it]=Modello di colore per tela bagnata
+Name[ja]=Wet & Sticky キャンバスカラーモデル
+Name[km]=ម៉ូដែល​ពណ៌​ទឹក & ស្អិត
+Name[ms]=Model Warna Kanvas Basah & Lekit
+Name[nb]=Fargemodell for vått og klissete lerret
+Name[nds]=Klöörmodell natt un backig Lienwand
+Name[ne]=ओसिलो र टाँसिने चित्रपट रङ मोडेल
+Name[nl]=Nat en kleverig canvasmodel
+Name[nn]=Fargemodell for vått lerret
+Name[pl]=Przestrzeń barw mokrego i lepkiego płótna
+Name[pt]=Modelo de Cores de Tela Molhado e Pegajoso
+Name[pt_BR]=Modelo de cores de tela Molhada & Pegajosa
+Name[ru]=Цветовое пространство с параметрами влажности и прилипания
+Name[sk]=Model farieb pre mokré a lepkavé plátno
+Name[sl]=Barvni model z mokrim in lepljivim platnom
+Name[sr]=Модел боја мокрог и лепљивог платна
+Name[sr@Latn]=Model boja mokrog i lepljivog platna
+Name[sv]=Våt och klibbig dukfärgmodell
+Name[uk]=Канва моделі кольорів з параметрами вогкості і клейкості
+Name[zh_CN]=湿性/粘性画布色彩模型
+Name[zh_TW]=濕 & 黏的畫布色彩模型
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-KDE-Library=kritawsplugin
+X-Krita-Version=2
+
diff --git a/krita/colorspaces/wetsticky/wet_sticky_plugin.cc b/krita/colorspaces/wetsticky/wet_sticky_plugin.cc
new file mode 100644
index 00000000..858b4810
--- /dev/null
+++ b/krita/colorspaces/wetsticky/wet_sticky_plugin.cc
@@ -0,0 +1,60 @@
+/*
+ * wet_sticky_plugin.cc -- Part of Krita
+ *
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * 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 <kiconloader.h>
+#include <kinstance.h>
+#include <kmessagebox.h>
+#include <kstandarddirs.h>
+#include <ktempfile.h>
+#include <kdebug.h>
+#include <kgenericfactory.h>
+
+#include <kis_colorspace_registry.h>
+#include <kis_debug_areas.h>
+#include "wet_sticky_plugin.h"
+
+#include "kis_wet_sticky_colorspace.h"
+#include "kis_ws_engine_filter.h"
+
+typedef KGenericFactory<WetStickyPlugin> WetStickyPluginFactory;
+K_EXPORT_COMPONENT_FACTORY( kritawsplugin, WetStickyPluginFactory( "kritacore" ) )
+
+
+WetStickyPlugin::WetStickyPlugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(WetStickyPluginFactory::instance());
+
+ // This is not a gui plugin; only load it when the doc is created.
+ if ( parent->inherits("KisFactory") )
+ {
+ KisColorSpace * colorSpaceWS = new KisWetStickyColorSpace();
+ Q_CHECK_PTR(colorSpaceWS);
+ KisColorSpaceRegistry::instance() -> add(colorSpaceWS);
+ KisFilterRegistry::instance()->add(new KisWSEngineFilter());
+ }
+
+}
+
+WetStickyPlugin::~WetStickyPlugin()
+{
+}
+
+#include "wet_sticky_plugin.moc"
diff --git a/krita/colorspaces/wetsticky/wet_sticky_plugin.h b/krita/colorspaces/wetsticky/wet_sticky_plugin.h
new file mode 100644
index 00000000..35b8207c
--- /dev/null
+++ b/krita/colorspaces/wetsticky/wet_sticky_plugin.h
@@ -0,0 +1,41 @@
+/*
+ * Copyright (c) 2005 Boudewijn Rempt ([email protected])
+ *
+ * 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 WET_STICKY_PLUGIN_H_
+#define WET_STICKY_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the Wet & Sticky colour space strategy.
+ *
+ * The Wet & Sticky paint system was first designed in 1991 by Tunde Cockshott
+ * and was further developed by David England and Kevin Waite. It was released
+ * under the GPL in 2005.
+ *
+ */
+class WetStickyPlugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ WetStickyPlugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~WetStickyPlugin();
+
+};
+
+#endif // WET_STICKY_PLUGIN_H_
diff --git a/krita/colorspaces/wetsticky/ws/GNU b/krita/colorspaces/wetsticky/ws/GNU
new file mode 100644
index 00000000..e69de29b
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/GNU
diff --git a/krita/colorspaces/wetsticky/ws/GNU Public Licence.txt b/krita/colorspaces/wetsticky/ws/GNU Public Licence.txt
new file mode 100644
index 00000000..a3f2100e
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/GNU Public Licence.txt
@@ -0,0 +1,341 @@
+ GNU GENERAL PUBLIC LICENSE
+ Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+ Preamble
+
+ The licenses for most software are designed to take away your
+freedom to share and change it. By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users. This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it. (Some other Free Software Foundation software is covered by
+the GNU Library General Public License instead.) You can apply it to
+your programs, too.
+
+ When we speak of free software, we are referring to freedom, not
+price. Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+ To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+ For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have. You must make sure that they, too, receive or can get the
+source code. And you must show them these terms so they know their
+rights.
+
+ We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+ Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software. If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+ Finally, any free program is threatened constantly by software
+patents. We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary. To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+ The precise terms and conditions for copying, distribution and
+modification follow.
+
+ GNU GENERAL PUBLIC LICENSE
+ TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+ 0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License. The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language. (Hereinafter, translation is included without limitation in
+the term "modification".) Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope. The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+ 1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+ 2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+ a) You must cause the modified files to carry prominent notices
+ stating that you changed the files and the date of any change.
+
+ b) You must cause any work that you distribute or publish, that in
+ whole or in part contains or is derived from the Program or any
+ part thereof, to be licensed as a whole at no charge to all third
+ parties under the terms of this License.
+
+ c) If the modified program normally reads commands interactively
+ when run, you must cause it, when started running for such
+ interactive use in the most ordinary way, to print or display an
+ announcement including an appropriate copyright notice and a
+ notice that there is no warranty (or else, saying that you provide
+ a warranty) and that users may redistribute the program under
+ these conditions, and telling the user how to view a copy of this
+ License. (Exception: if the Program itself is interactive but
+ does not normally print such an announcement, your work based on
+ the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole. If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works. But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+ 3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+ a) Accompany it with the complete corresponding machine-readable
+ source code, which must be distributed under the terms of Sections
+ 1 and 2 above on a medium customarily used for software interchange; or,
+
+ b) Accompany it with a written offer, valid for at least three
+ years, to give any third party, for a charge no more than your
+ cost of physically performing source distribution, a complete
+ machine-readable copy of the corresponding source code, to be
+ distributed under the terms of Sections 1 and 2 above on a medium
+ customarily used for software interchange; or,
+
+ c) Accompany it with the information you received as to the offer
+ to distribute corresponding source code. (This alternative is
+ allowed only for noncommercial distribution and only if you
+ received the program in object code or executable form with such
+ an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it. For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable. However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+ 4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License. Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+ 5. You are not required to accept this License, since you have not
+signed it. However, nothing else grants you permission to modify or
+distribute the Program or its derivative works. These actions are
+prohibited by law if you do not accept this License. Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+ 6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions. You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+ 7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License. If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all. For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices. Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+ 8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded. In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+ 9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time. Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number. If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation. If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+ 10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission. For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this. Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+ NO WARRANTY
+
+ 11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW. EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU. SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+ 12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+ END OF TERMS AND CONDITIONS
+
+ How to Apply These Terms to Your New Programs
+
+ If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+ To do so, attach the following notices to the program. It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+ <one line to give the program's name and a brief idea of what it does.>
+ Copyright (C) <year> <name of author>
+
+ 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
+
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+ Gnomovision version 69, Copyright (C) year name of author
+ Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+ This is free software, and you are welcome to redistribute it
+ under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License. Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary. Here is a sample; alter the names:
+
+ Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+ `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+ <signature of Ty Coon>, 1 April 1989
+ Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs. If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library. If this is what you want to do, use the GNU Library General
+Public License instead of this License.
+
diff --git a/krita/colorspaces/wetsticky/ws/README b/krita/colorspaces/wetsticky/ws/README
new file mode 100644
index 00000000..15f55e77
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/README
@@ -0,0 +1,4 @@
+
+The gear example
+
+This example program demonstrates how to use OpenGL display lists.
diff --git a/krita/colorspaces/wetsticky/ws/TODO b/krita/colorspaces/wetsticky/ws/TODO
new file mode 100644
index 00000000..91c48a03
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/TODO
@@ -0,0 +1,24 @@
+1/ Load in portable pixmaps (PPM). Set an arbitrary paint attribute
+map for each different colour. Otherwise load in a paint attribute
+map definition file.
+2/ Input from "brush". Incremental development of brush input.
+First simple mixing then
+empty brush moving paint
+paint on top of paint
+attribute application.
+3/ Animation
+1000000 = 1 fps
+500000 = 2 fps
+250000 = 4 fps
+125000 = 8 fps
+62500 = 16 fps
+41660 = 24 fps
+
+4/ NK times 178.9 real 49.4 user 13.3 sys
+ Orig times 636.6 real 111.1 user 43.6 sys
+
+5/ Cross section through volume
+
+6/ Separate Colour scale window
+
+7/ Transparency
diff --git a/krita/colorspaces/wetsticky/ws/after.jpg b/krita/colorspaces/wetsticky/ws/after.jpg
new file mode 100644
index 00000000..5116efdb
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/after.jpg
Binary files differ
diff --git a/krita/colorspaces/wetsticky/ws/anim.c b/krita/colorspaces/wetsticky/ws/anim.c
new file mode 100644
index 00000000..fed5379f
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/anim.c
@@ -0,0 +1,154 @@
+/*
+ FILE: x_interface.c
+ PURPOSE: Creation and access to an X windows interface
+ to wet+sticky using Athena Widgets
+ AUTHOR: David England
+ VERSION: 1.00 (13-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#define FRAME_LIMIT 36
+
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Intrinsic.h>
+
+#include <X11/cursorfont.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Shell.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Label.h>
+#include <stdio.h>
+
+#include "constants.h"
+#include "types.h"
+
+#include "engine.h"
+#include "canvas.h"
+
+/* Window Heirarchy -
+ Three shell widgets, one for colour output, two for attributes
+output
+ plus a back_up pixmap for redrawing
+*/
+
+static Widget top_level;
+static Widget colour_shell;
+static Widget colour_box;
+static Widget colour_canvas;
+static Pixmap colour_pm[FRAME_LIMIT];
+
+static GC gc;
+static GC tmp_gc;
+static long mask;
+static XGCValues values;
+
+Display *display;
+char pix_file[32];
+unsigned int delay;
+
+main(argc, argv)
+int argc;
+char *argv[];
+{
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ XEvent event;
+ int i, width, height;
+ int ret;
+ int c;
+
+ extern char *optarg;
+ extern int optind;
+
+ width = 300;
+ height = 300;
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL,
+ 0, &argc, argv);
+
+ delay = 100000; /*default delay in microseconds between frames */
+
+ while ((c = getopt(argc, argv, "D:")) != -1)
+ switch (c) {
+ case 'D':
+ delay = atoi(optarg);
+ delay = delay * 1000000;
+ break;
+ }
+
+
+ display = XtDisplay(top_level);
+
+ colour_shell = XtCreateApplicationShell("colour_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+ colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass,
+ colour_shell, NULL, 0);
+
+
+ colour_canvas = XtCreateManagedWidget("", labelWidgetClass,
+ colour_box, args, XtNumber(args));
+
+
+ /*XtAddEventHandler(colour_canvas, ExposureMask, False,
+ expose_event, 0);*/
+
+ XtRealizeWidget(colour_shell);
+
+ XSynchronize(display, True);
+
+ mask = GCBackground| GCForeground| GCFunction;
+
+ values.function = GXcopy;
+ values.background = 0;
+ values.foreground = 1;
+
+
+ gc = XtGetGC(colour_canvas, mask, &values);
+
+
+
+ fprintf(stderr,"Read files ...");
+ for (i=0; i < FRAME_LIMIT; i++) {
+ sprintf(pix_file,"pixmap.%d",i);
+ if ((XReadBitmapFile(display, XtWindow(colour_shell), pix_file,
+ &width, &height, &colour_pm[i], &ret, &ret)) !=
+ BitmapSuccess)
+ perror("bad bitmap");
+ }
+ fprintf(stderr,"done.\nBegin Animation\n");
+
+
+ for (;;) {
+ for (i=0; i < FRAME_LIMIT; i++) {
+ XCopyPlane(display, colour_pm[i],
+ XtWindow(colour_canvas),gc,
+ 0, 0, 300, 300, 0, 0, 1);
+ fprintf(stderr,"pre sleep\n");
+ usleep(delay);
+ }
+
+
+ } /* End for loop */
+}xk
+
diff --git a/krita/colorspaces/wetsticky/ws/before.jpg b/krita/colorspaces/wetsticky/ws/before.jpg
new file mode 100644
index 00000000..fc26b989
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/before.jpg
Binary files differ
diff --git a/krita/colorspaces/wetsticky/ws/canvas.c b/krita/colorspaces/wetsticky/ws/canvas.c
new file mode 100644
index 00000000..d2e27cd1
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/canvas.c
@@ -0,0 +1,514 @@
+/*
+ FILE: canvas.c
+ PURPOSE: Hides the canvas and provides its access and
+ manipuation routines.
+ AUTHOR: Kevin Waite
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "constants.h"
+#include "types.h"
+#include "canvas.h"
+#include <stdio.h>
+
+/* Declare the canvas data structure local to this module. It can
+ only be accessed via routines given in the header file for this module.
+ The (0,0) location for the canvas is at the top-left. */
+
+CELL canvas[CANVAS_WIDTH][CANVAS_HEIGHT];
+
+/* This module maintains a list of the addresses of cells that have
+ been modified since the last redraw and therefore need updating.
+ Points are added to this list by the need_to_repaint() routine
+ and are removed by the next_cell_for_repaint() function. The
+ pointer to the current tail of the list is updated by side-effect. */
+
+static POINT need_repainting[REDRAW_LIMIT];
+static int next_free = 0;
+static int next_to_repaint = 0;
+
+/* *********************************************************************** */
+
+int number_of_repaints_needed()
+/* Returns the number of cells that need to be repainted. */
+
+{
+ return (next_free);
+}
+
+/* *********************************************************************** */
+
+void need_to_repaint(point)
+/* The cell at this location needs to be redrawn since it has
+ been altered. Scan the list to see if it is already
+ scheduled for a repainting operation and only add it if
+ it is not there. */
+
+POINT point;
+
+{
+ int k;
+
+
+ /* If the list is already full then simply ignore the repaint
+ request - it will get done eventually anyway. */
+
+ if (next_free == REDRAW_LIMIT) return;
+
+ /* Check whether this point is already on the list. */
+
+ for (k=0; k < next_free; k++) {
+ if ((need_repainting[k].x == point.x) &&
+ (need_repainting[k].y == point.y)) break;
+ }
+
+ if (k < next_free) return; /* Already in the list. */
+
+ /* Add this new cell address to the end of the list. */
+
+ need_repainting[next_free].x = point.x;
+ need_repainting[next_free].y = point.y;
+ next_free++;
+}
+
+/* *********************************************************************** */
+
+void next_cell_for_repaint(cell, locus)
+/* This routine returns the next cell to be repainted, together with its
+ location on the canvas. This is determined by taking the next point
+ from the need_repainting list and accessing its cell. If the list is
+ empty then return NIL.
+ Note that the repainting operation will clear out the list before
+ any other new positions are added. */
+
+ CELL_PTR *cell;
+ POINT_PTR locus;
+
+{
+ if (next_to_repaint >= next_free) {
+ next_to_repaint = next_free = 0;
+ *(cell) = NIL;
+ return;
+ }
+
+ *(cell) = get_cell(need_repainting[next_to_repaint]);
+ locus->x = need_repainting[next_to_repaint].x;
+ locus->y = need_repainting[next_to_repaint].y;
+ next_to_repaint++;
+}
+
+/* *********************************************************************** */
+
+void next_cell_point (address)
+/* Sets the POINT giving the coordinate location of the next
+ cell on the canvas to be visited. There is an even probability
+ of each cell being visited. */
+
+POINT_PTR address;
+{
+ extern long random();
+
+ address->x = random() % CANVAS_WIDTH;
+ address->y = random() % CANVAS_HEIGHT;
+}
+
+
+/* *********************************************************************** */
+
+CELL_PTR get_cell (point)
+/* This function returns a pointer to the cell at the
+ given address on the canvas. */
+
+POINT point;
+
+{
+ return (&canvas[point.x][point.y]);
+}
+
+/* *********************************************************************** */
+
+DIRECTION anti_clockwise_from (arrow)
+/* Returns the direction found going anti-clockwise from the
+ given direction. */
+
+DIRECTION arrow;
+
+{
+ switch (arrow) {
+
+ case NORTH: return(WEST);
+ case EAST: return(NORTH);
+ case SOUTH: return(EAST);
+ case WEST: ;
+
+ }
+ return(SOUTH);
+}
+
+/* *********************************************************************** */
+
+DIRECTION clockwise_from (arrow)
+/* Returns the direction found going clockwise from the
+ given direction. */
+
+DIRECTION arrow;
+
+{
+ switch (arrow) {
+
+ case NORTH: return(EAST);
+ case EAST: return(SOUTH);
+ case SOUTH: return(WEST);
+ case WEST: ;
+
+ }
+ return(NORTH);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN neighbour (aPoint, direction, bPoint)
+/* Set bPoint to the coordinate of the point that can
+ be found by going one place in the given direction
+ from aPoint. The direction can be NORTH, EAST, WEST
+ or SOUTH. If bPoint will be off the canvas then the
+ function returns FALSE otherwise TRUE. */
+
+POINT aPoint;
+POINT_PTR bPoint;
+DIRECTION direction;
+
+{
+ int x, y;
+
+ switch (direction) {
+
+ case NORTH: x = 0; y = -1; break;
+ case EAST: x = 1; y = 0; break;
+ case SOUTH: x = 0; y = 1; break;
+ case WEST: x = -1; y = 0; break;
+ }
+
+ bPoint->x = aPoint.x + x;
+ bPoint->y = aPoint.y + y;
+
+ if ((bPoint->x >= CANVAS_WIDTH) || (bPoint->x < 0) ||
+ (bPoint->y >= CANVAS_HEIGHT) || (bPoint->y < 0)) return(FALSE);
+
+ return(TRUE);
+}
+
+/* *********************************************************************** */
+
+void initialise_paint (paint)
+/* Set this paint to be a dry, unmixing white. */
+
+PAINT_PTR paint;
+
+{
+ paint->colour.hue = 255;
+ paint->colour.saturation = 0.0;
+ paint->colour.lightness = 1.0;
+ paint->liquid_content = 0;
+ paint->drying_rate = 0;
+ paint->miscibility = 0;
+}
+
+/* *********************************************************************** */
+
+void initialise_cell(cell)
+/* Reset the given cell to a default value. */
+
+CELL_PTR cell;
+
+{
+ initialise_paint (&cell->contents);
+
+ cell->volume = UNFILLED; /* Indicates that no paint has yet been applied.
+*/
+ cell->absorbancy = 10;
+ cell->gravity.direction = SOUTH;
+ cell->gravity.strength = DEFAULT_GRAVITY_STRENGTH;
+}
+
+
+/* *********************************************************************** */
+
+void split_gravity()
+/* This routine is for test purposes only. It causes the right
+ half of the canvas to have gravity going NORTH with the left
+ half having gravity going SOUTH. */
+
+{
+ POINT p;
+ CELL_PTR cell;
+
+ /*for (p.x=CANVAS_WIDTH/2; p.x < CANVAS_WIDTH; p.x++) {*/
+ for (p.x=165; p.x < CANVAS_WIDTH; p.x++) {
+ for (p.y=0; p.y < CANVAS_HEIGHT; p.y++) {
+ cell = get_cell (p);
+ cell->gravity.direction = NORTH;
+ }
+ }
+}
+
+/* *********************************************************************** */
+
+void initialise_canvas()
+/* Before it can be used the canvas needs to be initialised to
+ a default state. This involves setting each of the cells to
+ have no paint and for gravity to be uniformly down. Each cell
+ has the default absorbancy value. */
+
+{
+ POINT p;
+ CELL_PTR cell;
+
+ for (p.x=0; p.x < CANVAS_WIDTH; p.x++) {
+ for (p.y=0; p.y < CANVAS_HEIGHT; p.y++) {
+ cell = get_cell (p);
+ initialise_cell (cell);
+ }
+ }
+}
+
+/* *********************************************************************** */
+
+void print_cell_attributes(cell)
+CELL_PTR cell;
+{
+ printf("Volume = %d\n", cell->volume);
+
+ printf("Liquid content = %d%%\n", cell->contents.liquid_content);
+ printf("Drying rate = %d%%\n", cell->contents.drying_rate);
+ printf("Miscibility = %d%%\n\n", cell->contents.miscibility);
+
+ printf("Saturation = %2f\n", cell->contents.colour.saturation);
+ printf("Lightness = %2f\n", cell->contents.colour.lightness);
+ printf("Hue = %d\n", cell->contents.colour.hue);
+ printf ("------------------------------\n\n");
+}
+
+/* *********************************************************************** */
+
+void blob_cell_alpha (cell)
+CELL_PTR cell;
+
+{
+ cell->contents.liquid_content = 100;
+ cell->contents.drying_rate = 10;
+ cell->contents.miscibility = 80;
+
+ cell->contents.colour.hue = 20;
+ cell->contents.colour.saturation = 1.0;
+ cell->contents.colour.lightness = 0.0;
+
+ cell->volume = 50;
+
+}
+
+/* *********************************************************************** */
+
+void blob_cell_beta (cell)
+CELL_PTR cell;
+
+{
+ cell->contents.liquid_content = 80;
+ cell->contents.drying_rate = 20;
+ cell->contents.miscibility = 90;
+
+ cell->contents.colour.hue = 70;
+ cell->contents.colour.saturation = 1.0;
+ cell->contents.colour.lightness = 0.7;
+
+ cell->volume = 30;
+
+}
+/* *********************************************************************** */
+
+void blob_cell_gamma (cell)
+CELL_PTR cell;
+
+{
+ cell->contents.liquid_content = 80;
+ cell->contents.drying_rate = 40;
+ cell->contents.miscibility = 80;
+
+ cell->contents.colour.hue = 100;
+ cell->contents.colour.saturation = 0.5;
+ cell->contents.colour.lightness = 0.4;
+
+ cell->volume = 50;
+
+}
+
+/* *********************************************************************** */
+
+void old_blob(width)
+/* This routine puts a square blob of various paints
+ of the given side length centred on the canvas.
+ This is used for test purposes. */
+
+int width;
+
+{
+ int count, lump, startx, starty, x, y;
+
+ width = (width > CANVAS_WIDTH) ? CANVAS_WIDTH : width;
+ width = (width > CANVAS_HEIGHT) ? CANVAS_HEIGHT : width;
+
+ printf("This run used a square blob of side %d pixels\n", width);
+ printf ("centred on the canvas. The blob was split into three equal\n");
+ printf ("vertical strips with the following paint attributes:\n\n");
+
+ startx = (CANVAS_WIDTH - width) / 2;
+ starty = (CANVAS_HEIGHT - width) / 2;
+ lump = width / 3;
+
+ count=0;
+ for (x = startx; x < startx + width; x++) {
+ for (y = starty; y < starty + width; y++) {
+ switch (count / lump) {
+
+ case 0: blob_cell_alpha (&canvas[x][y]); break;
+ case 1: blob_cell_beta (&canvas[x][y]); break;
+ default: blob_cell_gamma (&canvas[x][y]); break;
+
+ }
+ }
+ count++;
+ }
+ split_gravity();
+
+ print_cell_attributes (&canvas[startx][starty]);
+ print_cell_attributes (&canvas[startx + lump][starty]);
+ print_cell_attributes (&canvas[startx + (2*lump)][starty]);
+}
+
+gravity_set(x,y,x1,y1,attr)
+int x;
+int y;
+int x1;
+int y1;
+int attr;
+{
+ /* set the canavs absorbancy and gravity to various test values
+ in the region (x,y),(x1,y1)
+ */
+
+ int i,j;
+
+ for (i=x; i < x1; i++ )
+ for (j=y; j < y1; j++) {
+ canvas[i][j].absorbancy = 10; /* default 10 */
+ canvas[i][j].gravity.direction = SOUTH;
+ canvas[i][j].gravity.strength = DEFAULT_GRAVITY_STRENGTH;
+ /*DEFAULT_GRAVITY_STRENGTH*/
+ }
+}
+
+blob_set(x, y, x1, y1, attr)
+int x;
+int y;
+int x1;
+int y1;
+int attr;
+{
+ /* Set a blob of paint in the rectangle (x,y),(x1,y1) with
+ the attribute, attr (can be volume, liquidity or dryness*/
+ int i,j;
+ float colour;
+
+ colour = (3.6 * 122);
+ colour = 64;
+ fprintf(stderr, "attribute value %d %d\n", attr, (int)colour);
+
+
+ for (i=x; i < x1; i++ )
+ for (j=y; j < y1; j++) {
+ canvas[i][j].contents.liquid_content = 80;
+ canvas[i][j].contents.drying_rate = 50;
+ canvas[i][j].contents.miscibility = 80;
+
+ canvas[i][j].contents.colour.hue = (int)colour;
+ canvas[i][j].contents.colour.saturation = 1.0;
+ canvas[i][j].contents.colour.lightness = 0.7;
+
+ canvas[i][j].volume = attr;
+ }
+
+
+}
+
+void blob(type)
+int type;
+{
+
+ /* paint nine test blobs on the canvas */
+
+ /* X Example 1 All attributes at 80% except vol 0 - 100%*/
+
+ /* X Example 2 All attributes at 80% except liq 0 - 100% */
+
+ /* X Example 3 All attributes at 80% except dry 0 - 100% */
+
+ /* X Example 4 All attributes at 80% except absorp 100 - 0% */
+
+ /* X Example 5 All attributes at 80% except gravity 0 - 100% */
+
+ /* X Example 6 All attributes at 80% except direction N,S,E & W */
+
+ blob_set(20, 20, 80, 80, 0);
+ gravity_set(0, 0, 100, 100, SOUTH);
+
+ blob_set(120,20, 180, 80, 22);
+ gravity_set(150, 0, 300, 150, EAST);
+
+ blob_set(220,20,280,80,33);
+ gravity_set(0, 150, 150, 300, NORTH);
+
+ blob_set(20,120,80,180,44);
+ gravity_set(150, 150, 300, 300, WEST);
+
+ blob_set(120,120,180,180,55);
+ gravity_set(100, 100, 200, 200, 55);
+
+ blob_set(220,120, 280,180, 66);
+ gravity_set(200, 100, 300, 200, 66);
+
+ blob_set(20,220,80,280,77);
+ gravity_set(0, 200, 100, 300, 77);
+
+ blob_set(120,220,180,280,88);
+ gravity_set(100, 200, 200, 300, 88);
+
+ blob_set(220,220,280,280, 100);
+ gravity_set(200, 200, 300, 300, 100);
+
+}
+
+void
+load_file(filename, width, height)
+char *filename;
+int *width;
+int *height;
+{
+
+ /* Load in a file using the load_ppm_format() function
+ This loads in a file in Portable Pixmap format
+ */
+
+ load_ppm_format(filename, canvas, width, height);
+}
diff --git a/krita/colorspaces/wetsticky/ws/canvas.h b/krita/colorspaces/wetsticky/ws/canvas.h
new file mode 100644
index 00000000..2df50140
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/canvas.h
@@ -0,0 +1,70 @@
+/*
+ FILE: canvas.h
+ PURPOSE: Defines the public routines for manipulating the canvas.
+ AUTHOR: Kevin Waite
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+
+*/
+
+
+extern int number_of_repaints_needed();
+/* Returns the number of cells needing to repainted. */
+
+extern void need_to_repaint (/* POINT */);
+/* Requests that the cell at the given point be repainted
+ at the next update as it has been modified. */
+
+extern void next_cell_for_repaint (/* *CELL_PTR, POINT_PTR */);
+/* Returns a pointer to a cell that needs to be updated as well
+ as the location of that cell on the canvas. If there are
+ no more cells to be redrawn then the pointer will be NIL. */
+
+extern void next_cell_point (/* POINT_PTR */);
+/* Sets the POINT giving the coordinate location of the next
+ cell on the canvas to be visited. There is an even probability
+ of each cell being visited. */
+
+extern CELL_PTR get_cell (/* POINT */);
+/* This function returns a pointer to the cell at the
+ given address on the canvas. */
+
+extern DIRECTION anti_clockwise_from (/* DIRECTION */);
+/* Returns the direction found going clockwise from the
+ given direction. */
+
+extern DIRECTION clockwise_from (/* DIRECTION */);
+/* Returns the direction found going clockwise from the
+ given direction. */
+
+extern BOOLEAN neighbour (/* POINT, DIRECTION, POINT_PTR */);
+/* Set bPoint to the coordinate of the point that can
+ be found by going one place in the given direction
+ from aPoint. The direction can be NORTH, EAST, WEST
+ or SOUTH. If bPoint will be off the canvas then the
+ function returns FALSE otherwise TRUE. */
+
+extern void initialise_canvas();
+/* Before it can be used the canvas needs to be initialised to
+ a default state. This involves setting each of the cells to
+ have no paint and for gravity to be uniformly down. Each cell
+ has the default absorbancy value. */
+
+extern void blob( /* int */);
+/* This routine puts a square blob of black paint
+ of the given side length centred on the canvas.
+ This is used for test purposes. */
+
+extern void load_file(/*char *, int *, int * */);
+/* Load a file from a portable pixmap into the canvas */
diff --git a/krita/colorspaces/wetsticky/ws/cmap.c b/krita/colorspaces/wetsticky/ws/cmap.c
new file mode 100644
index 00000000..9e53b0ae
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/cmap.c
@@ -0,0 +1,681 @@
+/*
+ FILE: x_interface.c
+ PURPOSE: Creation and access to an X windows interface
+ to wet+sticky using Athena Widgets
+ AUTHOR: David England
+ VERSION: 1.00 (13-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Intrinsic.h>
+
+#include <X11/cursorfont.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Shell.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Label.h>
+#include <stdio.h>
+
+#include "constants.h"
+#include "types.h"
+#include "engine.h"
+#include "canvas.h"
+
+/* Window Heirarchy -
+ Three shell widgets, one for colour output, two for attributes output
+ plus a back_up pixmap for redrawing
+*/
+
+static Widget top_level;
+static Widget colour_shell;
+static Widget colour_box;
+static Widget colour_canvas;
+static Pixmap colour_pm;
+
+static Widget volume_shell;
+static Widget volume_box;
+static Widget volume_canvas;
+static Pixmap volume_pm;
+
+static Widget dryness_shell;
+static Widget dryness_box;
+static Widget dryness_canvas;
+static Pixmap dryness_pm;
+
+static GC gc;
+static GC tmp_gc;
+static long mask;
+static XGCValues values;
+
+static Colormap cmap;
+static XColor colours[256];
+void stroke();
+void stroke_motion();
+
+Display *display;
+int screen;
+Screen *screen_ptr;
+Window root;
+
+static int count=0;
+static int frame_count=0;
+char pix_file[64];
+
+void StartWindow();
+void StartUpWindows();
+
+static XtEventHandler
+expose_event(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the colour window if an exposure event is received */
+int width, height;
+
+ width = height = 300;
+
+ XCopyArea(XtDisplay(colour_canvas), colour_pm,
+ XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0);
+
+}
+
+
+static void
+expose_volume(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the volume window if an exposure event is received */
+int width, height;
+
+ width = height = 300;
+
+ XCopyArea(XtDisplay(volume_canvas), volume_pm,
+ XtWindow(volume_canvas), gc, 0, 0, width, height, 0,0);
+
+
+}
+
+static void
+expose_dryness(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the dryness window if an exposure event is received */
+int width, height;
+
+ width = height = 300;
+
+ XCopyArea(XtDisplay(dryness_canvas), dryness_pm,
+ XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0);
+
+
+}
+
+int
+GetHueValue(red, green, blue)
+int red;
+int green;
+int blue;
+{
+ XColor colour;
+
+ colour.red = red * 257;
+ colour.green = green * 257;
+ colour.blue = blue * 257;
+ colour.flags = DoRed | DoGreen | DoBlue;
+
+ if (XAllocColor(display, cmap, &colour) == 0)
+ fprintf(stderr,"colour allocation failed\n");
+
+ return (colour.pixel);
+}
+
+
+void
+DrawPoint(x,y,colour)
+int x;
+int y;
+int colour;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel);
+
+ XDrawPoint(XtDisplay(top_level), XtWindow(colour_canvas), gc, x, y);
+ XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y);
+}
+
+int
+DrawVolumePoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ /* later - use the range of the volume to affect the colour
+ value
+ */
+
+ if (XtWindow(volume_canvas) == NULL)
+ return (-1);
+
+ XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);
+
+ XDrawPoint(XtDisplay(top_level), XtWindow(volume_canvas), gc, x, y);
+ XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y);
+
+ return(0);
+}
+
+int
+DrawDrynessPoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ /* later - use the range of the dryness to affect the colour
+ value
+ */
+
+ if (XtWindow(dryness_canvas) == NULL)
+ return (-1);
+
+ XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);
+
+ XDrawPoint(XtDisplay(top_level), XtWindow(dryness_canvas), gc, x, y);
+ XDrawPoint(XtDisplay(top_level), dryness_pm, gc, x, y);
+
+ return(0);
+}
+
+void
+ClearWindow()
+{
+ XClearWindow(XtDisplay(top_level), XtWindow(colour_canvas));
+}
+
+static void
+CleanWindow(win)
+Drawable win;
+/* Fill a window with a solid, white rectangle */
+{
+XGCValues values;
+long mask;
+
+ values.background = colours[0].pixel;
+ values.foreground = colours[255].pixel;;
+ values.fill_style = FillSolid;
+ values.function = GXclear;
+
+
+ mask = GCBackground| GCForeground| GCFillStyle | GCFunction;
+
+ tmp_gc = XtGetGC(top_level, mask, &values);
+
+ XFillRectangle(XtDisplay(top_level), win, tmp_gc, 0, 0, 300, 300);
+
+}
+
+void SetupCmap()
+{
+int i;
+
+ for (i=0;i<256;i++) {
+ colours[i].red = i*257;
+ colours[i].flags = DoRed | DoBlue | DoGreen;
+ }
+
+ /* for (i=0;i<=127;i++)
+ colours[i].green = i*2*257;
+
+ for (i=128;i>0;i--)
+ colours[255-i].green = (i-1)*2*257;*/
+
+ for (i=0;i<64;i++)
+ colours[i].green = i*4*257;
+
+ for (i=64;i<128;i++)
+ colours[i].green = 65536-i*4*257;
+
+ for (i=128;i<192;i++)
+ colours[i].green = (i-128)*2*257;
+
+ for (i=192;i<255;i++)
+ colours[i].green = 65536-(i-128)*2*257;
+
+
+ for (i=0;i<256;i++)
+ colours[i].blue = 65536 - i*257;
+
+ colours[0].red = 65535;
+ colours[0].green = 65535;
+ colours[0].blue = 65535;
+}
+
+void
+SetupGreyMap()
+{
+int i;
+
+ for (i=0;i<256;i++) {
+ colours[i].red = i*257;
+ colours[255 - i].flags = DoRed | DoBlue | DoGreen;
+ }
+
+
+ for (i=0;i<256;i++)
+ colours[i].green = i*257;
+
+ for (i=0;i<256;i++)
+ colours[i].blue = i*257;
+
+ colours[255].red = 255*257;
+ colours[255].green = 255*257;
+ colours[255].blue = 255*257;
+
+}
+
+
+main(argc, argv)
+int argc;
+char **argv;
+/* Create colour window heirarchy and add event handlers */
+{
+
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+int width;
+int height;
+ int i;
+
+
+ width = 300;
+ height = 300;
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL,
+ 0, &argc, argv);
+
+
+ display = XtDisplay(top_level);
+ screen = DefaultScreen(display);
+ screen_ptr = ScreenOfDisplay(display, DefaultScreen(display));
+
+ root = RootWindow(display, screen);
+
+ colour_shell = XtCreateApplicationShell("colour_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+
+
+ colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass,
+ colour_shell, NULL, 0);
+
+
+ colour_canvas = XtCreateManagedWidget("", labelWidgetClass,
+ colour_box, args, XtNumber(args));
+
+
+ XtAddEventHandler(colour_canvas, ExposureMask, False, expose_event, 0);
+
+ XtAddEventHandler(colour_canvas, ButtonPressMask, False, stroke, 0);
+
+ XtAddEventHandler(colour_canvas, Button1MotionMask,
+ False, stroke_motion, 0);
+
+ XtRealizeWidget(colour_shell);
+
+ cmap = XCreateColormap( display, XtWindow(colour_shell),
+ XDefaultVisualOfScreen(screen_ptr), AllocAll);
+
+ for (i=0; i <= 255; i++)
+ colours[i].pixel = i;
+
+ XQueryColors(display, DefaultColormapOfScreen(screen_ptr),colours, 256);
+
+ /*SetupCmap();*/
+
+ SetupGreyMap();
+
+ XStoreColors(display, cmap, colours, 256);
+
+ i=0;
+ while( XAllocColorCells( display, DefaultColormapOfScreen(screen_ptr),
+ True, NULL, 0, &colours[i].pixel, 1 ) ) {
+ colours[i].pixel = i;
+ i++;
+ }
+
+ XSetWindowColormap(display, XtWindow(colour_shell), cmap);
+
+ XInstallColormap(display, cmap);
+
+ mask = GCBackground| GCForeground| GCFunction;
+
+ values.function = GXcopy;
+ values.background = colours[0].pixel;
+ values.foreground = colours[255].pixel;
+
+
+ gc = XtGetGC(colour_canvas, mask, &values);
+
+ colour_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ CleanWindow(colour_pm);
+
+ StartWindow (CANVAS_WIDTH, CANVAS_HEIGHT);
+
+ StartUpWindows();
+}
+
+
+void StartWindow(width, height)
+int width;
+int height;
+/* Create Volume heirarchy and add event handlers */
+{
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ volume_shell = XtCreateApplicationShell("volume_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+ volume_box = XtCreateManagedWidget("volume_box", boxWidgetClass,
+ volume_shell, NULL, 0);
+
+ volume_canvas = XtCreateManagedWidget("", labelWidgetClass,
+ volume_box, args, XtNumber(args));
+
+ XtAddEventHandler(volume_canvas, ExposureMask, False,
+ expose_volume, 0);
+
+ XtRealizeWidget(volume_shell);
+
+ XSetWindowColormap(display, XtWindow(volume_shell), cmap);
+
+ volume_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ CleanWindow(volume_pm);
+
+
+}
+
+void StartDrynessWindow(width, height)
+int width;
+int height;
+/* Create dryness heirarchy and add event handlers */
+{
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ dryness_shell = XtCreateApplicationShell("dryness_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+ dryness_box = XtCreateManagedWidget("dryness_box", boxWidgetClass,
+ dryness_shell, NULL, 0);
+ dryness_canvas
+= XtCreateManagedWidget("", labelWidgetClass,
+ dryness_box, args, XtNumber(args));
+
+ XtAddEventHandler(dryness_canvas, ExposureMask, False,
+ expose_dryness, 0);
+
+ XtRealizeWidget(dryness_shell);
+
+ XSetWindowColormap(display, XtWindow(dryness_shell), cmap);
+
+ dryness_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ CleanWindow(dryness_pm);
+
+}
+
+static void
+draw_labels()
+{
+ XSetForeground(XtDisplay(colour_shell), gc, colours[1].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(colour_canvas), gc, 10, 10,
+ "Colour", strlen("Colour"));
+ XDrawString(XtDisplay(colour_shell), colour_pm, gc, 10, 10,
+ "Colour", strlen("Colour"));
+
+ XSetForeground(XtDisplay(colour_shell), gc, colours[128].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(volume_canvas), gc, 10, 10,
+ "Volume", strlen("Volume"));
+ XDrawString(XtDisplay(colour_shell), volume_pm, gc, 10, 10,
+ "Volume", strlen("Volume"));
+
+ XSetForeground(XtDisplay(colour_shell), gc, colours[255].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(dryness_canvas), gc, 10, 10,
+ "Bump Map", strlen("Bump Map"));
+ XDrawString(XtDisplay(colour_shell), dryness_pm, gc, 10, 10,
+ "Bump Map", strlen("Bump Map"));
+}
+
+void paint_cell(cell, x, y)
+CELL_PTR cell;
+int x, y;
+
+{
+ int colour, volColour, dryness;
+ POINT p;
+
+ p.x = x;
+ p.y = y;
+
+ /* The current display simply maps hue onto the indices of the colour
+ table. This involves some scaling since hues are in the range [0,360)
+ with the colour table being [0,256). */
+
+ colour = (int) (cell->contents.colour.hue *
+ ((float) MAX_COLOUR_INDEX / 360.0));
+
+ /*DrawPoint(x,y,colour); */
+
+ /* volColour is an index into the colour table in the range [0,255].
+ It is used to give a false colour image of the canvas's volume. */
+
+ /*if (x < SCALE_WIDTH) return; Don't draw over colour scale. */
+
+ volColour = MIN(cell->volume * 2, 255);
+ volColour = MAX(volColour, 0);
+ /* Make unfilled cells have a zero vol. */
+
+ /*DrawVolumePoint(x,y,volColour);*/
+
+ /* Dryness will be in the range [0,255]. */
+ dryness = (cell->contents.liquid_content * 255) / 100;
+
+ /*DrawDrynessPoint(x,y,dryness);*/
+}
+
+
+
+void draw_false_colour_scale()
+/* This routine places a scale along the top of the volume window
+ showing the colours being used. Low is at the left edge.
+ The colour palette has indices 0..255. */
+{
+ int x, y;
+
+ /*for (x=0; x < 255; x++)
+ for (y=0; y < SCALE_WIDTH; y++) DrawVolumePoint(x,y,MIN(x, 255));*/
+}
+
+
+void draw_full_canvas()
+{
+ int x, y;
+ CELL_PTR cell;
+ POINT p;
+
+ if (DEBUG) {
+ printf ("Starting to paint full canvas...");
+ fflush(stdout);
+ }
+
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ for (y=0; y < CANVAS_HEIGHT; y++) {
+ p.x = x;
+ p.y = y;
+ /*cell = get_cell(p);*/
+ paint_cell(cell, x, y);
+ }
+ }
+ draw_false_colour_scale();
+ if (DEBUG) printf ("done.\n");
+}
+
+void
+bump_map()
+{
+ POINT p;
+ CELL_PTR cell;
+ register int x, y;
+ register int colour;
+
+
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ for (y=0; y < CANVAS_HEIGHT; y++) {
+ p.x = x;
+ p.y = y;
+ /*cell = get_cell(p);*/
+ /*colour = (int) new_intensity_value(p);*/
+
+/* colour = (int) (cell->contents.colour.hue *
+ ((float) MAX_COLOUR_INDEX / 360.0));*/
+ DrawDrynessPoint(x,y,colour);
+ }
+ }
+
+}
+
+
+void evolve_paint()
+{
+
+}
+
+
+
+void StartUpWindows()
+{
+/* Start the X windows event loop and paint processing */
+XEvent event;
+
+
+
+ for (;;) {
+ if (XtPending()) {
+ XtNextEvent(&event);
+ XtDispatchEvent(&event);
+ }
+ else {
+ /* Evolve paint and re-display*/
+ evolve_paint();
+ }
+
+ } /* End for loop */
+
+
+}
+
+void
+stroke(w, client_data, event)
+Widget w;
+caddr_t client_data;
+XEvent *event;
+{
+/* brush_stroke(event->xbutton.x, event->xbutton.y);*/
+
+
+ /*if ((XEvent *)event != (XEvent *)NULL)
+ else
+ printf("Null event\n"); */
+
+/* DrawPoint(event->xbutton.x, event->xbutton.y, 128);
+ DrawVolumePoint(event->xbutton.x, event->xbutton.y, 128);
+ DrawDrynessPoint(event->xbutton.x, event->xbutton.y, 128);*/
+
+
+ XSetForeground(XtDisplay(top_level), gc, colours[128].pixel);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ /*XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);*/
+
+ /*brush_stroke(event->xbutton.x, event->xbutton.y);*/
+}
+
+
+void
+stroke_motion(w, client_data, event)
+Widget w;
+caddr_t client_data;
+XEvent *event;
+{
+
+
+ /*if ((XEvent *)event != (XEvent *)NULL)
+ else
+ printf("Null event\n"); */
+
+
+ XSetForeground(XtDisplay(top_level), gc, colours[128].pixel);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+ XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ /*brush_stroke(event->xbutton.x, event->xbutton.y);*/
+}
+
diff --git a/krita/colorspaces/wetsticky/ws/constants.h b/krita/colorspaces/wetsticky/ws/constants.h
new file mode 100644
index 00000000..fa72bc92
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/constants.h
@@ -0,0 +1,69 @@
+/*
+ FILE: constants.h
+ PURPOSE: Constains all the #DEFINES for Wet&Sticky.
+ AUTHORS: Kevin Waite and David England
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+
+*/
+
+/* Some utility constants. */
+
+#define TRUE 1
+#define FALSE 0
+#define YES 1
+#define NO 0
+#define NIL 0
+#define DEBUG 1
+#define VERSION "1.0"
+
+/* Define the constants for colours in the HLS space. */
+
+#define UNFILLED -1
+#define MAX_COLOUR_INDEX 255
+
+
+/* Define the dimensions of the intelligent canvas. */
+
+#define CANVAS_WIDTH 300
+#define CANVAS_HEIGHT 300
+#define SCALE_WIDTH 30
+
+
+/* Define constants that control the evolution of the paint. */
+
+#define STEP_LIMIT 200
+#define REDRAW_LIMIT 500
+
+
+/* Define some constants used in testing the system. */
+
+#define DEFAULT_BLOB_SIZE (CANVAS_WIDTH / 3)
+#define BLOB_NAME "-blob"
+
+
+/* Constants used in modelling gravity. */
+
+#define NORTH 0
+#define EAST 1
+#define SOUTH 2
+#define WEST 3
+
+#define DEFAULT_GRAVITY_STRENGTH 10
+
+
+/* Define some macros. */
+
+#define MAX(A,B) ((A) > (B) ? (A) : (B))
+#define MIN(A,B) ((A) < (B) ? (A) : (B))
diff --git a/krita/colorspaces/wetsticky/ws/engine.c b/krita/colorspaces/wetsticky/ws/engine.c
new file mode 100644
index 00000000..19097d9f
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/engine.c
@@ -0,0 +1,802 @@
+/*
+ FILE: engine.c
+ PURPOSE: Defines the routines for the Paint Engine.
+ AUTHOR: Kevin Waite
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "constants.h"
+#include "types.h"
+#include "canvas.h"
+#include <math.h>
+
+extern double HEIGHT_SCALE;
+
+/* *********************************************************************** */
+
+int random_percent()
+/* This function returns a random number in the range [0,100]. */
+{
+ extern long random();
+
+ return (random() % 101);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN allow_event_based_on(value)
+/* The given value is a percentage. Compare this value
+ with a randomly generated percentage and if it is larger
+ then allow the event to happen (i.e. return TRUE) other-
+ wise return FALSE. */
+
+int value;
+
+{
+ if (value > random_percent()) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN age_paint(cell)
+/* Make the paint in the given cell older, i.e. let
+ if dry out a bit if it isn't already dry. This
+ function returns TRUE if the paint was already
+ dry or becomes so, and FALSE otherwise. */
+
+CELL_PTR cell;
+
+{
+ if (cell->volume == 0) return(TRUE);
+ if (cell->contents.liquid_content == 0) return(TRUE);
+ if (allow_event_based_on(cell->contents.drying_rate) == TRUE)
+ cell->contents.liquid_content--;
+
+ if (cell->contents.liquid_content == 0) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN similar_paint(aPaint, bPaint)
+/* Determine whether the two paints are similar. It is
+ assumed that aPaint has come from the host cell (and
+ so it is its miscibility value that is used). The
+ function returns TRUE if the paints are similar and
+ FALSE otherwise. */
+
+PAINT aPaint, bPaint;
+
+{
+ int delta;
+
+ delta = abs(aPaint.liquid_content - bPaint.liquid_content);
+ if (delta <= aPaint.miscibility) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+int surplus_paint(cell)
+/* Returns the amount of paint held by this cell greater than its
+ absorbancy value. This is the amount of paint that can flow. */
+
+CELL_PTR cell;
+
+{
+ return (MAX(cell->volume - cell->absorbancy, 0));
+}
+
+/* *********************************************************************** */
+
+BOOLEAN has_surplus_paint(cell)
+/* Does the given cell have excess paint, i.e. can paint flow out
+ of this cell. Return TRUE if it can and FALSE otherwise. */
+
+CELL_PTR cell;
+
+{
+ if (surplus_paint(cell) > 0) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+void stop() { /* Used for breakpointing. */ }
+
+void donate_paint(source, srcLocus, amount, dest, destLocus)
+/* The source cell is donating the specified volume of its paint
+ to the destination cell. The destination cell must mix this
+ new paint with its existing paint to yield a new paint.
+ This routine is also responsible for recording which cells
+ have been updated and so need repainting.
+
+ A special case is recognised where the destination has not yet
+ had any paint applied. This causes the donated paint to become
+ to new contents of this cell.
+
+*/
+
+CELL_PTR source, dest;
+POINT srcLocus, destLocus;
+int amount;
+
+{
+ float delta, ratio;
+ int iDelta;
+
+ source->volume -= amount;
+
+ if (dest->volume == UNFILLED) {
+
+ /* The donated paint is going into an unfilled cell.
+ Copy the source's attributes into the destination. */
+
+ dest->volume = amount;
+ dest->contents.colour.hue = source->contents.colour.hue;
+ dest->contents.colour.lightness = source->contents.colour.lightness;
+ dest->contents.colour.saturation = source->contents.colour.saturation;
+ dest->contents.liquid_content = source->contents.liquid_content;
+ dest->contents.miscibility = source->contents.miscibility;
+ dest->contents.drying_rate = source->contents.drying_rate;
+
+ } else {
+
+ /* Need to mix the existing paint in the dest with this amount
+ of new paint from the source. This is done using a linear
+ interpolation mechanism using the relative amounts of the
+ paint as the control. */
+
+ if (dest->volume != 0)
+ ratio = amount / (float)(dest->volume);
+
+ iDelta = source->contents.colour.hue - dest->contents.colour.hue;
+ if (iDelta != 0) {
+ dest->contents.colour.hue += (int)(ratio * iDelta);
+ if (dest->contents.colour.hue >= 360)
+ dest->contents.colour.hue -= 360;
+ }
+
+ iDelta = source->contents.drying_rate - dest->contents.drying_rate;
+ dest->contents.drying_rate += (int)((int)ratio * iDelta);
+ dest->contents.drying_rate %= 101;
+
+ iDelta = source->contents.liquid_content - dest->contents.liquid_content;
+ dest->contents.liquid_content += (int)(ratio * iDelta);
+ dest->contents.liquid_content %= 101;
+
+ iDelta = source->contents.miscibility - dest -> contents.miscibility;
+ dest->contents.miscibility += (int)(ratio * iDelta);
+ dest->contents.miscibility %= 101;
+
+ delta = source -> contents.colour.saturation - dest -> contents.colour.saturation;
+ dest -> contents.colour.saturation += ratio * delta;
+
+ delta = source->contents.colour.lightness - dest->contents.colour.lightness;
+ dest->contents.colour.lightness += ratio * delta;
+
+ dest->volume += amount; /* The new volume of paint in dest. */
+
+ }
+
+ need_to_repaint(destLocus);
+}
+
+/* *********************************************************************** */
+
+void handle_surface_tension(cell, locus)
+/* This routine handles the surface tension around the given cell.
+*/
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ DIRECTION direction[3];
+ POINT loci[3];
+ CELL_PTR buddy[3];
+ BOOLEAN ok, similar[3];
+ int weakCount, weak[3], count[3], excess, chosen, side, start, finish,
+k, lowest;
+
+ if (has_surplus_paint(cell) == FALSE) return;
+
+ direction[0] = cell->gravity.direction;
+ direction[1] = clockwise_from(direction[0]);
+ direction[2] = anti_clockwise_from(direction[0]);
+
+ for (k=0; k < 3; k++) {
+ ok = neighbour(locus, direction[k], &loci[k]);
+ if (ok == TRUE) {
+ buddy[k] = get_cell(loci[k]);
+ count[k] = 0;
+ } else count[k] = -1;
+ }
+
+ for (k=0; k < 3; k++)
+ similar[k] = (count[k] == -1)
+ ? FALSE
+ : similar_paint(cell->contents, buddy[k]->contents);
+
+ for (k=0; k < 3; k++) {
+ if ((count[k] != -1) && (similar[k] == FALSE)) {
+ count[k] = 0;
+ start = MAX(k-1, 0);
+ finish = MIN(k+1, 2);
+ for (side=start; side <= finish; side++)
+ if ((count[side] != -1) && (similar[side] == FALSE)) count[k]++;
+
+ }
+ }
+
+ lowest = 4;
+ for (k=0; k < 3; k++) if (count[k] >= 0) lowest = MIN(count[k], lowest);
+
+ weakCount = 0;
+ for (k=0; k < 3; k++) if (count[k] == lowest) weak[weakCount++] = k;
+
+ /* The weak array now holds weakCount indices of those sides that have
+ the lowest surface tension and therefore where any paint would flow over.
+ Now it is necessary to see whether paint will actually flow based on
+ a probability level using the liquidity and volume of the paint in the
+ cell as parameters. Paint will flow over only one of the weakest sides
+ with the side chosen at random. */
+
+ if (random_percent() > cell->contents.liquid_content) return; /* Too
+viscous. */
+
+ excess = surplus_paint(cell);
+ if (random_percent() > excess * 3) return;
+ /* The '3' in the previous statement is an empirically-derived multiplier.
+*/
+
+ /* The paint will flow. Pick one of the weakest sides at random. */
+
+ chosen = weak[random_percent() % weakCount];
+ donate_paint(cell, locus, (excess / 2), buddy[chosen], loci[chosen]);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN diffuse_paint(cell, locus)
+/* Diffuse paint among the neighbours of the given cell.
+ If this cell does not have surplus paint then return
+ TRUE otherwise return FALSE. */
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ extern long random();
+ DIRECTION down, direction;
+ CELL_PTR buddy;
+ POINT nlocus;
+ BOOLEAN ok;
+ int excess;
+
+ if (has_surplus_paint(cell) == FALSE) return(TRUE);
+
+ down = cell->gravity.direction;
+ direction = ((random() & 01) == 0)
+ ? clockwise_from(down)
+ : anti_clockwise_from(down);
+
+ ok = neighbour(locus, direction, &nlocus);
+ if (ok == FALSE) return(TRUE);
+
+ buddy = get_cell(nlocus);
+
+ if (similar_paint(cell->contents, buddy->contents) == FALSE) {
+ handle_surface_tension(cell, locus);
+ return(FALSE);
+ }
+
+ if (buddy->volume >= cell->volume) return(FALSE);
+
+ if (allow_event_based_on(cell->contents.liquid_content) == FALSE)
+ return(FALSE);
+
+ /* Transfer one particle of paint from cell to its buddy. */
+
+ excess = (cell->volume - buddy->volume) / 2;
+ donate_paint(cell, locus, excess, buddy, nlocus);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN apply_gravity(cell, locus)
+/* Subject the contents of the given cell to the effects
+ of gravity. Note that the direction of gravity is local
+ to the given cell. Locus is the address of this cell.
+ This function returns TRUE if the paint in this cell
+ cannot flow and FALSE otherwise.
+*/
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ extern long random();
+ POINT downhill;
+ CELL_PTR down;
+ BOOLEAN ok, can_flow;
+ int barrier, excess;
+
+ ok = neighbour(locus, cell->gravity.direction, &downhill);
+ if (ok == FALSE) return(TRUE); /* At bottom of canvas. */
+
+ down = get_cell(downhill);
+
+ can_flow = down->volume < (cell->volume + cell->gravity.strength)
+ ? TRUE : FALSE;
+
+ if (can_flow == FALSE) return(TRUE);
+
+ /* Although this paint can flow introduce a random value that
+ uses the viscosity of the paint to determine whether it does
+ actually flow. */
+
+ barrier = random() % 10;
+ if (cell->contents.liquid_content > barrier) {
+ /* Paint is actually moving. Move half of the excess downward. */
+
+ excess = (cell->volume - cell->absorbancy) / 2;
+ donate_paint(cell, locus, excess, down, downhill);
+ }
+
+ return(FALSE);
+}
+
+
+float lx, ly, lz;
+
+void
+compute_shade_vectors()
+{
+ extern float lx, ly, lz;
+ float D;
+
+ lx = 1.0; ly = -1.0; lz = 3.0;
+
+ D = sqrt ( lx * lx + ly * ly + lz * lz );
+
+ lx = lx/D; ly = ly/D; lz = lz/D;
+
+}
+
+/* *********************************************************************** **
+ **
+** new_intensity_value **
+** **
+** calculates shade value for a pixel from surface characteristics ** **
+ **
+** Revision History **
+** **
+** Rev Date By Description **
+** 1.0 1/12/91 DE Original **
+** 1.1 1/04/92 DE Include Phong Shading **
+** 1.2 11/08/92 JWP Parameterized Specular Component ** **
+ **
+*********************************************************************** */
+
+float calc_d();
+float calc_g();
+float calc_f();
+float sqr();
+void printvector();
+void vectscale();
+void vectadd();
+float magnitude();
+
+float
+normalize (x, y, z)
+ float x, y, z; /*vector x, y, z components*/
+{
+ float result;
+
+ /* function calculates the amount to divide each vector component
+ to normalize it to a unit vector. The parameters are the x,y,z
+ components and the result is the amount to divide by */
+
+ result = sqrt (x*x + y*y + z*z);
+ return (result);
+
+ }
+
+
+
+float Newnormalize(V, W)
+float *V;
+float *W;
+{
+ float temp;
+
+ temp = normalize(V[0], V[1], V[2]);
+
+ W[0] = V[0]/temp;
+ W[1] = V[1]/temp;
+ W[2] = V[2]/temp;
+
+ return temp;
+}
+
+float dot(V, W)
+ float V[3];
+ float W[3];
+{
+
+ return ( (V[0])*(W[0]) + (V[1])*(W[1]) + (V[2])*(W[2]) );
+
+}
+
+float Phong (Nv, Lv, Ev, shine)
+float Nv[3];
+float Lv[3];
+float Ev[3];
+float shine;
+{
+ float Hv[3];
+
+ Newnormalize(Ev, Ev);
+
+ Hv[0] = Ev[0] + Lv[0];
+ Hv[1] = Ev[1] + Lv[1];
+ Hv[2] = Ev[2] + Lv[2];
+
+ Newnormalize (Hv, Hv);
+
+ shine = abs(shine);
+ return( pow(dot(Nv, Hv), shine) );
+}
+
+
+/******************* Auxillary functions *****************************/
+
+/* Function : calc_c
+* Returns : the microfacet distribution function */
+
+float calc_d(cos_alpha,c3)
+float cos_alpha;
+float c3;
+{
+float d;
+d=sqr( sqr(c3) / ( sqr(cos_alpha)*(sqr(c3) -1) +1)); return d;
+}
+
+/*
+* Function : calc_g
+* Returns : the geometrical attenuation factor. *
+* This function should return values between 0.0 and 1.0, so if it's * negative I will return 0.0 Anyway it does not seem to make any difference * at all whether I return 0.0, the negative value or the minimum of the * absolute values of (temp1,temp2,temp3) */
+
+float calc_g(N,H,L,V)
+float N[3]; /* Normal vector */
+float H[3]; /* Half-way vector */
+float L[3]; /* Light vector */
+float V[3]; /* View vector */
+{
+ float temp1,temp2,temp3,ret;
+ float NdotH,NdotV,NdotL,VdotH;
+ NdotH=dot(N,H);
+ NdotV=dot(N,V);
+ NdotL=dot(N,L);
+ VdotH=dot(V,H);
+ temp1=1.0;
+ temp2=(2*NdotH*NdotV)/VdotH;
+ temp3=(2*NdotH*NdotL)/VdotH;
+ /* Find minimum value */
+ if (temp1 < temp2)
+ if (temp1 < temp3)
+ ret=temp1;
+ else
+ ret=temp3;
+ else
+ if (temp2 < temp3)
+ ret=temp2;
+ else
+ ret=temp3;
+ if (ret < 0.0)
+ ret=0.0;
+ return ret;
+}
+
+/* Function : calc_f
+* Returns : the Fresnel term
+*/
+
+float calc_f(L,H,mu)
+float L[3];
+float H[3];
+float mu;
+{
+ float temp1,temp2;
+ float c,g;
+ c=dot(L,H);
+ g=sqrt(sqr(mu)+sqr(c) -1);
+ temp1 = (sqr(g-c)/sqr(g+c))*0.5;
+ temp2 = 1+(sqr( c*(g+c)-1 ) / sqr( c*(g-c)+1)); return (temp1*temp2);
+}
+
+/* Function : sqr
+* Returns : the square of its argument
+*/
+
+float sqr(x)
+float x;
+{
+ return (x*x);
+}
+
+/* Function : printvector
+* prints the contents of a vector with 3 elements */
+
+void printvector(v)
+float v[3];
+{
+ printf("[%f,%f,%f] ",v[0],v[1],v[2]);
+}
+
+void vectscale(v1, k, vout, n)
+float *v1;
+float k;
+float *vout;
+int n;
+{ vout[0] = v1[0]*k;
+ vout[1] = v1[1]*k;
+ vout[2] = v1[2]*k;
+}
+
+void vectadd(v1, v2, vout, n)
+float *v1, *v2, *vout;
+int n;
+{ vout[0] = v1[0] + v2[0];
+ vout[1] = v1[1] + v2[1];
+ vout[2] = v1[2] + v2[2];
+}
+
+float magnitude(v)
+float *v;
+{ return( normalize(v[0], v[1], v[2]) );
+}
+
+float T_S(Nv, Lv, Ev, shine)
+float Nv[3]; /* Normalized Normal vector */
+float Lv[3]; /* Normalized Light-source vector */
+float Ev[3]; /* Un-normalized Eye vector */
+float shine; /* parameter to absorb Phong coeff */
+{
+ float Hv[3]; /* Half-way vector H */
+ float cos_alpha;
+ float t;
+ float mdf; /* Micro facet distribtuion function */
+ float gaf; /* Geometrical attenuation factor*/ float ft; /* The Fresnel term */
+ float c3;
+ float mu; /* Refractive index */
+
+ /*initialize appearance constants*/
+ c3 = shine;
+ mu = 200.0;
+
+ /*normalize eye vector*/
+
+ Newnormalize(Ev, Ev);
+
+/* Calculate the half-way vector H, between the light vector and the
+view vector */
+
+ vectadd(Ev,Lv,Hv,3);
+ t = magnitude(Hv,3);
+
+ vectscale(Hv,(1/t),Hv,3);
+
+ /* Calculate the micro-facet distribution function D */
+
+ cos_alpha=dot(Nv,Hv);
+ mdf=calc_d(cos_alpha,c3);
+
+
+ /* Calculate the geometrical attenuation factor */
+
+ gaf=calc_g(Nv,Hv,Lv,Ev);
+
+ /* Calculate the Fresnel Term */
+
+ ft=calc_f(Lv,Hv,mu);
+
+ /* Calculate specular component */
+
+ return( (mdf*gaf*ft) / dot(Nv,Lv) );
+}
+
+
+
+
+float
+new_intensity_value(a_pnt)
+POINT a_pnt;
+/* Calculate the new intensity value of a pixel
+in order to construct a bump map of the paint surface
+*/
+{
+float h, h1, h2, h3, h4;
+ float shininess;
+float Ka, Kd, Ks;
+ float wetmax, degree, norm, distance;
+ float g;
+float Nv[3];
+ float Ev[3];
+ float Hv[3];
+ float Lv[3];
+ extern float lx, ly, lz;
+float intensity, light_intensity;
+int liquid;
+POINT b_pnt;
+CELL_PTR cell;
+CELL_PTR next_cell;
+ int x_cntr, y_cntr;
+
+ Ka = 0.0;
+ Kd = 0.5;
+ Ks = 0.5;
+
+ wetmax = 100.0;
+ distance = 2500.0;
+ light_intensity = 2.0;
+ shininess = 0.3;
+
+ cell = get_cell(a_pnt);
+
+ h = (float)cell->volume;
+
+ if (neighbour(a_pnt, NORTH, &b_pnt)) {
+ next_cell = get_cell(b_pnt);
+ h1 = (float)next_cell->volume;
+ } else
+ h1 = h;
+
+ if (neighbour(a_pnt, EAST, &b_pnt)) {
+ next_cell = get_cell(b_pnt);
+ h2 = (float)next_cell->volume;
+ } else
+ h2 = h;
+
+ if (neighbour(a_pnt, SOUTH, &b_pnt)) {
+ next_cell = get_cell(b_pnt);
+ h3 = (float)next_cell->volume;
+ } else
+ h3 = h;
+
+ if (neighbour(a_pnt, WEST, &b_pnt)) {
+ next_cell = get_cell(b_pnt);
+ h4 = (float)next_cell->volume;
+ } else
+ h4 = h;
+
+ h1 = h1/HEIGHT_SCALE;
+ h2 = h2/HEIGHT_SCALE;
+ h3 = h3/HEIGHT_SCALE;
+ h4 = h4/HEIGHT_SCALE;
+
+ /* test fix for "disappearing" paint */
+
+ if (cell->contents.liquid_content == 0)
+ liquid = 1;
+ else
+ liquid = cell->contents.liquid_content;
+
+ degree = (float)abs(liquid)/wetmax;
+
+ x_cntr= 150 - a_pnt.x;
+ y_cntr= 150 - a_pnt.y;
+
+ Ks = light_intensity * Ks /* * degree*/ ;
+
+ Kd = light_intensity * Kd;
+
+/* shininess = shininess/degree; */
+
+
+ Nv[1] = h3 - h1;
+ Nv[0] = h4 - h2;
+ Nv[2] = 4.0;
+
+ Newnormalize (Nv, Nv);
+
+ Lv[0] = lx;
+ Lv[1] = ly;
+ Lv[2] = lz;
+
+ g = dot(Lv, Nv)*Kd + Ka;
+
+ g = g * (float)cell->contents.colour.hue;
+
+ Ev[0] = (float)x_cntr;
+ Ev[1] = (float)y_cntr;
+ Ev[2] = distance;
+
+ intensity = g + Ks*T_S(Nv, Lv, Ev, shininess);
+
+ if ( intensity > 255.0 ) {
+ intensity = 0.0;
+ } else {
+ if (intensity < 0.0)
+ intensity = 255.0;
+ else
+ intensity = 255.0 - intensity;
+ }
+
+
+ /*printf("wetness %d colour %d intensity %f guraud %f phong %f\n",
+ cell->contents.liquid_content,
+ cell->contents.colour.hue,
+ intensity,
+ g,
+ intensity - g);*/
+
+
+return (intensity);
+}
+
+
+/* *********************************************************************** */
+
+void single_step()
+/* This routine defines the paint steps involved in the
+ basic cycle of the painting engine. */
+
+{
+ POINT locus;
+ CELL_PTR cell;
+ BOOLEAN done;
+
+ next_cell_point(&locus);
+ cell = get_cell(locus);
+
+ done = age_paint(cell);
+ if (done == TRUE) return;
+
+ done = diffuse_paint(cell, locus);
+ if (done == TRUE) return;
+
+ done = apply_gravity(cell, locus);
+}
+
+brush_stroke(x,y)
+int x;
+int y;
+{
+ POINT pnt;
+ CELL_PTR cell;
+
+
+ pnt.x = x;
+ pnt.y = y;
+
+ cell = get_cell(pnt);
+
+ cell->contents.liquid_content = 100;
+ cell->contents.drying_rate = 10;
+ cell->contents.miscibility = 80;
+
+ cell->contents.colour.hue = 128;
+ cell->contents.colour.saturation = 1.0;
+ cell->contents.colour.lightness = 0.0;
+
+ cell->volume = 50;
+
+}
+
+
diff --git a/krita/colorspaces/wetsticky/ws/engine.h b/krita/colorspaces/wetsticky/ws/engine.h
new file mode 100644
index 00000000..b6072b0a
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/engine.h
@@ -0,0 +1,33 @@
+/*
+ FILE: engine.h
+ PURPOSE: Defines the routines for the Paint Engine.
+ AUTHOR: Kevin Waite
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+
+*/
+
+extern void single_step();
+/* This routine defines the paint steps involved in the
+ basic cycle of the painting engine. */
+
+extern brush_stroke();
+
+extern float intensity_value( /* POINT */);
+
+extern float new_intensity_value( /* POINT */);
+
+extern void compute_shade_vectors();
+
+
diff --git a/krita/colorspaces/wetsticky/ws/engine3.c b/krita/colorspaces/wetsticky/ws/engine3.c
new file mode 100644
index 00000000..03a7d4f3
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/engine3.c
@@ -0,0 +1,617 @@
+/*
+ FILE: engine.c
+ PURPOSE: Defines the routines for the Paint Engine.
+ AUTHOR: Kevin Waite
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "constants.h"
+#include "types.h"
+#include "canvas.h"
+#include <math.h>
+
+#define HEIGHT_SCALE 1.0
+
+/* *********************************************************************** */
+
+int random_percent()
+/* This function returns a random number in the range [0,100]. */
+{
+ extern long random();
+
+ return (random() % 101);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN allow_event_based_on(value)
+/* The given value is a percentage. Compare this value
+ with a randomly generated percentage and if it is larger
+ then allow the event to happen (i.e. return TRUE) other-
+ wise return FALSE. */
+
+int value;
+
+{
+ if (value > random_percent()) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN age_paint(cell)
+/* Make the paint in the given cell older, i.e. let
+ if dry out a bit if it isn't already dry. This
+ function returns TRUE if the paint was already
+ dry or becomes so, and FALSE otherwise. */
+
+CELL_PTR cell;
+
+{
+ if (cell->volume == 0) return(TRUE);
+ if (cell->contents.liquid_content == 0) return(TRUE);
+ if (allow_event_based_on(cell->contents.drying_rate) == TRUE)
+ cell->contents.liquid_content--;
+
+ if (cell->contents.liquid_content == 0) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN similar_paint(aPaint, bPaint)
+/* Determine whether the two paints are similar. It is
+ assumed that aPaint has come from the host cell (and
+ so it is its miscibility value that is used). The
+ function returns TRUE if the paints are similar and
+ FALSE otherwise. */
+
+PAINT aPaint, bPaint;
+
+{
+ int delta;
+
+ delta = abs(aPaint.liquid_content - bPaint.liquid_content);
+ if (delta <= aPaint.miscibility) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+int surplus_paint(cell)
+/* Returns the amount of paint held by this cell greater than its
+ absorbancy value. This is the amount of paint that can flow. */
+
+CELL_PTR cell;
+
+{
+ return (MAX(cell->volume - cell->absorbancy, 0));
+}
+
+/* *********************************************************************** */
+
+BOOLEAN has_surplus_paint(cell)
+/* Does the given cell have excess paint, i.e. can paint flow out
+ of this cell. Return TRUE if it can and FALSE otherwise. */
+
+CELL_PTR cell;
+
+{
+ if (surplus_paint(cell) > 0) return(TRUE);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+void stop() { /* Used for breakpointing. */ }
+
+void donate_paint(source, srcLocus, amount, dest, destLocus)
+/* The source cell is donating the specified volume of its paint
+ to the destination cell. The destination cell must mix this
+ new paint with its existing paint to yield a new paint.
+ This routine is also responsible for recording which cells
+ have been updated and so need repainting.
+
+ A special case is recognised where the destination has not yet
+ had any paint applied. This causes the donated paint to become
+ to new contents of this cell.
+
+*/
+
+CELL_PTR source, dest;
+POINT srcLocus, destLocus;
+int amount;
+
+{
+ float delta, ratio;
+ int iDelta;
+
+ source->volume -= amount;
+
+ if (dest->volume == UNFILLED) {
+
+ /* The donated paint is going into an unfilled cell.
+ Copy the source's attributes into the destination. */
+
+ dest->volume = amount;
+ dest->contents.colour.hue = source->contents.colour.hue;
+ dest->contents.colour.lightness = source->contents.colour.lightness;
+ dest->contents.colour.saturation = source->contents.colour.saturation;
+ dest->contents.liquid_content = source->contents.liquid_content;
+ dest->contents.miscibility = source->contents.miscibility;
+ dest->contents.drying_rate = source->contents.drying_rate;
+
+ } else {
+
+ /* Need to mix the existing paint in the dest with this amount
+ of new paint from the source. This is done using a linear
+ interpolation mechanism using the relative amounts of the
+ paint as the control. */
+
+ ratio = amount / (float)(dest->volume);
+
+ iDelta = source->contents.colour.hue - dest->contents.colour.hue;
+ if (iDelta != 0) {
+ dest->contents.colour.hue += (int)(ratio * iDelta);
+ if (dest->contents.colour.hue >= 360)
+ dest->contents.colour.hue -= 360;
+ }
+
+ iDelta = source->contents.drying_rate - dest->contents.drying_rate;
+ dest->contents.drying_rate += (int)(ratio * iDelta);
+ dest->contents.drying_rate %= 101;
+
+ iDelta = source->contents.liquid_content - dest->contents.liquid_content;
+ dest->contents.liquid_content += (int)(ratio * iDelta);
+ dest->contents.liquid_content %= 101;
+
+ iDelta = source->contents.miscibility - dest->contents.miscibility;
+ dest->contents.miscibility += (int)(ratio * iDelta);
+ dest->contents.miscibility %= 101;
+
+ delta = source->contents.colour.saturation - dest->contents.colour.saturation;
+ dest->contents.colour.saturation += ratio * delta;
+
+ delta = source->contents.colour.lightness - dest->contents.colour.lightness;
+ dest->contents.colour.lightness += ratio * delta;
+
+ dest->volume += amount; /* The new volume of paint in dest. */
+
+ }
+
+ need_to_repaint(destLocus);
+}
+
+/* *********************************************************************** */
+
+void handle_surface_tension(cell, locus)
+/* This routine handles the surface tension around the given cell.
+*/
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ DIRECTION direction[3];
+ POINT loci[3];
+ CELL_PTR buddy[3];
+ BOOLEAN ok, similar[3];
+ int weakCount, weak[3], count[3], excess, chosen, side, start, finish, k, lowest;
+
+ if (has_surplus_paint(cell) == FALSE) return;
+
+ direction[0] = cell->gravity.direction;
+ direction[1] = clockwise_from(direction[0]);
+ direction[2] = anti_clockwise_from(direction[0]);
+
+ for (k=0; k < 3; k++) {
+ ok = neighbour(locus, direction[k], &loci[k]);
+ if (ok == TRUE) {
+ buddy[k] = get_cell(loci[k]);
+ count[k] = 0;
+ } else count[k] = -1;
+ }
+
+ for (k=0; k < 3; k++)
+ similar[k] = (count[k] == -1)
+ ? FALSE
+ : similar_paint(cell->contents, buddy[k]->contents);
+
+ for (k=0; k < 3; k++) {
+ if ((count[k] != -1) && (similar[k] == FALSE)) {
+ count[k] = 0;
+ start = MAX(k-1, 0);
+ finish = MIN(k+1, 2);
+ for (side=start; side <= finish; side++)
+ if ((count[side] != -1) && (similar[side] == FALSE)) count[k]++;
+
+ }
+ }
+
+ lowest = 4;
+ for (k=0; k < 3; k++) if (count[k] >= 0) lowest = MIN(count[k], lowest);
+
+ weakCount = 0;
+ for (k=0; k < 3; k++) if (count[k] == lowest) weak[weakCount++] = k;
+
+ /* The weak array now holds weakCount indices of those sides that have
+ the lowest surface tension and therefore where any paint would flow over.
+ Now it is necessary to see whether paint will actually flow based on
+ a probability level using the liquidity and volume of the paint in the
+ cell as parameters. Paint will flow over only one of the weakest sides
+ with the side chosen at random. */
+
+ if (random_percent() > cell->contents.liquid_content) return; /* Too viscous. */
+
+ excess = surplus_paint(cell);
+ if (random_percent() > excess * 3) return;
+ /* The '3' in the previous statement is an empirically-derived multiplier. */
+
+ /* The paint will flow. Pick one of the weakest sides at random. */
+
+ chosen = weak[random_percent() % weakCount];
+ donate_paint(cell, locus, (excess / 2), buddy[chosen], loci[chosen]);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN diffuse_paint(cell, locus)
+/* Diffuse paint among the neighbours of the given cell.
+ If this cell does not have surplus paint then return
+ TRUE otherwise return FALSE. */
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ extern long random();
+ DIRECTION down, direction;
+ CELL_PTR buddy;
+ POINT nlocus;
+ BOOLEAN ok;
+ int excess;
+
+ if (has_surplus_paint(cell) == FALSE) return(TRUE);
+
+ down = cell->gravity.direction;
+ direction = ((random() & 01) == 0)
+ ? clockwise_from(down)
+ : anti_clockwise_from(down);
+
+ ok = neighbour(locus, direction, &nlocus);
+ if (ok == FALSE) return(TRUE);
+
+ buddy = get_cell(nlocus);
+
+ if (similar_paint(cell->contents, buddy->contents) == FALSE) {
+ handle_surface_tension(cell, locus);
+ return(FALSE);
+ }
+
+ if (buddy->volume >= cell->volume) return(FALSE);
+
+ if (allow_event_based_on(cell->contents.liquid_content) == FALSE)
+ return(FALSE);
+
+ /* Transfer one particle of paint from cell to its buddy. */
+
+ excess = (cell->volume - buddy->volume) / 2;
+ donate_paint(cell, locus, excess, buddy, nlocus);
+ return(FALSE);
+}
+
+/* *********************************************************************** */
+
+BOOLEAN apply_gravity(cell, locus)
+/* Subject the contents of the given cell to the effects
+ of gravity. Note that the direction of gravity is local
+ to the given cell. Locus is the address of this cell.
+ This function returns TRUE if the paint in this cell
+ cannot flow and FALSE otherwise.
+*/
+
+CELL_PTR cell;
+POINT locus;
+
+{
+ extern long random();
+ POINT downhill;
+ CELL_PTR down;
+ BOOLEAN ok, can_flow;
+ int barrier, excess;
+
+ ok = neighbour(locus, cell->gravity.direction, &downhill);
+ if (ok == FALSE) return(TRUE); /* At bottom of canvas. */
+
+ down = get_cell(downhill);
+
+ can_flow = down->volume < (cell->volume + cell->gravity.strength)
+ ? TRUE : FALSE;
+
+ if (can_flow == FALSE) return(TRUE);
+
+ /* Although this paint can flow introduce a random value that
+ uses the viscosity of the paint to determine whether it does
+ actually flow. */
+
+ barrier = random() % 10;
+ if (cell->contents.liquid_content > barrier) {
+ /* Paint is actually moving. Move half of the excess downward. */
+
+ excess = (cell->volume - cell->absorbancy) / 2;
+ donate_paint(cell, locus, excess, down, downhill);
+ }
+
+ return(FALSE);
+}
+
+
+float lx, ly, lz;
+
+void
+compute_shade_vectors()
+{
+ extern float lx, ly, lz;
+ float D;
+
+ lx = -1.0; ly = 1.0; lz = 2.0;
+
+ D = sqrt ( lx * lx + ly * ly + lz * lz );
+
+ lx = lx/D; ly = ly/D; lz = lz/D;
+
+}
+
+/* *********************************************************************** ** **
+** new_intensity_value **
+** **
+** calculates shade value for a pixel from surface characteristics ** ** **
+** Revision History **
+** **
+** Rev Date By Description **
+** 1.0 1/12/91 DE Original **
+** 1.1 1/04/92 DE Include Phong Shading **
+** 1.2 11/08/92 JWP Parameterized Specular Component ** ** **
+*********************************************************************** */
+float
+normalize (x, y, z)
+ float x, y, z; /*vector x, y, z components*/
+{
+ float result;
+
+ /* function calculates the amount to divide each vector component
+ to normalize it to a unit vector. The parameters are the x, y,
+z
+ components and the result is the amount to divide by */
+
+ result = sqrt (x*x + y*y + z*z);
+ return (result);
+
+ }
+
+
+
+float Newnormalize(V, W)
+float *V;
+float *W;
+{
+float temp;
+
+temp = normalize(V[0], V[1], V[2]);
+
+W[0] = V[0]/temp;
+W[1] = V[1]/temp;
+W[2] = V[2]/temp;
+
+return temp;
+}
+
+float dot(V, W)
+float V[3];
+float W[3];
+{
+
+return ( (V[0])*(W[0]) + (V[1])*(W[1]) + (V[2])*(W[2]) );
+
+}
+
+float Phong (Nv, Lv, Ev, shine)
+float Nv[3];
+float Lv[3];
+float Ev[3];
+float shine;
+{
+float Hv[3];
+
+Newnormalize(Ev, Ev);
+
+Hv[0] = Ev[0] + Lv[0];
+Hv[1] = Ev[1] + Lv[1];
+Hv[2] = Ev[2] + Lv[2];
+
+Newnormalize (Hv, Hv);
+
+shine = abs(shine);
+return( pow(dot(Nv, Hv), shine) );
+}
+
+
+float
+new_intensity_value(a_pnt)
+POINT a_pnt;
+/* Calculate the new intensity value of a pixel
+in order to construct a bump map of the paint surface
+*/
+{
+float h, h1, h2, h3, h4;
+ int shininess;
+float Ka, Kd, Ks;
+ float wetmax, degree, norm, distance;
+ float g;
+float Nv[3];
+ float Ev[3];
+ float Hv[3];
+ float Lv[3];
+ extern float lx, ly, lz;
+float intensity, light_intensity;
+POINT b_pnt;
+CELL_PTR cell;
+CELL_PTR next_cell;
+ int x_cntr, y_cntr;
+
+Ka = 0.1;
+Kd = 0.6;
+ Ks = 0.4;
+
+ wetmax = 100.0;
+ distance = 2500.0;
+ light_intensity = 2.0;
+ shininess = 200;
+
+cell = get_cell(a_pnt);
+
+h = (float)cell->volume;
+
+if (neighbour(a_pnt, NORTH, &b_pnt)) {
+next_cell = get_cell(b_pnt);
+h1 = (float)next_cell->volume;
+} else
+h1 = h;
+
+if (neighbour(a_pnt, EAST, &b_pnt)) {
+next_cell = get_cell(b_pnt);
+h2 = (float)next_cell->volume;
+} else
+h2 = h;
+
+if (neighbour(a_pnt, SOUTH, &b_pnt)) {
+next_cell = get_cell(b_pnt);
+h3 = (float)next_cell->volume;
+} else
+h3 = h;
+
+if (neighbour(a_pnt, WEST, &b_pnt)) {
+next_cell = get_cell(b_pnt);
+h4 = (float)next_cell->volume;
+} else
+h4 = h;
+
+h1 = h1/HEIGHT_SCALE;
+h2 = h2/HEIGHT_SCALE;
+h3 = h3/HEIGHT_SCALE;
+h4 = h4/HEIGHT_SCALE;
+
+ degree = (float)abs(cell->contents.liquid_content)/wetmax;
+
+ x_cntr= 150 - a_pnt.x;
+ y_cntr= 150 - a_pnt.y;
+
+ Ks = light_intensity * Ks * degree;
+
+ Kd = light_intensity * Kd;
+
+ shininess = (int)degree * shininess + 1;
+
+
+ Nv[1] = h3 - h1;
+ Nv[0] = h4 - h2;
+Nv[2] = 4.0;
+
+ Newnormalize (Nv, Nv);
+
+ Lv[0] = lx;
+Lv[1] = ly;
+ Lv[2] = lz;
+
+ g = dot(Lv, Nv)*Kd + Ka;
+
+ g = g * (float)cell->contents.colour.hue;
+
+Ev[0] = (float)x_cntr;
+Ev[1] = (float)y_cntr;
+Ev[2] = distance;
+
+ intensity = g + Ks*Phong(Nv, Lv, Ev, (float)shininess);
+
+ if ( intensity > 255.0 ) {
+ intensity = 0.0;
+ } else {
+ if (intensity < 0.0)
+ intensity = 255.0;
+ else
+ intensity = 255.0 - intensity;
+ }
+
+
+ /*printf("wetness %d colour %d intensity %f guraud %f phong %f\n",
+ cell->contents.liquid_content,
+ cell->contents.colour.hue,
+ intensity,
+ g,
+ intensity - g);*/
+
+
+return (intensity);
+}
+
+
+/* *********************************************************************** */
+
+void single_step()
+/* This routine defines the paint steps involved in the
+ basic cycle of the painting engine. */
+
+{
+ POINT locus;
+ CELL_PTR cell;
+ BOOLEAN done;
+
+ next_cell_point(&locus);
+ cell = get_cell(locus);
+
+ done = age_paint(cell);
+ if (done == TRUE) return;
+
+ done = diffuse_paint(cell, locus);
+ if (done == TRUE) return;
+
+ done = apply_gravity(cell, locus);
+}
+
+brush_stroke(x,y)
+int x;
+int y;
+{
+ POINT pnt;
+ CELL_PTR cell;
+
+
+ pnt.x = x;
+ pnt.y = y;
+
+ cell = get_cell(pnt);
+
+ cell->contents.liquid_content = 100;
+ cell->contents.drying_rate = 10;
+ cell->contents.miscibility = 80;
+
+ cell->contents.colour.hue = 128;
+ cell->contents.colour.saturation = 1.0;
+ cell->contents.colour.lightness = 0.0;
+
+ cell->volume = 50;
+
+}
+
diff --git a/krita/colorspaces/wetsticky/ws/load_ppm.c b/krita/colorspaces/wetsticky/ws/load_ppm.c
new file mode 100644
index 00000000..6368ee08
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/load_ppm.c
@@ -0,0 +1,244 @@
+/*
+ FILE: load_ppm.c
+ PURPOSE: Defines the routines to load a PPM portable pixmap image file.
+ AUTHOR: David England
+ VERSION: 1.00 (10-May-91)
+
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "constants.h"
+#include "types.h"
+#include "canvas.h"
+
+#include <ctype.h>
+#include <ppm.h>
+#include <ppmcmap.h>
+
+/* Max number of colors allowed in ppm input. */
+#define MAXCOLORS 256
+
+extern CELL canvas[CANVAS_WIDTH][CANVAS_HEIGHT];
+
+float
+max_rgb(r,g,b)
+float r;
+float g;
+float b;
+{
+ if ((r > g) && (r > b))
+ return (r);
+
+ if ((b > g) && (b > r))
+ return (b);
+
+ if ((g > b) && (g > r))
+ return (g);
+
+ return(0);
+}
+
+float
+min_rgb(r,g,b)
+float r;
+float g;
+float b;
+{
+ if ((r < g) && (b < g))
+ return (r);
+
+ if ((b < g) && (b < r))
+ return (b);
+
+ if ((g < b) && (g < r))
+ return (g);
+
+ return(0);
+}
+
+
+int
+GetHue(red, green, blue) /* rgb to hls */
+int red;
+int green;
+int blue;
+{
+ float min_col, max_col;
+ float h,s,l;
+ float rc, gc, bc;
+ float r, g, b;
+
+ r = (float)red/255.0;
+ b = (float)green/255.0;
+ g = (float)blue/255.0;
+
+ max_col = (float)max_rgb(r, g, b);
+ min_col = (float)min_rgb(r, g, b);
+
+ l = (max_col + min_col)/2.0 ;
+
+ if ( max_col == min_col) {
+ s = 0.0;
+ h = 0.0;
+ } else {
+ if ( l < 0.5) {
+ s = (max_col - min_col)/(max_col + min_col);
+ } else s = (max_col - min_col)/(2 - max_col - min_col);
+
+ rc = (max_col -r)/( max_col - min_col);
+ gc = (max_col -g)/(max_col - min_col);
+ bc = (max_col -b)/(max_col - min_col);
+
+ if (r == max_col)
+ h = bc - gc;
+ else if (g == max_col )
+ h = 2 + rc - bc;
+ else if (b == max_col)
+ h = 4 + gc -rc;
+
+ h = h * 60;
+
+ if ( h < 0.0)
+ h = h + 360;
+ }
+
+ return ((int)h);
+
+
+}
+
+GetHuePaint(r,g,b)
+int r;
+int g;
+int b;
+{
+
+ /*if ((r == 0) && (g == 0) && (b ==0)) {
+ canvas[i][j].contents.liquid_content = 0;
+ canvas[i][j].contents.drying_rate = 0;
+ canvas[i][j].contents.miscibility = 0;
+
+ canvas[i][j].contents.colour.hue = 0;
+ canvas[i][j].contents.colour.saturation = 1.0;
+ canvas[i][j].contents.colour.lightness = 0.0;
+ canvas[i][j].volume = 80;
+ return (0);
+ }
+
+ if ((r == 255) && (g == 255) && ( b == 255)) {
+ canvas[i][j].contents.liquid_content = 0;
+ canvas[i][j].contents.drying_rate = 0;
+ canvas[i][j].contents.miscibility = 0;
+
+ canvas[i][j].contents.colour.hue = 128;
+ canvas[i][j].contents.colour.saturation = 1.0;
+ canvas[i][j].contents.colour.lightness = 0.0;
+ canvas[i][j].volume = 80;
+ return (128);
+ }*/
+}
+
+load_ppm_format(filename, width, height)
+char *filename;
+int *width;
+int *height;
+{
+
+ FILE* ifp;
+ pixel **pixels;
+ int rows, cols, i, j;
+ pixval maxval;
+ int red, green, blue;
+ int hue;
+
+ /*ppm_init( &argc, argv );*/
+
+
+
+ ifp = pm_openr( filename);
+
+ pixels = ppm_readppm( ifp, &cols, &rows, &maxval );
+
+ *(width) = cols;
+ *(height) = rows;
+
+ fprintf(stderr,"Loading file %s, %dx%d. Please wait ", filename, rows,
+cols);
+
+ if (rows > CANVAS_HEIGHT)
+ rows = CANVAS_HEIGHT;
+
+ if (cols > CANVAS_WIDTH)
+ cols = CANVAS_WIDTH;
+
+ for (i=0; i< rows; i++) {
+ for (j=0; j< cols; j++) {
+ red = PPM_GETR(pixels[i][j]);
+ green = PPM_GETG(pixels[i][j]);
+ blue = PPM_GETB(pixels[i][j]);
+
+ /*hue = GetHue(red, green, blue);*/
+
+ /* For gray scale only */
+
+ hue = 255 - red;
+
+
+ /*fprintf(stderr,"hue %d ", hue);*/
+ /*GetHuePaint(red, green, blue, i, j);*/
+
+ canvas[i][j].contents.liquid_content = 80;
+ canvas[i][j].contents.drying_rate = 80;
+ canvas[i][j].contents.miscibility = 80;
+
+ canvas[i][j].contents.colour.hue = hue;
+ canvas[i][j].contents.colour.saturation = 1.0;
+ canvas[i][j].contents.colour.lightness = 0.0;
+ canvas[i][j].volume = (float)hue/2.5;
+
+ if (red == 0)
+ if (green == 0)
+ if ( blue == 0) {
+ canvas[i][j].contents.liquid_content = 0;
+ canvas[i][j].contents.drying_rate = 0;
+ canvas[i][j].contents.miscibility = 0;
+ canvas[i][j].contents.colour.hue = 0;
+ canvas[i][j].volume = 0;
+ }
+
+ if (red == 255)
+ if (green == 255)
+ if ( blue == 255) {
+ canvas[i][j].contents.liquid_content = 0;
+ canvas[i][j].contents.drying_rate = 0;
+ canvas[i][j].contents.miscibility = 0;
+ canvas[i][j].contents.colour.hue = 360;
+ canvas[i][j].volume = 0;
+ }
+
+
+ }
+ if (( i %10) == 0){
+ fprintf(stderr,".");
+ fflush(stderr);
+ }
+ }
+
+ printf(" done\n");
+
+ pm_close( ifp );
+
+ /*exit(0);*/
+
+}
diff --git a/krita/colorspaces/wetsticky/ws/main.c b/krita/colorspaces/wetsticky/ws/main.c
new file mode 100644
index 00000000..8185557a
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/main.c
@@ -0,0 +1,105 @@
+/*
+ FILE: main.c
+ PURPOSE: The top-level program for Wet&Sticky
+ AUTHOR: Kevin Waite and David England
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include "constants.h"
+#include "types.h"
+#include "canvas.h"
+#include "win_interface.h"
+#include <stdio.h>
+#include <string.h>
+#include <math.h>
+
+double HEIGHT_SCALE;
+
+void main(argc, argv)
+int argc;
+char *argv[];
+
+/*
+ The Wet&Sticky program can be executed with optional parameters.
+ Those parameters used by the X graphics system are stripped out.
+ If no parameters are given then the program runs as a purely
+ interactive system. This requires input handling which is not
+ yet implemented. If the argument is the string '-blob' then the
+ program uses a square blob as the starting image. Otherwise the
+ program assumes the argument is a filename containing a previously
+ stored canvas. This is then loaded into the canvas as a starting
+ point.
+*/
+
+{
+ char *filename;
+ extern void exit();
+ int width;
+ int height;
+ extern int optind, opterr;
+ extern char *optarg;
+ int c,i;
+ int blob_flag;
+
+
+ fprintf(stdout, "Wet&Sticky Version %s\n", VERSION);
+ fprintf(stdout, "Implemented by K.Waite and D.England, 1991\n");
+ fprintf(stdout, "Based on ideas by Tunde Cockshott\n\n");
+
+
+ initialise_canvas();
+ if (DEBUG) fprintf (stdout, "Finished initialising the canvas\n");
+
+ CreateWindows (&argc, argv, CANVAS_WIDTH , CANVAS_HEIGHT);
+
+ filename = argv[1];
+
+ blob_flag = 1;
+ HEIGHT_SCALE = 20.0;
+
+ opterr = 0;
+ fprintf(stderr, "HEIGHT %g\n", HEIGHT_SCALE);
+
+ while ((c = getopt(argc, argv, "f:s:")) != EOF)
+ switch (c) {
+ case 'f':
+ filename = optarg;
+ load_file(filename, &width, &height);
+ blob_flag = 0;
+ break;
+ case 's':
+ fprintf(stderr, "HEIGHT string %s \n",optarg);
+ HEIGHT_SCALE = atof(optarg);
+ break;
+ case '?':
+ break;
+ }
+
+ if (blob_flag)
+ blob (DEFAULT_BLOB_SIZE);
+
+ fprintf(stderr, "HEIGHT %g\n", HEIGHT_SCALE);
+
+ StartVolumeWindow (CANVAS_WIDTH, CANVAS_HEIGHT);
+ StartDrynessWindow (CANVAS_WIDTH, CANVAS_HEIGHT);
+
+ if (DEBUG) fprintf (stdout, "Finished preparing X\n");
+
+ if (DEBUG) fprintf (stdout, "Passing control to window manager\n");
+ StartWindows();
+ exit(0);
+
+}
diff --git a/krita/colorspaces/wetsticky/ws/makefile b/krita/colorspaces/wetsticky/ws/makefile
new file mode 100644
index 00000000..a14beb9a
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/makefile
@@ -0,0 +1,55 @@
+CFLAGS = -O3
+#CFLAGS = -g #-std
+LINT_FLAGS = -bchxu
+
+SOURCES = load_ppm.c canvas.c engine.c x_interface.c main.c
+OBJECTS = x_interface.o load_ppm.o engine.o canvas.o
+OBJECTS2= ogl_interface.o load_ppm.o engine.o canvas.o
+
+GFX_LIB=-L/usr/X11R6/lib \
+ -lXaw -lXmu -lXt -lX11 -lm -lppm -lpgm -lpbm
+
+#PPM_LIBS = ppm/libppm.a ppm/libpgm.a ppm/libpbm.a
+
+OGL_LIBS=-L/usr/X11R6/lib \
+ -laux -lGLU -lGL -lXext -lX11 -limp -lm -lppm -lpgm -lpbm
+
+OGL_INCS=-I/usr2/share/src/OpenGL/libaux
+
+CC=cc
+
+wet+sticky: constants.h canvas.h engine.h $(OBJECTS) main.c
+ ${CC} -o wet+sticky $(CFLAGS) main.c $(OBJECTS) $(GFX_LIB)
+
+wet+sticky2: constants.h canvas.h engine.h $(OBJECTS2) main.c
+ ${CC} -o wet+sticky2 $(CFLAGS) main.c $(OBJECTS2) $(OGL_LIBS)
+
+cmap: cmap.o
+ ${CC} -g -o cmap cmap.o $(GFX_LIB)
+
+anim: constants.h canvas.h engine.h anim.c
+ ${CC} -o anim $(CFLAGS) anim.c $(GFX_LIB)
+
+engine.o: types.h constants.h canvas.h engine.h
+ ${CC} -c $(CFLAGS) engine3.c
+
+canvas.o: types.h constants.h canvas.h
+ ${CC} -c $(CFLAGS) canvas.c
+
+x_interface.o: constants.h types.h canvas.h engine.h x_interface.c
+ ${CC} -c $(CFLAGS) x_interface.c
+
+ogl_interface.o: constants.h types.h canvas.h engine.h ogl_interface.c
+ ${CC} -c $(CFLAGS) ${OGL_INCS} ogl_interface.c
+
+load_ppm.o: constants.h types.h canvas.h engine.h load_ppm.c
+ ${CC} -c $(CFLAGS) load_ppm.c
+
+cmap.o: cmap.c
+ ${CC} -c -g cmap.c
+
+clean:
+ /bin/rm -f core
+ /bin/rm -f *.o
+
+lint: alint $(LINT_FLAGS) $(SOURCES)
diff --git a/krita/colorspaces/wetsticky/ws/mona.pgm b/krita/colorspaces/wetsticky/ws/mona.pgm
new file mode 100644
index 00000000..2060ee90
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/mona.pgm
Binary files differ
diff --git a/krita/colorspaces/wetsticky/ws/ogl_interface.c b/krita/colorspaces/wetsticky/ws/ogl_interface.c
new file mode 100644
index 00000000..76a552a9
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/ogl_interface.c
@@ -0,0 +1,302 @@
+/*
+ FILE: xgl_interface.c
+ PURPOSE: Creation and access to a OpenGL window
+ to wet+sticky using OpenGL
+ AUTHOR: David England
+ VERSION: 1.00 (21-June-96)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include <GL/gl.h>
+#include <GL/glu.h>
+/*#include <imp.h>*/
+/*#include "aux.h"*/
+
+#include <stdio.h>
+
+#include "constants.h"
+#include "types.h"
+#include "engine.h"
+#include "canvas.h"
+
+static int count=0;
+
+
+void nullProc()
+{
+}
+
+void SetupCmap()
+{
+}
+
+float Value(n1, n2, hue)
+float n1, n2, 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;
+}
+
+
+RGB_COLOUR hls_to_rgb(h, l, s)
+int h;
+float l;
+float s;
+{
+RGB_COLOUR rgb_colour;
+float m1, m2;
+
+if (l <= 0.5 )
+ m2 = l*(1+s);
+else
+ m2 = l+s - l*s;
+m1 = 2*l-m2;
+
+rgb_colour.r = Value(m1, m2, h+120);
+rgb_colour.g = Value(m1,m2, h);
+rgb_colour.b = Value(m1,m2, h-120);
+
+return (rgb_colour);
+}
+
+void
+DrawPoint(x,y,hls_col)
+int x;
+int y;
+HLS_COLOUR hls_col;
+/* Draw a point on the window and the back-up Pixmap */
+{
+RGB_COLOUR rgb_colour;
+
+ rgb_colour = hls_to_rgb(hls_col.hue,
+ hls_col.lightness,
+ hls_col.saturation);
+
+
+ printf("h %.2f l %.2f s %.2f\n", hls_col.hue, hls_col.lightness,
+ hls_col.saturation);
+
+ printf( "r %.2f g %.2f b %.2f\n", rgb_colour.r, rgb_colour.g,
+ rgb_colour.b);
+
+ glColor3f(rgb_colour.r, rgb_colour.g, rgb_colour.b);
+
+ glBegin(GL_POINTS);
+ glVertex2s(x,y);
+ glVertex2s(x+1,y+1);
+ glEnd();
+
+}
+
+void
+DrawVolumePoint(x,y,attr)
+int x;
+int y;
+int attr;
+{
+/*set colour, draw point at offset */
+}
+
+void
+DrawDrynessPoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+
+}
+
+void
+ClearWindow()
+{
+
+}
+
+static void
+CleanWindow()
+/* Fill a window with a solid, white rectangle */
+{
+}
+
+
+void CreateWindows(argc, argv, width, height)
+int *argc;
+char **argv;
+int width;
+int height;
+
+{
+
+ auxInitDisplayMode( AUX_RGBA);
+
+ auxInitPosition(50,50, width*3, height);
+
+ auxInitWindow(argv[0]);
+
+ glClearColor(1.0, 1.0, 1.0, 0.0);
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+}
+
+
+static void
+draw_labels()
+{
+}
+
+void paint_cell(cell, x, y)
+CELL_PTR cell;
+int x, y;
+
+{
+ DrawPoint(x,y, cell->contents.colour);
+
+ /* volColour is an index into the colour table in the range [0,255].
+ It is used to give a false colour image of the canvas's volume. */
+
+ /*DrawVolumePoint(x,y,volColour);*/
+
+
+ /*DrawDrynessPoint(x,y,dryness);*/
+}
+
+
+
+
+void draw_full_canvas()
+{
+ int x, y;
+ CELL_PTR cell;
+ POINT p;
+
+ glClear(GL_COLOR_BUFFER_BIT);
+
+ if (DEBUG) {
+ printf ("Starting to paint full canvas...");
+ fflush(stdout);
+ }
+
+ for (y=0; y < CANVAS_HEIGHT; y++)
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ p.x = x;
+ p.y = y;
+ cell = get_cell(p);
+ paint_cell(cell, x, y);
+ }
+
+ glFlush();
+ sleep(10);
+
+ if (DEBUG) printf ("done.\n");
+}
+
+void
+bump_map()
+{
+ POINT p;
+ CELL_PTR cell;
+ register int x, y;
+ register int colour;
+
+
+ for (y=0; y < CANVAS_HEIGHT; y++) {
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ p.x = x;
+ p.y = y;
+ cell = get_cell(p);
+ colour = (int) new_intensity_value(p);
+
+/* colour = (int) (cell->contents.colour.hue *
+ ((float) MAX_COLOUR_INDEX / 360.0));*/
+ DrawDrynessPoint(x,y,colour);
+ }
+ }
+
+}
+
+
+void evolve_paint()
+{
+ int k;
+ POINT p;
+ CELL_PTR cell;
+ int new_x, new_y;
+ extern int count;
+
+ /*count++;
+ if (count > 500) {
+ fprintf(stderr,".");
+ fflush(stderr);
+ bump_map();
+ }*/
+
+ for (k=0; k < STEP_LIMIT; k++) single_step();
+ while (TRUE) {
+ next_cell_for_repaint(&cell, &p);
+ if (cell == NIL) return;
+ paint_cell(cell, p.x, p.y);
+ glFlush();
+ }
+
+
+}
+
+void StartVolumeWindow()
+{
+}
+
+void StartDrynessWindow()
+{
+}
+
+void StartWindows()
+{
+
+
+ draw_full_canvas();
+ compute_shade_vectors(); /* Set vectors for shading */
+ draw_labels();
+
+ /*auxIdleFunc(evolve_paint);
+
+ auxMainLoop(draw_full_canvas);*/
+
+
+}
+
+void
+stroke()
+{
+
+}
+
+
+void
+stroke_motion()
+{
+
+}
+
diff --git a/krita/colorspaces/wetsticky/ws/test2.jpg b/krita/colorspaces/wetsticky/ws/test2.jpg
new file mode 100644
index 00000000..24b92c3d
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/test2.jpg
Binary files differ
diff --git a/krita/colorspaces/wetsticky/ws/test3.jpg b/krita/colorspaces/wetsticky/ws/test3.jpg
new file mode 100644
index 00000000..2b25a0d5
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/test3.jpg
Binary files differ
diff --git a/krita/colorspaces/wetsticky/ws/types.h b/krita/colorspaces/wetsticky/ws/types.h
new file mode 100644
index 00000000..af671f53
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/types.h
@@ -0,0 +1,72 @@
+/*
+ FILE: types.h
+ PURPOSE: Defines all the main types used in Wet&Sticky.
+ AUTHORS: Kevin Waite and David England
+ VERSION: 1.00 (10-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+
+
+*/
+
+
+/* A colour is specified as a vector in HLS space. Hue is a value
+ in the range 0..360 degrees with 0 degrees being red. Saturation
+ and Lightness are both in the range [0,1]. A lightness of 0 means
+ black, with 1 being white. A totally saturated colour has saturation
+ of 1.
+*/
+
+typedef struct hls_colour { short int hue; float saturation, lightness; }
+HLS_COLOUR;
+
+typedef struct rgb_colour {float r; float g; float b;}
+RGB_COLOUR;
+
+
+/* The address of a cell on the canvas. */
+
+typedef struct point { int x, y; } POINT, *POINT_PTR;
+
+
+/* A direction can be NORTH, EAST, SOUTH or WEST. */
+
+typedef short int DIRECTION;
+
+typedef short int BOOLEAN; /* FALSE or TRUE */
+
+
+typedef struct paint {
+ HLS_COLOUR colour;
+ int liquid_content; /* [0,100]. */
+ int drying_rate; /* [0,100]. */
+ int miscibility; /* [0,inf]. */
+} PAINT, *PAINT_PTR;
+
+
+/* Defines the strength and direction of gravity for a cell. */
+
+typedef struct gravity {
+ DIRECTION direction;
+ int strength; /* [0,Infinity). */
+} GRAVITY, *GRAVITY_PTR;
+
+
+/* Defines the contents and attributes of a cell on the canvas. */
+
+typedef struct cell {
+ PAINT contents; /* The paint in this cell. */
+ GRAVITY gravity; /* This cell's gravity. */
+ short int absorbancy; /* How much paint can this cell hold? */
+ short int volume; /* The volume of paint. */
+} CELL, *CELL_PTR;
diff --git a/krita/colorspaces/wetsticky/ws/win_interface.h b/krita/colorspaces/wetsticky/ws/win_interface.h
new file mode 100644
index 00000000..ee7a064b
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/win_interface.h
@@ -0,0 +1,28 @@
+/*
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
+ * Boston, MA 02110-1301, USA
+
+
+*/
+
+extern void DrawPoint(/* int x, int y; int colour*/);
+extern int DrawVolumePoint(/* int x, int y; int attr*/);
+extern int DrawDrynessPoint(/* int x, int y; int attr*/);
+extern void ClearWindow();
+extern void CreateWindows(/* int *argc, char *argv[], int width, int height*/);
+extern void StartWindows(); /* enter infinite loop */
+extern void StartVolumeWindow(/*int width, int height*/);
+ /* display attribute window */
+extern void StartDrynessWindow(/*int width, int height*/);
+ /* display attribute window */
+
+
diff --git a/krita/colorspaces/wetsticky/ws/x_interface.c b/krita/colorspaces/wetsticky/ws/x_interface.c
new file mode 100644
index 00000000..f4cb4901
--- /dev/null
+++ b/krita/colorspaces/wetsticky/ws/x_interface.c
@@ -0,0 +1,795 @@
+/*
+ FILE: x_interface.c
+ PURPOSE: Creation and access to an X windows interface
+ to wet+sticky using Athena Widgets
+ AUTHOR: David England
+ VERSION: 1.00 (13-May-91)
+
+Copyright 1991, 1992, 2002, 2003 Tunde Cockshott, Kevin Waite, David England.
+Contact David England [email protected]
+School of Computing and Maths Sciences,
+Liverpool John Moores University
+Liverpool L3 3AF
+United Kingdom
+Phone +44 151 231 2271
+
+
+Wet and Sticky 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. Wet and Sticky 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 Wet and Sticky; if not, write to the Free Software Foundation,
+Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+
+*/
+
+#include <X11/Xos.h>
+#include <X11/Xlib.h>
+#include <X11/Xutil.h>
+#include <X11/Intrinsic.h>
+
+#include <X11/cursorfont.h>
+#include <X11/StringDefs.h>
+
+#include <X11/Shell.h>
+#include <X11/Xaw/Box.h>
+#include <X11/Xaw/Label.h>
+#include <stdio.h>
+
+#include "constants.h"
+#include "types.h"
+#include "engine.h"
+#include "canvas.h"
+
+/* Window Heirarchy -
+ Three shell widgets, one for colour output, two for attributes output
+ plus a back_up pixmap for redrawing
+*/
+
+static Widget top_level;
+static Widget colour_shell;
+static Widget colour_box;
+static Widget colour_canvas;
+static Pixmap colour_pm;
+
+static Widget volume_shell;
+static Widget volume_box;
+static Widget volume_canvas;
+static Pixmap volume_pm;
+
+static Widget dryness_shell;
+static Widget dryness_box;
+static Widget dryness_canvas;
+static Pixmap dryness_pm;
+
+static GC gc;
+static GC tmp_gc;
+static long mask;
+static XGCValues values;
+
+static Colormap cmap;
+static XColor colours[256];
+void stroke();
+void stroke_motion();
+
+Display *display;
+int screen;
+Screen *screen_ptr;
+Window root;
+
+static int count=0;
+static int frame_count=0;
+char pix_file[64];
+
+static void
+expose_event(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the colour window if an exposure event is received */
+int width, height;
+
+ width = height = 300;
+
+ XCopyArea(XtDisplay(colour_canvas), colour_pm,
+ XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0);
+
+}
+
+
+static void
+expose_volume(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the volume window if an exposure event is received */
+int width, height;
+
+ width = 300;
+ height = 300;
+
+ XCopyArea(XtDisplay(volume_canvas), volume_pm,
+ XtWindow(volume_canvas), gc, 0, 0, width, height, 0,0);
+
+
+}
+
+static void
+expose_dryness(w, event)
+Widget w;
+XEvent *event;
+{
+/* Re-display the dryness window if an exposure event is received */
+int width, height;
+
+ width = height = 300;
+
+ XCopyArea(XtDisplay(dryness_canvas), dryness_pm,
+ XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0);
+
+
+}
+
+void expose_canvases()
+{
+int width, height;
+
+width = height = 300;
+
+ XCopyArea(XtDisplay(colour_canvas), colour_pm,
+ XtWindow(colour_canvas), gc, 0, 0, width, height, 0,0);
+
+ XCopyArea(XtDisplay(dryness_canvas), dryness_pm,
+ XtWindow(dryness_canvas), gc, 0, 0, width, height, 0,0);
+
+ XCopyArea(XtDisplay(dryness_canvas), dryness_pm,
+ XtWindow(dryness_canvas), gc, 0, 0, 300, 300, 0,0);
+
+}
+
+int
+GetHueValue(red, green, blue)
+int red;
+int green;
+int blue;
+{
+ XColor colour;
+
+ colour.red = red * 257;
+ colour.green = green * 257;
+ colour.blue = blue * 257;
+ colour.flags = DoRed | DoGreen | DoBlue;
+
+ if (XAllocColor(display, cmap, &colour) == 0)
+ fprintf(stderr,"colour allocation failed\n");
+
+ return (colour.pixel);
+}
+
+
+void
+DrawPoint(x,y,colour)
+int x;
+int y;
+int colour;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ /* PROBS ? */
+
+ XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel);
+
+ XDrawPoint(XtDisplay(top_level), XtWindow(colour_canvas), gc, x, y);
+ XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y);
+}
+
+void
+DrawBackgroundPoint(x,y,colour)
+int x;
+int y;
+int colour;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ /* PROBS ? */
+
+ XSetForeground(XtDisplay(top_level), gc, colours[colour].pixel);
+
+ XDrawPoint(XtDisplay(top_level), colour_pm, gc, x, y);
+}
+
+
+int
+DrawVolumePoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ if (XtWindow(volume_canvas) == NULL)
+ return (-1);
+
+ XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);
+
+ XDrawPoint(XtDisplay(top_level), XtWindow(volume_canvas), gc, x, y);
+ XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y);
+
+ return(0);
+}
+
+int
+DrawBackgroundVolumePoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ if (XtWindow(volume_canvas) == NULL)
+ return (-1);
+
+ XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);
+
+ XDrawPoint(XtDisplay(top_level), volume_pm, gc, x, y);
+
+ return(0);
+}
+
+
+int
+DrawDrynessPoint(x,y,attr)
+int x;
+int y;
+int attr;
+/* Draw a point on the window and the back-up Pixmap */
+{
+ /* later - use the range of the dryness to affect the colour
+ value
+ */
+
+ if (XtWindow(dryness_canvas) == NULL)
+ return (-1);
+
+ XSetForeground(XtDisplay(top_level), gc, colours[attr].pixel);
+
+/* XDrawPoint(XtDisplay(top_level), XtWindow(dryness_canvas), gc, x, y);
+*/
+ XDrawPoint(XtDisplay(top_level), dryness_pm, gc, x, y);
+
+ return(0);
+}
+
+void
+ClearWindow()
+{
+ XClearWindow(XtDisplay(top_level), XtWindow(colour_canvas));
+}
+
+static void
+CleanWindow(win)
+Drawable win;
+/* Fill a window with a solid, white rectangle */
+{
+XGCValues values;
+long mask;
+
+ values.background = colours[0].pixel;
+ values.foreground = colours[255].pixel;;
+ values.fill_style = FillSolid;
+ values.function = GXclear;
+
+
+ mask = GCBackground| GCForeground| GCFillStyle | GCFunction;
+
+ tmp_gc = XtGetGC(top_level, mask, &values);
+
+ XFillRectangle(XtDisplay(top_level), win, tmp_gc, 0, 0, 300, 300);
+
+}
+
+void SetupCmap()
+{
+int i;
+
+ for (i=0;i<256;i++) {
+ colours[i].red = i*257;
+ colours[i].flags = DoRed | DoBlue | DoGreen;
+ }
+
+ /* for (i=0;i<=127;i++)
+ colours[i].green = i*2*257;
+
+ for (i=128;i>0;i--)
+ colours[255-i].green = (i-1)*2*257;*/
+
+ for (i=0;i<64;i++)
+ colours[i].green = i*4*257;
+
+ for (i=64;i<128;i++)
+ colours[i].green = 65536-i*4*257;
+
+ for (i=128;i<192;i++)
+ colours[i].green = (i-128)*2*257;
+
+ for (i=192;i<255;i++)
+ colours[i].green = 65536-(i-128)*2*257;
+
+
+ for (i=0;i<256;i++)
+ colours[i].blue = 65536 - i*257;
+
+ colours[0].red = 65535;
+ colours[0].green = 65535;
+ colours[0].blue = 65535;
+}
+
+void
+SetupGreyMap()
+{
+int i;
+
+ for (i=0;i<256;i++) {
+ colours[i].red = i*257;
+ colours[255 - i].flags = DoRed | DoBlue | DoGreen;
+ }
+
+
+ for (i=0;i<256;i++)
+ colours[i].green = i*257;
+
+ for (i=0;i<256;i++)
+ colours[i].blue = i*257;
+
+ colours[255].red = 255*257;
+ colours[255].green = 255*257;
+ colours[255].blue = 255*257;
+
+}
+
+
+void CreateWindows(argc, argv, width, height)
+int *argc;
+char **argv;
+int width;
+int height;
+/* Create colour window heirarchy and add event handlers */
+{
+
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ int i;
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ top_level = XtInitialize("wet+sticky", "Wet+Sticky", NULL,
+ 0, argc, argv);
+
+
+ display = XtDisplay(top_level);
+ screen = DefaultScreen(display);
+ screen_ptr = ScreenOfDisplay(display, DefaultScreen(display));
+
+ root = RootWindow(display, screen);
+
+ colour_shell = XtCreateApplicationShell("colour_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+
+
+ colour_box = XtCreateManagedWidget("colour_box", boxWidgetClass,
+ colour_shell, NULL, 0);
+
+
+ colour_canvas = XtCreateManagedWidget("", labelWidgetClass,
+ colour_box, args, XtNumber(args));
+
+
+ XtAddEventHandler(colour_canvas, ExposureMask, False, expose_event, 0);
+
+ XtAddEventHandler(colour_canvas, ButtonPressMask, False, stroke, 0);
+
+ XtAddEventHandler(colour_canvas, Button1MotionMask,
+ False, stroke_motion, 0);
+
+ XtRealizeWidget(colour_shell);
+
+ cmap = XCreateColormap( display, XtWindow(colour_shell),
+ XDefaultVisualOfScreen(screen_ptr), AllocAll);
+
+ for (i=0; i <= 255; i++)
+ colours[i].pixel = i;
+
+ XQueryColors(display, DefaultColormapOfScreen(screen_ptr),colours, 256);
+
+ SetupCmap();
+
+ /*SetupGreyMap();*/
+
+ XStoreColors(display, cmap, colours, 256);
+
+ i=0;
+ while( XAllocColorCells( display, DefaultColormapOfScreen(screen_ptr),
+ True, NULL, 0, &colours[i].pixel, 1 ) ) {
+ colours[i].pixel = i;
+ i++;
+ }
+
+ XSetWindowColormap(display, XtWindow(colour_shell), cmap);
+
+ XInstallColormap(display, cmap);
+
+ mask = GCBackground| GCForeground| GCFunction;
+
+ values.function = GXcopy;
+ values.background = colours[0].pixel;
+ values.foreground = colours[255].pixel;
+
+
+ gc = XtGetGC(colour_canvas, mask, &values);
+
+ colour_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ CleanWindow(colour_pm);
+
+}
+
+
+void StartVolumeWindow(width, height)
+int width;
+int height;
+/* Create Volume heirarchy and add event handlers */
+{
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ volume_shell = XtCreateApplicationShell("volume_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+ volume_box = XtCreateManagedWidget("volume_box", boxWidgetClass,
+ volume_shell, NULL, 0);
+
+ volume_canvas = XtCreateManagedWidget("", labelWidgetClass,
+ volume_box, args, XtNumber(args));
+
+ XtAddEventHandler(volume_canvas, ExposureMask, False,
+ expose_volume, 0);
+
+ XtRealizeWidget(volume_shell);
+
+ XSetWindowColormap(display, XtWindow(volume_shell), cmap);
+
+ volume_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ CleanWindow(volume_pm);
+
+
+}
+
+void StartDrynessWindow(width, height)
+int width;
+int height;
+/* Create dryness heirarchy and add event handlers */
+{
+ static Arg args[]={
+ {XtNwidth, (XtArgVal) 0},
+ {XtNheight, (XtArgVal)0} };
+
+ char name[32];
+
+ args[0].value = (XtArgVal)width;
+
+ args[1].value = (XtArgVal)height;
+
+ dryness_shell = XtCreateApplicationShell("dryness_frame",
+ topLevelShellWidgetClass, NULL, 0);
+
+ dryness_box = XtCreateManagedWidget("dryness_box", boxWidgetClass,
+ dryness_shell, NULL, 0);
+ dryness_canvas = XtCreateManagedWidget("Name", labelWidgetClass,
+ dryness_box, args, XtNumber(args));
+
+ fprintf(stderr,"Bumps %d\n",(int)dryness_canvas);
+
+ XtAddEventHandler(dryness_canvas, ExposureMask, False,
+ expose_dryness, 0);
+
+ XtRealizeWidget(dryness_shell);
+
+ XSetWindowColormap(display, XtWindow(dryness_shell), cmap);
+
+ dryness_pm = XCreatePixmap(XtDisplay(top_level),
+ XtWindow(colour_shell), width, height,
+ XDefaultDepth(XtDisplay(top_level), 0));
+
+ XStoreName(display, XtWindow(dryness_shell), "bumps");
+
+ CleanWindow(dryness_pm);
+
+}
+
+static void
+draw_labels()
+{
+ XSetForeground(XtDisplay(colour_shell), gc, colours[1].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(colour_canvas), gc, 10, 10,
+ "Colour", strlen("Colour"));
+ XDrawString(XtDisplay(colour_shell), colour_pm, gc, 10, 10,
+ "Colour", strlen("Colour"));
+
+ XSetForeground(XtDisplay(colour_shell), gc, colours[128].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(volume_canvas), gc, 10, 10,
+ "Volume", strlen("Volume"));
+ XDrawString(XtDisplay(colour_shell), volume_pm, gc, 10, 10,
+ "Volume", strlen("Volume"));
+
+ XSetForeground(XtDisplay(colour_shell), gc, colours[255].pixel);
+
+ XDrawString(XtDisplay(colour_shell), XtWindow(dryness_canvas), gc, 10, 10,
+ "Bump Map", strlen("Bump Map"));
+ XDrawString(XtDisplay(colour_shell), dryness_pm, gc, 10, 10,
+ "Bump Map", strlen("Bump Map"));
+}
+
+void paint_cell(cell, x, y)
+CELL_PTR cell;
+int x, y;
+
+{
+ int colour, volColour, dryness;
+ POINT p;
+
+ p.x = x;
+ p.y = y;
+
+ /* The current display simply maps hue onto the indices of the colour
+ table. This involves some scaling since hues are in the range [0,360)
+ with the colour table being [0,256). */
+
+ colour = (int) (cell->contents.colour.hue *
+ ((float) MAX_COLOUR_INDEX / 360.0));
+
+ DrawBackgroundPoint(x,y,colour);
+
+ /* volColour is an index into the colour table in the range [0,255].
+ It is used to give a false colour image of the canvas's volume. */
+
+ /*if (x < SCALE_WIDTH) return; Don't draw over colour scale. */
+
+ volColour = MIN(cell->volume * 2, 255);
+ volColour = MAX(volColour, 0);
+ /* Make unfilled cells have a zero vol. */
+
+ DrawBackgroundVolumePoint(x,y,volColour);
+
+ /* Dryness will be in the range [0,255]. */
+ dryness = (cell->contents.liquid_content * 255) / 100;
+
+ /*DrawDrynessPoint(x,y,dryness);*/
+}
+
+
+
+void draw_false_colour_scale()
+/* This routine places a scale along the top of the volume window
+ showing the colours being used. Low is at the left edge.
+ The colour palette has indices 0..255. */
+{
+ int x, y;
+
+ /*for (x=0; x < 255; x++)
+ for (y=0; y < SCALE_WIDTH; y++) DrawVolumePoint(x,y,MIN(x, 255));*/
+}
+
+
+void draw_full_canvas()
+{
+ int x, y;
+ CELL_PTR cell;
+ POINT p;
+
+ if (DEBUG) {
+ printf ("Starting to paint full canvas...");
+ fflush(stdout);
+ }
+
+ for (y=0; y < CANVAS_HEIGHT; y++)
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ p.x = x;
+ p.y = y;
+ cell = get_cell(p);
+ paint_cell(cell, x, y);
+ }
+
+ expose_canvases();
+
+ draw_false_colour_scale();
+ if (DEBUG) printf ("done.\n");
+}
+
+void
+bump_map()
+{
+ POINT p;
+ CELL_PTR cell;
+ register int x, y;
+ register int colour;
+
+
+ for (y=0; y < CANVAS_HEIGHT; y++) {
+ for (x=0; x < CANVAS_WIDTH; x++) {
+ p.x = x;
+ p.y = y;
+ cell = get_cell(p);
+ colour = (int) new_intensity_value(p);
+
+/* colour = (int) (cell->contents.colour.hue *
+ ((float) MAX_COLOUR_INDEX / 360.0));*/
+ DrawDrynessPoint(x,y,colour);
+ }
+ }
+
+}
+
+draw_cmap_line()
+
+{
+
+int i;
+
+ for (i=0; i< 255; i++) {
+ DrawDrynessPoint(0,i,i);
+ }
+}
+
+void evolve_paint()
+{
+ int k;
+ POINT p;
+ CELL_PTR cell;
+ int new_x, new_y;
+ Window tempChild;
+ extern Window root;
+ extern int count;
+ extern int frame_count;
+
+ count++;
+ if (count > 5000) {
+ fprintf(stderr,".");
+ fflush(stderr);
+ bump_map();
+ expose_canvases();
+
+ /*XTranslateCoordinates(display,XtWindow(dryness_canvas), root,
+ 0,0, &new_x, &new_y, &tempChild);*/
+ /*if (frame_count < 10)
+ sprintf(pix_file,"xwd -name bumps -out pixmap0%d.xwd &" ,frame_count);
+ else
+ sprintf(pix_file,"xwd -name bumps -out pixmap%d.xwd &" ,frame_count);
+ */
+
+
+ /*system(pix_file);*/
+ /*XWriteBitmapFile(display, pix_file,dryness_pm, 300, 300,-1,-1 );*/
+ count = 0;
+ frame_count++;
+ /*if (frame_count > 250) {
+ fprintf(stderr,"Done\n");
+ sleep(2);
+ exit(0);
+ } */
+ /*exit(0)*/;
+ }
+
+
+
+ for (k=0; k < STEP_LIMIT; k++) single_step();
+ while (TRUE) {
+ next_cell_for_repaint(&cell, &p);
+ if (cell == NIL) return;
+ paint_cell(cell, p.x, p.y);
+ }
+
+}
+
+
+
+void StartWindows()
+{
+/* Start the X windows event loop and paint processing */
+XEvent event;
+
+
+ draw_full_canvas();
+ compute_shade_vectors(); /* Set vectors for shading */
+ draw_labels();
+
+ for (;;) {
+ if (XtPending()) {
+ XtNextEvent(&event);
+ XtDispatchEvent(&event);
+ }
+ else {
+ /* Evolve paint and re-display*/
+ evolve_paint();
+ }
+
+ } /* End for loop */
+
+
+}
+
+void
+stroke(w, client_data, event)
+Widget w;
+caddr_t client_data;
+XEvent *event;
+{
+/* brush_stroke(event->xbutton.x, event->xbutton.y);*/
+
+
+ /*if ((XEvent *)event != (XEvent *)NULL)
+ else
+ printf("Null event\n"); */
+
+/* DrawPoint(event->xbutton.x, event->xbutton.y, 128);
+ DrawVolumePoint(event->xbutton.x, event->xbutton.y, 128);
+ DrawDrynessPoint(event->xbutton.x, event->xbutton.y, 128);*/
+
+
+ XSetForeground(XtDisplay(top_level), gc, colours[128].pixel);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ brush_stroke(event->xbutton.x, event->xbutton.y);
+}
+
+
+void
+stroke_motion(w, client_data, event)
+Widget w;
+caddr_t client_data;
+XEvent *event;
+{
+
+
+ /*if ((XEvent *)event != (XEvent *)NULL)
+ else
+ printf("Null event\n"); */
+
+
+ XSetForeground(XtDisplay(top_level), gc, colours[128].pixel);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(colour_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+ XFillRectangle(XtDisplay(top_level), XtWindow(volume_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ XFillRectangle(XtDisplay(top_level), XtWindow(dryness_canvas), gc,
+ event->xmotion.x, event->xmotion.y ,1, 1);
+
+ brush_stroke(event->xbutton.x, event->xbutton.y);
+}
+
diff --git a/krita/colorspaces/wetsticky/wstool.ui b/krita/colorspaces/wetsticky/wstool.ui
new file mode 100644
index 00000000..4dab3233
--- /dev/null
+++ b/krita/colorspaces/wetsticky/wstool.ui
@@ -0,0 +1,262 @@
+<!DOCTYPE UI><UI version="3.3" stdsetdef="1">
+<class>WdgWSPaintOp</class>
+<widget class="QWidget">
+ <property name="name">
+ <cstring>WdgWSPaintOp</cstring>
+ </property>
+ <property name="geometry">
+ <rect>
+ <x>0</x>
+ <y>0</y>
+ <width>582</width>
+ <height>359</height>
+ </rect>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QGroupBox" row="0" column="0">
+ <property name="name">
+ <cstring>grpGravity</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Gravity</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>chkGravity</cstring>
+ </property>
+ <property name="text">
+ <string>Paint &amp;gravity</string>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lblDirection</cstring>
+ </property>
+ <property name="text">
+ <string>Direction:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intDryingRate</cstring>
+ </property>
+ </widget>
+ <widget class="QComboBox" row="1" column="1">
+ <item>
+ <property name="text">
+ <string>Up</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Right</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Down</string>
+ </property>
+ </item>
+ <item>
+ <property name="text">
+ <string>Left</string>
+ </property>
+ </item>
+ <property name="name">
+ <cstring>cmbGravitationalDirection</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>lblStrength</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Strength:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intGravitationalStrength</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="2" column="1">
+ <property name="name">
+ <cstring>intGravitationalStrength</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="1" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>grpPaint</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Paint</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="QLabel" row="0" column="0">
+ <property name="name">
+ <cstring>lblDryingRate</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Drying rate:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intDryingRate</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="1" column="0" rowspan="2" colspan="4">
+ <property name="name">
+ <cstring>chkLiquid</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Liquid content:</string>
+ </property>
+ <property name="checked">
+ <bool>true</bool>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="0" column="1" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>intDryingRate</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="2" column="2" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>intMiscibility</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="3" column="3">
+ <property name="name">
+ <cstring>intLiquidContent</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0" rowspan="1" colspan="3">
+ <property name="name">
+ <cstring>lblMiscibility</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Miscibility:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intMiscibility</cstring>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ <widget class="QGroupBox" row="0" column="1">
+ <property name="name">
+ <cstring>grpSubstrate</cstring>
+ </property>
+ <property name="title">
+ <string>&amp;Canvas</string>
+ </property>
+ <grid>
+ <property name="name">
+ <cstring>unnamed</cstring>
+ </property>
+ <widget class="KIntNumInput" row="3" column="1">
+ <property name="name">
+ <cstring>intHeight</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="3" column="0">
+ <property name="name">
+ <cstring>lblHeight</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Height:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intHeight</cstring>
+ </property>
+ </widget>
+ <widget class="KIntNumInput" row="2" column="1">
+ <property name="name">
+ <cstring>intAbsorbency</cstring>
+ </property>
+ <property name="minValue">
+ <number>0</number>
+ </property>
+ <property name="maxValue">
+ <number>100</number>
+ </property>
+ </widget>
+ <widget class="QLabel" row="2" column="0">
+ <property name="name">
+ <cstring>lblAbsorbency</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Absorbency:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>intAbsorbency</cstring>
+ </property>
+ </widget>
+ <widget class="QLabel" row="1" column="0">
+ <property name="name">
+ <cstring>lblColor</cstring>
+ </property>
+ <property name="text">
+ <string>&amp;Color:</string>
+ </property>
+ <property name="buddy" stdset="0">
+ <cstring>bnCanvasColor</cstring>
+ </property>
+ </widget>
+ <widget class="QCheckBox" row="0" column="0" rowspan="1" colspan="2">
+ <property name="name">
+ <cstring>chkCanvas</cstring>
+ </property>
+ <property name="text">
+ <string>Paint canvas attributes</string>
+ </property>
+ <property name="accel">
+ <string></string>
+ </property>
+ </widget>
+ <widget class="KColorButton" row="1" column="1">
+ <property name="name">
+ <cstring>bnCanvasColor</cstring>
+ </property>
+ <property name="text">
+ <string></string>
+ </property>
+ </widget>
+ </grid>
+ </widget>
+ </grid>
+</widget>
+<customwidgets>
+</customwidgets>
+<layoutdefaults spacing="6" margin="11"/>
+<includehints>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+ <includehint>knuminput.h</includehint>
+</includehints>
+</UI>
diff --git a/krita/colorspaces/ycbcr_u16/Makefile.am b/krita/colorspaces/ycbcr_u16/Makefile.am
new file mode 100644
index 00000000..5dbfac1b
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u16/Makefile.am
@@ -0,0 +1,27 @@
+# Install the desktop file needed to detect the plugin
+kde_services_DATA = krita_ycbcr_u16_plugin.desktop
+
+INCLUDES = -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../kritacolor/ \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+lib_LTLIBRARIES = libkrita_ycbcr_u16.la
+
+libkrita_ycbcr_u16_la_LDFLAGS = $(all_libraries)
+libkrita_ycbcr_u16_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = krita_ycbcr_u16_plugin.la
+
+# Srcs for the plugin
+krita_ycbcr_u16_plugin_la_SOURCES = ycbcr_u16_plugin.cc
+noinst_HEADERS = ycbcr_u16_plugin.h kis_ycbcr_u16_colorspace.h
+
+krita_ycbcr_u16_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+krita_ycbcr_u16_plugin_la_LIBADD = libkrita_ycbcr_u16.la ../../kritacolor/libkritacolor.la
+
+METASOURCES = AUTO
+
+libkrita_ycbcr_u16_la_SOURCES = kis_ycbcr_u16_colorspace.cc
diff --git a/krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.cc b/krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.cc
new file mode 100644
index 00000000..3155457f
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.cc
@@ -0,0 +1,338 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <[email protected]>
+ *
+ * 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_ycbcr_u16_colorspace.h"
+
+#include <qimage.h>
+
+#include <kis_integer_maths.h>
+
+const Q_INT32 MAX_CHANNEL_YCbCr = 3;
+const Q_INT32 MAX_CHANNEL_YCbCrA = 4;
+
+KisYCbCrU16ColorSpace::KisYCbCrU16ColorSpace(KisColorSpaceFactoryRegistry* parent, KisProfile* /*p*/)
+ : KisU16BaseColorSpace(KisID("YCbCrAU16", i18n("YCbCr (16-bit integer/channel)")), TYPE_YCbCr_16, icSigYCbCrData, parent, 0)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Y"), "Y", PIXEL_Y * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16)));
+ m_channels.push_back(new KisChannelInfo(i18n("Cb"), "Cb", PIXEL_Cb * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16)));
+ m_channels.push_back(new KisChannelInfo(i18n("Cr"), "Cr", PIXEL_Cr * sizeof(Q_UINT16), KisChannelInfo::COLOR, KisChannelInfo::UINT16, sizeof(Q_UINT16)));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), "A", PIXEL_ALPHA * sizeof(Q_UINT16), KisChannelInfo::ALPHA, KisChannelInfo::UINT16, sizeof(Q_UINT16)));
+
+ m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT16);
+ KisAbstractColorSpace::init();
+}
+
+
+KisYCbCrU16ColorSpace::~KisYCbCrU16ColorSpace()
+{
+}
+
+void KisYCbCrU16ColorSpace::setPixel(Q_UINT8 *dst, Q_UINT16 Y, Q_UINT16 Cb, Q_UINT16 Cr, Q_UINT16 alpha) const
+{
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->Y = Y;
+ dstPixel->Cb = Cb;
+ dstPixel->Cr = Cr;
+ dstPixel->alpha = alpha;
+}
+
+void KisYCbCrU16ColorSpace::getPixel(const Q_UINT8 *src, Q_UINT16 *Y, Q_UINT16 *Cb, Q_UINT16 *Cr, Q_UINT16 *alpha) const
+{
+ const Pixel *srcPixel = reinterpret_cast<const Pixel *>(src);
+
+ *Y = srcPixel->Y;
+ *Cb = srcPixel->Cb;
+ *Cr = srcPixel->Cr;
+ *alpha = srcPixel->alpha;
+
+}
+
+void KisYCbCrU16ColorSpace::fromQColor(const QColor& c, Q_UINT8 *dstU8, KisProfile * profile )
+{
+ if(getProfile())
+ {
+ KisU16BaseColorSpace::fromQColor(c, dstU8, profile);
+ } else {
+ Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
+ dst->Y = computeY( c.red(), c.green(), c.blue());
+ dst->Cb = computeCb( c.red(), c.green(), c.blue());
+ dst->Cr = computeCr( c.red(), c.green(), c.blue());
+ }
+}
+
+void KisYCbCrU16ColorSpace::fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dstU8, KisProfile * profile )
+{
+ if(getProfile())
+ {
+ KisU16BaseColorSpace::fromQColor(c, opacity, dstU8, profile);
+ } else {
+ Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
+ dst->Y = computeY( c.red(), c.green(), c.blue());
+ dst->Cb = computeCb( c.red(), c.green(), c.blue());
+ dst->Cr = computeCr( c.red(), c.green(), c.blue());
+ dst->alpha = opacity;
+ }
+}
+
+void KisYCbCrU16ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, KisProfile * profile)
+{
+ if(getProfile())
+ {
+ KisU16BaseColorSpace::toQColor(srcU8, c, profile);
+
+ } else {
+ const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
+ c->setRgb(computeRed(src->Y,src->Cb,src->Cr) >> 8, computeGreen(src->Y,src->Cb,src->Cr) >> 8, computeBlue(src->Y,src->Cb,src->Cr) >> 8);
+ }
+}
+
+void KisYCbCrU16ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_UINT8 *opacity, KisProfile * profile)
+{
+ if(getProfile())
+ {
+ KisU16BaseColorSpace::toQColor(srcU8, c, opacity, profile);
+ } else {
+ const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
+ c->setRgb(computeRed(src->Y,src->Cb,src->Cr) >> 8, computeGreen(src->Y,src->Cb,src->Cr) >> 8, computeBlue(src->Y,src->Cb,src->Cr) >> 8);
+ *opacity = src->alpha;
+ }
+}
+
+Q_UINT8 KisYCbCrU16ColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8)
+{
+ if(getProfile())
+ return KisU16BaseColorSpace::difference(src1U8, src2U8);
+ const Pixel *src1 = reinterpret_cast<const Pixel *>(src1U8);
+ const Pixel *src2 = reinterpret_cast<const Pixel *>(src2U8);
+
+ return QMAX(QABS(src2->Y - src1->Y), QMAX(QABS(src2->Cb - src1->Cb), QABS(src2->Cr - src1->Cr))) >> 8;
+
+}
+
+void KisYCbCrU16ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+ Q_UINT16 totalY = 0, totalCb = 0, totalCr = 0, newAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel *pixel = reinterpret_cast<const Pixel *>(*colors);
+
+ Q_UINT16 alpha = pixel->alpha;
+ float alphaTimesWeight = alpha * *weights;
+
+ totalY += (Q_UINT16)(pixel->Y * alphaTimesWeight);
+ totalCb += (Q_UINT16)(pixel->Cb * alphaTimesWeight);
+ totalCr += (Q_UINT16)(pixel->Cr * alphaTimesWeight);
+ newAlpha += (Q_UINT16)(alphaTimesWeight);
+
+ weights++;
+ colors++;
+ }
+
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->alpha = newAlpha;
+
+ if (newAlpha > 0) {
+ totalY = totalY / newAlpha;
+ totalCb = totalCb / newAlpha;
+ totalCr = totalCr / newAlpha;
+ }
+
+ dstPixel->Y = totalY;
+ dstPixel->Cb = totalCb;
+ dstPixel->Cr = totalCr;
+}
+
+QValueVector<KisChannelInfo *> KisYCbCrU16ColorSpace::channels() const {
+ return m_channels;
+}
+
+Q_UINT32 KisYCbCrU16ColorSpace::nChannels() const {
+ return MAX_CHANNEL_YCbCrA;
+}
+
+Q_UINT32 KisYCbCrU16ColorSpace::nColorChannels() const {
+ return MAX_CHANNEL_YCbCr;
+}
+
+Q_UINT32 KisYCbCrU16ColorSpace::pixelSize() const {
+ return MAX_CHANNEL_YCbCrA * sizeof(Q_UINT16);
+}
+
+
+QImage KisYCbCrU16ColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, KisProfile * dstProfile, Q_INT32 renderingIntent, float exposure )
+{
+ if(getProfile())
+ return KisU16BaseColorSpace::convertToQImage( data, width, height, dstProfile, renderingIntent, exposure);
+
+ QImage img = QImage(width, height, 32, 0, QImage::LittleEndian);
+ img.setAlphaBuffer(true);
+
+ Q_INT32 i = 0;
+ uchar *j = img.bits();
+
+ while ( i < width * height * MAX_CHANNEL_YCbCrA) {
+ Q_UINT16 Y = *( data + i + PIXEL_Y );
+ Q_UINT16 Cb = *( data + i + PIXEL_Cb );
+ Q_UINT16 Cr = *( data + i + PIXEL_Cr );
+ *( j + 3) = *( data + i + PIXEL_ALPHA ) >> 8;
+ *( j + 2 ) = computeRed(Y,Cb,Cr) >> 8;
+ *( j + 1 ) = computeGreen(Y,Cb,Cr) >> 8;
+ *( j + 0 ) = computeBlue(Y,Cb,Cr) >> 8;
+ i += MAX_CHANNEL_YCbCrA;
+ j += 4;
+ }
+ return img;
+}
+
+
+void KisYCbCrU16ColorSpace::bitBlt(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *srcAlphaMask, Q_INT32 maskRowStride, Q_UINT8 opacity, Q_INT32 rows, Q_INT32 cols, const KisCompositeOp& op)
+{
+ switch (op.op()) {
+ case COMPOSITE_UNDEF:
+ // Undefined == no composition
+ break;
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY:
+ compositeCopy(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
+ break;
+ default:
+ break;
+ }
+}
+
+void KisYCbCrU16ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT16 *src = reinterpret_cast<const Q_UINT16 *>(srcRowStart);
+ Q_UINT16 *dst = reinterpret_cast<Q_UINT16 *>(dstRowStart);
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ Q_UINT16 srcAlpha = src[PIXEL_ALPHA];
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, UINT8_TO_UINT16(U8_mask));
+ }
+ mask++;
+ }
+
+ if (srcAlpha != U16_OPACITY_TRANSPARENT) {
+
+ if (opacity != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_MULT(srcAlpha, opacity);
+ }
+
+ if (srcAlpha == U16_OPACITY_OPAQUE) {
+ memcpy(dst, src, MAX_CHANNEL_YCbCrA * sizeof(Q_UINT16));
+ } else {
+ Q_UINT16 dstAlpha = dst[PIXEL_ALPHA];
+
+ Q_UINT16 srcBlend;
+
+ if (dstAlpha == U16_OPACITY_OPAQUE) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_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, MAX_CHANNEL_YCbCr * sizeof(Q_UINT16));
+ } else {
+ dst[PIXEL_Y] = UINT16_BLEND(src[PIXEL_Y], dst[PIXEL_Y], srcBlend);
+ dst[PIXEL_Cb] = UINT16_BLEND(src[PIXEL_Cb], dst[PIXEL_Cb], srcBlend);
+ dst[PIXEL_Cr] = UINT16_BLEND(src[PIXEL_Cr], dst[PIXEL_Cr], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_YCbCrA;
+ dst += MAX_CHANNEL_YCbCrA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart) {
+ maskRowStart += maskRowStride;
+ }
+ }
+}
+
+void KisYCbCrU16ColorSpace::compositeErase(Q_UINT8 *dst, Q_INT32 dstRowSize, const Q_UINT8 *src, Q_INT32 srcRowSize, const Q_UINT8 *srcAlphaMask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 cols, Q_UINT8 /*opacity*/)
+{
+ while (rows-- > 0)
+ {
+ const Pixel *s = reinterpret_cast<const Pixel *>(src);
+ Pixel *d = reinterpret_cast<Pixel *>(dst);
+ const Q_UINT8 *mask = srcAlphaMask;
+
+ for (Q_INT32 i = cols; i > 0; i--, s++, d++)
+ {
+ Q_UINT16 srcAlpha = s->alpha;
+
+ // apply the alphamask
+ if (mask != 0) {
+ Q_UINT8 U8_mask = *mask;
+
+ if (U8_mask != OPACITY_OPAQUE) {
+ srcAlpha = UINT16_BLEND(srcAlpha, U16_OPACITY_OPAQUE, UINT8_TO_UINT16(U8_mask));
+ }
+ mask++;
+ }
+ d->alpha = UINT16_MULT(srcAlpha, d->alpha);
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ if(srcAlphaMask) {
+ srcAlphaMask += maskRowStride;
+ }
+ }
+}
+
+KisCompositeOpList KisYCbCrU16ColorSpace::userVisiblecompositeOps() const
+{
+ KisCompositeOpList list;
+
+ list.append(KisCompositeOp(COMPOSITE_OVER));
+ return list;
+}
diff --git a/krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.h b/krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.h
new file mode 100644
index 00000000..b2dcd341
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u16/kis_ycbcr_u16_colorspace.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <[email protected]>
+ *
+ * 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_YCBCR_U16_COLORSPACE_H
+#define KIS_YCBCR_U16_COLORSPACE_H
+
+#include <kis_u16_base_colorspace.h>
+
+#include <klocale.h>
+
+#define LUMA_RED 0.2989
+#define LUMA_GREEN 0.587
+#define LUMA_BLUE 0.114
+
+class KisYCbCrU16ColorSpace : public KisU16BaseColorSpace
+{
+ public:
+ KisYCbCrU16ColorSpace(KisColorSpaceFactoryRegistry* parent, KisProfile* p);
+ ~KisYCbCrU16ColorSpace();
+ virtual bool willDegrade(ColorSpaceIndependence )
+ {
+ return false;
+ };
+ public:
+ void setPixel(Q_UINT8 *pixel, Q_UINT16 Y, Q_UINT16 Cb, Q_UINT16 Cr, Q_UINT16 alpha) const;
+ void getPixel(const Q_UINT8 *pixel, Q_UINT16 *Y, Q_UINT16 *Cb, Q_UINT16 *Cr, Q_UINT16 *alpha) const;
+
+ virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0);
+ virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0);
+
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0);
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0);
+
+ virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2);
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+
+ virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
+ KisProfile * dstProfile,
+ Q_INT32 renderingIntent,
+ float exposure = 0.0f);
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+ protected:
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+
+ private:
+#define CLAMP_TO_16BITCHANNEL(a) CLAMP(a, 0, Q_UINT16_MAX)
+ inline Q_UINT16 computeRed(Q_UINT16 Y, Q_UINT16 /*Cb*/, Q_UINT16 Cr)
+ {
+ return (Q_UINT16)( CLAMP_TO_16BITCHANNEL( (Cr - 32768)* (2-2*LUMA_RED) + Y ) );
+ }
+ inline Q_UINT16 computeGreen(Q_UINT16 Y, Q_UINT16 Cb, Q_UINT16 Cr)
+ {
+ return (Q_UINT16)( CLAMP_TO_16BITCHANNEL( (Y - LUMA_BLUE * computeBlue(Y,Cb,Cr) - LUMA_RED * computeRed(Y,Cb,Cr) ) / LUMA_GREEN ) );
+ }
+ inline Q_UINT16 computeBlue(Q_UINT16 Y, Q_UINT16 Cb, Q_UINT16 /*Cr*/)
+ {
+ return (Q_UINT16)( CLAMP_TO_16BITCHANNEL( (Cb - 32768)*(2 - 2 * LUMA_BLUE) + Y) );
+ }
+ inline Q_UINT16 computeY( Q_UINT16 r, Q_UINT16 b, Q_UINT16 g)
+ {
+ return (Q_UINT16)( CLAMP_TO_16BITCHANNEL( LUMA_RED*r + LUMA_GREEN*g + LUMA_BLUE*b ) );
+ }
+ inline Q_UINT16 computeCb( Q_UINT16 r, Q_UINT16 b, Q_UINT16 g)
+ {
+ return (Q_UINT16)( CLAMP_TO_16BITCHANNEL( (b - computeY(r,g,b))/(2-2*LUMA_BLUE) + 32768) );
+ }
+ inline Q_UINT16 computeCr( Q_UINT16 r, Q_UINT16 b, Q_UINT16 g)
+ {
+ return (Q_UINT8)( CLAMP_TO_16BITCHANNEL( (r - computeY(r,g,b))/(2-2*LUMA_RED) + 32768) );
+ }
+#undef CLAMP_TO_16BITCHANNEL
+
+ static const Q_UINT8 PIXEL_Y = 0;
+ static const Q_UINT8 PIXEL_Cb = 1;
+ static const Q_UINT8 PIXEL_Cr = 2;
+ static const Q_UINT8 PIXEL_ALPHA = 3;
+
+ struct Pixel {
+ Q_UINT16 Y;
+ Q_UINT16 Cb;
+ Q_UINT16 Cr;
+ Q_UINT16 alpha;
+ };
+};
+
+class KisYCbCrU16ColorSpaceFactory : public KisColorSpaceFactory
+{
+ public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("YCbCrAU16", i18n("YCbCr (16-bit integer/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return TYPE_YCbCr_16; };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icSigYCbCrData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisYCbCrU16ColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return ""; };
+};
+
+
+#endif
diff --git a/krita/colorspaces/ycbcr_u16/krita_ycbcr_u16_plugin.desktop b/krita/colorspaces/ycbcr_u16/krita_ycbcr_u16_plugin.desktop
new file mode 100644
index 00000000..3581582d
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u16/krita_ycbcr_u16_plugin.desktop
@@ -0,0 +1,71 @@
+[Desktop Entry]
+Name=YCbCr Color Model (16-bit integer)
+Name[bg]=Цветови модел YCbCr (16 бита)
+Name[ca]=Model de color YCbCr (enters de 16 bits)
+Name[da]=YCbCr-farvemodel (16-bit heltal)
+Name[de]=YCbCr-Farbmodell (16-bit Ganzzahl)
+Name[el]=Χρωματικό μοντέλο YCbCr (16-bit ακέραιοι)
+Name[eo]=YCbCr-Kolormodelo (16-bita entjero)
+Name[es]=Modelo de color YCbCr (entero de 16 bits)
+Name[et]=YCbCr värvimudel (16-bitine täisarv)
+Name[fa]=مدل رنگ YCbCr )عدد صحیح ۱۶ بیتی(
+Name[fr]=Modèle de couleurs YCbCr (entiers 16 bits)
+Name[fy]=YCbCr-kleurmodel (16-bit integer)
+Name[gl]=Modelo de Cores YCbCr (inteiro de 16-bit)
+Name[hu]=YCbCr színmodell (16 bites egész)
+Name[it]=Modello di colore YCbCr (intero a 16 bit)
+Name[ja]=YCbCr カラーモデル (16 ビット整数)
+Name[km]=គំរូ​ពណ៌ CMYK (ចំនួន​គត់ ១៦ ប៊ីត)
+Name[lt]=YCbCr spalvų modelis (16-bitų sveikasis)
+Name[nb]=YCbCr-fargemodell (16-bit heltall)
+Name[nds]=YCbCr-Klöörmodell (16-Bit Heeltall)
+Name[ne]=वाईसी ी ी आर रङ मोडेल (१६-बिट इन्टिजर)
+Name[nl]=YCbCr-kleurmodel (16-bit integer)
+Name[pl]=Przestrzeń barw YCbCr (16-bitowa liczbowa całkowita)
+Name[pt]=Modelo de Cor YCbCr (inteiros de 16 bits)
+Name[pt_BR]=Modelo de Cor YCbCr (inteiros de 16 bits)
+Name[ru]=YCbCr (целое 16-бит)
+Name[sk]=Model farieb YCbCr (16-biové čísla)
+Name[sl]=Barvni model YCbCr (16-bitno celo število)
+Name[sr]=YCbCr модел боја (16-битно целобројно)
+Name[sr@Latn]=YCbCr model boja (16-bitno celobrojno)
+Name[sv]=YCbCr-färgmodell (16-bitars heltal)
+Name[uk]=Модель кольорів YCbCr (16-бітне ціле)
+Name[uz]=YCbCr rang usuli (16-bit butun)
+Name[uz@cyrillic]=YCbCr ранг усули (16-бит бутун)
+Name[zh_TW]=YCbCr 色彩模型 (16-bit 整數)
+Comment=Color model for 16-bit integer per channel YCbCr images
+Comment[bg]=Цветови модел за 16 битови YCbCr изображения
+Comment[ca]=Model de color d'enters de 16 bits per a canal d'imatges YCbCr
+Comment[da]=Farvemodel for 16-bit heltal pr kanal YCbCr-billeder
+Comment[de]=Farbmodell für 16-bit pro Kanal YCbCr-Bilder
+Comment[el]=Χρωματικό μοντέλο για 16-bit ακεραίους ανά κανάλι YCbCr εικόνες
+Comment[es]=Modelo de color de entero de 16 bits por canal para imágenes YCbCr
+Comment[et]=16-bitiste täisarvuliste kanalitega YCbCr-piltide värvimudel
+Comment[fa]=مدل رنگ برای عدد صحیح ۱۶ بیتی برای هر تصویر YCbCr مجرا
+Comment[fr]=Modèle de couleurs pour des images YCbCr à 16 bits par canal
+Comment[fy]=Kleurmodel foar16-bit/kanaal fan YCbCr-ôfbyldings
+Comment[gl]=Modelo de Cores para imaxes YCbCr de inteiro de 16-bit por canal
+Comment[hu]=Színmodell 16 bit/csatorna YCbCr képekhez
+Comment[it]=Modello di colore per immagini YCbCr a canale di 16 bit interi
+Comment[ja]=16 ビット整数/チャンネル YCbCr 画像のためのカラーモデル
+Comment[km]=គំរូ​ពណ៌​សម្រាប់​រូបភាព CMYK ចំនួនគត់ ១៦ ប៊ីត​ក្នុង​មួយ​ឆានែល
+Comment[nb]=Fargemodell for YCbCr-bilder med 16-bit heltall per kanal
+Comment[nds]=Klöörmodell för YCbCr-Biller mit 16-Bit Heeltall pro Kanaal
+Comment[ne]=प्रति च्यानल वाईसीबीसीआर छविहरूको १६-बिट इन्टिजरका लागि रङ मोडेल
+Comment[nl]=Kleurmodel voor 16-bit/kanaal van YCbCr-afbeeldingen
+Comment[pl]=Przestrzeń barw dla obrazków YCbCr z 16-bitowymi liczbami całkowitymi na kanał
+Comment[pt]=Modelo de cor para imagens YCbCr com 16 bits por canal
+Comment[pt_BR]=Modelo de cor para imagens YCbCr com 16 bits por canal
+Comment[ru]=Цветовое пространство YCbCr (целое 16-бит/канал)
+Comment[sk]=Model farieb pre YCbCr obrázky so 16 bitmi na kanál
+Comment[sl]=Barvni model za slike YCbCr s 16 biti/kanal
+Comment[sr]=Модел боја за YCbCr слике, 16-битно целобројно по каналу
+Comment[sr@Latn]=Model boja za YCbCr slike, 16-bitno celobrojno po kanalu
+Comment[sv]=Färgmodell för YCbCr-bilder med 16-bitars heltal per kanal
+Comment[uk]=Модель кольорів для зображень YCbCr з цілим 16-біт/канал
+Comment[zh_TW]=每色頻為 16-bit 的 YCbCr 圖片色彩模型
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-KDE-Library=krita_ycbcr_u16_plugin
+X-Krita-Version=2
diff --git a/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc b/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc
new file mode 100644
index 00000000..0ab9ed4b
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.cc
@@ -0,0 +1,60 @@
+/*
+ * ycbcr_u16_plugin.cc -- Part of Krita
+ *
+ * Copyright (c) 2006 Cyrille Berger <[email protected]>
+ *
+ * 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 <kinstance.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <kis_debug_areas.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_basic_histogram_producers.h>
+#include <kis_debug_areas.h>
+#include "ycbcr_u16_plugin.h"
+#include "kis_ycbcr_u16_colorspace.h"
+
+typedef KGenericFactory<YCbCrU16Plugin> YCbCrU16PluginFactory;
+K_EXPORT_COMPONENT_FACTORY( krita_ycbcr_u16_plugin, YCbCrU16PluginFactory( "krita" ) )
+
+
+YCbCrU16Plugin::YCbCrU16Plugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(YCbCrU16PluginFactory::instance());
+
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") )
+ {
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry*>( parent );
+
+ KisColorSpace * colorSpaceYCbCrU16 = new KisYCbCrU16ColorSpace(f, 0);
+ KisColorSpaceFactory * csf = new KisYCbCrU16ColorSpaceFactory();
+ Q_CHECK_PTR(colorSpaceYCbCrU16);
+ f->add(csf);
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicU16HistogramProducer>
+ (KisID("YCbCr16HISTO", i18n("YCbCr16")), colorSpaceYCbCrU16) );
+ }
+
+}
+
+YCbCrU16Plugin::~YCbCrU16Plugin()
+{
+}
+
+#include "ycbcr_u16_plugin.moc"
diff --git a/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h b/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h
new file mode 100644
index 00000000..3b079ee7
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u16/ycbcr_u16_plugin.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <[email protected]>
+ *
+ * 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 YCBCR_U16_PLUGIN_H_
+#define YCBCR_U16_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the YCbCr U16 colour space strategy.
+ */
+class YCbCrU16Plugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ YCbCrU16Plugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~YCbCrU16Plugin();
+
+};
+
+
+#endif // YCBCR_U16_PLUGIN_H_
diff --git a/krita/colorspaces/ycbcr_u8/Makefile.am b/krita/colorspaces/ycbcr_u8/Makefile.am
new file mode 100644
index 00000000..bb534bc1
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u8/Makefile.am
@@ -0,0 +1,29 @@
+# Install the desktop file needed to detect the plugin
+
+
+INCLUDES = -I$(srcdir)/../../sdk \
+ -I$(srcdir)/../../kritacolor/color_strategy/ \
+ -I$(srcdir)/../../kritacolor/ \
+ $(KOFFICE_INCLUDES) \
+ $(all_includes)
+
+lib_LTLIBRARIES = libkrita_ycbcr_u8.la
+
+libkrita_ycbcr_u8_la_LDFLAGS = $(all_libraries)
+libkrita_ycbcr_u8_la_LIBADD = ../../kritacolor/libkritacolor.la
+
+# Install this plugin in the KDE modules directory
+kde_module_LTLIBRARIES = krita_ycbcr_u8_plugin.la
+
+# Srcs for the plugin
+krita_ycbcr_u8_plugin_la_SOURCES = ycbcr_u8_plugin.cc
+noinst_HEADERS = ycbcr_u8_plugin.h kis_ycbcr_u8_colorspace.h
+
+krita_ycbcr_u8_plugin_la_LDFLAGS = $(all_libraries) -module $(KDE_PLUGIN)
+krita_ycbcr_u8_plugin_la_LIBADD = libkrita_ycbcr_u8.la ../../kritacolor/libkritacolor.la
+
+METASOURCES = AUTO
+
+
+libkrita_ycbcr_u8_la_SOURCES = kis_ycbcr_u8_colorspace.cc
+kde_services_DATA = krita_ycbcr_u8_plugin.desktop
diff --git a/krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.cc b/krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.cc
new file mode 100644
index 00000000..7c6707c5
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.cc
@@ -0,0 +1,344 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <[email protected]>
+ *
+ * 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_ycbcr_u8_colorspace.h"
+
+#include <qimage.h>
+
+#include <kis_integer_maths.h>
+
+const Q_INT32 MAX_CHANNEL_YCbCr = 3;
+const Q_INT32 MAX_CHANNEL_YCbCrA = 4;
+
+KisYCbCrU8ColorSpace::KisYCbCrU8ColorSpace(KisColorSpaceFactoryRegistry* parent, KisProfile* /*p*/)
+ : KisU8BaseColorSpace(KisID("YCbCrAU8", i18n("YCbCr (8-bit integer/channel)")), TYPE_YCbCr_8, icSigYCbCrData, parent, 0)
+{
+ m_channels.push_back(new KisChannelInfo(i18n("Y"), "Y", PIXEL_Y * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
+ m_channels.push_back(new KisChannelInfo(i18n("Cb"), "Cb", PIXEL_Cb * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
+ m_channels.push_back(new KisChannelInfo(i18n("Cr"), "Cr", PIXEL_Cr * sizeof(Q_UINT8), KisChannelInfo::COLOR, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
+ m_channels.push_back(new KisChannelInfo(i18n("Alpha"), "A", PIXEL_ALPHA * sizeof(Q_UINT8), KisChannelInfo::ALPHA, KisChannelInfo::UINT8, sizeof(Q_UINT8)));
+
+ m_alphaPos = PIXEL_ALPHA * sizeof(Q_UINT8);
+ KisAbstractColorSpace::init();
+}
+
+
+KisYCbCrU8ColorSpace::~KisYCbCrU8ColorSpace()
+{
+}
+
+void KisYCbCrU8ColorSpace::setPixel(Q_UINT8 *dst, Q_UINT8 Y, Q_UINT8 Cb, Q_UINT8 Cr, Q_UINT8 alpha) const
+{
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->Y = Y;
+ dstPixel->Cb = Cb;
+ dstPixel->Cr = Cr;
+ dstPixel->alpha = alpha;
+}
+
+void KisYCbCrU8ColorSpace::getPixel(const Q_UINT8 *src, Q_UINT8 *Y, Q_UINT8 *Cb, Q_UINT8 *Cr, Q_UINT8 *alpha) const
+{
+ const Pixel *srcPixel = reinterpret_cast<const Pixel *>(src);
+
+ *Y = srcPixel->Y;
+ *Cb = srcPixel->Cb;
+ *Cr = srcPixel->Cr;
+ *alpha = srcPixel->alpha;
+
+}
+
+void KisYCbCrU8ColorSpace::fromQColor(const QColor& c, Q_UINT8 *dstU8, KisProfile * profile )
+{
+ if(getProfile())
+ {
+ KisU8BaseColorSpace::fromQColor(c, dstU8, profile);
+ } else {
+ Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
+ dst->Y = computeY( c.red(), c.green(), c.blue());
+ dst->Cb = computeCb( c.red(), c.green(), c.blue());
+ dst->Cr = computeCr( c.red(), c.green(), c.blue());
+ }
+}
+
+void KisYCbCrU8ColorSpace::fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dstU8, KisProfile * profile )
+{
+ if(getProfile())
+ {
+ KisU8BaseColorSpace::fromQColor(c, opacity, dstU8, profile);
+ } else {
+ Pixel *dst = reinterpret_cast<Pixel *>(dstU8);
+ dst->Y = computeY( c.red(), c.green(), c.blue());
+ dst->Cb = computeCb( c.red(), c.green(), c.blue());
+ dst->Cr = computeCr( c.red(), c.green(), c.blue());
+ dst->alpha = opacity;
+ }
+}
+
+void KisYCbCrU8ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, KisProfile * profile)
+{
+ if(getProfile())
+ {
+ KisU8BaseColorSpace::toQColor(srcU8, c, profile);
+
+ } else {
+ const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
+ c->setRgb(computeRed(src->Y,src->Cb,src->Cr), computeGreen(src->Y,src->Cb,src->Cr), computeBlue(src->Y,src->Cb,src->Cr));
+ }
+}
+
+void KisYCbCrU8ColorSpace::toQColor(const Q_UINT8 *srcU8, QColor *c, Q_UINT8 *opacity, KisProfile * profile)
+{
+ if(getProfile())
+ {
+ KisU8BaseColorSpace::toQColor(srcU8, c, opacity, profile);
+ } else {
+ const Pixel *src = reinterpret_cast<const Pixel *>(srcU8);
+ c->setRgb(computeRed(src->Y,src->Cb,src->Cr), computeGreen(src->Y,src->Cb,src->Cr), computeBlue(src->Y,src->Cb,src->Cr));
+ *opacity = src->alpha;
+ }
+}
+
+Q_UINT8 KisYCbCrU8ColorSpace::difference(const Q_UINT8 *src1U8, const Q_UINT8 *src2U8)
+{
+ if(getProfile())
+ return KisU8BaseColorSpace::difference(src1U8, src2U8);
+ const Pixel *src1 = reinterpret_cast<const Pixel *>(src1U8);
+ const Pixel *src2 = reinterpret_cast<const Pixel *>(src2U8);
+
+ return QMAX(QABS(src2->Y - src1->Y), QMAX(QABS(src2->Cb - src1->Cb), QABS(src2->Cr - src1->Cr)));
+
+}
+
+void KisYCbCrU8ColorSpace::mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const
+{
+ Q_UINT8 totalY = 0, totalCb = 0, totalCr = 0, newAlpha = 0;
+
+ while (nColors--)
+ {
+ const Pixel *pixel = reinterpret_cast<const Pixel *>(*colors);
+
+ Q_UINT8 alpha = pixel->alpha;
+ float alphaTimesWeight = alpha * *weights;
+
+ totalY += (Q_UINT8)(pixel->Y * alphaTimesWeight);
+ totalCb += (Q_UINT8)(pixel->Cb * alphaTimesWeight);
+ totalCr += (Q_UINT8)(pixel->Cr * alphaTimesWeight);
+ newAlpha += (Q_UINT8)(alphaTimesWeight);
+
+ weights++;
+ colors++;
+ }
+
+ Pixel *dstPixel = reinterpret_cast<Pixel *>(dst);
+
+ dstPixel->alpha = newAlpha;
+
+ if (newAlpha > 0) {
+ totalY = totalY / newAlpha;
+ totalCb = totalCb / newAlpha;
+ totalCr = totalCr / newAlpha;
+ }
+
+ dstPixel->Y = totalY;
+ dstPixel->Cb = totalCb;
+ dstPixel->Cr = totalCr;
+}
+
+QValueVector<KisChannelInfo *> KisYCbCrU8ColorSpace::channels() const {
+ return m_channels;
+}
+
+Q_UINT32 KisYCbCrU8ColorSpace::nChannels() const {
+ return MAX_CHANNEL_YCbCrA;
+}
+
+Q_UINT32 KisYCbCrU8ColorSpace::nColorChannels() const {
+ return MAX_CHANNEL_YCbCr;
+}
+
+Q_UINT32 KisYCbCrU8ColorSpace::pixelSize() const {
+ return MAX_CHANNEL_YCbCrA*sizeof(Q_UINT8);
+}
+
+
+QImage KisYCbCrU8ColorSpace::convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height, KisProfile * dstProfile, Q_INT32 renderingIntent, float exposure )
+{
+ if(getProfile())
+ return KisU8BaseColorSpace::convertToQImage( data, width, height, dstProfile, renderingIntent, exposure);
+
+ QImage img = QImage(width, height, 32, 0, QImage::LittleEndian);
+ img.setAlphaBuffer(true);
+
+ Q_INT32 i = 0;
+ uchar *j = img.bits();
+
+ while ( i < width * height * MAX_CHANNEL_YCbCrA) {
+ Q_UINT8 Y = *( data + i + PIXEL_Y );
+ Q_UINT8 Cb = *( data + i + PIXEL_Cb );
+ Q_UINT8 Cr = *( data + i + PIXEL_Cr );
+ *( j + 3) = *( data + i + PIXEL_ALPHA );
+ *( j + 2 ) = computeRed(Y,Cb,Cr);
+ *( j + 1 ) = computeGreen(Y,Cb,Cr);
+ *( j + 0 ) = computeBlue(Y,Cb,Cr);
+ i += MAX_CHANNEL_YCbCrA;
+ j += 4;
+ }
+ return img;
+}
+
+
+void KisYCbCrU8ColorSpace::bitBlt(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *srcAlphaMask, Q_INT32 maskRowStride, Q_UINT8 opacity, Q_INT32 rows, Q_INT32 cols, const KisCompositeOp& op)
+{
+ switch (op.op()) {
+ case COMPOSITE_UNDEF:
+ // Undefined == no composition
+ break;
+ case COMPOSITE_OVER:
+ compositeOver(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_COPY:
+ compositeCopy(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
+ break;
+ case COMPOSITE_ERASE:
+ compositeErase(dst, dstRowStride, src, srcRowStride, srcAlphaMask, maskRowStride, rows, cols, opacity);
+ break;
+ default:
+ break;
+ }
+}
+
+void KisYCbCrU8ColorSpace::compositeOver(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 *maskRowStart, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 opacity)
+{
+ while (rows > 0) {
+
+ const Q_UINT8 *src = srcRowStart;
+ Q_UINT8 *dst = dstRowStart;
+ const Q_UINT8 *mask = maskRowStart;
+ Q_INT32 columns = numColumns;
+
+ while (columns > 0) {
+
+ Q_UINT8 srcAlpha = src[PIXEL_ALPHA];
+
+ // apply the alphamask
+ if (mask != 0) {
+ if (*mask != OPACITY_OPAQUE) {
+ srcAlpha *= *mask;
+ }
+ mask++;
+ }
+
+ if (srcAlpha > OPACITY_TRANSPARENT) {
+
+ if (opacity < OPACITY_OPAQUE) {
+ srcAlpha *= opacity;
+ }
+
+ if (srcAlpha == OPACITY_OPAQUE) {
+ memcpy(dst, src, MAX_CHANNEL_YCbCrA * sizeof(Q_UINT8));
+ } else {
+ Q_UINT8 dstAlpha = dst[PIXEL_ALPHA];
+
+ Q_UINT8 srcBlend;
+
+ if (dstAlpha == OPACITY_OPAQUE ) {
+ srcBlend = srcAlpha;
+ } else {
+ Q_UINT8 newAlpha = dstAlpha + (OPACITY_OPAQUE - dstAlpha) * srcAlpha;
+ dst[PIXEL_ALPHA] = newAlpha;
+
+ if (newAlpha > 0) {
+ srcBlend = srcAlpha / newAlpha;
+ } else {
+ srcBlend = srcAlpha;
+ }
+ }
+
+ if (srcBlend == OPACITY_OPAQUE) {
+ memcpy(dst, src, MAX_CHANNEL_YCbCr * sizeof(Q_UINT8));
+ } else {
+ dst[PIXEL_Y] = UINT8_BLEND(src[PIXEL_Y], dst[PIXEL_Y], srcBlend);
+ dst[PIXEL_Cb] = UINT8_BLEND(src[PIXEL_Cb], dst[PIXEL_Cb], srcBlend);
+ dst[PIXEL_Cr] = UINT8_BLEND(src[PIXEL_Cr], dst[PIXEL_Cr], srcBlend);
+ }
+ }
+ }
+
+ columns--;
+ src += MAX_CHANNEL_YCbCrA;
+ dst += MAX_CHANNEL_YCbCrA;
+ }
+
+ rows--;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ if(maskRowStart) {
+ maskRowStart += maskRowStride;
+ }
+ }
+}
+
+void KisYCbCrU8ColorSpace::compositeErase(Q_UINT8 *dst, Q_INT32 dstRowSize, const Q_UINT8 *src, Q_INT32 srcRowSize, const Q_UINT8 *srcAlphaMask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 cols, Q_UINT8 /*opacity*/)
+{
+ while (rows-- > 0)
+ {
+ const Pixel *s = reinterpret_cast<const Pixel *>(src);
+ Pixel *d = reinterpret_cast<Pixel *>(dst);
+ const Q_UINT8 *mask = srcAlphaMask;
+
+ for (Q_INT32 i = cols; i > 0; i--, s++, d++)
+ {
+ Q_UINT8 srcAlpha = s -> alpha;
+
+ // apply the alphamask
+ if (mask != 0) {
+ if (*mask != OPACITY_OPAQUE) {
+ srcAlpha = *mask;
+ }
+ mask++;
+ }
+ d -> alpha = srcAlpha * d -> alpha;
+ }
+
+ dst += dstRowSize;
+ src += srcRowSize;
+ if(srcAlphaMask) {
+ srcAlphaMask += maskRowStride;
+ }
+ }
+}
+
+void KisYCbCrU8ColorSpace::compositeCopy(Q_UINT8 *dstRowStart, Q_INT32 dstRowStride, const Q_UINT8 *srcRowStart, Q_INT32 srcRowStride, const Q_UINT8 */*mask*/, Q_INT32 /*maskRowStride*/, Q_INT32 rows, Q_INT32 numColumns, Q_UINT8 /*opacity*/)
+{
+ while (rows > 0) {
+ memcpy(dstRowStart, srcRowStart, numColumns * sizeof(Pixel));
+ --rows;
+ srcRowStart += srcRowStride;
+ dstRowStart += dstRowStride;
+ }
+}
+
+KisCompositeOpList KisYCbCrU8ColorSpace::userVisiblecompositeOps() const
+{
+ KisCompositeOpList list;
+
+ list.append(KisCompositeOp(COMPOSITE_OVER));
+ return list;
+}
diff --git a/krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h b/krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h
new file mode 100644
index 00000000..bc4d8329
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u8/kis_ycbcr_u8_colorspace.h
@@ -0,0 +1,144 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <[email protected]>
+ *
+ * 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_YCBCR_U8_COLORSPACE_H
+#define KIS_YCBCR_U8_COLORSPACE_H
+
+#include <kis_u8_base_colorspace.h>
+
+#include <klocale.h>
+
+#define LUMA_RED 0.2989
+#define LUMA_GREEN 0.587
+#define LUMA_BLUE 0.114
+
+class KisYCbCrU8ColorSpace : public KisU8BaseColorSpace
+{
+ public:
+ KisYCbCrU8ColorSpace(KisColorSpaceFactoryRegistry* parent, KisProfile* p);
+ ~KisYCbCrU8ColorSpace();
+ virtual bool willDegrade(ColorSpaceIndependence )
+ {
+ return false;
+ };
+ public:
+ void setPixel(Q_UINT8 *pixel, Q_UINT8 Y, Q_UINT8 Cb, Q_UINT8 Cr, Q_UINT8 alpha) const;
+ void getPixel(const Q_UINT8 *pixel, Q_UINT8 *Y, Q_UINT8 *Cb, Q_UINT8 *Cr, Q_UINT8 *alpha) const;
+
+ virtual void fromQColor(const QColor& c, Q_UINT8 *dst, KisProfile * profile = 0);
+ virtual void fromQColor(const QColor& c, Q_UINT8 opacity, Q_UINT8 *dst, KisProfile * profile = 0);
+
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, KisProfile * profile = 0);
+ virtual void toQColor(const Q_UINT8 *src, QColor *c, Q_UINT8 *opacity, KisProfile * profile = 0);
+
+ virtual Q_UINT8 difference(const Q_UINT8 *src1, const Q_UINT8 *src2);
+ virtual void mixColors(const Q_UINT8 **colors, const Q_UINT8 *weights, Q_UINT32 nColors, Q_UINT8 *dst) const;
+
+ virtual QValueVector<KisChannelInfo *> channels() const;
+ virtual Q_UINT32 nChannels() const;
+ virtual Q_UINT32 nColorChannels() const;
+ virtual Q_UINT32 pixelSize() const;
+
+ virtual QImage convertToQImage(const Q_UINT8 *data, Q_INT32 width, Q_INT32 height,
+ KisProfile * dstProfile,
+ Q_INT32 renderingIntent,
+ float exposure = 0.0f);
+
+ virtual KisCompositeOpList userVisiblecompositeOps() const;
+
+ protected:
+
+ virtual void bitBlt(Q_UINT8 *dst,
+ Q_INT32 dstRowStride,
+ const Q_UINT8 *src,
+ Q_INT32 srcRowStride,
+ const Q_UINT8 *srcAlphaMask,
+ Q_INT32 maskRowStride,
+ Q_UINT8 opacity,
+ Q_INT32 rows,
+ Q_INT32 cols,
+ const KisCompositeOp& op);
+
+ void compositeOver(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeErase(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+ void compositeCopy(Q_UINT8 *dst, Q_INT32 dstRowStride, const Q_UINT8 *src, Q_INT32 srcRowStride, const Q_UINT8 *mask, Q_INT32 maskRowStride, Q_INT32 rows, Q_INT32 columns, Q_UINT8 opacity);
+
+ private:
+#define CLAMP_TO_8BITCHANNEL(a) CLAMP(a, 0, Q_UINT8_MAX)
+ inline Q_UINT8 computeRed(Q_UINT8 Y, Q_UINT8 /*Cb*/, Q_UINT8 Cr)
+ {
+ return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( (Cr - 128)* (2-2*LUMA_RED) + Y ) );
+ }
+ inline Q_UINT8 computeGreen(Q_UINT8 Y, Q_UINT8 Cb, Q_UINT8 Cr)
+ {
+ return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( (Y - LUMA_BLUE * computeBlue(Y,Cb,Cr) - LUMA_RED * computeRed(Y,Cb,Cr) ) / LUMA_GREEN ) );
+ }
+ inline Q_UINT8 computeBlue(Q_UINT8 Y, Q_UINT8 Cb, Q_UINT8 /*Cr*/)
+ {
+ return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( (Cb - 128)*(2 - 2 * LUMA_BLUE) + Y) );
+ }
+ inline Q_UINT8 computeY( Q_UINT8 r, Q_UINT8 b, Q_UINT8 g)
+ {
+ return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( LUMA_RED*r + LUMA_GREEN*g + LUMA_BLUE*b ) );
+ }
+ inline Q_UINT8 computeCb( Q_UINT8 r, Q_UINT8 b, Q_UINT8 g)
+ {
+ return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( (b - computeY(r,g,b))/(2-2*LUMA_BLUE) + 128) );
+ }
+ inline Q_UINT8 computeCr( Q_UINT8 r, Q_UINT8 b, Q_UINT8 g)
+ {
+ return (Q_UINT8)( CLAMP_TO_8BITCHANNEL( (r - computeY(r,g,b))/(2-2*LUMA_RED) + 128) );
+ }
+#undef CLAMP_TO_8BITCHANNEL
+
+ static const Q_UINT8 PIXEL_Y = 0;
+ static const Q_UINT8 PIXEL_Cb = 1;
+ static const Q_UINT8 PIXEL_Cr = 2;
+ static const Q_UINT8 PIXEL_ALPHA = 3;
+
+ struct Pixel {
+ Q_UINT8 Y;
+ Q_UINT8 Cb;
+ Q_UINT8 Cr;
+ Q_UINT8 alpha;
+ };
+};
+
+class KisYCbCrU8ColorSpaceFactory : public KisColorSpaceFactory
+{
+ public:
+ /**
+ * Krita definition for use in .kra files and internally: unchanging name +
+ * i18n'able description.
+ */
+ virtual KisID id() const { return KisID("YCbCrAU8", i18n("YCbCr (8-bit integer/channel)")); };
+
+ /**
+ * lcms colorspace type definition.
+ */
+ virtual Q_UINT32 colorSpaceType() { return TYPE_YCbCr_8; };
+
+ virtual icColorSpaceSignature colorSpaceSignature() { return icSigYCbCrData; };
+
+ virtual KisColorSpace *createColorSpace(KisColorSpaceFactoryRegistry * parent, KisProfile *p) { return new KisYCbCrU8ColorSpace(parent, p); };
+
+ virtual QString defaultProfile() { return ""; };
+};
+
+#endif
diff --git a/krita/colorspaces/ycbcr_u8/krita_ycbcr_u8_plugin.desktop b/krita/colorspaces/ycbcr_u8/krita_ycbcr_u8_plugin.desktop
new file mode 100644
index 00000000..2c29e972
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u8/krita_ycbcr_u8_plugin.desktop
@@ -0,0 +1,71 @@
+[Desktop Entry]
+Name=YCbCr Color Model (8-bit integer)
+Name[bg]=Цветови модел YCbCr (16 бита)
+Name[ca]=Model de color YCbCr (enters de 16 bits)
+Name[da]=YCbCr-farvemodel (8-bit heltal)
+Name[de]=YCbCr-Farbmodell (8-bit Ganzzahl)
+Name[el]=Χρωματικό μοντέλο YCbCr (16-bit ακέραιοι)
+Name[eo]=YCbCr-Kolormodelo (8-bita entjero)
+Name[es]=Modelo de color YCbCr (entero de 8 bits)
+Name[et]=YCbCr värvimudel (8-bitine täisarv)
+Name[fa]=مدل رنگ YCbCr )عدد صحیح ۸ بیتی(
+Name[fr]=Modèle de couleurs YCbCr (entiers 8 bits)
+Name[fy]=YCbCr-kleurmodel (8-bit integer)
+Name[gl]=Modelo de Cores YCbCr (inteiro de 8-bit)
+Name[hu]=YCbCr színmodell (8 bites egész)
+Name[it]=Modello di colore YCbCr (intero a 8 bit)
+Name[ja]=YCbCr カラーモデル (8 ビット整数)
+Name[km]=គំរូ​ពណ៌ CMYK (ចំនួនគត់ ១៦ ប៊ីត)
+Name[lt]=YCbCr spalvų modelis (8-bitų sveikasis)
+Name[nb]=YCbCr fargemodell (8-bit heltall)
+Name[nds]=YCbCr-Klöörmodell (8-Bit Heeltall)
+Name[ne]=वाईसीबीसीआर रङ मोडेल (८-बिट इन्टिजर)
+Name[nl]=YCbCr-kleurmodel (8-bit integer)
+Name[pl]=Przestrzeń barw YCbCr (8-bitowa liczbowa całkowita)
+Name[pt]=Modelo de Cor YCbCr (inteiros de 8 bits)
+Name[pt_BR]=Modelo de Cor YCbCr (inteiros de 8 bits)
+Name[ru]=YCbCr (целое 8-бит)
+Name[sk]=Model farieb YCbCr (8-biové čísla)
+Name[sl]=Barvni model YCbCr (8-bitno celo število)
+Name[sr]=YCbCr модел боја (8-битно целобројно)
+Name[sr@Latn]=YCbCr model boja (8-bitno celobrojno)
+Name[sv]=YCbCr-färgmodell (8-bitars heltal)
+Name[uk]=Модель кольорів YCbCr (ціле 8-біт)
+Name[uz]=YCbCr rang usuli (8-bit butun)
+Name[uz@cyrillic]=YCbCr ранг усули (8-бит бутун)
+Name[zh_TW]=YCbCr 色彩模型 (16-bit 整數)
+Comment=Color model for 8-bit integer per channel YCbCr images
+Comment[bg]=Цветови модел за 16 битови YCbCr изображения
+Comment[ca]=Model de color d'enters de 16 bits per a canal d'imatges YCbCr
+Comment[da]=Farvemodel for 8-bit heltal pr kanal YCbCr-billeder
+Comment[de]=Farbmodell für 8-bit pro Kanal YCbCr-Bilder
+Comment[el]=Χρωματικό μοντέλο για 8-bit ακεραίους ανά κανάλι YCbCr εικόνες
+Comment[es]=Modelo de color de entero de 16 bits por canal para imágenes YCbCr
+Comment[et]=8-bitiste täisarvuliste kanalitega YCbCr-piltide värvimudel
+Comment[fa]=مدل رنگ برای عدد صحیح ۸ بیتی برای هر تصویر YCbCr مجرا
+Comment[fr]=Modèle de couleurs pour des images YCbCr à 8 bits par canal
+Comment[fy]=Kleurmodel foar 8-bit/kanaal fan YCbCr-ôfbyldings
+Comment[gl]=Modelo de Cores para imaxes YCbCr de inteiro de 8-bit por canal
+Comment[hu]=Színmodell 8 bit/csatorna YCbCr képekhez
+Comment[it]=Modello di colore per immagini YCbCr a canale di 8 bit interi
+Comment[ja]=8 ビット整数/チャンネル YCbCr 画像のためのカラーモデル
+Comment[km]=ម៉ូដែល​ពណ៌​សម្រាប់​ចំនួន​គត់ 8-bit ក្នុង​ឆានែល​រូបភាព YCbCr
+Comment[nb]=Fargemodell for YCbCr-bilder med 8 bit heltall per kanal
+Comment[nds]=Klöörmodell för YCbCr-Biller mit 8-Bit Heeltall pro Kanaal
+Comment[ne]=प्रति वाईसीबीसीआर छविहरूको ८-बिट इन्टिजरका लागि रङ मोडेल
+Comment[nl]=Kleurmodel voor 8-bit/kanaal van YCbCr-afbeeldingen
+Comment[pl]=Przestrzeń barw dla obrazków YCbCr z 8-bitowymi liczbami całkowitymi na kanał
+Comment[pt]=Modelo de cor para imagens YCbCr com 8 bits por canal
+Comment[pt_BR]=Modelo de cor para imagens YCbCr com 8 bits por canal
+Comment[ru]=Цветовое пространство YCbCr (целое 8-бит/канал)
+Comment[sk]=Model farieb pre YCbCr obrázky s 8 bitmi na kanál
+Comment[sl]=Barvni model za slike YCbCr z 8 biti/kanal
+Comment[sr]=Модел боја за YCbCr слике, 8-битно целобројно по каналу
+Comment[sr@Latn]=Model boja za YCbCr slike, 8-bitno celobrojno po kanalu
+Comment[sv]=Färgmodell för YCbCr-bilder med 8-bitars heltal per kanal
+Comment[uk]=Модель кольорів для зображень YCbCr з цілим 8-біт/канал
+Comment[zh_TW]=每色頻為 16-bit 的 YCbCr 圖片色彩模型
+ServiceTypes=Krita/ColorSpace
+Type=Service
+X-KDE-Library=krita_ycbcr_u8_plugin
+X-Krita-Version=2
diff --git a/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc b/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc
new file mode 100644
index 00000000..751e3f31
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.cc
@@ -0,0 +1,62 @@
+/*
+ * ycbcr_u8_plugin.cc -- Part of Krita
+ *
+ * Copyright (c) 2006 Cyrille Berger <[email protected]>
+ *
+ * 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 "ycbcr_u8_plugin.h"
+
+#include <kinstance.h>
+#include <kgenericfactory.h>
+#include <kdebug.h>
+
+#include <kis_debug_areas.h>
+#include <kis_colorspace_factory_registry.h>
+#include <kis_basic_histogram_producers.h>
+#include <kis_debug_areas.h>
+
+#include "kis_ycbcr_u8_colorspace.h"
+
+typedef KGenericFactory<YCbCrU8Plugin> YCbCrU8PluginFactory;
+K_EXPORT_COMPONENT_FACTORY( krita_ycbcr_u8_plugin, YCbCrU8PluginFactory( "krita" ) )
+
+
+YCbCrU8Plugin::YCbCrU8Plugin(QObject *parent, const char *name, const QStringList &)
+ : KParts::Plugin(parent, name)
+{
+ setInstance(YCbCrU8PluginFactory::instance());
+
+ if ( parent->inherits("KisColorSpaceFactoryRegistry") )
+ {
+ KisColorSpaceFactoryRegistry * f = dynamic_cast<KisColorSpaceFactoryRegistry*>( parent );
+
+ KisColorSpace * colorSpaceYCbCrU8 = new KisYCbCrU8ColorSpace(f, 0);
+ KisColorSpaceFactory * csf = new KisYCbCrU8ColorSpaceFactory();
+ Q_CHECK_PTR(colorSpaceYCbCrU8);
+ f->add(csf);
+ KisHistogramProducerFactoryRegistry::instance()->add(
+ new KisBasicHistogramProducerFactory<KisBasicU16HistogramProducer>
+ (KisID("YCBR8HISTO", i18n("YCBR8")), colorSpaceYCbCrU8) );
+ }
+
+}
+
+YCbCrU8Plugin::~YCbCrU8Plugin()
+{
+}
+
+#include "ycbcr_u8_plugin.moc"
diff --git a/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h b/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h
new file mode 100644
index 00000000..ef418784
--- /dev/null
+++ b/krita/colorspaces/ycbcr_u8/ycbcr_u8_plugin.h
@@ -0,0 +1,37 @@
+/*
+ * Copyright (c) 2006 Cyrille Berger <[email protected]>
+ *
+ * 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 YCBCR_U8_PLUGIN_H_
+#define YCBCR_U8_PLUGIN_H_
+
+#include <kparts/plugin.h>
+
+/**
+ * A plugin wrapper around the YCbCr U8 colour space strategy.
+ */
+class YCbCrU8Plugin : public KParts::Plugin
+{
+ Q_OBJECT
+public:
+ YCbCrU8Plugin(QObject *parent, const char *name, const QStringList &);
+ virtual ~YCbCrU8Plugin();
+
+};
+
+
+#endif // YCBCR_U8_PLUGIN_H_