Coverage Report

Created: 2025-11-11 06:36

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libheif/libheif/codecs/encoder.cc
Line
Count
Source
1
/*
2
 * HEIF codec.
3
 * Copyright (c) 2024 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 "codecs/encoder.h"
22
23
#include "error.h"
24
#include "context.h"
25
#include "plugin_registry.h"
26
#include "api_structs.h"
27
#include "color-conversion/colorconversion.h"
28
29
30
void Encoder::CodedImageData::append(const uint8_t* data, size_t size)
31
0
{
32
0
  bitstream.insert(bitstream.end(), data, data + size);
33
0
}
34
35
36
void Encoder::CodedImageData::append_with_4bytes_size(const uint8_t* data, size_t size)
37
0
{
38
0
  assert(size <= 0xFFFFFFFF);
39
40
0
  uint8_t size_field[4];
41
0
  size_field[0] = (uint8_t) ((size >> 24) & 0xFF);
42
0
  size_field[1] = (uint8_t) ((size >> 16) & 0xFF);
43
0
  size_field[2] = (uint8_t) ((size >> 8) & 0xFF);
44
0
  size_field[3] = (uint8_t) ((size >> 0) & 0xFF);
45
46
0
  bitstream.insert(bitstream.end(), size_field, size_field + 4);
47
0
  bitstream.insert(bitstream.end(), data, data + size);
48
0
}
49
50
51
52
static nclx_profile compute_target_nclx_profile(const std::shared_ptr<HeifPixelImage>& image, const heif_color_profile_nclx* output_nclx_profile)
53
0
{
54
0
  nclx_profile target_nclx_profile;
55
56
  // If there is an output NCLX specified, use that.
57
0
  if (output_nclx_profile) {
58
0
    target_nclx_profile.set_from_heif_color_profile_nclx(output_nclx_profile);
59
0
  }
60
    // Otherwise, if there is an input NCLX, keep that.
61
0
  else if (image->has_nclx_color_profile()) {
62
0
    target_nclx_profile = image->get_color_profile_nclx();
63
0
  }
64
    // Otherwise, just use the defaults (set below)
65
0
  else {
66
0
    target_nclx_profile.set_undefined();
67
0
  }
68
69
0
  target_nclx_profile.replace_undefined_values_with_sRGB_defaults();
70
71
0
  return target_nclx_profile;
72
0
}
73
74
75
static bool nclx_profile_matches_spec(heif_colorspace colorspace,
76
                                      std::optional<nclx_profile> image_nclx,
77
                                      const heif_color_profile_nclx* spec_nclx)
78
0
{
79
0
  if (colorspace != heif_colorspace_YCbCr) {
80
0
    return true;
81
0
  }
82
83
  // No target specification -> always matches
84
0
  if (!spec_nclx) {
85
0
    return true;
86
0
  }
87
88
0
  if (!image_nclx) {
89
0
    static nclx_profile default_nclx;
90
0
    default_nclx.set_sRGB_defaults();
91
92
    // if no input nclx is specified, compare against default one
93
0
    image_nclx = default_nclx;
94
0
  }
95
96
0
  if (image_nclx->get_full_range_flag() != (spec_nclx->full_range_flag == 0 ? false : true)) {
97
0
    return false;
98
0
  }
99
100
0
  if (image_nclx->get_matrix_coefficients() != spec_nclx->matrix_coefficients) {
101
0
    return false;
102
0
  }
103
104
  // TODO: are the colour primaries relevant for matrix-coefficients != 12,13 ?
105
  //       If not, we should skip this test for anything else than matrix-coefficients != 12,13.
106
0
  if (image_nclx->get_colour_primaries() != spec_nclx->color_primaries) {
107
0
    return false;
108
0
  }
109
110
0
  return true;
111
0
}
112
113
114
extern void fill_default_color_conversion_options_ext(heif_color_conversion_options_ext& options);
115
116
Result<std::shared_ptr<HeifPixelImage>> Encoder::convert_colorspace_for_encoding(const std::shared_ptr<HeifPixelImage>& image,
117
                                                                                 struct heif_encoder* encoder,
118
                                                                                 const struct heif_encoding_options& options,
119
                                                                                 const heif_security_limits* security_limits)
120
0
{
121
0
  const heif_color_profile_nclx* output_nclx_profile;
122
123
0
  if (const auto* nclx = get_forced_output_nclx()) {
124
0
    output_nclx_profile = nclx;
125
0
  } else {
126
0
    output_nclx_profile = options.output_nclx_profile;
127
0
  }
128
129
130
0
  heif_colorspace colorspace = image->get_colorspace();
131
0
  heif_chroma chroma = image->get_chroma_format();
132
133
0
  if (encoder->plugin->plugin_api_version >= 2) {
134
0
    encoder->plugin->query_input_colorspace2(encoder->encoder, &colorspace, &chroma);
135
0
  }
136
0
  else {
137
0
    encoder->plugin->query_input_colorspace(&colorspace, &chroma);
138
0
  }
139
140
141
  // If output format forces an NCLX, use that. Otherwise use user selected NCLX.
142
143
0
  nclx_profile target_nclx_profile = compute_target_nclx_profile(image, output_nclx_profile);
144
145
  // --- convert colorspace
146
147
0
  std::shared_ptr<HeifPixelImage> output_image;
148
149
0
  const std::optional<nclx_profile> image_nclx = image->get_color_profile_nclx();
150
151
0
  if (colorspace == image->get_colorspace() &&
152
0
      chroma == image->get_chroma_format() &&
153
0
      nclx_profile_matches_spec(colorspace, image_nclx, output_nclx_profile)) {
154
0
    return image;
155
0
  }
156
157
158
  // @TODO: use color profile when converting
159
0
  int output_bpp = 0; // same as input
160
161
  //auto target_nclx = std::make_shared<color_profile_nclx>();
162
  //target_nclx->set_from_heif_color_profile_nclx(target_heif_nclx);
163
164
0
  return convert_colorspace(image, colorspace, chroma, target_nclx_profile,
165
0
                            output_bpp, options.color_conversion_options, nullptr,
166
0
                            security_limits);
167
0
}