Krita Source Code Documentation
Loading...
Searching...
No Matches
KoColorSpaceRegistry.cpp
Go to the documentation of this file.
1/*
2 * SPDX-FileCopyrightText: 2003 Patrick Julien <freak@codepimps.org>
3 * SPDX-FileCopyrightText: 2004, 2010 Cyrille Berger <cberger@cberger.net>
4 *
5 * SPDX-License-Identifier: LGPL-2.1-or-later
6*/
7
9
10#include <QHash>
11
12#include <QReadWriteLock>
13#include <QDir>
14#include <QGlobalStatic>
15
16#include "KoPluginLoader.h"
17#include "KoGenericRegistry.h"
18#include "DebugPigment.h"
20#include "KoColorSpace.h"
21#include "KoColorProfile.h"
24
30#include "KoColorSpace_p.h"
31
32#include "kis_assert.h"
35
37
39
40
41struct Q_DECL_HIDDEN KoColorSpaceRegistry::Private {
42
43 // interface for KoColorSpaceFactory
44 struct ProfileRegistrationInterface;
45 // interface for KoColorConversionSystem
46 struct ConversionSystemInterface;
47
48
50
52
55 QHash<QString, const KoColorSpace *> csMap;
56 QScopedPointer<ConversionSystemInterface> conversionSystemInterface;
57 KoColorConversionSystem *colorConversionSystem {nullptr};
58 KoColorConversionCache* colorConversionCache {nullptr};
59 const KoColorSpace *rgbU8sRGB {nullptr};
60 const KoColorSpace *lab16sLAB {nullptr};
61 const KoColorSpace *alphaCs {nullptr};
62 const KoColorSpace *alphaU16Cs {nullptr};
63#ifdef HAVE_OPENEXR
64 const KoColorSpace *alphaF16Cs {nullptr};
65#endif
66 const KoColorSpace *alphaF32Cs {nullptr};
67 QReadWriteLock registrylock;
68
78 const KoColorSpace* getCachedColorSpaceImpl(const QString & csId, const QString & profileName) const;
79
80 QString idsToCacheName(const QString & csId, const QString & profileName) const;
81 QString defaultProfileForCsIdImpl(const QString &csID);
82 const KoColorProfile * profileForCsIdWithFallbackImpl(const QString &csID, const QString &profileName);
83 QString colorSpaceIdImpl(const QString & colorModelId, const QString & colorDepthId) const;
84
85 const KoColorSpace *lazyCreateColorSpaceImpl(const QString &csID, const KoColorProfile *profile);
86
92 template<class LockPolicy = NormalLockPolicy>
93 const KoColorSpace * colorSpace1(const QString &colorSpaceId, const QString &pName = QString());
94
101 const KoColorSpace * colorSpace1(const QString &colorSpaceId, const KoColorProfile *profile);
102};
103
105{
107 : q(parentRegistry)
108 {
109 }
110
111 const KoColorSpace * colorSpace(const QString & colorModelId, const QString & colorDepthId, const QString &profileName) override {
112 return q->d->colorSpace1<NoLockPolicy>(q->d->colorSpaceIdImpl(colorModelId, colorDepthId), profileName);
113 }
114
115 const KoColorSpaceFactory* colorSpaceFactory(const QString &colorModelId, const QString &colorDepthId) const override {
116 return q->d->colorSpaceFactoryRegistry.get(q->d->colorSpaceIdImpl(colorModelId, colorDepthId));
117 }
118
120 return q->d->profileStorage.profilesFor(csf);
121 }
122
125 Q_FOREACH (KoColorSpaceFactory* csf, q->d->colorSpaceFactoryRegistry.values()) {
126 if (csf->profileIsCompatible(profile)) {
127 csfs.push_back(csf);
128 }
129 }
130 return csfs;
131 }
132
133private:
135};
136
138{
139 if (!s_instance.exists()) {
140 s_instance->init();
141 }
142 return s_instance;
143}
144
145
147{
148 d->rgbU8sRGB = 0;
149 d->lab16sLAB = 0;
150 d->alphaCs = 0;
151 d->alphaU16Cs = 0;
152#ifdef HAVE_OPENEXR
153 d->alphaF16Cs = 0;
154#endif
155 d->alphaF32Cs = 0;
156
157 d->conversionSystemInterface.reset(new Private::ConversionSystemInterface(this));
158 d->colorConversionSystem = new KoColorConversionSystem(d->conversionSystemInterface.data());
159 d->colorConversionCache = new KoColorConversionCache;
160
162
164
165 // Create the built-in colorspaces
166 QList<KoColorSpaceFactory *> localFactories;
167 localFactories
170 #ifdef HAVE_OPENEXR
171 << new KoAlphaF16ColorSpaceFactory()
172 #endif
177
178 Q_FOREACH (KoColorSpaceFactory *factory, localFactories) {
179 add(factory);
180 }
181
183 config.blacklist = "ColorSpacePluginsDisabled";
184 config.group = "krita";
185 KoPluginLoader::instance()->load("Krita/ColorSpace", config);
186
187 KoPluginLoader::PluginsConfig configExtensions;
188 configExtensions.blacklist = "ColorSpaceExtensionsPluginsDisabled";
189 configExtensions.group = "krita";
190 KoPluginLoader::instance()->load("Krita/ColorSpaceExtension", configExtensions);
191
192
193 dbgPigment << "Loaded the following colorspaces:";
194 Q_FOREACH (const KoID& id, listKeys()) {
195 dbgPigment << "\t" << id.id() << "," << id.name();
196 }
197}
198
200{
201 d->colorConversionSystem = nullptr;
202 d->colorConversionCache = nullptr;
203}
204
206{
207 delete d->colorConversionSystem;
208 d->colorConversionSystem = nullptr;
209
210 Q_FOREACH (const KoColorSpace * cs, d->csMap) {
211 cs->d->deletability = OwnedByRegistryRegistryDeletes;
212 delete cs;
213 }
214 d->csMap.clear();
215
216 // deleting colorspaces calls a function in the cache
217 delete d->colorConversionCache;
218 d->colorConversionCache = nullptr;
219
220 // Delete the colorspace factories
221 Q_FOREACH(KoColorSpaceFactory *f, d->colorSpaceFactoryRegistry.values()) {
222 d->colorSpaceFactoryRegistry.remove(f->id());
223 delete f;
224 }
225 Q_FOREACH(KoColorSpaceFactory *f, d->colorSpaceFactoryRegistry.doubleEntries()) {
226 delete f;
227 }
228
229 delete d;
230}
231
233{
234 QWriteLocker l(&d->registrylock);
235 d->colorSpaceFactoryRegistry.add(item);
236 d->colorConversionSystem->insertColorSpace(item);
237}
238
240{
241 QWriteLocker l(&d->registrylock);
242
243 QList<QString> toremove;
244 Q_FOREACH (const KoColorSpace * cs, d->csMap) {
245 if (cs->id() == item->id()) {
246 toremove.push_back(d->idsToCacheName(cs->id(), cs->profile()->name()));
247 cs->d->deletability = OwnedByRegistryRegistryDeletes;
248 }
249 }
250
251 Q_FOREACH (const QString& id, toremove) {
252 d->csMap.remove(id);
253 // TODO: should not it delete the color space when removing it from the map ?
254 }
255 d->colorSpaceFactoryRegistry.remove(item->id());
256}
257
258void KoColorSpaceRegistry::addProfileAlias(const QString& name, const QString& to)
259{
260 d->profileStorage.addProfileAlias(name, to);
261}
262
263QString KoColorSpaceRegistry::profileAlias(const QString& name) const
264{
265 return d->profileStorage.profileAlias(name);
266}
267
269{
270 return d->profileStorage.profileByName(name);
271}
272
274{
275 return d->profileStorage.profileByUniqueId(id);
276}
277
279{
280 QReadLocker l(&d->registrylock);
281 return d->profileStorage.profilesFor(d->colorSpaceFactoryRegistry.value(csID));
282}
283
284const KoColorSpace * KoColorSpaceRegistry::colorSpace(const QString & colorModelId, const QString & colorDepthId, const KoColorProfile *profile)
285{
286 return d->colorSpace1(colorSpaceId(colorModelId, colorDepthId), profile);
287}
288
289const KoColorSpace * KoColorSpaceRegistry::colorSpace(const QString & colorModelId, const QString & colorDepthId, const QString &profileName)
290{
291 return d->colorSpace1(colorSpaceId(colorModelId, colorDepthId), profileName);
292}
293
294const KoColorSpace * KoColorSpaceRegistry::colorSpace(const QString & colorModelId, const QString & colorDepthId)
295{
296 return d->colorSpace1(colorSpaceId(colorModelId, colorDepthId));
297}
298
299bool KoColorSpaceRegistry::profileIsCompatible(const KoColorProfile *profile, const QString &colorSpaceId)
300{
301 QReadLocker l(&d->registrylock);
302 KoColorSpaceFactory *csf = d->colorSpaceFactoryRegistry.value(colorSpaceId);
303
304 return csf ? csf->profileIsCompatible(profile) : false;
305}
306
308{
309 d->profileStorage.addProfile(p);
310}
311
313{
314 if (!p->valid()) return;
315
316 QWriteLocker locker(&d->registrylock);
317 if (p->valid()) {
319 d->colorConversionSystem->insertColorProfile(p);
320 }
321}
322
324{
325 addProfile(profile->clone());
326}
327
329{
330 d->profileStorage.removeProfile(profile);
331 // FIXME: how about removing it from conversion system?
332}
333
334const KoColorSpace* KoColorSpaceRegistry::Private::getCachedColorSpaceImpl(const QString & csID, const QString & profileName) const
335{
336 auto it = csMap.find(idsToCacheName(csID, profileName));
337
338 if (it != csMap.end()) {
339 return it.value();
340 }
341
342 return 0;
343}
344
345QString KoColorSpaceRegistry::Private::idsToCacheName(const QString & csID, const QString & profileName) const
346{
347 return csID + "<comb>" + profileName;
348}
349
350QString KoColorSpaceRegistry::defaultProfileForColorSpace(const QString &colorSpaceId) const
351{
352 QReadLocker l(&d->registrylock);
353 return d->defaultProfileForCsIdImpl(colorSpaceId);
354}
355
356KoColorConversionTransformation *KoColorSpaceRegistry::createColorConverter(const KoColorSpace *srcColorSpace, const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
357{
358 QWriteLocker l(&d->registrylock);
359 return d->colorConversionSystem->createColorConverter(srcColorSpace, dstColorSpace, renderingIntent, conversionFlags);
360}
361
362void KoColorSpaceRegistry::createColorConverters(const KoColorSpace *colorSpace, const QList<QPair<KoID, KoID> > &possibilities, KoColorConversionTransformation *&fromCS, KoColorConversionTransformation *&toCS) const
363{
364 QWriteLocker l(&d->registrylock);
365 d->colorConversionSystem->createColorConverters(colorSpace, possibilities, fromCS, toCS);
366}
367
368QString KoColorSpaceRegistry::Private::defaultProfileForCsIdImpl(const QString &csID)
369{
370 QString defaultProfileName;
371
372 KoColorSpaceFactory *csf = colorSpaceFactoryRegistry.value(csID);
373 if (csf) {
374 defaultProfileName = csf->defaultProfile();
375 } else {
376 dbgPigmentCSRegistry << "Unknown color space type : " << csID;
377 }
378
379 return defaultProfileName;
380}
381
382const KoColorProfile *KoColorSpaceRegistry::Private::profileForCsIdWithFallbackImpl(const QString &csID, const QString &profileName)
383{
384 const KoColorProfile *profile = 0;
385
386 // last attempt at getting a profile, sometimes the default profile, like adobe cmyk isn't available.
387 profile = profileStorage.profileByName(profileName);
388 if (!profile) {
389 dbgPigmentCSRegistry << "Profile not found :" << profileName;
390
391 // first try: default
392 profile = profileStorage.profileByName(defaultProfileForCsIdImpl(csID));
393
394 if (!profile) {
395 // second try: first profile in the list
396 QList<const KoColorProfile *> profiles = profileStorage.profilesFor(colorSpaceFactoryRegistry.value(csID));
397 if (profiles.isEmpty() || !profiles.first()) {
398 dbgPigmentCSRegistry << "Couldn't fetch a fallback profile:" << profileName;
399 qWarning() << "profileForCsIdWithFallbackImpl couldn't fetch a fallback profile for " << qUtf8Printable(profileName);
400 return 0;
401 }
402
403 profile = profiles.first();
404 }
405 }
406
407 return profile;
408}
409
410const KoColorSpace *KoColorSpaceRegistry::Private::lazyCreateColorSpaceImpl(const QString &csID, const KoColorProfile *profile)
411{
412 const KoColorSpace *cs = 0;
413
414 /*
415 * We need to check again here, a thread requesting the same colorspace could've added it
416 * already, in between the read unlock and write lock.
417 * TODO: We also potentially changed profileName content, which means we maybe are going to
418 * create a colorspace that's actually in the space registry cache, but currently this might
419 * not be an issue because the colorspace should be cached also by the factory, so it won't
420 * create a new instance. That being said, having two caches with the same stuff doesn't make
421 * much sense.
422 */
423 cs = getCachedColorSpaceImpl(csID, profile->name());
424 if (!cs) {
425 KoColorSpaceFactory *csf = colorSpaceFactoryRegistry.value(csID);
426 if (!csf) {
427 qWarning() << "Unable to create color space factory for" << csID;
428 return 0;
429 }
430 cs = csf->grabColorSpace(profile);
431 if (!cs) {
432 dbgPigmentCSRegistry << "Unable to create color space";
433 qWarning() << "lazyCreateColorSpaceImpl was unable to create a color space for " << csID;
434 return 0;
435 }
436
437 dbgPigmentCSRegistry << "colorspace count: " << csMap.count()
438 << ", adding name: " << idsToCacheName(cs->id(), cs->profile()->name())
439 << "\n\tcsID" << csID
440 << "\n\tcs->id()" << cs->id()
441 << "\n\tcs->profile()->name()" << cs->profile()->name()
442 << "\n\tprofile->name()" << profile->name();
443 Q_ASSERT(cs->id() == csID);
444 Q_ASSERT(cs->profile()->name() == profile->name());
445 csMap[idsToCacheName(cs->id(), cs->profile()->name())] = cs;
446 cs->d->deletability = OwnedByRegistryDoNotDelete;
447 }
448
449 return cs;
450}
451
452template<class LockPolicy>
453const KoColorSpace * KoColorSpaceRegistry::Private::colorSpace1(const QString &csID, const QString &pName)
454{
455 QString profileName = pName;
456
457 const KoColorSpace *cs = 0;
458
459 {
460 typename LockPolicy::ReadLocker l(&registrylock);
461
462 if (profileName.isEmpty()) {
463 profileName = defaultProfileForCsIdImpl(csID);
464 }
465
466 if (!profileName.isEmpty()) {
467 // quick attempt to fetch a cached color space
468 cs = getCachedColorSpaceImpl(csID, profileName);
469 }
470 }
471
472 if (!cs) {
473 // slow attempt to create a color space
474 typename LockPolicy::WriteLocker l(&registrylock);
475
476 const KoColorProfile *profile =
477 profileForCsIdWithFallbackImpl(csID, profileName);
478
479 if (!profile) return 0;
480
481 cs = lazyCreateColorSpaceImpl(csID, profile);
482 }
483 else {
484 KIS_SAFE_ASSERT_RECOVER_NOOP(cs->id() == csID);
485 KIS_SAFE_ASSERT_RECOVER_NOOP(cs->profile()->name() == profileName);
486 }
487
488 return cs;
489}
490
491
492const KoColorSpace * KoColorSpaceRegistry::Private::colorSpace1(const QString &csID, const KoColorProfile *profile)
493{
494 if (csID.isEmpty()) {
495 return 0;
496 } else if (!profile) {
497 return colorSpace1(csID);
498 }
499
500 const KoColorSpace *cs = 0;
501
502 {
503 QReadLocker l(&registrylock);
504 cs = getCachedColorSpaceImpl(csID, profile->name());
505 }
506
507 // the profile should have already been added to the registry by createColorProfile() method
508 KIS_SAFE_ASSERT_RECOVER(profileStorage.containsProfile(profile)) {
509 // warning! locking happens inside addProfile!
510 q->addProfile(profile);
511 }
512
513 if (!cs) {
514 // The profile was not stored and thus not the combination either
515 QWriteLocker l(&registrylock);
516 KoColorSpaceFactory *csf = colorSpaceFactoryRegistry.value(csID);
517
518 if (!csf) {
519 dbgPigmentCSRegistry << "Unknown color space type :" << csf;
520 return 0;
521 }
522
523 if (!csf->profileIsCompatible(profile)) {
524 dbgPigmentCSRegistry << "Profile is not compatible:" << csf << profile->name();
525 return 0;
526 }
527
528 cs = lazyCreateColorSpaceImpl(csID, profile);
529 }
530
531 return cs;
532}
533
535{
536 if (!d->alphaCs) {
537 d->alphaCs = d->colorSpace1(KoAlphaColorSpace::colorSpaceId());
538 }
539 Q_ASSERT(d->alphaCs);
540 return d->alphaCs;
541}
542
544{
545 if (!d->alphaU16Cs) {
546 d->alphaU16Cs = d->colorSpace1(KoAlphaU16ColorSpace::colorSpaceId());
547 }
548 Q_ASSERT(d->alphaU16Cs);
549 return d->alphaU16Cs;
550}
551
552#ifdef HAVE_OPENEXR
553const KoColorSpace * KoColorSpaceRegistry::alpha16f()
554{
555 if (!d->alphaF16Cs) {
556 d->alphaF16Cs = d->colorSpace1(KoAlphaF16ColorSpace::colorSpaceId());
557 }
558 Q_ASSERT(d->alphaF16Cs);
559 return d->alphaF16Cs;
560}
561#endif
562
564{
565 if (!d->alphaF32Cs) {
566 d->alphaF32Cs = d->colorSpace1(KoAlphaF32ColorSpace::colorSpaceId());
567 }
568 Q_ASSERT(d->alphaF32Cs);
569 return d->alphaF32Cs;
570}
571
572const KoColorSpace *KoColorSpaceRegistry::graya8(const QString &profile)
573{
574
575 if (profile.isEmpty()) {
576 KoColorSpaceFactory* factory = d->colorSpaceFactoryRegistry.get(GrayAColorModelID.id());
578 }
579 else {
581 }
582
583}
584
586{
587 if (!profile) {
588 return graya8();
589 }
590 else {
592 }
593
594}
595
596const KoColorSpace *KoColorSpaceRegistry::graya16(const QString &profile)
597{
598 if (profile.isEmpty()) {
599 KoColorSpaceFactory* factory = d->colorSpaceFactoryRegistry.get(GrayAColorModelID.id());
601 }
602 else {
604 }
605
606}
607
609{
610 if (!profile) {
611 return graya16();
612 }
613 else {
615 }
616}
617
618
619const KoColorSpace * KoColorSpaceRegistry::rgb8(const QString &profileName)
620{
621 if (profileName.isEmpty()) {
622 if (!d->rgbU8sRGB) {
623 d->rgbU8sRGB = d->colorSpace1(KoRgbU8ColorSpace::colorSpaceId());
624 }
625 Q_ASSERT(d->rgbU8sRGB);
626 return d->rgbU8sRGB;
627 }
628 return d->colorSpace1(KoRgbU8ColorSpace::colorSpaceId(), profileName);
629}
630
632{
633 if (profile == 0) {
634 if (!d->rgbU8sRGB) {
635 d->rgbU8sRGB = d->colorSpace1(KoRgbU8ColorSpace::colorSpaceId());
636 }
637 Q_ASSERT(d->rgbU8sRGB);
638 return d->rgbU8sRGB;
639 }
640 return d->colorSpace1(KoRgbU8ColorSpace::colorSpaceId(), profile);
641}
642
643const KoColorSpace * KoColorSpaceRegistry::rgb16(const QString &profileName)
644{
645 return d->colorSpace1(KoRgbU16ColorSpace::colorSpaceId(), profileName);
646}
647
649{
650 return d->colorSpace1(KoRgbU16ColorSpace::colorSpaceId(), profile);
651}
652
653const KoColorSpace * KoColorSpaceRegistry::lab16(const QString &profileName)
654{
655 if (profileName.isEmpty()) {
656 if (!d->lab16sLAB) {
657 d->lab16sLAB = d->colorSpace1(KoLabColorSpace::colorSpaceId());
658 }
659 return d->lab16sLAB;
660 }
661 return d->colorSpace1(KoLabColorSpace::colorSpaceId(), profileName);
662}
663
665{
666 if (profile == 0) {
667 if (!d->lab16sLAB) {
668 d->lab16sLAB = d->colorSpace1(KoLabColorSpace::colorSpaceId());
669 }
670 Q_ASSERT(d->lab16sLAB);
671 return d->lab16sLAB;
672 }
673 return d->colorSpace1(KoLabColorSpace::colorSpaceId(), profile);
674}
675
677{
678 return profileByName("Rec2020-elle-V4-g10.icc");
679}
680
682{
683 return profileByName("High Dynamic Range UHDTV Wide Color Gamut Display (Rec. 2020) - SMPTE ST 2084 PQ EOTF");
684}
685
687{
688 return profileByName("sRGB-elle-V2-g10.icc");
689}
690
692{
693 return profileByName("sRGB-elle-V2-srgbtrc.icc");
694}
695
696const KoColorProfile *KoColorSpaceRegistry::profileFor(const QVector<double> &colorants, ColorPrimaries colorPrimaries, TransferCharacteristics transferFunction) const
697{
698 if (colorPrimaries == PRIMARIES_ITU_R_BT_709_5) {
699 if (transferFunction == TRC_IEC_61966_2_1) {
700 return p709SRGBProfile();
701 } else if (transferFunction == TRC_LINEAR) {
702 return p709G10Profile();
703 }
704 }
705
706 if (colorPrimaries == PRIMARIES_ITU_R_BT_2020_2_AND_2100_0) {
707 if (transferFunction == TRC_ITU_R_BT_2100_0_PQ) {
708 return p2020PQProfile();
709 } else if (transferFunction == TRC_LINEAR) {
710 return p2020G10Profile();
711 }
712 }
713
714 QList<const KoColorProfile*> list = d->profileStorage.profilesFor(colorants, colorPrimaries, transferFunction);
715 if (!list.empty()) {
716 return list.first();
717 }
718
720 if (engine) {
721 return engine->getProfile(colorants, colorPrimaries, transferFunction);
722 }
723
724 return nullptr;
725}
726
728{
729 QReadLocker l(&d->registrylock);
730
731 QList<KoID> ids;
732 QList<KoColorSpaceFactory*> factories = d->colorSpaceFactoryRegistry.values();
733 Q_FOREACH (KoColorSpaceFactory* factory, factories) {
734 if (!ids.contains(factory->colorModelId())
735 && (option == AllColorSpaces || factory->userVisible())) {
736 ids << factory->colorModelId();
737 }
738 }
739 return ids;
740}
742{
743 return colorDepthList(colorModelId.id(), option);
744}
745
746
748{
749 QReadLocker l(&d->registrylock);
750
751 QList<KoID> ids;
752 QList<KoColorSpaceFactory*> factories = d->colorSpaceFactoryRegistry.values();
753 Q_FOREACH (KoColorSpaceFactory* factory, factories) {
754 if (!ids.contains(KoID(factory->colorDepthId()))
755 && factory->colorModelId().id() == colorModelId
756 && (option == AllColorSpaces || factory->userVisible())) {
757 ids << factory->colorDepthId();
758 }
759 }
760 QList<KoID> r;
761
764 if (ids.contains(Float16BitsColorDepthID)) r << Float16BitsColorDepthID;
765 if (ids.contains(Float32BitsColorDepthID)) r << Float32BitsColorDepthID;
766 if (ids.contains(Float64BitsColorDepthID)) r << Float64BitsColorDepthID;
767
768 return r;
769}
770
771QString KoColorSpaceRegistry::Private::colorSpaceIdImpl(const QString & colorModelId, const QString & colorDepthId) const
772{
773 for (auto it = colorSpaceFactoryRegistry.constBegin(); it != colorSpaceFactoryRegistry.constEnd(); ++it) {
774 if (it.value()->colorModelId().id() == colorModelId && it.value()->colorDepthId().id() == colorDepthId) {
775 return it.value()->id();
776 }
777 }
778 return "";
779}
780
781QString KoColorSpaceRegistry::colorSpaceId(const QString & colorModelId, const QString & colorDepthId) const
782{
783 QReadLocker l(&d->registrylock);
784 return d->colorSpaceIdImpl(colorModelId, colorDepthId);
785}
786
787QString KoColorSpaceRegistry::colorSpaceId(const KoID& colorModelId, const KoID& colorDepthId) const
788{
789 return colorSpaceId(colorModelId.id(), colorDepthId.id());
790}
791
792KoID KoColorSpaceRegistry::colorSpaceColorModelId(const QString & _colorSpaceId) const
793{
794 QReadLocker l(&d->registrylock);
795
796 KoColorSpaceFactory* factory = d->colorSpaceFactoryRegistry.get(_colorSpaceId);
797 if (factory) {
798 return factory->colorModelId();
799 } else {
800 return KoID();
801 }
802}
803
804KoID KoColorSpaceRegistry::colorSpaceColorDepthId(const QString & _colorSpaceId) const
805{
806 QReadLocker l(&d->registrylock);
807
808 KoColorSpaceFactory* factory = d->colorSpaceFactoryRegistry.get(_colorSpaceId);
809 if (factory) {
810 return factory->colorDepthId();
811 } else {
812 return KoID();
813 }
814}
815
817{
818 return d->colorConversionSystem;
819}
820
822{
823 return d->colorConversionCache;
824}
825
827{
828 if (_colorSpace->d->deletability != NotOwnedByRegistry) {
829 return _colorSpace;
830 } else if (*_colorSpace == *d->alphaCs) {
831 return d->alphaCs;
832 } else {
833 const KoColorSpace* cs = d->colorSpace1(_colorSpace->id(), _colorSpace->profile());
834 Q_ASSERT(cs);
835 Q_ASSERT(*cs == *_colorSpace);
836 return cs;
837 }
838}
839
841{
842 QReadLocker l(&d->registrylock);
843 QList<KoID> answer;
844 Q_FOREACH (const QString& key, d->colorSpaceFactoryRegistry.keys()) {
845 answer.append(KoID(key, d->colorSpaceFactoryRegistry.get(key)->name()));
846 }
847
848 return answer;
849}
850
852{
853 ProfileRegistrationInterface(KoColorSpaceRegistry::Private *_d) : d(_d) {}
854
855 const KoColorProfile* profileByName(const QString &profileName) const override {
856 return d->profileStorage.profileByName(profileName);
857 }
858
859 void registerNewProfile(KoColorProfile *profile) override {
860 d->profileStorage.addProfile(profile);
861 d->colorConversionSystem->insertColorProfile(profile);
862 }
863
865};
866
867const KoColorProfile* KoColorSpaceRegistry::createColorProfile(const QString& colorModelId, const QString& colorDepthId, const QByteArray& rawData)
868{
869 QWriteLocker l(&d->registrylock);
870 KoColorSpaceFactory* factory_ = d->colorSpaceFactoryRegistry.get(d->colorSpaceIdImpl(colorModelId, colorDepthId));
871
872 Private::ProfileRegistrationInterface interface(d);
873 return factory_->colorProfile(rawData, &interface);
874}
875
877{
878 QList<const KoColorSpace*> colorSpaces;
879
880 // TODO: thread-unsafe code: the factories might change right after the lock in released
881 // HINT: used in a unittest only!
882
883 d->registrylock.lockForRead();
884 QList<KoColorSpaceFactory*> factories = d->colorSpaceFactoryRegistry.values();
885 d->registrylock.unlock();
886
887 Q_FOREACH (KoColorSpaceFactory* factory, factories) {
888 // Don't test with ycbcr for now, since we don't have a default profile for it.
889 if (factory->colorModelId().id().startsWith("Y")) continue;
890 if (visibility == AllColorSpaces || factory->userVisible()) {
891 if (pSelection == OnlyDefaultProfile) {
892 const KoColorSpace *cs = d->colorSpace1(factory->id());
893 if (cs) {
894 colorSpaces.append(cs);
895 }
896 else {
897 warnPigment << "Could not create colorspace for id" << factory->id() << "since there is no working default profile";
898 }
899 } else {
901 Q_FOREACH (const KoColorProfile * profile, profiles) {
902 const KoColorSpace *cs = d->colorSpace1(factory->id(), profile);
903 if (cs) {
904 colorSpaces.append(cs);
905 }
906 else {
907 warnPigment << "Could not create colorspace for id" << factory->id() << "and profile" << profile->name();
908 }
909 }
910 }
911 }
912 }
913
914 return colorSpaces;
915}
#define dbgPigment
#define warnPigment
#define dbgPigmentCSRegistry
const Params2D p
Q_GLOBAL_STATIC(KisStoragePluginRegistry, s_instance)
KoAlphaColorSpaceFactoryImpl< AlphaU16Traits > KoAlphaU16ColorSpaceFactory
KoAlphaColorSpaceFactoryImpl< AlphaU8Traits > KoAlphaColorSpaceFactory
KoAlphaColorSpaceFactoryImpl< AlphaF32Traits > KoAlphaF32ColorSpaceFactory
const KoID Float32BitsColorDepthID("F32", ki18n("32-bit float/channel"))
const KoID Float64BitsColorDepthID("F64", ki18n("64-bit float/channel"))
const KoID GrayAColorModelID("GRAYA", ki18n("Grayscale/Alpha"))
const KoID Float16BitsColorDepthID("F16", ki18n("16-bit float/channel"))
const KoID Integer8BitsColorDepthID("U8", ki18n("8-bit integer/channel"))
const KoID Integer16BitsColorDepthID("U16", ki18n("16-bit integer/channel"))
ColorPrimaries
The colorPrimaries enum Enum of colorants, follows ITU H.273 for values 0 to 255, and has extra known...
@ PRIMARIES_ITU_R_BT_2020_2_AND_2100_0
@ PRIMARIES_ITU_R_BT_709_5
TransferCharacteristics
The transferCharacteristics enum Enum of transfer characteristics, follows ITU H.273 for values 0 to ...
@ TRC_ITU_R_BT_2100_0_PQ
@ TRC_IEC_61966_2_1
@ NotOwnedByRegistry
@ OwnedByRegistryDoNotDelete
@ OwnedByRegistryRegistryDeletes
static QString colorSpaceId()
The KoColorProfileStorage class is a "composite subclass" of KoColorSpaceRegistry that ensures that t...
const KoColorProfile * profileByName(const QString &name) const
QList< const KoColorProfile * > profilesFor(const KoColorSpaceFactory *csf) const
bool containsProfile(const KoColorProfile *profile)
containsProfile shows if a profile is registered in the storage
static KoColorSpaceEngineRegistry * instance()
Private *const d
virtual const KoColorProfile * profile() const =0
const T value(const QString &id) const
T get(const QString &id) const
QHash< QString, T >::const_iterator constBegin() const
QHash< QString, T >::const_iterator constEnd() const
Definition KoID.h:30
QString id() const
Definition KoID.cpp:63
static QString colorSpaceId()
void load(const QString &serviceType, const PluginsConfig &config=PluginsConfig(), QObject *owner=0, bool cache=true)
static KoPluginLoader * instance()
static QString colorSpaceId()
static QString colorSpaceId()
#define KIS_SAFE_ASSERT_RECOVER(cond)
Definition kis_assert.h:126
#define KIS_SAFE_ASSERT_RECOVER_NOOP(cond)
Definition kis_assert.h:130
virtual KoColorProfile * clone() const =0
virtual const KoColorProfile * getProfile(const QVector< double > &colorants, ColorPrimaries colorPrimaries, TransferCharacteristics transferFunction)=0
getProfile This tries to generate a profile with the given characteristics and add it to the registry...
virtual KoID colorDepthId() const =0
virtual QString defaultProfile() const =0
virtual KoID colorModelId() const =0
virtual QString id() const =0
virtual bool userVisible() const =0
const KoColorProfile * colorProfile(const QByteArray &rawData, ProfileRegistrationInterface *registrationInterface) const
virtual bool profileIsCompatible(const KoColorProfile *profile) const =0
const KoColorSpace * grabColorSpace(const KoColorProfile *profile)
QList< const KoColorProfile * > profilesFor(const KoColorSpaceFactory *csf) const override
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const QString &profileName) override
const KoColorSpaceFactory * colorSpaceFactory(const QString &colorModelId, const QString &colorDepthId) const override
QList< const KoColorSpaceFactory * > colorSpacesFor(const KoColorProfile *profile) const override
ConversionSystemInterface(KoColorSpaceRegistry *parentRegistry)
const KoColorProfile * profileByName(const QString &profileName) const override
const KoColorProfile * profileByName(const QString &name) const
const KoColorSpace * colorSpace1(const QString &colorSpaceId, const QString &pName=QString())
QString colorSpaceId(const QString &colorModelId, const QString &colorDepthId) const
const KoColorSpace * lab16(const QString &profileName=QString())
const KoColorSpace * alpha32f()
KoColorConversionCache * colorConversionCache
const KoColorSpace * lazyCreateColorSpaceImpl(const QString &csID, const KoColorProfile *profile)
QList< KoID > colorDepthList(const KoID &colorModelId, ColorSpaceListVisibility option) const
void addProfileAlias(const QString &name, const QString &to)
const KoColorSpace * permanentColorspace(const KoColorSpace *_colorSpace)
@ OnlyDefaultProfile
Only add the default profile.
QString idsToCacheName(const QString &csId, const QString &profileName) const
const KoColorProfile * profileFor(const QVector< double > &colorants, ColorPrimaries colorPrimaries, TransferCharacteristics transferFunction) const
profileFor tries to find the profile that matches these characteristics, if no such profile is found,...
QString colorSpaceIdImpl(const QString &colorModelId, const QString &colorDepthId) const
QString defaultProfileForCsIdImpl(const QString &csID)
QList< const KoColorSpace * > allColorSpaces(ColorSpaceListVisibility visibility, ColorSpaceListProfilesSelection pSelection)
const KoColorSpace * colorSpace(const QString &colorModelId, const QString &colorDepthId, const KoColorProfile *profile)
const KoColorSpace * colorSpace1(const QString &colorSpaceId, const KoColorProfile *profile)
KoColorConversionTransformation * createColorConverter(const KoColorSpace *srcColorSpace, const KoColorSpace *dstColorSpace, KoColorConversionTransformation::Intent renderingIntent, KoColorConversionTransformation::ConversionFlags conversionFlags) const
static KoColorSpaceRegistry * instance()
Private(KoColorSpaceRegistry *_q)
const KoColorSpace * graya8(const QString &profile=QString())
const KoColorSpace * graya16(const QString &profile=QString())
KoID colorSpaceColorDepthId(const QString &_colorSpaceId) const
const KoColorProfile * p709G10Profile() const
const KoColorProfile * p709SRGBProfile() const
void remove(KoColorSpaceFactory *item)
KoGenericRegistry< KoColorSpaceFactory * > colorSpaceFactoryRegistry
const KoColorSpace * rgb8(const QString &profileName=QString())
bool profileIsCompatible(const KoColorProfile *profile, const QString &colorSpaceId)
QString defaultProfileForColorSpace(const QString &colorSpaceId) const
const KoColorProfile * profileByUniqueId(const QByteArray &id) const
const KoColorProfile * p2020PQProfile() const
const KoColorSpace * getCachedColorSpaceImpl(const QString &csId, const QString &profileName) const
const KoColorSpace * rgb16(const QString &profileName=QString())
const KoColorSpace * alpha8()
const KoColorProfile * profileForCsIdWithFallbackImpl(const QString &csID, const QString &profileName)
QList< KoID > colorModelsList(ColorSpaceListVisibility option) const
KoID colorSpaceColorModelId(const QString &_colorSpaceId) const
void add(KoColorSpaceFactory *item)
QList< const KoColorProfile * > profilesFor(const QString &csID) const
void addProfileToMap(KoColorProfile *p)
QString profileAlias(const QString &name) const
const KoColorSpace * alpha16()
void createColorConverters(const KoColorSpace *colorSpace, const QList< QPair< KoID, KoID > > &possibilities, KoColorConversionTransformation *&fromCS, KoColorConversionTransformation *&toCS) const
const KoColorProfile * p2020G10Profile() const
KoColorConversionSystem * colorConversionSystem
void removeProfile(KoColorProfile *profile)
@ AllColorSpaces
All color space even those not visible to the user.
const KoColorProfile * createColorProfile(const QString &colorModelId, const QString &colorDepthId, const QByteArray &rawData)
QScopedPointer< ConversionSystemInterface > conversionSystemInterface
void addProfile(KoColorProfile *profile)
QHash< QString, const KoColorSpace * > csMap
KoColorProfileStorage profileStorage
QList< KoID > listKeys() const
const char * blacklist
This contains the variable name for the list of plugins (by library name) that will not be loaded.