chalk

kis_abstract_colorspace.cpp
1/*
2 * Copyright (c) 2002 Patrick Julien <freak@codepimps.org>
3 * Copyright (c) 2004 Cyrille Berger <cberger@cberger.net>
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
18 */
19#include <tqimage.h>
20
21#include <kdebug.h>
22#include <tdeconfig.h>
23
24#include "kis_abstract_colorspace.h"
25#include "kis_global.h"
26#include "kis_profile.h"
27#include "kis_id.h"
28#include "kis_integer_maths.h"
29#include "kis_color_conversions.h"
30#include "kis_colorspace_factory_registry.h"
31#include "kis_channelinfo.h"
32
33class KisColorAdjustmentImpl : public KisColorAdjustment
34{
35 public:
36
37 KisColorAdjustmentImpl() : KisColorAdjustment()
38 {
39 csProfile = 0;
40 transform = 0;
41 profiles[0] = 0;
42 profiles[1] = 0;
43 profiles[2] = 0;
44 };
45
46 ~KisColorAdjustmentImpl() {
47
48 if (transform)
49 cmsDeleteTransform(transform);
50 if (profiles[0] && profiles[0] != csProfile)
51 cmsCloseProfile(profiles[0]);
52 if(profiles[1] && profiles[1] != csProfile)
53 cmsCloseProfile(profiles[1]);
54 if(profiles[2] && profiles[2] != csProfile)
55 cmsCloseProfile(profiles[2]);
56 }
57
58 cmsHPROFILE csProfile;
59 cmsHPROFILE profiles[3];
60 cmsHTRANSFORM transform;
61};
62
64 DWORD cmType,
65 icColorSpaceSignature colorSpaceSignature,
67 KisProfile *p)
68 : m_parent( parent )
69 , m_profile( p )
70 , m_id( id )
71 , m_cmType( cmType )
72 , m_colorSpaceSignature( colorSpaceSignature )
73{
74 m_alphaPos = -1;
75 m_alphaSize = -1;
76 m_qcolordata = 0;
77 m_lastUsedDstColorSpace = 0;
78 m_lastUsedTransform = 0;
79 m_lastRGBProfile = 0;
80 m_lastToRGB = 0;
81 m_lastFromRGB = 0;
82 m_defaultFromRGB = 0;
83 m_defaultToRGB = 0;
84 m_defaultFromLab = 0;
85 m_defaultToLab = 0;
86}
87
88void KisAbstractColorSpace::init()
89{
90 // Default pixel buffer for TQColor conversion
91 m_qcolordata = new TQ_UINT8[3];
92 TQ_CHECK_PTR(m_qcolordata);
93
94 if (m_profile == 0) return;
95
96 // For conversions from default rgb
97 m_lastFromRGB = cmsCreate_sRGBProfile();
98
99 m_defaultFromRGB = cmsCreateTransform(m_lastFromRGB, TYPE_BGR_8,
100 m_profile->profile(), m_cmType,
101 INTENT_PERCEPTUAL, 0);
102
103 m_defaultToRGB = cmsCreateTransform(m_profile->profile(), m_cmType,
104 m_lastFromRGB, TYPE_BGR_8,
105 INTENT_PERCEPTUAL, 0);
106
107 cmsHPROFILE hLab = cmsCreateLabProfile(NULL);
108
109 m_defaultFromLab = cmsCreateTransform(hLab, TYPE_Lab_16, m_profile->profile(), m_cmType,
110 INTENT_PERCEPTUAL, 0);
111
112 m_defaultToLab = cmsCreateTransform(m_profile->profile(), m_cmType, hLab, TYPE_Lab_16,
113 INTENT_PERCEPTUAL, 0);
114}
115
116KisAbstractColorSpace::~KisAbstractColorSpace()
117{
118}
119
120
121
122void KisAbstractColorSpace::fromTQColor(const TQColor& color, TQ_UINT8 *dst, KisProfile * profile)
123{
124 m_qcolordata[2] = color.red();
125 m_qcolordata[1] = color.green();
126 m_qcolordata[0] = color.blue();
127
128
129 if (profile == 0) {
130 // Default sRGB
131 if (!m_defaultFromRGB) return;
132
133 cmsDoTransform(m_defaultFromRGB, m_qcolordata, dst, 1);
134 }
135 else {
136 if (m_lastFromRGB == 0 || (m_lastFromRGB != 0 && m_lastRGBProfile != profile->profile())) {
137 m_lastFromRGB = cmsCreateTransform(profile->profile(), TYPE_BGR_8,
138 m_profile->profile(), m_cmType,
139 INTENT_PERCEPTUAL, 0);
140 m_lastRGBProfile = profile->profile();
141
142 }
143 cmsDoTransform(m_lastFromRGB, m_qcolordata, dst, 1);
144 }
145
146 setAlpha(dst, OPACITY_OPAQUE, 1);
147}
148
149void KisAbstractColorSpace::fromTQColor(const TQColor& color, TQ_UINT8 opacity, TQ_UINT8 *dst, KisProfile * profile)
150{
151 fromTQColor(color, dst, profile);
152 setAlpha(dst, opacity, 1);
153}
154
155void KisAbstractColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile * profile)
156{
157 if (profile == 0) {
158 // Default sRGB transform
159 if (!m_defaultToRGB) return;
160 cmsDoTransform(m_defaultToRGB, const_cast <TQ_UINT8 *>(src), m_qcolordata, 1);
161 }
162 else {
163 if (m_lastToRGB == 0 || (m_lastToRGB != 0 && m_lastRGBProfile != profile->profile())) {
164 m_lastToRGB = cmsCreateTransform(m_profile->profile(), m_cmType,
165 profile->profile(), TYPE_BGR_8,
166 INTENT_PERCEPTUAL, 0);
167 m_lastRGBProfile = profile->profile();
168 }
169 cmsDoTransform(m_lastToRGB, const_cast <TQ_UINT8 *>(src), m_qcolordata, 1);
170 }
171 c->setRgb(m_qcolordata[2], m_qcolordata[1], m_qcolordata[0]);
172}
173
174void KisAbstractColorSpace::toTQColor(const TQ_UINT8 *src, TQColor *c, TQ_UINT8 *opacity, KisProfile * profile)
175{
176 toTQColor(src, c, profile);
177 *opacity = getAlpha(src);
178}
179
180void KisAbstractColorSpace::toLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const
181{
182 if ( m_defaultToLab == 0 ) return;
183
184 cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8 *>( src ), dst, nPixels );
185}
186
187void KisAbstractColorSpace::fromLabA16(const TQ_UINT8 * src, TQ_UINT8 * dst, const TQ_UINT32 nPixels) const
188{
189 if ( m_defaultFromLab == 0 ) return;
190
191 cmsDoTransform( m_defaultFromLab, const_cast<TQ_UINT8 *>( src ), dst, nPixels );
192}
193
194
195void KisAbstractColorSpace::getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex)
196{
197 if (channelIndex < m_channels.count()) {
198
199 fromTQColor(TQt::black, OPACITY_TRANSPARENT, dstPixel);
200
201 const KisChannelInfo *channelInfo = m_channels[channelIndex];
202 memcpy(dstPixel + channelInfo->pos(), srcPixel + channelInfo->pos(), channelInfo->size());
203 }
204}
205
207 TQ_UINT8 * dst,
208 KisColorSpace * dstColorSpace,
209 TQ_UINT32 numPixels,
210 TQ_INT32 renderingIntent)
211{
212 if (dstColorSpace->colorSpaceType() == colorSpaceType()
213 && dstColorSpace->getProfile() == getProfile())
214 {
215 if (src!= dst)
216 memcpy (dst, src, numPixels * pixelSize());
217
218 return true;
219 }
220
221 cmsHTRANSFORM tf = 0;
222
223 TQ_INT32 srcPixelSize = pixelSize();
224 TQ_INT32 dstPixelSize = dstColorSpace->pixelSize();
225
226 if (m_lastUsedTransform != 0 && m_lastUsedDstColorSpace != 0) {
227 if (dstColorSpace->colorSpaceType() == m_lastUsedDstColorSpace->colorSpaceType() &&
228 dstColorSpace->getProfile() == m_lastUsedDstColorSpace->getProfile()) {
229 tf = m_lastUsedTransform;
230 }
231 }
232
233 if (!tf && m_profile && dstColorSpace->getProfile()) {
234
235 if (!m_transforms.contains(dstColorSpace)) {
236 tf = createTransform(dstColorSpace,
237 m_profile,
238 dstColorSpace->getProfile(),
239 renderingIntent);
240 if (tf) {
241 // XXX: Should we clear the transform cache if it gets too big?
242 m_transforms[dstColorSpace] = tf;
243 }
244 }
245 else {
246 tf = m_transforms[dstColorSpace];
247 }
248
249 if ( tf ) {
250 m_lastUsedTransform = tf;
251 m_lastUsedDstColorSpace = dstColorSpace;
252 }
253 }
254
255 if (tf) {
256
257 cmsDoTransform(tf, const_cast<TQ_UINT8 *>(src), dst, numPixels);
258
259 // Lcms does nothing to the destination alpha channel so we must convert that manually.
260 while (numPixels > 0) {
261 TQ_UINT8 alpha = getAlpha(src);
262 dstColorSpace->setAlpha(dst, alpha, 1);
263
264 src += srcPixelSize;
265 dst += dstPixelSize;
266 numPixels--;
267 }
268
269 return true;
270 }
271
272 // Last resort fallback. This will be removed when this class is renamed KisLCMSColorSpace after 1.5.
273 while (numPixels > 0) {
274 TQColor color;
275 TQ_UINT8 opacity;
276
277 toTQColor(src, &color, &opacity);
278 dstColorSpace->fromTQColor(color, opacity, dst);
279
280 src += srcPixelSize;
281 dst += dstPixelSize;
282 numPixels--;
283 }
284
285 return true;
286}
287
288
289KisColorAdjustment *KisAbstractColorSpace::createBrightnessContrastAdjustment(TQ_UINT16 *transferValues)
290{
291 if (!m_profile) return 0;
292
293 LPGAMMATABLE transferFunctions[3];
294 transferFunctions[0] = cmsBuildGamma(256, 1.0);
295 transferFunctions[1] = cmsBuildGamma(256, 1.0);
296 transferFunctions[2] = cmsBuildGamma(256, 1.0);
297
298 for(int i =0; i < 256; i++)
299 transferFunctions[0]->GammaTable[i] = transferValues[i];
300
301 KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
302 adj->profiles[1] = cmsCreateLinearizationDeviceLink(icSigLabData, transferFunctions);
303 cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass);
304
305 adj->profiles[0] = m_profile->profile();
306 adj->profiles[2] = m_profile->profile();
307 adj->transform = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0);
308 adj->csProfile = m_profile->profile();
309 return adj;
310}
311
312typedef struct {
313 double Saturation;
314
315} BCHSWADJUSTS, *LPBCHSWADJUSTS;
316
317
318static int desaturateSampler(WORD In[], WORD Out[], LPVOID /*Cargo*/)
319{
320 cmsCIELab LabIn, LabOut;
321 cmsCIELCh LChIn, LChOut;
322 //LPBCHSWADJUSTS bchsw = (LPBCHSWADJUSTS) Cargo;
323
324 cmsLabEncoded2Float(&LabIn, In);
325
326 cmsLab2LCh(&LChIn, &LabIn);
327
328 // Do some adjusts on LCh
329 LChOut.L = LChIn.L;
330 LChOut.C = 0;//LChIn.C + bchsw->Saturation;
331 LChOut.h = LChIn.h;
332
333 cmsLCh2Lab(&LabOut, &LChOut);
334
335 // Back to encoded
336 cmsFloat2LabEncoded(Out, &LabOut);
337
338 return 1;
339}
340
342{
343 if (!m_profile) return 0;
344
345 KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
346
347 adj->profiles[0] = m_profile->profile();
348 adj->profiles[2] = m_profile->profile();
349 adj->csProfile = m_profile->profile();
350
351 LPLUT Lut;
352 BCHSWADJUSTS bchsw;
353
354 bchsw.Saturation = -25;
355
356 adj->profiles[1] = _cmsCreateProfilePlaceholder();
357 if (!adj->profiles[1]) // can't allocate
358 return NULL;
359
360 cmsSetDeviceClass(adj->profiles[1], icSigAbstractClass);
361 cmsSetColorSpace(adj->profiles[1], icSigLabData);
362 cmsSetPCS(adj->profiles[1], icSigLabData);
363
364 cmsSetRenderingIntent(adj->profiles[1], INTENT_PERCEPTUAL);
365
366 // Creates a LUT with 3D grid only
367 Lut = cmsAllocLUT();
368
369 cmsAlloc3DGrid(Lut, 32, 3, 3);
370
371 if (!cmsSample3DGrid(Lut, desaturateSampler, static_cast<LPVOID>(&bchsw), 0)) {
372 // Shouldn't reach here
373 cmsFreeLUT(Lut);
374 cmsCloseProfile(adj->profiles[1]);
375 return NULL;
376 }
377
378 // Create tags
379
380 cmsAddTag(adj->profiles[1], icSigDeviceMfgDescTag, (LPVOID) "(chalk internal)");
381 cmsAddTag(adj->profiles[1], icSigProfileDescriptionTag, (LPVOID) "chalk saturation abstract profile");
382 cmsAddTag(adj->profiles[1], icSigDeviceModelDescTag, (LPVOID) "saturation built-in");
383
384 cmsAddTag(adj->profiles[1], icSigMediaWhitePointTag, (LPVOID) cmsD50_XYZ());
385
386 cmsAddTag(adj->profiles[1], icSigAToB0Tag, (LPVOID) Lut);
387
388 // LUT is already on virtual profile
389 cmsFreeLUT(Lut);
390
391 adj->transform = cmsCreateMultiprofileTransform(adj->profiles, 3, m_cmType, m_cmType, INTENT_PERCEPTUAL, 0);
392
393 return adj;
394}
395
396KisColorAdjustment *KisAbstractColorSpace::createPerChannelAdjustment(TQ_UINT16 **transferValues)
397{
398 if (!m_profile) return 0;
399
400 LPGAMMATABLE *transferFunctions = new LPGAMMATABLE[nColorChannels()+1];
401
402 for(uint ch=0; ch < nColorChannels(); ch++) {
403 transferFunctions[ch] = cmsBuildGamma(256, 1.0);
404 for(uint i =0; i < 256; i++) {
405 transferFunctions[ch]->GammaTable[i] = transferValues[ch][i];
406 }
407 }
408
409 KisColorAdjustmentImpl *adj = new KisColorAdjustmentImpl;
410 adj->profiles[0] = cmsCreateLinearizationDeviceLink(colorSpaceSignature(), transferFunctions);
411 adj->profiles[1] = NULL;
412 adj->profiles[2] = NULL;
413 adj->csProfile = m_profile->profile();
414 adj->transform = cmsCreateTransform(adj->profiles[0], m_cmType, NULL, m_cmType, INTENT_PERCEPTUAL, 0);
415
416 delete [] transferFunctions;
417
418 return adj;
419}
420
421
422void KisAbstractColorSpace::applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *adjustment, TQ_INT32 nPixels)
423{
424 KisColorAdjustmentImpl * adj = dynamic_cast<KisColorAdjustmentImpl*>(adjustment);
425 if (adj)
426 cmsDoTransform(adj->transform, const_cast<TQ_UINT8 *>(src), dst, nPixels);
427}
428
429
430void KisAbstractColorSpace::invertColor(TQ_UINT8 * src, TQ_INT32 nPixels)
431{
432 TQColor c;
433 TQ_UINT8 opacity;
434 TQ_UINT32 psize = pixelSize();
435
436 while (nPixels--)
437 {
438 toTQColor(src, &c, &opacity);
439 c.setRgb(TQ_UINT8_MAX - c.red(), TQ_UINT8_MAX - c.green(), TQ_UINT8_MAX - c.blue());
440 fromTQColor( c, opacity, src);
441
442 src += psize;
443 }
444}
445
446TQ_UINT8 KisAbstractColorSpace::difference(const TQ_UINT8* src1, const TQ_UINT8* src2)
447{
448 if (m_defaultToLab) {
449
450 TQ_UINT8 lab1[8], lab2[8];
451 cmsCIELab labF1, labF2;
452
453 if (getAlpha(src1) == OPACITY_TRANSPARENT || getAlpha(src2) == OPACITY_TRANSPARENT)
454 return (getAlpha(src1) == getAlpha(src2) ? 0 : 255);
455
456 cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8*>( src1 ), lab1, 1);
457 cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8*>( src2 ), lab2, 1);
458 cmsLabEncoded2Float(&labF1, (WORD *)lab1);
459 cmsLabEncoded2Float(&labF2, (WORD *)lab2);
460 double diff = cmsDeltaE(&labF1, &labF2);
461 if(diff>255)
462 return 255;
463 else
464 return TQ_INT8(diff);
465 }
466 else {
467 TQColor c1;
468 TQ_UINT8 opacity1;
469 toTQColor(src1, &c1, &opacity1);
470
471 TQColor c2;
472 TQ_UINT8 opacity2;
473 toTQColor(src2, &c2, &opacity2);
474
475 TQ_UINT8 red = abs(c1.red() - c2.red());
476 TQ_UINT8 green = abs(c1.green() - c2.green());
477 TQ_UINT8 blue = abs(c1.blue() - c2.blue());
478 return TQMAX(red, TQMAX(green, blue));
479 }
480}
481
482void KisAbstractColorSpace::mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const
483{
484 TQ_UINT32 totalRed = 0, totalGreen = 0, totalBlue = 0, newAlpha = 0;
485
486 TQColor c;
487 TQ_UINT8 opacity;
488
489 while (nColors--)
490 {
491 // Ugly hack to get around the current constness mess of the colour strategy...
492 const_cast<KisAbstractColorSpace *>(this)->toTQColor(*colors, &c, &opacity);
493
494 TQ_UINT32 alphaTimesWeight = UINT8_MULT(opacity, *weights);
495
496 totalRed += c.red() * alphaTimesWeight;
497 totalGreen += c.green() * alphaTimesWeight;
498 totalBlue += c.blue() * alphaTimesWeight;
499 newAlpha += alphaTimesWeight;
500
501 weights++;
502 colors++;
503 }
504
505 Q_ASSERT(newAlpha <= 255);
506
507 if (newAlpha > 0) {
508 totalRed = UINT8_DIVIDE(totalRed, newAlpha);
509 totalGreen = UINT8_DIVIDE(totalGreen, newAlpha);
510 totalBlue = UINT8_DIVIDE(totalBlue, newAlpha);
511 }
512
513 // Divide by 255.
514 totalRed += 0x80;
515
516 TQ_UINT32 dstRed = ((totalRed >> 8) + totalRed) >> 8;
517 Q_ASSERT(dstRed <= 255);
518
519 totalGreen += 0x80;
520 TQ_UINT32 dstGreen = ((totalGreen >> 8) + totalGreen) >> 8;
521 Q_ASSERT(dstGreen <= 255);
522
523 totalBlue += 0x80;
524 TQ_UINT32 dstBlue = ((totalBlue >> 8) + totalBlue) >> 8;
525 Q_ASSERT(dstBlue <= 255);
526
527 const_cast<KisAbstractColorSpace *>(this)->fromTQColor(TQColor(dstRed, dstGreen, dstBlue), newAlpha, dst);
528}
529
530void KisAbstractColorSpace::convolveColors(TQ_UINT8** colors, TQ_INT32 * kernelValues, KisChannelInfo::enumChannelFlags channelFlags,
531 TQ_UINT8 *dst, TQ_INT32 factor, TQ_INT32 offset, TQ_INT32 nColors) const
532{
533 TQ_INT32 totalRed = 0, totalGreen = 0, totalBlue = 0, totalAlpha = 0;
534
535 TQColor dstColor;
536 TQ_UINT8 dstOpacity;
537
538 const_cast<KisAbstractColorSpace *>(this)->toTQColor(dst, &dstColor, &dstOpacity);
539
540 while (nColors--)
541 {
542 TQ_INT32 weight = *kernelValues;
543
544 if (weight != 0) {
545 TQColor c;
546 TQ_UINT8 opacity;
547 const_cast<KisAbstractColorSpace *>(this)->toTQColor( *colors, &c, &opacity );
548 totalRed += c.red() * weight;
549 totalGreen += c.green() * weight;
550 totalBlue += c.blue() * weight;
551 totalAlpha += opacity * weight;
552 }
553 colors++;
554 kernelValues++;
555 }
556
557
558 if (channelFlags & KisChannelInfo::FLAG_COLOR) {
559 const_cast<KisAbstractColorSpace *>(this)->fromTQColor(TQColor(CLAMP((totalRed / factor) + offset, 0, TQ_UINT8_MAX),
560 CLAMP((totalGreen / factor) + offset, 0, TQ_UINT8_MAX),
561 CLAMP((totalBlue / factor) + offset, 0, TQ_UINT8_MAX)),
562 dstOpacity,
563 dst);
564 }
565 if (channelFlags & KisChannelInfo::FLAG_ALPHA) {
566 const_cast<KisAbstractColorSpace *>(this)->fromTQColor(dstColor, CLAMP((totalAlpha/ factor) + offset, 0, TQ_UINT8_MAX), dst);
567 }
568
569}
570
571void KisAbstractColorSpace::darken(const TQ_UINT8 * src, TQ_UINT8 * dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const
572{
573 if (m_defaultToLab) {
574 TQ_UINT16 * labcache = new TQ_UINT16[nPixels * 4];
575 cmsDoTransform( m_defaultToLab, const_cast<TQ_UINT8*>( src ), reinterpret_cast<TQ_UINT8*>( labcache ), nPixels );
576 for ( int i = 0; i < nPixels * 4; ++i ) {
577 if ( compensate ) {
578 labcache[i] = static_cast<TQ_UINT16>( ( labcache[i] * shade ) / ( compensation * 255 ) );
579 }
580 else {
581 labcache[i] = static_cast<TQ_UINT16>( labcache[i] * shade / 255 );
582 }
583 }
584 cmsDoTransform( m_defaultFromLab, reinterpret_cast<TQ_UINT8*>( labcache ), dst, nPixels );
585
586 // Copy alpha
587 for ( int i = 0; i < nPixels; ++i ) {
588 TQ_UINT8 alpha = getAlpha( src );
589 setAlpha( dst, alpha, 1 );
590 }
591 delete [] labcache;
592 }
593 else {
594
595 TQColor c;
596 TQ_INT32 psize = pixelSize();
597
598 for (int i = 0; i < nPixels; ++i) {
599
600 const_cast<KisAbstractColorSpace *>(this)->toTQColor(src + (i * psize), &c);
601 TQ_INT32 r, g, b;
602
603 if (compensate) {
604 r = static_cast<TQ_INT32>( TQMIN(255, (c.red() * shade) / (compensation * 255)));
605 g = static_cast<TQ_INT32>( TQMIN(255, (c.green() * shade) / (compensation * 255)));
606 b = static_cast<TQ_INT32>( TQMIN(255, (c.blue() * shade) / (compensation * 255)));
607 }
608 else {
609 r = static_cast<TQ_INT32>( TQMIN(255, (c.red() * shade / 255)));
610 g = static_cast<TQ_INT32>( TQMIN(255, (c.green() * shade / 255)));
611 b = static_cast<TQ_INT32>( TQMIN(255, (c.blue() * shade / 255)));
612 }
613 c.setRgb(r, g, b);
614
615 const_cast<KisAbstractColorSpace *>(this)->fromTQColor( c, dst + (i * psize));
616 }
617 }
618}
619
620TQ_UINT8 KisAbstractColorSpace::intensity8(const TQ_UINT8 * src) const
621{
622 TQColor c;
623 TQ_UINT8 opacity;
624 const_cast<KisAbstractColorSpace *>(this)->toTQColor(src, &c, &opacity);
625 return static_cast<TQ_UINT8>((c.red() * 0.30 + c.green() * 0.59 + c.blue() * 0.11) + 0.5);
626
627}
628
629
631{
632 return KisID("Basic");
633}
634
636 TQ_INT32 dststride,
637 KisColorSpace * srcSpace,
638 const TQ_UINT8 *src,
639 TQ_INT32 srcRowStride,
640 const TQ_UINT8 *srcAlphaMask,
641 TQ_INT32 maskRowStride,
642 TQ_UINT8 opacity,
643 TQ_INT32 rows,
644 TQ_INT32 cols,
645 const KisCompositeOp& op)
646{
647 if (rows <= 0 || cols <= 0)
648 return;
649
650 if (this != srcSpace) {
651 TQ_UINT32 len = pixelSize() * rows * cols;
652
653 // If our conversion cache is too small, extend it.
654 if (!m_conversionCache.resize( len, TQGArray::SpeedOptim )) {
655 kdWarning() << "Could not allocate enough memory for the conversion!\n";
656 // XXX: We should do a slow, pixel by pixel bitblt here...
657 abort();
658 }
659
660 for (TQ_INT32 row = 0; row < rows; row++) {
661 srcSpace->convertPixelsTo(src + row * srcRowStride,
662 m_conversionCache.data() + row * cols * pixelSize(), this,
663 cols);
664 }
665
666 // The old srcRowStride is no longer valid because we converted to the current cs
667 srcRowStride = cols * pixelSize();
668
669 bitBlt(dst,
670 dststride,
671 m_conversionCache.data(),
672 srcRowStride,
673 srcAlphaMask,
674 maskRowStride,
675 opacity,
676 rows,
677 cols,
678 op);
679
680 }
681 else {
682 bitBlt(dst,
683 dststride,
684 src,
685 srcRowStride,
686 srcAlphaMask,
687 maskRowStride,
688 opacity,
689 rows,
690 cols,
691 op);
692 }
693}
694
695TQImage KisAbstractColorSpace::convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height,
696 KisProfile *dstProfile,
697 TQ_INT32 renderingIntent, float /*exposure*/)
698
699{
700 TQImage img = TQImage(width, height, 32, 0, TQImage::LittleEndian);
701 img.setAlphaBuffer( true );
702
703 KisColorSpace * dstCS;
704
705 if (dstProfile)
706 dstCS = m_parent->getColorSpace(KisID("RGBA",""),dstProfile->productName());
707 else
708 dstCS = m_parent->getRGB8();
709
710 if (data)
711 convertPixelsTo(const_cast<TQ_UINT8 *>(data), img.bits(), dstCS, width * height, renderingIntent);
712
713 return img;
714}
715
716
717cmsHTRANSFORM KisAbstractColorSpace::createTransform(KisColorSpace * dstColorSpace,
718 KisProfile * srcProfile,
719 KisProfile * dstProfile,
720 TQ_INT32 renderingIntent)
721{
722 TDEConfig * cfg = TDEGlobal::config();
723 bool bpCompensation = cfg->readBoolEntry("useBlackPointCompensation", false);
724
725 int flags = 0;
726
727 if (bpCompensation) {
728 flags = cmsFLAGS_BLACKPOINTCOMPENSATION;
729 }
730
731 if (dstColorSpace && dstProfile && srcProfile ) {
732 cmsHTRANSFORM tf = cmsCreateTransform(srcProfile->profile(),
734 dstProfile->profile(),
735 dstColorSpace->colorSpaceType(),
736 renderingIntent,
737 flags);
738
739 return tf;
740 }
741 return 0;
742}
743
744void KisAbstractColorSpace::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)
745{
746 TQ_UINT8 *dst = dstRowStart;
747 const TQ_UINT8 *src = srcRowStart;
748 TQ_INT32 bytesPerPixel = pixelSize();
749
750 while (rows > 0) {
751 memcpy(dst, src, numColumns * bytesPerPixel);
752
753 if (opacity != OPACITY_OPAQUE) {
754 multiplyAlpha(dst, opacity, numColumns);
755 }
756
757 dst += dstRowStride;
758 src += srcRowStride;
759 --rows;
760 }
761}
762
virtual void invertColor(TQ_UINT8 *src, TQ_INT32 nPixels)
Invert color channels of the given pixels.
virtual void mixColors(const TQ_UINT8 **colors, const TQ_UINT8 *weights, TQ_UINT32 nColors, TQ_UINT8 *dst) const
Mix the colors given their weights and return in dst The sum of weights is assumed 255.
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
Convolve the given array of pointers to pixels and return the result in dst.
virtual TQ_UINT8 intensity8(const TQ_UINT8 *src) const
Calculate the intensity of the given pixel, scaled down to the range 0-255.
virtual void toTQColor(const TQ_UINT8 *src, TQColor *c, KisProfile *profile=0)
The toTQColor methods take a byte array that is at least pixelSize() long and converts the contents t...
KisAbstractColorSpace(const KisID &id, DWORD cmType, icColorSpaceSignature colorSpaceSignature, KisColorSpaceFactoryRegistry *parent, KisProfile *profile)
virtual KisColorAdjustment * createBrightnessContrastAdjustment(TQ_UINT16 *transferValues)
Create an adjustment object for adjusting the brightness and contrast transferValues is a 256 bins ar...
virtual void darken(const TQ_UINT8 *src, TQ_UINT8 *dst, TQ_INT32 shade, bool compensate, double compensation, TQ_INT32 nPixels) const
Darken all color channels with the given amount.
TQ_UINT32 colorSpaceType()
lcms colorspace type definition.
virtual KisID mathToolboxID() const
Create a mathematical toolbox compatible with this colorspace.
virtual TQ_UINT32 nColorChannels() const =0
The total number of color channels (excludes alpha and substance) for a single pixel in this color mo...
virtual TQ_UINT8 difference(const TQ_UINT8 *src1, const TQ_UINT8 *src2)
Get the difference between 2 colors, normalized in the range (0,255).
virtual void fromLabA16(const TQ_UINT8 *src, TQ_UINT8 *dst, const TQ_UINT32 nPixels) const
Convert the specified data from Lab.
virtual TQImage convertToTQImage(const TQ_UINT8 *data, TQ_INT32 width, TQ_INT32 height, KisProfile *dstProfile, TQ_INT32 renderingIntent=INTENT_PERCEPTUAL, float exposure=0.0f)
Convert the pixels in data to (8-bit BGRA) TQImage using the specified profiles.
virtual void getSingleChannelPixel(TQ_UINT8 *dstPixel, const TQ_UINT8 *srcPixel, TQ_UINT32 channelIndex)
Set dstPixel to the pixel containing only the given channel of srcPixel.
virtual void applyAdjustment(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorAdjustment *, TQ_INT32 nPixels)
Apply the adjustment created with onr of the other functions.
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)
Compose two arrays of pixels together.
virtual KisColorAdjustment * createDesaturateAdjustment()
Create an adjustment object for desaturating.
virtual KisColorAdjustment * createPerChannelAdjustment(TQ_UINT16 **transferValues)
Create an adjustment object for adjusting individual channels transferValues is an array of nColorCha...
virtual void toLabA16(const TQ_UINT8 *src, TQ_UINT8 *dst, const TQ_UINT32 nPixels) const
Convert the specified data to Lab.
virtual bool convertPixelsTo(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorSpace *dstColorSpace, TQ_UINT32 numPixels, TQ_INT32 renderingIntent=INTENT_PERCEPTUAL)
Convert a byte array of srcLen pixels *src to the specified color space and put the converted bytes i...
virtual KisProfile * getProfile() const
Return the profile of this color space.
virtual KisID id() const
Chalk definition for use in .kra files and internally: unchanging name + i18n'able description.
virtual void fromTQColor(const TQColor &c, TQ_UINT8 *dst, KisProfile *profile=0)
The fromTQColor methods take a given color defined as an RGB TQColor and fills a byte array with the ...
virtual TQ_UINT32 pixelSize() const =0
The size in bytes of a single pixel in this color model.
This class gives some basic information about a channel, that is, one of the components that makes up...
TQ_INT32 size() const
returns the number of bytes this channel takes
TQ_INT32 pos() const
returns the position of the first byte of the channel in the pixel
A colorspace is the definition of a certain color model in Chalk.
virtual void fromTQColor(const TQColor &c, TQ_UINT8 *dst, KisProfile *profile=0)=0
The fromTQColor methods take a given color defined as an RGB TQColor and fills a byte array with the ...
virtual TQ_UINT8 getAlpha(const TQ_UINT8 *pixel) const =0
Get the alpha value of the given pixel, downscaled to an 8-bit value.
virtual bool convertPixelsTo(const TQ_UINT8 *src, TQ_UINT8 *dst, KisColorSpace *dstColorSpace, TQ_UINT32 numPixels, TQ_INT32 renderingIntent=INTENT_PERCEPTUAL)=0
Convert a byte array of srcLen pixels *src to the specified color space and put the converted bytes i...
virtual TQ_UINT32 pixelSize() const =0
The size in bytes of a single pixel in this color model.
virtual void multiplyAlpha(TQ_UINT8 *pixels, TQ_UINT8 alpha, TQ_INT32 nPixels)=0
Multiply the alpha channel of the given run of pixels by the given value.
virtual void setAlpha(TQ_UINT8 *pixels, TQ_UINT8 alpha, TQ_INT32 nPixels) const =0
Set the alpha channel of the given run of pixels to the given value.
virtual TQ_UINT32 colorSpaceType()=0
lcms colorspace type definition.
virtual KisProfile * getProfile() const =0
Return the profile of this color space.
Chalk has a large number of extensible resources.
Definition kis_id.h:57