windowscodecs: Silence fixme for IID_CMetaBitmapRenderTarget.
[wine.git] / libs / lcms2 / src / cmsalpha.c
blob63e6046a62fde3164eff6fa2b9e086b6aeae80fc
1 //---------------------------------------------------------------------------------
2 //
3 // Little Color Management System
4 // Copyright (c) 1998-2023 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:
13 // The above copyright notice and this permission notice shall be included in
14 // all copies or substantial portions of the Software.
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.
24 //---------------------------------------------------------------------------------
27 #include "lcms2_internal.h"
29 // Alpha copy ------------------------------------------------------------------------------------------------------------------
31 // This macro return words stored as big endian
32 #define CHANGE_ENDIAN(w) (cmsUInt16Number) ((cmsUInt16Number) ((w)<<8)|((w)>>8))
35 // Floor to byte, taking care of saturation
36 cmsINLINE cmsUInt8Number _cmsQuickSaturateByte(cmsFloat64Number d)
38 d += 0.5;
39 if (d <= 0) return 0;
40 if (d >= 255.0) return 255;
42 return (cmsUInt8Number) _cmsQuickFloorWord(d);
46 // Return the size in bytes of a given formatter
47 static
48 cmsUInt32Number trueBytesSize(cmsUInt32Number Format)
50 cmsUInt32Number fmt_bytes = T_BYTES(Format);
52 // For double, the T_BYTES field returns zero
53 if (fmt_bytes == 0)
54 return sizeof(double);
56 // Otherwise, it is already correct for all formats
57 return fmt_bytes;
61 // Several format converters
63 typedef void(*cmsFormatterAlphaFn)(void* dst, const void* src);
66 // From 8
68 static
69 void copy8(void* dst, const void* src)
71 memmove(dst, src, 1);
74 static
75 void from8to16(void* dst, const void* src)
77 cmsUInt8Number n = *(cmsUInt8Number*)src;
78 *(cmsUInt16Number*) dst = (cmsUInt16Number) FROM_8_TO_16(n);
81 static
82 void from8to16SE(void* dst, const void* src)
84 cmsUInt8Number n = *(cmsUInt8Number*)src;
85 *(cmsUInt16Number*)dst = CHANGE_ENDIAN(FROM_8_TO_16(n));
88 static
89 void from8toFLT(void* dst, const void* src)
91 *(cmsFloat32Number*)dst = (cmsFloat32Number) (*(cmsUInt8Number*)src) / 255.0f;
94 static
95 void from8toDBL(void* dst, const void* src)
97 *(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt8Number*)src) / 255.0;
100 static
101 void from8toHLF(void* dst, const void* src)
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
112 // From 16
114 static
115 void from16to8(void* dst, const void* src)
117 cmsUInt16Number n = *(cmsUInt16Number*)src;
118 *(cmsUInt8Number*) dst = FROM_16_TO_8(n);
121 static
122 void from16SEto8(void* dst, const void* src)
124 cmsUInt16Number n = *(cmsUInt16Number*)src;
125 *(cmsUInt8Number*)dst = FROM_16_TO_8(CHANGE_ENDIAN(n));
128 static
129 void copy16(void* dst, const void* src)
131 memmove(dst, src, 2);
134 static
135 void from16to16(void* dst, const void* src)
137 cmsUInt16Number n = *(cmsUInt16Number*)src;
138 *(cmsUInt16Number*)dst = CHANGE_ENDIAN(n);
141 static
142 void from16toFLT(void* dst, const void* src)
144 *(cmsFloat32Number*)dst = (*(cmsUInt16Number*)src) / 65535.0f;
147 static
148 void from16SEtoFLT(void* dst, const void* src)
150 *(cmsFloat32Number*)dst = (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0f;
153 static
154 void from16toDBL(void* dst, const void* src)
156 *(cmsFloat64Number*)dst = (cmsFloat64Number) (*(cmsUInt16Number*)src) / 65535.0;
159 static
160 void from16SEtoDBL(void* dst, const void* src)
162 *(cmsFloat64Number*)dst = (cmsFloat64Number) (CHANGE_ENDIAN(*(cmsUInt16Number*)src)) / 65535.0;
165 static
166 void from16toHLF(void* dst, const void* src)
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
177 static
178 void from16SEtoHLF(void* dst, const void* src)
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
188 // From Float
190 static
191 void fromFLTto8(void* dst, const void* src)
193 cmsFloat32Number n = *(cmsFloat32Number*)src;
194 *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
197 static
198 void fromFLTto16(void* dst, const void* src)
200 cmsFloat32Number n = *(cmsFloat32Number*)src;
201 *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0);
204 static
205 void fromFLTto16SE(void* dst, const void* src)
207 cmsFloat32Number n = *(cmsFloat32Number*)src;
208 cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0);
210 *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
213 static
214 void copy32(void* dst, const void* src)
216 memmove(dst, src, sizeof(cmsFloat32Number));
219 static
220 void fromFLTtoDBL(void* dst, const void* src)
222 cmsFloat32Number n = *(cmsFloat32Number*)src;
223 *(cmsFloat64Number*)dst = (cmsFloat64Number)n;
226 static
227 void fromFLTtoHLF(void* dst, const void* src)
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
239 // From HALF
241 static
242 void fromHLFto8(void* dst, const void* src)
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
254 static
255 void fromHLFto16(void* dst, const void* src)
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
266 static
267 void fromHLFto16SE(void* dst, const void* src)
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
279 static
280 void fromHLFtoFLT(void* dst, const void* src)
282 #ifndef CMS_NO_HALF_SUPPORT
283 *(cmsFloat32Number*)dst = _cmsHalf2Float(*(cmsUInt16Number*)src);
284 #else
285 cmsUNUSED_PARAMETER(dst);
286 cmsUNUSED_PARAMETER(src);
287 #endif
290 static
291 void fromHLFtoDBL(void* dst, const void* src)
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
301 // From double
302 static
303 void fromDBLto8(void* dst, const void* src)
305 cmsFloat64Number n = *(cmsFloat64Number*)src;
306 *(cmsUInt8Number*)dst = _cmsQuickSaturateByte(n * 255.0);
309 static
310 void fromDBLto16(void* dst, const void* src)
312 cmsFloat64Number n = *(cmsFloat64Number*)src;
313 *(cmsUInt16Number*)dst = _cmsQuickSaturateWord(n * 65535.0f);
316 static
317 void fromDBLto16SE(void* dst, const void* src)
319 cmsFloat64Number n = *(cmsFloat64Number*)src;
320 cmsUInt16Number i = _cmsQuickSaturateWord(n * 65535.0f);
321 *(cmsUInt16Number*)dst = CHANGE_ENDIAN(i);
324 static
325 void fromDBLtoFLT(void* dst, const void* src)
327 cmsFloat64Number n = *(cmsFloat64Number*)src;
328 *(cmsFloat32Number*)dst = (cmsFloat32Number) n;
331 static
332 void fromDBLtoHLF(void* dst, const void* src)
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
343 static
344 void copy64(void* dst, const void* src)
346 memmove(dst, src, sizeof(cmsFloat64Number));
350 // Returns the position (x or y) of the formatter in the table of functions
351 static
352 int FormatterPos(cmsUInt32Number frm)
354 cmsUInt32Number b = T_BYTES(frm);
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))
366 if (T_ENDIAN16(frm))
367 return 2; // 16SE
368 else
369 return 1; // 16
371 if (b == 1 && !T_FLOAT(frm))
372 return 0; // 8
373 return -1; // not recognized
376 // Obtains an alpha-to-alpha function formatter
377 static
378 cmsFormatterAlphaFn _cmsGetFormatterAlpha(cmsContext id, cmsUInt32Number in, cmsUInt32Number out)
380 static cmsFormatterAlphaFn FormattersAlpha[6][6] = {
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 }};
389 int in_n = FormatterPos(in);
390 int out_n = FormatterPos(out);
392 if (in_n < 0 || out_n < 0 || in_n > 5 || out_n > 5) {
394 cmsSignalError(id, cmsERROR_UNKNOWN_EXTENSION, "Unrecognized alpha channel width");
395 return NULL;
398 return FormattersAlpha[in_n][out_n];
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[])
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;
417 // Sanity check
418 if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
419 return FALSE;
421 memset(channels, 0, sizeof(channels));
423 // Separation is independent of starting point and only depends on channel size
424 for (i = 0; i < extra; i++)
425 ComponentPointerIncrements[i] = pixelSize;
427 // Handle do swap
428 for (i = 0; i < total_chans; i++)
430 if (T_DOSWAP(Format)) {
431 channels[i] = total_chans - i - 1;
433 else {
434 channels[i] = i;
438 // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012
439 if (T_SWAPFIRST(Format) && total_chans > 1) {
441 cmsUInt32Number tmp = channels[0];
442 for (i = 0; i < total_chans-1; i++)
443 channels[i] = channels[i + 1];
445 channels[total_chans - 1] = tmp;
448 // Handle size
449 if (channelSize > 1)
450 for (i = 0; i < total_chans; i++) {
451 channels[i] *= channelSize;
454 for (i = 0; i < extra; i++)
455 ComponentStartingOrder[i] = channels[i + nchannels];
457 return TRUE;
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[])
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);
476 // Sanity check
477 if (total_chans <= 0 || total_chans >= cmsMAXCHANNELS)
478 return FALSE;
480 memset(channels, 0, sizeof(channels));
482 // Separation is independent of starting point and only depends on channel size
483 for (i = 0; i < extra; i++)
484 ComponentPointerIncrements[i] = channelSize;
486 // Handle do swap
487 for (i = 0; i < total_chans; i++)
489 if (T_DOSWAP(Format)) {
490 channels[i] = total_chans - i - 1;
492 else {
493 channels[i] = i;
497 // Handle swap first (ROL of positions), example CMYK -> KCMY | 0123 -> 3012
498 if (T_SWAPFIRST(Format) && total_chans > 0) {
500 cmsUInt32Number tmp = channels[0];
501 for (i = 0; i < total_chans - 1; i++)
502 channels[i] = channels[i + 1];
504 channels[total_chans - 1] = tmp;
507 // Handle size
508 for (i = 0; i < total_chans; i++) {
509 channels[i] *= BytesPerPlane;
512 for (i = 0; i < extra; i++)
513 ComponentStartingOrder[i] = channels[i + nchannels];
515 return TRUE;
520 // Dispatcher por chunky and planar RGB
521 static
522 cmsBool ComputeComponentIncrements(cmsUInt32Number Format,
523 cmsUInt32Number BytesPerPlane,
524 cmsUInt32Number ComponentStartingOrder[],
525 cmsUInt32Number ComponentPointerIncrements[])
527 if (T_PLANAR(Format)) {
529 return ComputeIncrementsForPlanar(Format, BytesPerPlane, ComponentStartingOrder, ComponentPointerIncrements);
531 else {
532 return ComputeIncrementsForChunky(Format, ComponentStartingOrder, ComponentPointerIncrements);
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)
544 cmsUInt32Number i, j, k;
545 cmsUInt32Number nExtra;
546 cmsUInt32Number SourceStartingOrder[cmsMAXCHANNELS];
547 cmsUInt32Number SourceIncrements[cmsMAXCHANNELS];
548 cmsUInt32Number DestStartingOrder[cmsMAXCHANNELS];
549 cmsUInt32Number DestIncrements[cmsMAXCHANNELS];
551 cmsFormatterAlphaFn copyValueFn;
553 // Make sure we need some copy
554 if (!(p->dwOriginalFlags & cmsFLAGS_COPY_ALPHA))
555 return;
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;
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;
566 // Anything to do?
567 if (nExtra == 0)
568 return;
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;
576 // Check for conversions 8, 16, half, float, dbl
577 copyValueFn = _cmsGetFormatterAlpha(p->ContextID, p->InputFormat, p->OutputFormat);
578 if (copyValueFn == NULL)
579 return;
581 if (nExtra == 1) { // Optimized routine for copying a single extra channel quickly
583 cmsUInt8Number* SourcePtr;
584 cmsUInt8Number* DestPtr;
586 cmsUInt32Number SourceStrideIncrement = 0;
587 cmsUInt32Number DestStrideIncrement = 0;
589 // The loop itself
590 for (i = 0; i < LineCount; i++) {
592 // Prepare pointers for the loop
593 SourcePtr = (cmsUInt8Number*)in + SourceStartingOrder[0] + SourceStrideIncrement;
594 DestPtr = (cmsUInt8Number*)out + DestStartingOrder[0] + DestStrideIncrement;
596 for (j = 0; j < PixelsPerLine; j++) {
598 copyValueFn(DestPtr, SourcePtr);
600 SourcePtr += SourceIncrements[0];
601 DestPtr += DestIncrements[0];
604 SourceStrideIncrement += Stride->BytesPerLineIn;
605 DestStrideIncrement += Stride->BytesPerLineOut;
609 else { // General case with more than one extra channel
611 cmsUInt8Number* SourcePtr[cmsMAXCHANNELS];
612 cmsUInt8Number* DestPtr[cmsMAXCHANNELS];
614 cmsUInt32Number SourceStrideIncrements[cmsMAXCHANNELS];
615 cmsUInt32Number DestStrideIncrements[cmsMAXCHANNELS];
617 memset(SourceStrideIncrements, 0, sizeof(SourceStrideIncrements));
618 memset(DestStrideIncrements, 0, sizeof(DestStrideIncrements));
620 // The loop itself
621 for (i = 0; i < LineCount; i++) {
623 // Prepare pointers for the loop
624 for (j = 0; j < nExtra; j++) {
626 SourcePtr[j] = (cmsUInt8Number*)in + SourceStartingOrder[j] + SourceStrideIncrements[j];
627 DestPtr[j] = (cmsUInt8Number*)out + DestStartingOrder[j] + DestStrideIncrements[j];
630 for (j = 0; j < PixelsPerLine; j++) {
632 for (k = 0; k < nExtra; k++) {
634 copyValueFn(DestPtr[k], SourcePtr[k]);
636 SourcePtr[k] += SourceIncrements[k];
637 DestPtr[k] += DestIncrements[k];
641 for (j = 0; j < nExtra; j++) {
643 SourceStrideIncrements[j] += Stride->BytesPerLineIn;
644 DestStrideIncrements[j] += Stride->BytesPerLineOut;