Coverage Report

Created: 2025-06-22 08:04

/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