@@ -17,6 +17,196 @@ static void FreeImageData(void *info, const void *data, size_t size) {
17
17
free ((void *)data);
18
18
}
19
19
20
+ static void CalcWhitePoint (uint16_t const colorPrimaries, vImageWhitePoint* const white) {
21
+ float primaries[8 ];
22
+ avifNclxColourPrimariesGetValues (colorPrimaries, primaries);
23
+ white->white_x = primaries[6 ];
24
+ white->white_y = primaries[7 ];
25
+ }
26
+
27
+ static void CalcRGBPrimaries (uint16_t const colorPrimaries, vImageRGBPrimaries* const prim) {
28
+ float primaries[8 ];
29
+ avifNclxColourPrimariesGetValues (colorPrimaries, primaries);
30
+ prim->red_x = primaries[0 ];
31
+ prim->red_y = primaries[1 ];
32
+ prim->green_x = primaries[2 ];
33
+ prim->green_y = primaries[3 ];
34
+ prim->blue_x = primaries[4 ];
35
+ prim->blue_y = primaries[5 ];
36
+ prim->white_x = primaries[6 ];
37
+ prim->white_y = primaries[7 ];
38
+ }
39
+
40
+ static void CalcTransferFunction (uint16_t const transferCharacteristics, vImageTransferFunction* const tf) {
41
+ // See: https://www.itu.int/rec/T-REC-H.273/en
42
+ static const float alpha = 1 .099296826809442f ;
43
+ static const float beta = 0 .018053968510807f ;
44
+ /*
45
+ // R' = c0 * pow( c1 * R + c2, gamma ) + c3, (R >= cutoff)
46
+ // R' = c4 * R + c5 (R < cutoff)
47
+ */
48
+
49
+ switch (transferCharacteristics) {
50
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_GAMMA28: // 5
51
+ tf->cutoff = -INFINITY;
52
+ tf->c0 = 1 .0f ;
53
+ tf->c1 = 1 .0f ;
54
+ tf->c2 = 0 .0f ;
55
+ tf->c3 = 0 .0f ;
56
+ tf->c4 = 0 .0f ;
57
+ tf->c5 = 0 .0f ;
58
+ tf->gamma = 1 .0f /2 .8f ;
59
+ break ;
60
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT709: // 1
61
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT601: // 6
62
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT2020_10BIT: // 14
63
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT2020_12BIT: // 15
64
+ tf->cutoff = beta;
65
+ //
66
+ tf->c0 = alpha;
67
+ tf->c1 = 1 .0f ;
68
+ tf->c2 = 0 .0f ;
69
+ tf->gamma = 0 .45f ;
70
+ tf->c3 = -(alpha - 1 );
71
+ //
72
+ tf->c4 = 4 .5f ;
73
+ tf->c5 = 0 .0f ;
74
+ break ;
75
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_ST240: // 7
76
+ tf->cutoff = beta;
77
+ //
78
+ tf->c0 = alpha;
79
+ tf->c1 = 1 .0f ;
80
+ tf->c2 = 0 .0f ;
81
+ tf->gamma = 0 .45f ;
82
+ tf->c3 = -(alpha - 1 );
83
+ //
84
+ tf->c4 = 4 .0f ;
85
+ tf->c5 = 0 .0f ;
86
+ break ;
87
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_LINEAR: // 8
88
+ tf->cutoff = INFINITY;
89
+ //
90
+ tf->c0 = 1 .0f ;
91
+ tf->c1 = 1 .0f ;
92
+ tf->c2 = 0 .0f ;
93
+ tf->gamma = 1 .0f ;
94
+ tf->c3 = 0 .0f ;
95
+ //
96
+ tf->c4 = 4 .0f ;
97
+ tf->c5 = 0 .0f ;
98
+ break ;
99
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_IEC61966: // 11
100
+ tf->cutoff = beta;
101
+ //
102
+ tf->c0 = alpha;
103
+ tf->c1 = 1 .0f ;
104
+ tf->c2 = 0 .0f ;
105
+ tf->gamma = 0 .45f ;
106
+ tf->c3 = -(alpha - 1 );
107
+ //
108
+ tf->c4 = 4 .5f ;
109
+ tf->c5 = 0 .0f ;
110
+ break ;
111
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT1361_EXTENDED: // 12
112
+ tf->cutoff = beta;
113
+ //
114
+ tf->c0 = alpha;
115
+ tf->c1 = 1 .0f ;
116
+ tf->c2 = 0 .0f ;
117
+ tf->gamma = 0 .45f ;
118
+ tf->c3 = -(alpha - 1 );
119
+ //
120
+ tf->c4 = 4 .5f ;
121
+ tf->c5 = 0 .0f ;
122
+ break ;
123
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_SRGB: // 13
124
+ tf->cutoff = beta;
125
+ //
126
+ tf->c0 = alpha;
127
+ tf->c1 = 1 .0f ;
128
+ tf->c2 = 0 .0f ;
129
+ tf->gamma = 1 .0f /2 .4f ;
130
+ tf->c3 = -(alpha - 1 );
131
+ //
132
+ tf->c4 = 12 .92f ;
133
+ tf->c5 = 0 .0f ;
134
+ break ;
135
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_ST428: // 17
136
+ tf->cutoff = -INFINITY;
137
+ //
138
+ tf->c0 = 1 .0f ;
139
+ tf->c1 = 48 .0f / 52 .37f ;
140
+ tf->c2 = 0 .0f ;
141
+ tf->gamma = 1 .0f /2 .6f ;
142
+ tf->c3 = 0 .0f ;
143
+ //
144
+ tf->c4 = 1 .0f ;
145
+ tf->c5 = 0 .0f ;
146
+ break ;
147
+ // Can't be represented by vImageTransferFunction. Use gamma 2.2 as a fallback.
148
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_ST2084: // 16
149
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT2100_HLG: // 18
150
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_LOG_100_1: // 9
151
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_LOG_100_SQRT: // 10
152
+ //
153
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_UNKNOWN: // 0
154
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_UNSPECIFIED: // 2
155
+ case AVIF_NCLX_TRANSFER_CHARACTERISTICS_GAMMA22: // 4
156
+ default :
157
+ tf->cutoff = -INFINITY;
158
+ tf->c0 = 1 .0f ;
159
+ tf->c1 = 1 .0f ;
160
+ tf->c2 = 0 .0f ;
161
+ tf->c3 = 0 .0f ;
162
+ tf->c4 = 0 .0f ;
163
+ tf->c5 = 0 .0f ;
164
+ tf->gamma = 1 .0f /2 .2f ;
165
+ break ;
166
+ }
167
+ }
168
+ static CGColorSpaceRef CreateColorSpaceMono (uint16_t const colorPrimaries, uint16_t const transferCharacteristics) {
169
+ if (@available (macOS 10.10 , iOS 8.0 , tvOS 8.0 , *)) {
170
+ vImage_Error err;
171
+ vImageWhitePoint white;
172
+ vImageTransferFunction transfer;
173
+ CalcWhitePoint (colorPrimaries, &white);
174
+ CalcTransferFunction (transferCharacteristics, &transfer);
175
+ CGColorSpaceRef colorSpace = vImageCreateMonochromeColorSpaceWithWhitePointAndTransferFunction (&white, &transfer, kCGRenderingIntentDefault , kvImagePrintDiagnosticsToConsole, &err);
176
+ if (err != kvImageNoError) {
177
+ NSLog (@" [BUG] Failed to create monochrome color space: %ld " , err);
178
+ if (colorSpace != NULL ) {
179
+ CGColorSpaceRelease (colorSpace);
180
+ }
181
+ return NULL ;
182
+ }
183
+ return colorSpace;
184
+ }else {
185
+ return NULL ;
186
+ }
187
+ }
188
+
189
+ static CGColorSpaceRef CreateColorSpaceRGB (uint16_t const colorPrimaries, uint16_t const transferCharacteristics) {
190
+ if (@available (macOS 10.10 , iOS 8.0 , tvOS 8.0 , *)) {
191
+ vImage_Error err;
192
+ vImageRGBPrimaries primaries;
193
+ vImageTransferFunction transfer;
194
+ CalcRGBPrimaries (colorPrimaries, &primaries);
195
+ CalcTransferFunction (transferCharacteristics, &transfer);
196
+ CGColorSpaceRef colorSpace = vImageCreateRGBColorSpaceWithPrimariesAndTransferFunction (&primaries, &transfer, kCGRenderingIntentDefault , kvImagePrintDiagnosticsToConsole, &err);
197
+ if (err != kvImageNoError) {
198
+ NSLog (@" [BUG] Failed to create monochrome color space: %ld " , err);
199
+ if (colorSpace != NULL ) {
200
+ CGColorSpaceRelease (colorSpace);
201
+ }
202
+ return NULL ;
203
+ }
204
+ return colorSpace;
205
+ }else {
206
+ return NULL ;
207
+ }
208
+ }
209
+
20
210
static void CalcColorSpaceMono (avifImage * avif, CGColorSpaceRef* ref, BOOL * shouldRelease) {
21
211
static CGColorSpaceRef defaultColorSpace;
22
212
{
@@ -46,12 +236,81 @@ static void CalcColorSpaceMono(avifImage * avif, CGColorSpaceRef* ref, BOOL* sho
46
236
*shouldRelease = FALSE ;
47
237
return ;
48
238
}
49
- // TODO: (ledyba-z):
50
- // We can support other color spaces using
51
- // vImageCreateMonochromeColorSpaceWithWhitePointAndTransferFunction
52
- // https://github.com/link-u/SDWebImageAVIFCoder/tree/feature/create-custom-colorspaces
53
- *ref = defaultColorSpace;
54
- *shouldRelease = FALSE ;
239
+ uint16_t const colorPrimaries = avif->nclx .colourPrimaries ;
240
+ uint16_t const transferCharacteristics = avif->nclx .transferCharacteristics ;
241
+ if ((colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_UNKNOWN ||
242
+ colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_UNSPECIFIED) &&
243
+ (transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_UNKNOWN ||
244
+ transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_UNSPECIFIED)) {
245
+ *ref = defaultColorSpace;
246
+ *shouldRelease = FALSE ;
247
+ return ;
248
+ }
249
+ if (colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_SRGB &&
250
+ transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_SRGB) {
251
+ static CGColorSpaceRef sRGB = NULL ;
252
+ static dispatch_once_t onceToken;
253
+ dispatch_once (&onceToken, ^{
254
+ sRGB = CreateColorSpaceMono (colorPrimaries, transferCharacteristics);
255
+ if (sRGB == NULL ) {
256
+ sRGB = defaultColorSpace;
257
+ }
258
+ });
259
+ *ref = sRGB ;
260
+ *shouldRelease = FALSE ;
261
+ return ;
262
+ }
263
+ if (colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_BT709 &&
264
+ transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT709) {
265
+ static CGColorSpaceRef bt709 = NULL ;
266
+ static dispatch_once_t onceToken;
267
+ dispatch_once (&onceToken, ^{
268
+ bt709 = CreateColorSpaceMono (colorPrimaries, transferCharacteristics);
269
+ if (bt709 == NULL ) {
270
+ bt709 = defaultColorSpace;
271
+ }
272
+ });
273
+ *ref = bt709;
274
+ *shouldRelease = FALSE ;
275
+ return ;
276
+ }
277
+ if (colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_BT2020 &&
278
+ (transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT2020_10BIT ||
279
+ transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_BT2020_12BIT)) {
280
+ static CGColorSpaceRef bt2020 = NULL ;
281
+ static dispatch_once_t onceToken;
282
+ dispatch_once (&onceToken, ^{
283
+ bt2020 = CreateColorSpaceMono (colorPrimaries, transferCharacteristics);
284
+ if (bt2020 == NULL ) {
285
+ bt2020 = defaultColorSpace;
286
+ }
287
+ });
288
+ *ref = bt2020;
289
+ *shouldRelease = FALSE ;
290
+ return ;
291
+ }
292
+ if (colorPrimaries == AVIF_NCLX_COLOUR_PRIMARIES_P3 &&
293
+ transferCharacteristics == AVIF_NCLX_TRANSFER_CHARACTERISTICS_SRGB) {
294
+ static CGColorSpaceRef p3 = NULL ;
295
+ static dispatch_once_t onceToken;
296
+ dispatch_once (&onceToken, ^{
297
+ p3 = CreateColorSpaceMono (colorPrimaries, transferCharacteristics);
298
+ if (p3 == NULL ) {
299
+ p3 = defaultColorSpace;
300
+ }
301
+ });
302
+ *ref = p3;
303
+ *shouldRelease = FALSE ;
304
+ return ;
305
+ }
306
+
307
+ *ref = CreateColorSpaceMono (colorPrimaries, transferCharacteristics);
308
+ if (*ref != NULL ) {
309
+ *shouldRelease = TRUE ;
310
+ } else {
311
+ *ref = defaultColorSpace;
312
+ *shouldRelease = FALSE ;
313
+ }
55
314
}
56
315
57
316
static void CalcColorSpaceRGB (avifImage * avif, CGColorSpaceRef* ref, BOOL * shouldRelease) {
@@ -261,12 +520,13 @@ static void CalcColorSpaceRGB(avifImage * avif, CGColorSpaceRef* ref, BOOL* shou
261
520
return ;
262
521
}
263
522
264
- // TODO: (ledyba-z):
265
- // We can support other color spaces using
266
- // vImageCreateRGBColorSpaceWithPrimariesAndTransferFunction
267
- // https://github.com/link-u/SDWebImageAVIFCoder/tree/feature/create-custom-colorspaces
268
- *ref = defaultColorSpace;
269
- *shouldRelease = FALSE ;
523
+ *ref = CreateColorSpaceRGB (colorPrimaries, transferCharacteristics);
524
+ if (*ref != NULL ) {
525
+ *shouldRelease = TRUE ;
526
+ } else {
527
+ *ref = defaultColorSpace;
528
+ *shouldRelease = FALSE ;
529
+ }
270
530
}
271
531
272
532
static CGImageRef CreateImageFromBuffer (avifImage * avif, vImage_Buffer* result) {
0 commit comments