You can not select more than 25 topics
Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
313 lines
12 KiB
313 lines
12 KiB
/*
|
|
* Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
|
|
* Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
|
|
*
|
|
* This program is free software; you can redistribute it and/or modify
|
|
* it under the terms of the GNU General Public License as published by
|
|
* the Free Software Foundation; either version 2 of the License, or
|
|
* (at your option) any later version.
|
|
*
|
|
* This program is distributed in the hope that it will be useful,
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
* GNU General Public License for more details.
|
|
*
|
|
* You should have received a copy of the GNU General Public License
|
|
* along with this program; if not, write to the Free Software
|
|
* Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
|
|
*/
|
|
#ifndef KIS_ABSTRACT_COLORSPACE_H_
|
|
#define KIS_ABSTRACT_COLORSPACE_H_
|
|
|
|
#include <strings.h>
|
|
|
|
#include <tqmap.h>
|
|
#include <tqcolor.h>
|
|
#include <tqstringlist.h>
|
|
#include <tqpair.h>
|
|
|
|
#include "kis_global.h"
|
|
#include "kis_channelinfo.h"
|
|
#include "kis_profile.h"
|
|
#include "kis_id.h"
|
|
#include "kis_composite_op.h"
|
|
#include "kis_colorspace.h"
|
|
#include "koffice_export.h"
|
|
|
|
|
|
class TQPainter;
|
|
class KisPixelRO;
|
|
class KisColorSpaceFactoryRegistry;
|
|
|
|
|
|
/**
|
|
* A colorspace strategy is the definition of a certain color model
|
|
* in Chalk.
|
|
*/
|
|
class KRITA_EXPORT KisAbstractColorSpace : public KisColorSpace {
|
|
|
|
|
|
public:
|
|
|
|
/**
|
|
* @param id The unique human and machine readable identifiation of this colorspace
|
|
* @param cmType the lcms type indentification for this colorspace, may be 0
|
|
* @param colorSpaceSignature the icc identification for this colorspace, may be 0
|
|
* @param parent the registry that owns this instance
|
|
* @param profile the profile this colorspace uses for transforms
|
|
*/
|
|
KisAbstractColorSpace(const KisID & id,
|
|
DWORD cmType,
|
|
icColorSpaceSignature colorSpaceSignature,
|
|
KisColorSpaceFactoryRegistry * parent,
|
|
KisProfile *profile);
|
|
|
|
void init();
|
|
|
|
virtual ~KisAbstractColorSpace();
|
|
|
|
virtual bool operator==(const KisAbstractColorSpace& rhs) const {
|
|
return (m_id == rhs.m_id && m_profile == rhs.m_profile);
|
|
}
|
|
|
|
|
|
//================== Information about this color strategy ========================//
|
|
|
|
public:
|
|
|
|
|
|
//========== Channels =====================================================//
|
|
|
|
// Return a vector describing all the channels this color model has.
|
|
virtual TQValueVector<KisChannelInfo *> channels() const = 0;
|
|
|
|
virtual TQ_UINT32 nChannels() const = 0;
|
|
|
|
virtual TQ_UINT32 nColorChannels() const = 0;
|
|
|
|
virtual TQ_UINT32 nSubstanceChannels() const { return 0; };
|
|
|
|
virtual TQ_UINT32 pixelSize() const = 0;
|
|
|
|
virtual TQString channelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const = 0;
|
|
|
|
virtual TQString normalisedChannelValueText(const TQ_UINT8 *pixel, TQ_UINT32 channelIndex) const = 0;
|
|
|
|
virtual TQ_UINT8 scaleToU8(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) = 0;
|
|
|
|
virtual TQ_UINT16 scaleToU16(const TQ_UINT8 * srcPixel, TQ_INT32 channelPos) = 0;
|
|
|
|
virtual void getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex);
|
|
|
|
//========== Identification ===============================================//
|
|
|
|
virtual KisID id() const { return m_id; }
|
|
|
|
void setColorSpaceType(TQ_UINT32 type) { m_cmType = type; }
|
|
TQ_UINT32 colorSpaceType() { return m_cmType; }
|
|
|
|
virtual icColorSpaceSignature colorSpaceSignature() { return m_colorSpaceSignature; }
|
|
|
|
//========== Capabilities =================================================//
|
|
|
|
virtual KisCompositeOpList userVisiblecompositeOps() const = 0;
|
|
|
|
/**
|
|
* Returns true if the colorspace supports channel values outside the
|
|
* (normalised) range 0 to 1.
|
|
*/
|
|
virtual bool hasHighDynamicRange() const { return false; }
|
|
|
|
//========== Display profiles =============================================//
|
|
|
|
virtual KisProfile * getProfile() const { return m_profile; };
|
|
|
|
|
|
//================= Conversion functions ==================================//
|
|
|
|
|
|
virtual void fromTQColor(const TQColor& c, TQ_UINT8 *dst, KisProfile * profile = 0);
|
|
virtual void fromTQColor(const TQColor& c, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile = 0);
|
|
|
|
virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile = 0);
|
|
virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile = 0);
|
|
|
|
|
|
virtual void toLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const;
|
|
virtual void fromLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const;
|
|
|
|
virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height,
|
|
KisProfile * dstProfile,
|
|
TQ_INT32 renderingIntent = INTENT_PERCEPTUAL,
|
|
float exposure = 0.0f);
|
|
|
|
virtual bool convertPixelsTo(const TQ_UINT8 * src,
|
|
TQ_UINT8 * dst, KisColorSpace * dstColorSpace,
|
|
TQ_UINT32 numPixels,
|
|
TQ_INT32 renderingIntent = INTENT_PERCEPTUAL);
|
|
|
|
//============================== Manipulation fucntions ==========================//
|
|
|
|
|
|
//
|
|
// The manipulation functions have default implementations that _convert_ the pixel
|
|
// to a TQColor and back. Reimplement these methods in your color strategy!
|
|
//
|
|
virtual KisColorAdjustment *createBrightnessContrastAdjustment(TQ_UINT16 *transferValues);
|
|
|
|
virtual KisColorAdjustment *createDesaturateAdjustment();
|
|
|
|
virtual KisColorAdjustment *createPerChannelAdjustment(TQ_UINT16 **transferValues);
|
|
|
|
virtual void applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels);
|
|
|
|
virtual void invertColor(TQ_UINT8 * src, TQ_INT32 nPixels);
|
|
|
|
virtual TQ_UINT8 difference(const TQ_UINT8* src1, const TQ_UINT8* src2);
|
|
|
|
virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const;
|
|
|
|
virtual void convolveColors(TQ_UINT8** colors, TQ_INT32* kernelValues, KisChannelInfo::enumChannelFlags channelFlags, TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nPixels) const;
|
|
|
|
virtual void darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const;
|
|
|
|
virtual TQ_UINT8 intensity8(const TQ_UINT8 * src) const;
|
|
|
|
virtual KisID mathToolboxID() const;
|
|
|
|
virtual void bitBlt(TQ_UINT8 *dst,
|
|
TQ_INT32 dststride,
|
|
KisColorSpace * srcSpace,
|
|
const TQ_UINT8 *src,
|
|
TQ_INT32 srcRowStride,
|
|
const TQ_UINT8 *srcAlphaMask,
|
|
TQ_INT32 maskRowStride,
|
|
TQ_UINT8 opacity,
|
|
TQ_INT32 rows,
|
|
TQ_INT32 cols,
|
|
const KisCompositeOp& op);
|
|
|
|
//========================== END of Public API ========================================//
|
|
|
|
protected:
|
|
|
|
|
|
/**
|
|
* Compose two byte arrays containing pixels in the same color
|
|
* model together.
|
|
*/
|
|
virtual void bitBlt(TQ_UINT8 *dst,
|
|
TQ_INT32 dstRowSize,
|
|
const TQ_UINT8 *src,
|
|
TQ_INT32 srcRowStride,
|
|
const TQ_UINT8 *srcAlphaMask,
|
|
TQ_INT32 maskRowStride,
|
|
TQ_UINT8 opacity,
|
|
TQ_INT32 rows,
|
|
TQ_INT32 cols,
|
|
const KisCompositeOp& op) = 0;
|
|
|
|
virtual cmsHTRANSFORM createTransform(KisColorSpace * dstColorSpace,
|
|
KisProfile * srcProfile,
|
|
KisProfile * dstProfile,
|
|
TQ_INT32 renderingIntent);
|
|
|
|
virtual void compositeCopy(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride, const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride, const TQ_UINT8 *maskRowStart, TQ_INT32 maskRowStride, TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity);
|
|
|
|
|
|
// So I don't need to re-implement it everywhere.
|
|
template <typename ColorType,
|
|
typename NativeMult, typename Uint8ToNative, typename NativeOpacityTest,
|
|
int AlphaPos, int NonAlphaSize, int TotalSize>
|
|
void abstractCompositeAlphaDarken(TQ_UINT8 *dstRowStart, TQ_INT32 dstRowStride,
|
|
const TQ_UINT8 *srcRowStart, TQ_INT32 srcRowStride,
|
|
const TQ_UINT8 *maskRowStart, TQ_INT32 maskRowStride,
|
|
TQ_INT32 rows, TQ_INT32 numColumns, TQ_UINT8 opacity,
|
|
NativeMult nativeMult, Uint8ToNative uint8ToNative,
|
|
NativeOpacityTest nativeOpacityTest) {
|
|
while (rows > 0) {
|
|
|
|
const ColorType *src = reinterpret_cast<const ColorType*>(srcRowStart);
|
|
ColorType *dst = reinterpret_cast<ColorType*>(dstRowStart);
|
|
const TQ_UINT8 *mask = maskRowStart;
|
|
TQ_INT32 columns = numColumns;
|
|
|
|
while (columns > 0) {
|
|
|
|
ColorType srcAlpha = src[AlphaPos];
|
|
ColorType dstAlpha = dst[AlphaPos];
|
|
|
|
// apply the alphamask
|
|
if(mask != 0)
|
|
{
|
|
if(*mask != OPACITY_OPAQUE)
|
|
srcAlpha = nativeMult(srcAlpha, uint8ToNative(*mask));
|
|
mask++;
|
|
}
|
|
|
|
if (opacity != OPACITY_OPAQUE) {
|
|
srcAlpha = nativeMult(srcAlpha, uint8ToNative(opacity));
|
|
}
|
|
|
|
// not transparent
|
|
if (nativeOpacityTest(srcAlpha) && srcAlpha >= dstAlpha) {
|
|
dst[AlphaPos] = srcAlpha;
|
|
memcpy(dst, src, NonAlphaSize * sizeof(ColorType));
|
|
}
|
|
|
|
columns--;
|
|
src += TotalSize;
|
|
dst += TotalSize;
|
|
}
|
|
|
|
rows--;
|
|
srcRowStart += srcRowStride;
|
|
dstRowStart += dstRowStride;
|
|
if(maskRowStart)
|
|
maskRowStart += maskRowStride;
|
|
}
|
|
}
|
|
|
|
protected:
|
|
|
|
TQStringList m_profileFilenames;
|
|
TQ_UINT8 * m_qcolordata; // A small buffer for conversion from and to qcolor.
|
|
TQ_INT32 m_alphaPos; // The position in _bytes_ of the alpha channel
|
|
TQ_INT32 m_alphaSize; // The width in _bytes_ of the alpha channel
|
|
|
|
TQValueVector<KisChannelInfo *> m_channels;
|
|
|
|
KisColorSpaceFactoryRegistry * m_parent;
|
|
|
|
private:
|
|
|
|
cmsHTRANSFORM m_defaultToRGB; // Default transform to 8 bit sRGB
|
|
cmsHTRANSFORM m_defaultFromRGB; // Default transform from 8 bit sRGB
|
|
|
|
cmsHPROFILE m_lastRGBProfile; // Last used profile to transform to/from RGB
|
|
cmsHTRANSFORM m_lastToRGB; // Last used transform to transform to RGB
|
|
cmsHTRANSFORM m_lastFromRGB; // Last used transform to transform from RGB
|
|
|
|
cmsHTRANSFORM m_defaultToLab;
|
|
cmsHTRANSFORM m_defaultFromLab;
|
|
|
|
KisProfile * m_profile;
|
|
KisColorSpace *m_lastUsedDstColorSpace;
|
|
cmsHTRANSFORM m_lastUsedTransform;
|
|
|
|
KisID m_id;
|
|
DWORD m_cmType; // The colorspace type as defined by littlecms
|
|
icColorSpaceSignature m_colorSpaceSignature; // The colorspace signature as defined in icm/icc files
|
|
|
|
// cmsHTRANSFORM is a void *, so this should work.
|
|
typedef TQMap<KisColorSpace *, cmsHTRANSFORM> TransformMap;
|
|
TransformMap m_transforms; // Cache for existing transforms
|
|
|
|
KisAbstractColorSpace(const KisAbstractColorSpace&);
|
|
KisAbstractColorSpace& operator=(const KisAbstractColorSpace&);
|
|
|
|
TQMemArray<TQ_UINT8> m_conversionCache; // XXX: This will be a bad problem when we have threading.
|
|
};
|
|
|
|
#endif // KIS_STRATEGY_COLORSPACE_H_
|