Coverage Report

Created: 2025-07-18 06:37

/src/libheif/libheif/codecs/jpeg_dec.cc
Line
Count
Source (jump to first uncovered line)
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 "jpeg_dec.h"
22
#include "jpeg_boxes.h"
23
#include "error.h"
24
#include "context.h"
25
26
#include <string>
27
#include <algorithm>
28
29
30
Result<std::vector<uint8_t>> Decoder_JPEG::read_bitstream_configuration_data() const
31
0
{
32
0
  if (m_jpgC) {
33
0
    return m_jpgC->get_data();
34
0
  }
35
0
  else {
36
0
    return std::vector<uint8_t>{};
37
0
  }
38
0
}
39
40
41
// This checks whether a start code FFCx with nibble 'x' is a SOF marker.
42
// E.g. FFC0-FFC3 are, while FFC4 is not.
43
static bool isSOF[16] = {true, true, true, true, false, true, true, true,
44
                         false, true, true, true, false, true, true, true};
45
46
Error Decoder_JPEG::parse_SOF()
47
0
{
48
0
  if (m_config) {
49
0
    return Error::Ok;
50
0
  }
51
52
  // image data, usually from 'mdat'
53
54
0
  auto dataResult = get_compressed_data();
55
0
  if (dataResult.error) {
56
0
    return dataResult.error;
57
0
  }
58
59
0
  const std::vector<uint8_t>& data = dataResult.value;
60
61
0
  const Error error_invalidSOF{heif_error_Invalid_input,
62
0
                               heif_suberror_Unspecified,
63
0
                               "Invalid JPEG SOF header"};
64
65
0
  for (size_t i = 0; i + 1 < data.size(); i++) {
66
0
    if (data[i] == 0xFF && (data[i + 1] & 0xF0) == 0xC0 && isSOF[data[i + 1] & 0x0F]) {
67
68
0
      if (i + 9 >= data.size()) {
69
0
        return error_invalidSOF;
70
0
      }
71
72
0
      ConfigInfo info;
73
0
      info.sample_precision = data[i + 4];
74
0
      info.nComponents = data[i + 9];
75
76
0
      if (i + 11 + 3 * info.nComponents >= data.size()) {
77
0
        return error_invalidSOF;
78
0
      }
79
80
0
      for (int c = 0; c < std::min(info.nComponents, uint8_t(3)); c++) {
81
0
        int ss = data[i + 11 + 3 * c];
82
0
        info.h_sampling[c] = (ss >> 4) & 0xF;
83
0
        info.v_sampling[c] = ss & 0xF;
84
0
      }
85
86
0
      if (info.nComponents == 1) {
87
0
        info.chroma = heif_chroma_monochrome;
88
0
      }
89
0
      else if (info.nComponents != 3) {
90
0
        return error_invalidSOF;
91
0
      }
92
0
      else {
93
0
        if (info.h_sampling[1] != info.h_sampling[2] ||
94
0
            info.v_sampling[1] != info.v_sampling[2]) {
95
0
          return error_invalidSOF;
96
0
        }
97
98
0
        if (info.h_sampling[0] == 2 && info.v_sampling[0] == 2 &&
99
0
            info.h_sampling[1] == 1 && info.v_sampling[1] == 1) {
100
0
          info.chroma = heif_chroma_420;
101
0
        }
102
0
        else if (info.h_sampling[0] == 2 && info.v_sampling[0] == 1 &&
103
0
                 info.h_sampling[1] == 1 && info.v_sampling[1] == 1) {
104
0
          info.chroma = heif_chroma_422;
105
0
        }
106
0
        else if (info.h_sampling[0] == 1 && info.v_sampling[0] == 1 &&
107
0
                 info.h_sampling[1] == 1 && info.v_sampling[1] == 1) {
108
0
          info.chroma = heif_chroma_444;
109
0
        }
110
0
        else {
111
0
          return error_invalidSOF;
112
0
        }
113
0
      }
114
115
0
      m_config = info;
116
117
0
      return Error::Ok;
118
0
    }
119
0
  }
120
121
0
  return error_invalidSOF;
122
0
}
123
124
125
int Decoder_JPEG::get_luma_bits_per_pixel() const
126
0
{
127
0
  Error err = const_cast<Decoder_JPEG*>(this)->parse_SOF();
128
0
  if (err) {
129
0
    return -1;
130
0
  }
131
0
  else {
132
0
    return m_config->sample_precision;
133
0
  }
134
0
}
135
136
137
int Decoder_JPEG::get_chroma_bits_per_pixel() const
138
0
{
139
0
  return get_luma_bits_per_pixel();
140
0
}
141
142
143
Error Decoder_JPEG::get_coded_image_colorspace(heif_colorspace* out_colorspace, heif_chroma* out_chroma) const
144
0
{
145
0
  Error err = const_cast<Decoder_JPEG*>(this)->parse_SOF();
146
0
  if (err) {
147
0
    return err;
148
0
  }
149
150
0
  *out_chroma = m_config->chroma;
151
152
0
  if (*out_chroma == heif_chroma_monochrome) {
153
0
    *out_colorspace = heif_colorspace_monochrome;
154
0
  }
155
0
  else {
156
0
    *out_colorspace = heif_colorspace_YCbCr;
157
0
  }
158
159
0
  return Error::Ok;
160
0
}