diff options
author | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
---|---|---|
committer | tpearson <tpearson@283d02a7-25f6-0310-bc7c-ecb5cbfe19da> | 2010-01-20 01:29:50 +0000 |
commit | 8362bf63dea22bbf6736609b0f49c152f975eb63 (patch) | |
tree | 0eea3928e39e50fae91d4e68b21b1e6cbae25604 /krita/colorspaces | |
download | koffice-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')
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>&Image</text> + <Menu name="Mode"><text>&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 Binary files differnew file mode 100644 index 00000000..5c844c2f --- /dev/null +++ b/krita/colorspaces/cmyk_u8/templates/cr48-action-template_cmyk_empty.png 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 Binary files differnew file mode 100644 index 00000000..a1ad0ae5 --- /dev/null +++ b/krita/colorspaces/cmyk_u8/templates/crsc-action-template_cmyk_empty.svgz 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 Binary files differnew file mode 100644 index 00000000..7fb7a166 --- /dev/null +++ b/krita/colorspaces/cmyk_u8/templates/white_2000x800.kra 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>&Image</text> + <Menu name="Mode"><text>&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 Binary files differnew file mode 100644 index 00000000..3ea63818 --- /dev/null +++ b/krita/colorspaces/gray_u8/templates/cr48-action-template_gray_empty.png 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 Binary files differnew file mode 100644 index 00000000..93af227f --- /dev/null +++ b/krita/colorspaces/gray_u8/templates/crsc-action-template_gray_empty.svgz 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 Binary files differnew file mode 100644 index 00000000..f1865a64 --- /dev/null +++ b/krita/colorspaces/gray_u8/templates/white_640x480.kra 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>&Image</text> + <Menu name="Mode"><text>&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>&Image</text> + <Menu name="Mode"><text>&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>&Image</text> + <Menu name="Mode"><text>&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>&Image</text> + <Menu name="Mode"><text>&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 Binary files differnew file mode 100644 index 00000000..ec4d6ddc --- /dev/null +++ b/krita/colorspaces/rgb_u8/templates/cr48-action-template_rgb_empty.png 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 Binary files differnew file mode 100644 index 00000000..3ea7b854 --- /dev/null +++ b/krita/colorspaces/rgb_u8/templates/crsc-action-template_rgb_empty.svgz 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 Binary files differnew file mode 100644 index 00000000..eb026588 --- /dev/null +++ b/krita/colorspaces/rgb_u8/templates/transparent_1024x768.kra 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 Binary files differnew file mode 100644 index 00000000..be96fb23 --- /dev/null +++ b/krita/colorspaces/rgb_u8/templates/transparent_1280x1024.kra 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 Binary files differnew file mode 100644 index 00000000..b01685a9 --- /dev/null +++ b/krita/colorspaces/rgb_u8/templates/transparent_1600x1200.kra 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 Binary files differnew file mode 100644 index 00000000..59777c92 --- /dev/null +++ b/krita/colorspaces/rgb_u8/templates/transparent_640x480.kra 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 Binary files differnew file mode 100644 index 00000000..0a7702ad --- /dev/null +++ b/krita/colorspaces/rgb_u8/templates/white_1024x768.kra 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 Binary files differnew file mode 100644 index 00000000..8d552419 --- /dev/null +++ b/krita/colorspaces/rgb_u8/templates/white_1280x1024.kra 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 Binary files differnew file mode 100644 index 00000000..7c037d9e --- /dev/null +++ b/krita/colorspaces/rgb_u8/templates/white_1600x1200.kra 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 Binary files differnew file mode 100644 index 00000000..2a0265d0 --- /dev/null +++ b/krita/colorspaces/rgb_u8/templates/white_640x480.kra 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, ¤t, 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>&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 Binary files differnew file mode 100644 index 00000000..b1b6317d --- /dev/null +++ b/krita/colorspaces/wetsticky/brushop/wetpaintbrush.png 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 Binary files differnew file mode 100644 index 00000000..5116efdb --- /dev/null +++ b/krita/colorspaces/wetsticky/ws/after.jpg 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 Binary files differnew file mode 100644 index 00000000..fc26b989 --- /dev/null +++ b/krita/colorspaces/wetsticky/ws/before.jpg 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 Binary files differnew file mode 100644 index 00000000..2060ee90 --- /dev/null +++ b/krita/colorspaces/wetsticky/ws/mona.pgm 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 Binary files differnew file mode 100644 index 00000000..24b92c3d --- /dev/null +++ b/krita/colorspaces/wetsticky/ws/test2.jpg diff --git a/krita/colorspaces/wetsticky/ws/test3.jpg b/krita/colorspaces/wetsticky/ws/test3.jpg Binary files differnew file mode 100644 index 00000000..2b25a0d5 --- /dev/null +++ b/krita/colorspaces/wetsticky/ws/test3.jpg 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>&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 &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>&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>&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>&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>&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>&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>&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>&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>&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>&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_ |