/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 <string.h> |
9 | | |
10 | | #include <algorithm> |
11 | | |
12 | | namespace jxl { |
13 | | |
14 | 39.2M | static float Clamp(float x) { return std::max(std::min(1.0f, x), 0.0f); } |
15 | | |
16 | | void PerformAlphaBlending(const AlphaBlendingInputLayer& bg, |
17 | | const AlphaBlendingInputLayer& fg, |
18 | | const AlphaBlendingOutput& out, size_t num_pixels, |
19 | 41.6k | bool alpha_is_premultiplied, bool clamp) { |
20 | 41.6k | if (alpha_is_premultiplied) { |
21 | 13.5M | for (size_t x = 0; x < num_pixels; ++x) { |
22 | 13.5M | float fga = clamp ? Clamp(fg.a[x]) : fg.a[x]; |
23 | 13.5M | out.r[x] = (fg.r[x] + bg.r[x] * (1.f - fga)); |
24 | 13.5M | out.g[x] = (fg.g[x] + bg.g[x] * (1.f - fga)); |
25 | 13.5M | out.b[x] = (fg.b[x] + bg.b[x] * (1.f - fga)); |
26 | 13.5M | out.a[x] = (1.f - (1.f - fga) * (1.f - bg.a[x])); |
27 | 13.5M | } |
28 | 23.7k | } else { |
29 | 17.9M | for (size_t x = 0; x < num_pixels; ++x) { |
30 | 17.9M | float fga = clamp ? Clamp(fg.a[x]) : fg.a[x]; |
31 | 17.9M | const float new_a = 1.f - (1.f - fga) * (1.f - bg.a[x]); |
32 | 17.9M | const float rnew_a = (new_a > 0 ? 1.f / new_a : 0.f); |
33 | 17.9M | out.r[x] = (fg.r[x] * fga + bg.r[x] * bg.a[x] * (1.f - fga)) * rnew_a; |
34 | 17.9M | out.g[x] = (fg.g[x] * fga + bg.g[x] * bg.a[x] * (1.f - fga)) * rnew_a; |
35 | 17.9M | out.b[x] = (fg.b[x] * fga + bg.b[x] * bg.a[x] * (1.f - fga)) * rnew_a; |
36 | 17.9M | out.a[x] = new_a; |
37 | 17.9M | } |
38 | 23.7k | } |
39 | 41.6k | } |
40 | | void PerformAlphaBlending(const float* bg, const float* bga, const float* fg, |
41 | | const float* fga, float* out, size_t num_pixels, |
42 | 43.5k | bool alpha_is_premultiplied, bool clamp) { |
43 | 43.5k | if (bg == bga && fg == fga) { |
44 | 3.81M | for (size_t x = 0; x < num_pixels; ++x) { |
45 | 3.80M | float fa = clamp ? fga[x] : Clamp(fga[x]); |
46 | 3.80M | out[x] = (1.f - (1.f - fa) * (1.f - bga[x])); |
47 | 3.80M | } |
48 | 29.8k | } else { |
49 | 29.8k | if (alpha_is_premultiplied) { |
50 | 188k | for (size_t x = 0; x < num_pixels; ++x) { |
51 | 181k | float fa = clamp ? fga[x] : Clamp(fga[x]); |
52 | 181k | out[x] = (fg[x] + bg[x] * (1.f - fa)); |
53 | 181k | } |
54 | 22.8k | } else { |
55 | 2.29M | for (size_t x = 0; x < num_pixels; ++x) { |
56 | 2.27M | float fa = clamp ? fga[x] : Clamp(fga[x]); |
57 | 2.27M | const float new_a = 1.f - (1.f - fa) * (1.f - bga[x]); |
58 | 2.27M | const float rnew_a = (new_a > 0 ? 1.f / new_a : 0.f); |
59 | 2.27M | out[x] = (fg[x] * fa + bg[x] * bga[x] * (1.f - fa)) * rnew_a; |
60 | 2.27M | } |
61 | 22.8k | } |
62 | 29.8k | } |
63 | 43.5k | } |
64 | | |
65 | | void PerformAlphaWeightedAdd(const float* bg, const float* fg, const float* fga, |
66 | 80.9k | float* out, size_t num_pixels, bool clamp) { |
67 | 80.9k | if (fg == fga) { |
68 | 6.56k | memcpy(out, bg, num_pixels * sizeof(*out)); |
69 | 74.3k | } else if (clamp) { |
70 | 10.0M | for (size_t x = 0; x < num_pixels; ++x) { |
71 | 9.99M | out[x] = bg[x] + fg[x] * Clamp(fga[x]); |
72 | 9.99M | } |
73 | 38.3k | } else { |
74 | 8.21M | for (size_t x = 0; x < num_pixels; ++x) { |
75 | 8.17M | out[x] = bg[x] + fg[x] * fga[x]; |
76 | 8.17M | } |
77 | 35.9k | } |
78 | 80.9k | } |
79 | | |
80 | | void PerformMulBlending(const float* bg, const float* fg, float* out, |
81 | 49.1k | size_t num_pixels, bool clamp) { |
82 | 49.1k | if (clamp) { |
83 | 8.98M | for (size_t x = 0; x < num_pixels; ++x) { |
84 | 8.95M | out[x] = bg[x] * Clamp(fg[x]); |
85 | 8.95M | } |
86 | 29.1k | } else { |
87 | 3.45M | for (size_t x = 0; x < num_pixels; ++x) { |
88 | 3.43M | out[x] = bg[x] * fg[x]; |
89 | 3.43M | } |
90 | 20.0k | } |
91 | 49.1k | } |
92 | | |
93 | | void PremultiplyAlpha(float* JXL_RESTRICT r, float* JXL_RESTRICT g, |
94 | | float* JXL_RESTRICT b, const float* JXL_RESTRICT a, |
95 | 0 | size_t num_pixels) { |
96 | 0 | for (size_t x = 0; x < num_pixels; ++x) { |
97 | 0 | const float multiplier = std::max(kSmallAlpha, a[x]); |
98 | 0 | r[x] *= multiplier; |
99 | 0 | g[x] *= multiplier; |
100 | 0 | b[x] *= multiplier; |
101 | 0 | } |
102 | 0 | } |
103 | | |
104 | | void UnpremultiplyAlpha(float* JXL_RESTRICT r, float* JXL_RESTRICT g, |
105 | | float* JXL_RESTRICT b, const float* JXL_RESTRICT a, |
106 | 0 | size_t num_pixels) { |
107 | 0 | for (size_t x = 0; x < num_pixels; ++x) { |
108 | 0 | const float multiplier = 1.f / std::max(kSmallAlpha, a[x]); |
109 | 0 | r[x] *= multiplier; |
110 | 0 | g[x] *= multiplier; |
111 | 0 | b[x] *= multiplier; |
112 | 0 | } |
113 | 0 | } |
114 | | |
115 | | } // namespace jxl |