Coverage Report

Created: 2025-08-12 07:37

/src/libheif/libheif/common_utils.cc
Line
Count
Source (jump to first uncovered line)
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
700
{
27
700
  switch (c) {
28
0
    case heif_chroma_monochrome:
29
0
    case heif_chroma_444:
30
0
      return 1;
31
32
113
    case heif_chroma_420:
33
700
    case heif_chroma_422:
34
700
      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
700
  }
42
700
}
43
44
45
uint8_t chroma_v_subsampling(heif_chroma c)
46
700
{
47
700
  switch (c) {
48
0
    case heif_chroma_monochrome:
49
0
    case heif_chroma_444:
50
587
    case heif_chroma_422:
51
587
      return 1;
52
53
113
    case heif_chroma_420:
54
113
      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
700
  }
62
700
}
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.00k
{
70
2.00k
  if (channel == heif_channel_Cb ||
71
2.00k
      channel == heif_channel_Cr) {
72
0
    uint8_t chromaSubH = chroma_h_subsampling(chroma);
73
74
0
    switch (mode) {
75
0
      case scaling_mode::round_up:
76
        // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
77
0
        return (width + chromaSubH - 1) / chromaSubH;
78
0
      case scaling_mode::round_down:
79
        // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
80
0
        return width / chromaSubH;
81
0
      case scaling_mode::is_divisible:
82
0
        assert(width % chromaSubH == 0);
83
0
        return width / chromaSubH;
84
0
      default:
85
0
        assert(false);
86
0
        return 0;
87
0
    }
88
2.00k
  } else {
89
2.00k
    return width;
90
2.00k
  }
91
2.00k
}
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.00k
{
99
2.00k
  if (channel == heif_channel_Cb ||
100
2.00k
      channel == heif_channel_Cr) {
101
0
    uint8_t chromaSubV = chroma_v_subsampling(chroma);
102
103
0
    switch (mode) {
104
0
      case scaling_mode::round_up:
105
        // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
106
0
        return (height + chromaSubV - 1) / chromaSubV;
107
0
      case scaling_mode::round_down:
108
        // NOLINTNEXTLINE(clang-analyzer-core.DivideZero)
109
0
        return height / chromaSubV;
110
0
      case scaling_mode::is_divisible:
111
0
        assert(height % chromaSubV == 0);
112
0
        return height / chromaSubV;
113
0
      default:
114
0
        assert(false);
115
0
        return 0;
116
0
    }
117
2.00k
  } else {
118
2.00k
    return height;
119
2.00k
  }
120
2.00k
}
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
0
{
128
0
  *subsampled_width = get_subsampled_size_h(width, channel, chroma, scaling_mode::round_up);
129
0
  *subsampled_height = get_subsampled_size_v(height, channel, chroma, scaling_mode::round_up);
130
0
}
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
105k
{
153
105k
  std::string str("    ");
154
105k
  str[0] = static_cast<char>((code >> 24) & 0xFF);
155
105k
  str[1] = static_cast<char>((code >> 16) & 0xFF);
156
105k
  str[2] = static_cast<char>((code >> 8) & 0xFF);
157
105k
  str[3] = static_cast<char>((code >> 0) & 0xFF);
158
159
105k
  return str;
160
105k
}
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 Error{heif_error_Invalid_input,
167
0
                 heif_suberror_Unspecified,
168
0
                 "Null length string"};
169
0
  }
170
171
0
  if (vec.back() != 0) {
172
0
    return Error{heif_error_Invalid_input,
173
0
                 heif_suberror_Unspecified,
174
0
                 "utf8string not null-terminated"};
175
0
  }
176
177
0
  for (size_t i=0;i<vec.size()-1;i++) {
178
0
    if (vec[i] == 0) {
179
0
      return Error{heif_error_Invalid_input,
180
0
                   heif_suberror_Unspecified,
181
0
                   "utf8string with null character"};
182
0
    }
183
0
  }
184
185
0
  return std::string(vec.begin(), vec.end()-1);
186
0
}