Coverage Report

Created: 2025-11-16 07:14

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libjxl/lib/jxl/alpha.cc
Line
Count
Source
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
62.4M
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
66.5k
                          bool alpha_is_premultiplied, bool clamp) {
22
66.5k
  if (alpha_is_premultiplied) {
23
2.71M
    for (size_t x = 0; x < num_pixels; ++x) {
24
2.69M
      float fga = clamp ? Clamp(fg.a[x]) : fg.a[x];
25
2.69M
      out.r[x] = (fg.r[x] + bg.r[x] * (1.f - fga));
26
2.69M
      out.g[x] = (fg.g[x] + bg.g[x] * (1.f - fga));
27
2.69M
      out.b[x] = (fg.b[x] + bg.b[x] * (1.f - fga));
28
2.69M
      out.a[x] = (1.f - (1.f - fga) * (1.f - bg.a[x]));
29
2.69M
    }
30
43.2k
  } else {
31
11.9M
    for (size_t x = 0; x < num_pixels; ++x) {
32
11.8M
      float fga = clamp ? Clamp(fg.a[x]) : fg.a[x];
33
11.8M
      const float new_a = 1.f - (1.f - fga) * (1.f - bg.a[x]);
34
11.8M
      const float rnew_a = (new_a > 0 ? 1.f / new_a : 0.f);
35
11.8M
      out.r[x] = (fg.r[x] * fga + bg.r[x] * bg.a[x] * (1.f - fga)) * rnew_a;
36
11.8M
      out.g[x] = (fg.g[x] * fga + bg.g[x] * bg.a[x] * (1.f - fga)) * rnew_a;
37
11.8M
      out.b[x] = (fg.b[x] * fga + bg.b[x] * bg.a[x] * (1.f - fga)) * rnew_a;
38
11.8M
      out.a[x] = new_a;
39
11.8M
    }
40
43.2k
  }
41
66.5k
}
42
void PerformAlphaBlending(const float* bg, const float* bga, const float* fg,
43
                          const float* fga, float* out, size_t num_pixels,
44
195k
                          bool alpha_is_premultiplied, bool clamp) {
45
195k
  if (bg == bga && fg == fga) {
46
6.22M
    for (size_t x = 0; x < num_pixels; ++x) {
47
6.18M
      float fa = clamp ? Clamp(fga[x]) : fga[x];
48
6.18M
      out[x] = (1.f - (1.f - fa) * (1.f - bga[x]));
49
6.18M
    }
50
156k
  } else {
51
156k
    if (alpha_is_premultiplied) {
52
629k
      for (size_t x = 0; x < num_pixels; ++x) {
53
578k
        float fa = clamp ? Clamp(fga[x]) : fga[x];
54
578k
        out[x] = (fg[x] + bg[x] * (1.f - fa));
55
578k
      }
56
105k
    } else {
57
18.6M
      for (size_t x = 0; x < num_pixels; ++x) {
58
18.5M
        float fa = clamp ? Clamp(fga[x]) : fga[x];
59
18.5M
        const float new_a = 1.f - (1.f - fa) * (1.f - bga[x]);
60
18.5M
        const float rnew_a = (new_a > 0 ? 1.f / new_a : 0.f);
61
18.5M
        out[x] = (fg[x] * fa + bg[x] * bga[x] * (1.f - fa)) * rnew_a;
62
18.5M
      }
63
105k
    }
64
156k
  }
65
195k
}
66
67
void PerformAlphaWeightedAdd(const float* bg, const float* fg, const float* fga,
68
90.2k
                             float* out, size_t num_pixels, bool clamp) {
69
90.2k
  if (fg == fga) {
70
1.95k
    memcpy(out, bg, num_pixels * sizeof(*out));
71
88.2k
  } else if (clamp) {
72
3.76M
    for (size_t x = 0; x < num_pixels; ++x) {
73
3.74M
      out[x] = bg[x] + fg[x] * Clamp(fga[x]);
74
3.74M
    }
75
66.8k
  } else {
76
23.1M
    for (size_t x = 0; x < num_pixels; ++x) {
77
23.1M
      out[x] = bg[x] + fg[x] * fga[x];
78
23.1M
    }
79
66.8k
  }
80
90.2k
}
81
82
void PerformMulBlending(const float* bg, const float* fg, float* out,
83
249k
                        size_t num_pixels, bool clamp) {
84
249k
  if (clamp) {
85
42.2M
    for (size_t x = 0; x < num_pixels; ++x) {
86
42.0M
      out[x] = bg[x] * Clamp(fg[x]);
87
42.0M
    }
88
205k
  } else {
89
4.72M
    for (size_t x = 0; x < num_pixels; ++x) {
90
4.68M
      out[x] = bg[x] * fg[x];
91
4.68M
    }
92
44.2k
  }
93
249k
}
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