Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
wine-mirror
GitHub Repository: wine-mirror/wine
Path: blob/master/libs/lcms2/src/cmsalpha.c
4391 views
1
//---------------------------------------------------------------------------------
2
//
3
// Little Color Management System
4
// Copyright (c) 1998-2024 Marti Maria Saguer
5
//
6
// Permission is hereby granted, free of charge, to any person obtaining
7
// a copy of this software and associated documentation files (the "Software"),
8
// to deal in the Software without restriction, including without limitation
9
// the rights to use, copy, modify, merge, publish, distribute, sublicense,
10
// and/or sell copies of the Software, and to permit persons to whom the Software
11
// is furnished to do so, subject to the following conditions:
12
//
13
// The above copyright notice and this permission notice shall be included in
14
// all copies or substantial portions of the Software.
15
//
16
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
// EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO
18
// THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
// NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
// LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
// OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
// WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
//
24
//---------------------------------------------------------------------------------
25
//
26
27
#include "lcms2_internal.h"
28
29
// Alpha copy ------------------------------------------------------------------------------------------------------------------
30
31
// This macro return words stored as big endian
32
#define CHANGE_ENDIAN(w) (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8))
33
34
35
// Floor to byte, taking care of saturation
36
cmsINLINE cmsUInt8Number _cmsQuickSaturateByte(cmsFloat64Number d)
37
{
38
d += 0.5;
39
if (d <= 0) return 0;
40
if (d >= 255.0) return 255;
41
42
return (cmsUInt8Number) _cmsQuickFloorWord(d);
43
}
44
45
46
// Return the size in bytes of a given formatter
47
static
48
cmsUInt32Number trueBytesSize(cmsUInt32Number Format)
49
{
50
cmsUInt32Number fmt_bytes = T_BYTES(Format);
51
52
// For double, the T_BYTES field returns zero
53
if (fmt_bytes == 0)
54
return sizeof(double);
55
56
// Otherwise, it is already correct for all formats
57
return fmt_bytes;
58
}
59
60
61
// Several format converters
62
63
typedef void(*cmsFormatterAlphaFn)(void* dst, const void* src);
64
65
66
// From 8
67
68
static
69
void copy8(void* dst, const void* src)
70
{
71
memmove(dst, src, 1);
72
}
73
74
static
75
void from8to16(void* dst, const void* src)
76
{
77
cmsUInt8Number n = *(cmsUInt8Number*)src;
78
*(cmsUInt16Number*) dst = (cmsUInt16Number) FROM_8_TO_16(n);
79
}
80
81
static
82
void from8to16SE(void* dst, const void* src)
83
{
84
cmsUInt8Number n = *(cmsUInt8Number*)src;
85
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(FROM_8_TO_16(n));
86
}
87
88
static
89
void from8toFLT(void* dst, const void* src)
90
{
91
*(cmsFloat32Number*)dst = (cmsFloat32Number) (*(cmsUInt8Number*)src) / 255.0f;
92
}
93
94
static
95
void from8toDBL(void* dst, const void* src)
96
{
97
*(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt8Number*)src) / 255.0;
98
}
99
100
static
101
void from8toHLF(void* dst, const void* src)
102
{
103
#ifndef CMS_NO_HALF_SUPPORT
104
cmsFloat32Number n = (*(cmsUInt8Number*)src) / 255.0f;
105
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
106
#else
107
cmsUNUSED_PARAMETER(dst);
108
cmsUNUSED_PARAMETER(src);
109
#endif
110
}
111
112
// From 16
113
114
static
115
void from16to8(void* dst, const void* src)
116
{
117
cmsUInt16Number n = *(cmsUInt16Number*)src;
118
*(cmsUInt8Number*) dst = FROM_16_TO_8(n);
119
}
120
121
static
122
void from16SEto8(void* dst, const void* src)
123
{
124
cmsUInt16Number n = *(cmsUInt16Number*)src;
125
*(cmsUInt8Number*)dst = FROM_16_TO_8(CHANGE_ENDIAN(n));
126
}
127
128
static
129
void copy16(void* dst, const void* src)
130
{
131
memmove(dst, src, 2);
132
}
133
134
static
135
void from16to16(void* dst, const void* src)
136
{
137
cmsUInt16Number n = *(cmsUInt16Number*)src;
138
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(n);
139
}
140
141
static
142
void from16toFLT(void* dst, const void* src)
143
{
144
*(cmsFloat32Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f;
145
}
146
147
static
148
void from16SEtoFLT(void* dst, const void* src)
149
{
150
*(cmsFloat32Number*)dst = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f;
151
}
152
153
static
154
void from16toDBL(void* dst, const void* src)
155
{
156
*(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt16Number*)src) / 65535.0;
157
}
158
159
static
160
void from16SEtoDBL(void* dst, const void* src)
161
{
162
*(cmsFloat64Number*)dst = (cmsFloat64Number) (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0;
163
}
164
165
static
166
void from16toHLF(void* dst, const void* src)
167
{
168
#ifndef CMS_NO_HALF_SUPPORT
169
cmsFloat32Number n = (*(cmsUInt16Number*)src) / 65535.0f;
170
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
171
#else
172
cmsUNUSED_PARAMETER(dst);
173
cmsUNUSED_PARAMETER(src);
174
#endif
175
}
176
177
static
178
void from16SEtoHLF(void* dst, const void* src)
179
{
180
#ifndef CMS_NO_HALF_SUPPORT
181
cmsFloat32Number n = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f;
182
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
183
#else
184
cmsUNUSED_PARAMETER(dst);
185
cmsUNUSED_PARAMETER(src);
186
#endif
187
}
188
// From Float
189
190
static
191
void fromFLTto8(void* dst, const void* src)
192
{
193
cmsFloat32Number n = *(cmsFloat32Number*)src;
194
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
195
}
196
197
static
198
void fromFLTto16(void* dst, const void* src)
199
{
200
cmsFloat32Number n = *(cmsFloat32Number*)src;
201
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0);
202
}
203
204
static
205
void fromFLTto16SE(void* dst, const void* src)
206
{
207
cmsFloat32Number n = *(cmsFloat32Number*)src;
208
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0);
209
210
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
211
}
212
213
static
214
void copy32(void* dst, const void* src)
215
{
216
memmove(dst, src, sizeof(cmsFloat32Number));
217
}
218
219
static
220
void fromFLTtoDBL(void* dst, const void* src)
221
{
222
cmsFloat32Number n = *(cmsFloat32Number*)src;
223
*(cmsFloat64Number*)dst = (cmsFloat64Number)n;
224
}
225
226
static
227
void fromFLTtoHLF(void* dst, const void* src)
228
{
229
#ifndef CMS_NO_HALF_SUPPORT
230
cmsFloat32Number n = *(cmsFloat32Number*)src;
231
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
232
#else
233
cmsUNUSED_PARAMETER(dst);
234
cmsUNUSED_PARAMETER(src);
235
#endif
236
}
237
238
239
// From HALF
240
241
static
242
void fromHLFto8(void* dst, const void* src)
243
{
244
#ifndef CMS_NO_HALF_SUPPORT
245
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
246
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
247
#else
248
cmsUNUSED_PARAMETER(dst);
249
cmsUNUSED_PARAMETER(src);
250
#endif
251
252
}
253
254
static
255
void fromHLFto16(void* dst, const void* src)
256
{
257
#ifndef CMS_NO_HALF_SUPPORT
258
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
259
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0);
260
#else
261
cmsUNUSED_PARAMETER(dst);
262
cmsUNUSED_PARAMETER(src);
263
#endif
264
}
265
266
static
267
void fromHLFto16SE(void* dst, const void* src)
268
{
269
#ifndef CMS_NO_HALF_SUPPORT
270
cmsFloat32Number n = _cmsHalf2Float(*(cmsUInt16Number*)src);
271
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0);
272
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
273
#else
274
cmsUNUSED_PARAMETER(dst);
275
cmsUNUSED_PARAMETER(src);
276
#endif
277
}
278
279
static
280
void fromHLFtoFLT(void* dst, const void* src)
281
{
282
#ifndef CMS_NO_HALF_SUPPORT
283
*(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src);
284
#else
285
cmsUNUSED_PARAMETER(dst);
286
cmsUNUSED_PARAMETER(src);
287
#endif
288
}
289
290
static
291
void fromHLFtoDBL(void* dst, const void* src)
292
{
293
#ifndef CMS_NO_HALF_SUPPORT
294
*(cmsFloat64Number*)dst = (cmsFloat64Number)_cmsHalf2Float(*(cmsUInt16Number*)src);
295
#else
296
cmsUNUSED_PARAMETER(dst);
297
cmsUNUSED_PARAMETER(src);
298
#endif
299
}
300
301
// From double
302
static
303
void fromDBLto8(void* dst, const void* src)
304
{
305
cmsFloat64Number n = *(cmsFloat64Number*)src;
306
*(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
307
}
308
309
static
310
void fromDBLto16(void* dst, const void* src)
311
{
312
cmsFloat64Number n = *(cmsFloat64Number*)src;
313
*(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
314
}
315
316
static
317
void fromDBLto16SE(void* dst, const void* src)
318
{
319
cmsFloat64Number n = *(cmsFloat64Number*)src;
320
cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);
321
*(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
322
}
323
324
static
325
void fromDBLtoFLT(void* dst, const void* src)
326
{
327
cmsFloat64Number n = *(cmsFloat64Number*)src;
328
*(cmsFloat32Number*)dst = (cmsFloat32Number) n;
329
}
330
331
static
332
void fromDBLtoHLF(void* dst, const void* src)
333
{
334
#ifndef CMS_NO_HALF_SUPPORT
335
cmsFloat32Number n = (cmsFloat32Number) *(cmsFloat64Number*)src;
336
*(cmsUInt16Number*)dst = _cmsFloat2Half(n);
337
#else
338
cmsUNUSED_PARAMETER(dst);
339
cmsUNUSED_PARAMETER(src);
340
#endif
341
}
342
343
static
344
void copy64(void* dst, const void* src)
345
{
346
memmove(dst, src, sizeof(cmsFloat64Number));
347
}
348
349
350
// Returns the position (x or y) of the formatter in the table of functions
351
static
352
int FormatterPos(cmsUInt32Number frm)
353
{
354
cmsUInt32Number b = T_BYTES(frm);
355
356
if (b == 0 && T_FLOAT(frm))
357
return 5; // DBL
358
#ifndef CMS_NO_HALF_SUPPORT
359
if (b == 2 && T_FLOAT(frm))
360
return 3; // HLF
361
#endif
362
if (b == 4 && T_FLOAT(frm))
363
return 4; // FLT
364
if (b == 2 && !T_FLOAT(frm))
365
{
366
if (T_ENDIAN16(frm))
367
return 2; // 16SE
368
else
369
return 1; // 16
370
}
371
if (b == 1 && !T_FLOAT(frm))
372
return 0; // 8
373
return -1; // not recognized
374
}
375
376
// Obtains an alpha-to-alpha function formatter
377
static
378
cmsFormatterAlphaFn _cmsGetFormatterAlpha(cmsContext id, cmsUInt32Number in, cmsUInt32Number out)
379
{
380
static cmsFormatterAlphaFn FormattersAlpha[6][6] = {
381
382
/* from 8 */ { copy8, from8to16, from8to16SE, from8toHLF, from8toFLT, from8toDBL },
383
/* from 16*/ { from16to8, copy16, from16to16, from16toHLF, from16toFLT, from16toDBL },
384
/* from 16SE*/{ from16SEto8, from16to16, copy16, from16SEtoHLF,from16SEtoFLT, from16SEtoDBL },
385
/* from HLF*/ { fromHLFto8, fromHLFto16, fromHLFto16SE, copy16, fromHLFtoFLT, fromHLFtoDBL },
386
/* from FLT*/ { fromFLTto8, fromFLTto16, fromFLTto16SE, fromFLTtoHLF, copy32, fromFLTtoDBL },
387
/* from DBL*/ { fromDBLto8, fromDBLto16, fromDBLto16SE, fromDBLtoHLF, fromDBLtoFLT, copy64 }};
388
389
int in_n = FormatterPos(in);
390
int out_n = FormatterPos(out);
391
392
if (in_n < 0 || out_n < 0 || in_n > 5 || out_n > 5) {
393
394
cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized alpha channel width");
395
return NULL;
396
}
397
398
return FormattersAlpha[in_n][out_n];
399
}
400
401
402
403
// This function computes the distance from each component to the next one in bytes.
404
static
405
cmsBool ComputeIncrementsForChunky(cmsUInt32Number Format,
406
cmsUInt32Number ComponentStartingOrder[],
407
cmsUInt32Number ComponentPointerIncrements[])
408
{
409
cmsUInt32Number channels[cmsMAXCHANNELS];
410
cmsUInt32Number extra = T_EXTRA(Format);
411
cmsUInt32Number nchannels = T_CHANNELS(Format);
412
cmsUInt32Number total_chans = nchannels + extra;
413
cmsUInt32Number i;
414
cmsUInt32Number channelSize = trueBytesSize(Format);
415
cmsUInt32Number pixelSize = channelSize * total_chans;
416
417
// Sanity check
418
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
419
return FALSE;
420
421
memset(channels, 0, sizeof(channels));
422
423
// Separation is independent of starting point and only depends on channel size
424
for (i = 0; i < extra; i++)
425
ComponentPointerIncrements[i] = pixelSize;
426
427
// Handle do swap
428
for (i = 0; i < total_chans; i++)
429
{
430
if (T_DOSWAP(Format)) {
431
channels[i] = total_chans - i - 1;
432
}
433
else {
434
channels[i] = i;
435
}
436
}
437
438
// Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012
439
if (T_SWAPFIRST(Format) && total_chans > 1) {
440
441
cmsUInt32Number tmp = channels[0];
442
for (i = 0; i < total_chans-1; i++)
443
channels[i] = channels[i + 1];
444
445
channels[total_chans - 1] = tmp;
446
}
447
448
// Handle size
449
if (channelSize > 1)
450
for (i = 0; i < total_chans; i++) {
451
channels[i] *= channelSize;
452
}
453
454
for (i = 0; i < extra; i++)
455
ComponentStartingOrder[i] = channels[i + nchannels];
456
457
return TRUE;
458
}
459
460
461
462
// On planar configurations, the distance is the stride added to any non-negative
463
static
464
cmsBool ComputeIncrementsForPlanar(cmsUInt32Number Format,
465
cmsUInt32Number BytesPerPlane,
466
cmsUInt32Number ComponentStartingOrder[],
467
cmsUInt32Number ComponentPointerIncrements[])
468
{
469
cmsUInt32Number channels[cmsMAXCHANNELS];
470
cmsUInt32Number extra = T_EXTRA(Format);
471
cmsUInt32Number nchannels = T_CHANNELS(Format);
472
cmsUInt32Number total_chans = nchannels + extra;
473
cmsUInt32Number i;
474
cmsUInt32Number channelSize = trueBytesSize(Format);
475
476
// Sanity check
477
if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
478
return FALSE;
479
480
memset(channels, 0, sizeof(channels));
481
482
// Separation is independent of starting point and only depends on channel size
483
for (i = 0; i < extra; i++)
484
ComponentPointerIncrements[i] = channelSize;
485
486
// Handle do swap
487
for (i = 0; i < total_chans; i++)
488
{
489
if (T_DOSWAP(Format)) {
490
channels[i] = total_chans - i - 1;
491
}
492
else {
493
channels[i] = i;
494
}
495
}
496
497
// Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012
498
if (T_SWAPFIRST(Format) && total_chans > 0) {
499
500
cmsUInt32Number tmp = channels[0];
501
for (i = 0; i < total_chans - 1; i++)
502
channels[i] = channels[i + 1];
503
504
channels[total_chans - 1] = tmp;
505
}
506
507
// Handle size
508
for (i = 0; i < total_chans; i++) {
509
channels[i] *= BytesPerPlane;
510
}
511
512
for (i = 0; i < extra; i++)
513
ComponentStartingOrder[i] = channels[i + nchannels];
514
515
return TRUE;
516
}
517
518
519
520
// Dispatcher por chunky and planar RGB
521
static
522
cmsBool ComputeComponentIncrements(cmsUInt32Number Format,
523
cmsUInt32Number BytesPerPlane,
524
cmsUInt32Number ComponentStartingOrder[],
525
cmsUInt32Number ComponentPointerIncrements[])
526
{
527
if (T_PLANAR(Format)) {
528
529
return ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements);
530
}
531
else {
532
return ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements);
533
}
534
535
}
536
537
// Handles extra channels copying alpha if requested by the flags
538
void _cmsHandleExtraChannels(_cmsTRANSFORM* p, const void* in,
539
void* out,
540
cmsUInt32Number PixelsPerLine,
541
cmsUInt32Number LineCount,
542
const cmsStride* Stride)
543
{
544
cmsUInt32Number i, j, k;
545
cmsUInt32Number nExtra;
546
cmsUInt32Number SourceStartingOrder[cmsMAXCHANNELS];
547
cmsUInt32Number SourceIncrements[cmsMAXCHANNELS];
548
cmsUInt32Number DestStartingOrder[cmsMAXCHANNELS];
549
cmsUInt32Number DestIncrements[cmsMAXCHANNELS];
550
551
cmsFormatterAlphaFn copyValueFn;
552
553
// Make sure we need some copy
554
if (!(p->dwOriginalFlags & cmsFLAGS_COPY_ALPHA))
555
return;
556
557
// Exit early if in-place color-management is occurring - no need to copy extra channels to themselves.
558
if (p->InputFormat == p->OutputFormat && in == out)
559
return;
560
561
// Make sure we have same number of alpha channels. If not, just return as this should be checked at transform creation time.
562
nExtra = T_EXTRA(p->InputFormat);
563
if (nExtra != T_EXTRA(p->OutputFormat))
564
return;
565
566
// Anything to do?
567
if (nExtra == 0)
568
return;
569
570
// Compute the increments
571
if (!ComputeComponentIncrements(p->InputFormat, Stride->BytesPerPlaneIn, SourceStartingOrder, SourceIncrements))
572
return;
573
if (!ComputeComponentIncrements(p->OutputFormat, Stride->BytesPerPlaneOut, DestStartingOrder, DestIncrements))
574
return;
575
576
// Check for conversions 8, 16, half, float, dbl
577
copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat);
578
if (copyValueFn == NULL)
579
return;
580
581
if (nExtra == 1) { // Optimized routine for copying a single extra channel quickly
582
583
cmsUInt8Number* SourcePtr;
584
cmsUInt8Number* DestPtr;
585
586
size_t SourceStrideIncrement = 0;
587
size_t DestStrideIncrement = 0;
588
589
// The loop itself
590
for (i = 0; i < LineCount; i++) {
591
592
// Prepare pointers for the loop
593
SourcePtr = (cmsUInt8Number*)in + SourceStartingOrder[0] + SourceStrideIncrement;
594
DestPtr = (cmsUInt8Number*)out + DestStartingOrder[0] + DestStrideIncrement;
595
596
for (j = 0; j < PixelsPerLine; j++) {
597
598
copyValueFn(DestPtr, SourcePtr);
599
600
SourcePtr += SourceIncrements[0];
601
DestPtr += DestIncrements[0];
602
}
603
604
SourceStrideIncrement += Stride->BytesPerLineIn;
605
DestStrideIncrement += Stride->BytesPerLineOut;
606
}
607
608
}
609
else { // General case with more than one extra channel
610
611
cmsUInt8Number* SourcePtr[cmsMAXCHANNELS];
612
cmsUInt8Number* DestPtr[cmsMAXCHANNELS];
613
614
size_t SourceStrideIncrements[cmsMAXCHANNELS];
615
size_t DestStrideIncrements[cmsMAXCHANNELS];
616
617
memset(SourceStrideIncrements, 0, sizeof(SourceStrideIncrements));
618
memset(DestStrideIncrements, 0, sizeof(DestStrideIncrements));
619
620
// The loop itself
621
for (i = 0; i < LineCount; i++) {
622
623
// Prepare pointers for the loop
624
for (j = 0; j < nExtra; j++) {
625
626
SourcePtr[j] = (cmsUInt8Number*)in + SourceStartingOrder[j] + SourceStrideIncrements[j];
627
DestPtr[j] = (cmsUInt8Number*)out + DestStartingOrder[j] + DestStrideIncrements[j];
628
}
629
630
for (j = 0; j < PixelsPerLine; j++) {
631
632
for (k = 0; k < nExtra; k++) {
633
634
copyValueFn(DestPtr[k], SourcePtr[k]);
635
636
SourcePtr[k] += SourceIncrements[k];
637
DestPtr[k] += DestIncrements[k];
638
}
639
}
640
641
for (j = 0; j < nExtra; j++) {
642
643
SourceStrideIncrements[j] += Stride->BytesPerLineIn;
644
DestStrideIncrements[j] += Stride->BytesPerLineOut;
645
}
646
}
647
}
648
}
649
650