Coverage Report

Created: 2025-12-31 07:53

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/common_utils.cc
Line
Count
Source
1
/*
2
 * HEIF codec.
3
 * Copyright (c) 2023 Dirk Farin <dirk.farin@gmail.com>
4
 *
5
 * This file is part of libheif.
6
 *
7
 * libheif is free software: you can redistribute it and/or modify
8
 * it under the terms of the GNU Lesser General Public License as
9
 * published by the Free Software Foundation, either version 3 of
10
 * the License, or (at your option) any later version.
11
 *
12
 * libheif is distributed in the hope that it will be useful,
13
 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14
 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
 * GNU Lesser General Public License for more details.
16
 *
17
 * You should have received a copy of the GNU Lesser General Public License
18
 * along with libheif.  If not, see <http://www.gnu.org/licenses/>.
19
 */
20
21
#include "common_utils.h"
22
#include <cassert>
23
24
25
uint8_t chroma_h_subsampling(heif_chroma c)
26
2.96k
{
27
2.96k
  switch (c) {
28
0
    case heif_chroma_monochrome:
29
2.24k
    case heif_chroma_444:
30
2.24k
      return 1;
31
32
662
    case heif_chroma_420:
33
712
    case heif_chroma_422:
34
712
      return 2;
35
36
0
    case heif_chroma_interleaved_RGB:
37
0
    case heif_chroma_interleaved_RGBA:
38
0
    default:
39
0
      assert(false);
40
0
      return 0;
41
2.96k
  }
42
2.96k
}
43
44
45
uint8_t chroma_v_subsampling(heif_chroma c)
46
2.96k
{
47
2.96k
  switch (c) {
48
0
    case heif_chroma_monochrome:
49
2.24k
    case heif_chroma_444:
50
2.29k
    case heif_chroma_422:
51
2.29k
      return 1;
52
53
662
    case heif_chroma_420:
54
662
      return 2;
55
56
0
    case heif_chroma_interleaved_RGB:
57
0
    case heif_chroma_interleaved_RGBA:
58
0
    default:
59
0
      assert(false);
60
0
      return 0;
61
2.96k
  }
62
2.96k
}
63
64
65
uint32_t get_subsampled_size_h(uint32_t width,
66
                               heif_channel channel,
67
                               heif_chroma chroma,
68
                               scaling_mode mode)
69
2.11k
{
70
2.11k
  if (channel == heif_channel_Cb ||
71
1.92k
      channel == heif_channel_Cr) {
72
368
    uint8_t chromaSubH = chroma_h_subsampling(chroma);
73
74
368
    switch (mode) {
75
16
      case scaling_mode::round_up:
76
        // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
77
16
        return (width + chromaSubH - 1) / chromaSubH;
78
176
      case scaling_mode::round_down:
79
        // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
80
176
        return width / chromaSubH;
81
176
      case scaling_mode::is_divisible:
82
176
        assert(width % chromaSubH == 0);
83
176
        return width / chromaSubH;
84
0
      default:
85
0
        assert(false);
86
0
        return 0;
87
368
    }
88
1.75k
  } else {
89
1.75k
    return width;
90
1.75k
  }
91
2.11k
}
92
93
94
uint32_t get_subsampled_size_v(uint32_t height,
95
                               heif_channel channel,
96
                               heif_chroma chroma,
97
                               scaling_mode mode)
98
2.11k
{
99
2.11k
  if (channel == heif_channel_Cb ||
100
1.92k
      channel == heif_channel_Cr) {
101
368
    uint8_t chromaSubV = chroma_v_subsampling(chroma);
102
103
368
    switch (mode) {
104
16
      case scaling_mode::round_up:
105
        // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
106
16
        return (height + chromaSubV - 1) / chromaSubV;
107
176
      case scaling_mode::round_down:
108
        // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
109
176
        return height / chromaSubV;
110
176
      case scaling_mode::is_divisible:
111
176
        assert(height % chromaSubV == 0);
112
176
        return height / chromaSubV;
113
0
      default:
114
0
        assert(false);
115
0
        return 0;
116
368
    }
117
1.75k
  } else {
118
1.75k
    return height;
119
1.75k
  }
120
2.11k
}
121
122
123
void get_subsampled_size(uint32_t width, uint32_t height,
124
                         heif_channel channel,
125
                         heif_chroma chroma,
126
                         uint32_t* subsampled_width, uint32_t* subsampled_height)
127
16
{
128
16
  *subsampled_width = get_subsampled_size_h(width, channel, chroma, scaling_mode::round_up);
129
16
  *subsampled_height = get_subsampled_size_v(height, channel, chroma, scaling_mode::round_up);
130
16
}
131
132
133
134
uint8_t compute_avif_profile(int bits_per_pixel, heif_chroma chroma)
135
0
{
136
0
  if (bits_per_pixel <= 10 &&
137
0
      (chroma == heif_chroma_420 ||
138
0
       chroma == heif_chroma_monochrome)) {
139
0
    return 0;
140
0
  }
141
0
  else if (bits_per_pixel <= 10 &&
142
0
           chroma == heif_chroma_444) {
143
0
    return 1;
144
0
  }
145
0
  else {
146
0
    return 2;
147
0
  }
148
0
}
149
150
151
std::string fourcc_to_string(uint32_t code)
152
903k
{
153
903k
  std::string str("    ");
154
903k
  str[0] = static_cast<char>((code >> 24) & 0xFF);
155
903k
  str[1] = static_cast<char>((code >> 16) & 0xFF);
156
903k
  str[2] = static_cast<char>((code >> 8) & 0xFF);
157
903k
  str[3] = static_cast<char>((code >> 0) & 0xFF);
158
159
903k
  return str;
160
903k
}
161
162
163
Result<std::string> vector_to_string(const std::vector<uint8_t>& vec)
164
0
{
165
0
  if (vec.empty()) {
166
0
    return std::string{}; // return empty string
167
0
  }
168
169
0
  if (vec.back() != 0) {
170
0
    return Error{heif_error_Invalid_input,
171
0
                 heif_suberror_Unspecified,
172
0
                 "utf8string not null-terminated"};
173
0
  }
174
175
0
  for (size_t i=0;i<vec.size()-1;i++) {
176
0
    if (vec[i] == 0) {
177
0
      return Error{heif_error_Invalid_input,
178
0
                   heif_suberror_Unspecified,
179
0
                   "utf8string with null character"};
180
0
    }
181
0
  }
182
183
0
  return std::string(vec.begin(), vec.end()-1);
184
0
}