/src/libjxl/lib/jxl/alpha.cc
Line | Count | Source (jump to first uncovered line) |
1 | | // Copyright (c) the JPEG XL Project Authors. All rights reserved. |
2 | | // |
3 | | // Use of this source code is governed by a BSD-style |
4 | | // license that can be found in the LICENSE file. |
5 | | |
6 | | #include "lib/jxl/alpha.h" |
7 | | |
8 | | #include <algorithm> |
9 | | #include <cstring> |
10 | | |
11 | | #include "lib/jxl/base/common.h" |
12 | | #include "lib/jxl/base/compiler_specific.h" |
13 | | |
14 | | namespace jxl { |
15 | | |
16 | 22.2M | static float Clamp(float x) { return jxl::Clamp1(x, 0.0f, 1.0f); } |
17 | | |
18 | | void PerformAlphaBlending(const AlphaBlendingInputLayer& bg, |
19 | | const AlphaBlendingInputLayer& fg, |
20 | | const AlphaBlendingOutput& out, size_t num_pixels, |
21 | 6.61k | bool alpha_is_premultiplied, bool clamp) { |
22 | 6.61k | if (alpha_is_premultiplied) { |
23 | 130 | for (size_t x = 0; x < num_pixels; ++x) { |
24 | 117 | float fga = clamp ? Clamp(fg.a[x]) : fg.a[x]; |
25 | 117 | out.r[x] = (fg.r[x] + bg.r[x] * (1.f - fga)); |
26 | 117 | out.g[x] = (fg.g[x] + bg.g[x] * (1.f - fga)); |
27 | 117 | out.b[x] = (fg.b[x] + bg.b[x] * (1.f - fga)); |
28 | 117 | out.a[x] = (1.f - (1.f - fga) * (1.f - bg.a[x])); |
29 | 117 | } |
30 | 6.60k | } else { |
31 | 1.08M | for (size_t x = 0; x < num_pixels; ++x) { |
32 | 1.07M | float fga = clamp ? Clamp(fg.a[x]) : fg.a[x]; |
33 | 1.07M | const float new_a = 1.f - (1.f - fga) * (1.f - bg.a[x]); |
34 | 1.07M | const float rnew_a = (new_a > 0 ? 1.f / new_a : 0.f); |
35 | 1.07M | out.r[x] = (fg.r[x] * fga + bg.r[x] * bg.a[x] * (1.f - fga)) * rnew_a; |
36 | 1.07M | out.g[x] = (fg.g[x] * fga + bg.g[x] * bg.a[x] * (1.f - fga)) * rnew_a; |
37 | 1.07M | out.b[x] = (fg.b[x] * fga + bg.b[x] * bg.a[x] * (1.f - fga)) * rnew_a; |
38 | 1.07M | out.a[x] = new_a; |
39 | 1.07M | } |
40 | 6.60k | } |
41 | 6.61k | } |
42 | | void PerformAlphaBlending(const float* bg, const float* bga, const float* fg, |
43 | | const float* fga, float* out, size_t num_pixels, |
44 | 17.9k | bool alpha_is_premultiplied, bool clamp) { |
45 | 17.9k | if (bg == bga && fg == fga) { |
46 | 6.57M | for (size_t x = 0; x < num_pixels; ++x) { |
47 | 6.56M | float fa = clamp ? Clamp(fga[x]) : fga[x]; |
48 | 6.56M | out[x] = (1.f - (1.f - fa) * (1.f - bga[x])); |
49 | 6.56M | } |
50 | 9.71k | } else { |
51 | 8.24k | if (alpha_is_premultiplied) { |
52 | 14.6k | for (size_t x = 0; x < num_pixels; ++x) { |
53 | 14.5k | float fa = clamp ? Clamp(fga[x]) : fga[x]; |
54 | 14.5k | out[x] = (fg[x] + bg[x] * (1.f - fa)); |
55 | 14.5k | } |
56 | 8.14k | } else { |
57 | 261k | for (size_t x = 0; x < num_pixels; ++x) { |
58 | 253k | float fa = clamp ? Clamp(fga[x]) : fga[x]; |
59 | 253k | const float new_a = 1.f - (1.f - fa) * (1.f - bga[x]); |
60 | 253k | const float rnew_a = (new_a > 0 ? 1.f / new_a : 0.f); |
61 | 253k | out[x] = (fg[x] * fa + bg[x] * bga[x] * (1.f - fa)) * rnew_a; |
62 | 253k | } |
63 | 8.14k | } |
64 | 8.24k | } |
65 | 17.9k | } |
66 | | |
67 | | void PerformAlphaWeightedAdd(const float* bg, const float* fg, const float* fga, |
68 | 55.3k | float* out, size_t num_pixels, bool clamp) { |
69 | 55.3k | if (fg == fga) { |
70 | 10.9k | memcpy(out, bg, num_pixels * sizeof(*out)); |
71 | 44.4k | } else if (clamp) { |
72 | 11.7M | for (size_t x = 0; x < num_pixels; ++x) { |
73 | 11.7M | out[x] = bg[x] + fg[x] * Clamp(fga[x]); |
74 | 11.7M | } |
75 | 30.1k | } else { |
76 | 3.72M | for (size_t x = 0; x < num_pixels; ++x) { |
77 | 3.71M | out[x] = bg[x] + fg[x] * fga[x]; |
78 | 3.71M | } |
79 | 14.2k | } |
80 | 55.3k | } |
81 | | |
82 | | void PerformMulBlending(const float* bg, const float* fg, float* out, |
83 | 217k | size_t num_pixels, bool clamp) { |
84 | 217k | if (clamp) { |
85 | 7.73M | for (size_t x = 0; x < num_pixels; ++x) { |
86 | 7.70M | out[x] = bg[x] * Clamp(fg[x]); |
87 | 7.70M | } |
88 | 184k | } else { |
89 | 37.8M | for (size_t x = 0; x < num_pixels; ++x) { |
90 | 37.6M | out[x] = bg[x] * fg[x]; |
91 | 37.6M | } |
92 | 184k | } |
93 | 217k | } |
94 | | |
95 | | void PremultiplyAlpha(float* JXL_RESTRICT r, float* JXL_RESTRICT g, |
96 | | float* JXL_RESTRICT b, const float* JXL_RESTRICT a, |
97 | 0 | size_t num_pixels) { |
98 | 0 | for (size_t x = 0; x < num_pixels; ++x) { |
99 | 0 | const float multiplier = std::max(kSmallAlpha, a[x]); |
100 | 0 | r[x] *= multiplier; |
101 | 0 | g[x] *= multiplier; |
102 | 0 | b[x] *= multiplier; |
103 | 0 | } |
104 | 0 | } |
105 | | |
106 | | void UnpremultiplyAlpha(float* JXL_RESTRICT r, float* JXL_RESTRICT g, |
107 | | float* JXL_RESTRICT b, const float* JXL_RESTRICT a, |
108 | 0 | size_t num_pixels) { |
109 | 0 | for (size_t x = 0; x < num_pixels; ++x) { |
110 | 0 | const float multiplier = 1.f / std::max(kSmallAlpha, a[x]); |
111 | 0 | r[x] *= multiplier; |
112 | 0 | g[x] *= multiplier; |
113 | 0 | b[x] *= multiplier; |
114 | 0 | } |
115 | 0 | } |
116 | | |
117 | | } // namespace jxl |