/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 | } |