libpromeki 1.0.0-alpha
PROfessional MEdia toolKIt
 
Loading...
Searching...
No Matches
colormodel.h
Go to the documentation of this file.
1
8#pragma once
9
10
11#include <promeki/config.h>
12#if PROMEKI_ENABLE_CORE
13#include <promeki/namespace.h>
14#include <promeki/string.h>
15#include <promeki/list.h>
16#include <promeki/array.h>
17#include <promeki/error.h>
18#include <promeki/result.h>
19#include <promeki/ciepoint.h>
20#include <promeki/matrix3x3.h>
21#include <promeki/datatype.h>
22
23PROMEKI_NAMESPACE_BEGIN
24
25class DataStream;
26
143class ColorModel {
144 public:
145 PROMEKI_DATATYPE(ColorModel, DataTypeColorModel, 1)
146
147
148 Error writeToStream(DataStream &s) const;
150 template <uint32_t V> static Result<ColorModel> readFromStream(DataStream &s);
151
159 enum ID {
160 Invalid = 0,
161 sRGB = 1,
162 LinearSRGB = 2,
163 Rec709 = 3,
164 LinearRec709 = 4,
165 Rec601_PAL = 5,
166 LinearRec601_PAL = 6,
167 Rec601_NTSC = 7,
168 LinearRec601_NTSC = 8,
169 Rec2020 = 9,
170 LinearRec2020 = 10,
171 DCI_P3 = 11,
172 LinearDCI_P3 = 12,
173 AdobeRGB = 13,
174 LinearAdobeRGB = 14,
175 ACES_AP0 = 15,
176 ACES_AP1 = 16,
177 CIEXYZ = 17,
178 CIELab = 18,
179 HSV_sRGB = 19,
180 HSL_sRGB = 20,
181 YCbCr_Rec709 = 21,
182 YCbCr_Rec601 = 22,
183 YCbCr_Rec2020 = 23,
184 // ---- HDR (BT.2100) ----
185 // Same chromaticity primaries as Rec2020 / BT.2020
186 // but different EOTF. Carried as distinct
187 // ColorModel IDs so a PixelFormat / ImageDesc that
188 // says "PQ" wires the correct transfer through
189 // every consumer that reads ColorModel::toH273.
190 Rec2020_PQ = 24,
191 Rec2020_HLG = 25,
192 YCbCr_Rec2020_PQ = 26,
193 YCbCr_Rec2020_HLG = 27,
194 DCI_P3_PQ = 28,
195 UserDefined = 1024
196 };
197
206 enum Type {
207 TypeInvalid = 0,
208 TypeRGB,
209 TypeXYZ,
210 TypeLab,
211 TypeYCbCr,
212 TypeHSV,
213 TypeHSL
214 };
215
227 struct CompInfo {
228 String name;
229 String abbrev;
230 float nativeMin;
231 float nativeMax;
232 };
233
243 typedef double (*TransferFunc)(double);
244
255 typedef Array<CIEPoint, 4> Primaries;
256
258 using IDList = ::promeki::List<ID>;
259
270 struct Data {
271 ID id = Invalid;
272 Type type = TypeInvalid;
273 String name;
274 String desc;
275 Primaries primaries;
276 CompInfo comps[3] = {};
277 TransferFunc oetf = nullptr;
278 TransferFunc eotf = nullptr;
279 bool linear = false;
280 ID linearCounterpart = Invalid;
281 ID nonlinearCounterpart = Invalid;
282 ID parentModel = Invalid;
283 Matrix3x3 rgbToXyz;
284 Matrix3x3 xyzToRgb;
285 Matrix3x3 toParentMatrix;
286 Matrix3x3 fromParentMatrix;
287 float toParentOffset[3] = {};
288 float fromParentOffset[3] = {};
289 void (*toXYZFunc)(const Data *d, const float *src,
290 float *dst) = nullptr;
291 void (*fromXYZFunc)(const Data *d, const float *src,
292 float *dst) = nullptr;
293 };
294
303 static ID registerType();
304
314 static void registerData(Data &&data);
315
323 static IDList registeredIDs();
324
330 static ColorModel lookup(const String &name);
331
343 static Result<ColorModel> fromString(const String &name) {
344 ColorModel m = lookup(name);
345 if (!m.isValid()) return makeError<ColorModel>(Error::IdNotFound);
346 return makeResult(m);
347 }
348
367 struct H273 {
368 uint8_t primaries = 0;
369 uint8_t transfer = 0;
370 uint8_t matrix = 0;
371 };
372
395 static H273 toH273(ID id);
396
403 inline ColorModel(ID id = Invalid);
404
406 ID id() const { return _d->id; }
407
409 bool isValid() const { return _d != nullptr && _d->type != TypeInvalid; }
410
412 bool operator==(const ColorModel &other) const { return _d == other._d; }
413
415 bool operator!=(const ColorModel &other) const { return _d != other._d; }
416
418 Type type() const { return _d->type; }
419
421 const String &name() const { return _d->name; }
422
424 String toString() const { return _d->name; }
425
427 const String &desc() const { return _d->desc; }
428
434 size_t compCount() const { return 3; }
435
441 const CompInfo &compInfo(size_t index) const { return _d->comps[index < 3 ? index : 0]; }
442
448 const Primaries &primaries() const { return _d->primaries; }
449
456 const CIEPoint &whitePoint() const { return _d->primaries[3]; }
457
461 bool isLinear() const { return _d->linear; }
462
470 inline ColorModel linearCounterpart() const;
471
478 inline ColorModel nonlinearCounterpart() const;
479
486 double applyTransfer(double linear) const { return _d->oetf(linear); }
487
494 double removeTransfer(double encoded) const { return _d->eotf(encoded); }
495
503 inline ColorModel parentModel() const;
504
511 void toXYZ(const float *src, float *dst) const { _d->toXYZFunc(_d, src, dst); }
512
519 void fromXYZ(const float *src, float *dst) const { _d->fromXYZFunc(_d, src, dst); }
520
527 float toNative(size_t comp, float normalized) const {
528 if (comp >= 3) return 0.0f;
529 const CompInfo &ci = _d->comps[comp];
530 return ci.nativeMin + normalized * (ci.nativeMax - ci.nativeMin);
531 }
532
539 float fromNative(size_t comp, float native) const {
540 if (comp >= 3) return 0.0f;
541 const CompInfo &ci = _d->comps[comp];
542 float range = ci.nativeMax - ci.nativeMin;
543 if (range == 0.0f) return 0.0f;
544 return (native - ci.nativeMin) / range;
545 }
546
548 const Data *data() const { return _d; }
549
550 private:
551 const Data *_d = nullptr;
552 static const Data *lookupData(ID id);
553};
554
555// Deferred inline definitions that require the full class to be visible.
556
557inline ColorModel::ColorModel(ID id) : _d(lookupData(id)) {}
558
559inline ColorModel ColorModel::linearCounterpart() const {
560 ID lcid = _d->linearCounterpart;
561 return lcid != Invalid ? ColorModel(lcid) : *this;
562}
563
564inline ColorModel ColorModel::nonlinearCounterpart() const {
565 ID nlid = _d->nonlinearCounterpart;
566 return nlid != Invalid ? ColorModel(nlid) : *this;
567}
568
569inline ColorModel ColorModel::parentModel() const {
570 return ColorModel(_d->parentModel);
571}
572
573PROMEKI_NAMESPACE_END
574
575#endif // PROMEKI_ENABLE_CORE