Coverage Report

Created: 2025-12-03 07:54

next uncovered line (L), next uncovered region (R), next uncovered branch (B)
/src/libjxl/lib/jxl/jpeg/jpeg_data.cc
Line
Count
Source
1
// Copyright (c) the JPEG XL Project Authors. All rights reserved.
2
//
3
// Use of this source code is governed by a BSD-style
4
// license that can be found in the LICENSE file.
5
6
#include "lib/jxl/jpeg/jpeg_data.h"
7
8
#include <jxl/types.h>
9
10
#include <algorithm>
11
#include <cstddef>
12
#include <cstdint>
13
#include <cstring>
14
#include <hwy/base.h>
15
#include <vector>
16
17
#include "lib/jxl/base/common.h"
18
#include "lib/jxl/base/printf_macros.h"
19
#include "lib/jxl/base/status.h"
20
#include "lib/jxl/common.h"  // kMaxNumPasses, JPEGXL_ENABLE_TRANSCODE_JPEG
21
#include "lib/jxl/field_encodings.h"
22
#include "lib/jxl/fields.h"
23
24
namespace jxl {
25
namespace jpeg {
26
27
#if JPEGXL_ENABLE_TRANSCODE_JPEG
28
29
namespace {
30
enum JPEGComponentType : uint32_t {
31
  kGray = 0,
32
  kYCbCr = 1,
33
  kRGB = 2,
34
  kCustom = 3,
35
};
36
37
struct JPEGInfo {
38
  size_t num_app_markers = 0;
39
  size_t num_com_markers = 0;
40
  size_t num_scans = 0;
41
  size_t num_intermarker = 0;
42
  bool has_dri = false;
43
};
44
45
4.25M
Status VisitMarker(uint8_t* marker, Visitor* visitor, JPEGInfo* info) {
46
4.25M
  uint32_t marker32 = *marker - 0xc0;
47
4.25M
  JXL_RETURN_IF_ERROR(visitor->Bits(6, 0x00, &marker32));
48
4.24M
  *marker = marker32 + 0xc0;
49
4.24M
  if ((*marker & 0xf0) == 0xe0) {
50
1.73M
    info->num_app_markers++;
51
1.73M
  }
52
4.24M
  if (*marker == 0xfe) {
53
88.6k
    info->num_com_markers++;
54
88.6k
  }
55
4.24M
  if (*marker == 0xda) {
56
810k
    info->num_scans++;
57
810k
  }
58
  // We use a fake 0xff marker to signal intermarker data.
59
4.24M
  if (*marker == 0xff) {
60
289k
    info->num_intermarker++;
61
289k
  }
62
4.24M
  if (*marker == 0xdd) {
63
6.86k
    info->has_dri = true;
64
6.86k
  }
65
4.24M
  return true;
66
4.25M
}
67
68
}  // namespace
69
70
22.7k
Status JPEGData::VisitFields(Visitor* visitor) {
71
22.7k
  bool is_gray = components.size() == 1;
72
22.7k
  JXL_RETURN_IF_ERROR(visitor->Bool(false, &is_gray));
73
22.2k
  if (visitor->IsReading()) {
74
22.2k
    components.resize(is_gray ? 1 : 3);
75
22.2k
  }
76
22.2k
  JPEGInfo info;
77
22.2k
  if (visitor->IsReading()) {
78
22.2k
    uint8_t marker = 0xc0;
79
4.25M
    do {
80
4.25M
      JXL_RETURN_IF_ERROR(VisitMarker(&marker, visitor, &info));
81
4.24M
      marker_order.push_back(marker);
82
4.24M
      if (marker_order.size() > 16384) {
83
2
        return JXL_FAILURE("Too many markers: %" PRIuS "\n",
84
2
                           marker_order.size());
85
2
      }
86
4.24M
    } while (marker != 0xd9);
87
22.2k
  } else {
88
0
    if (marker_order.size() > 16384) {
89
0
      return JXL_FAILURE("Too many markers: %" PRIuS "\n", marker_order.size());
90
0
    }
91
0
    for (uint8_t& marker : marker_order) {
92
0
      JXL_RETURN_IF_ERROR(VisitMarker(&marker, visitor, &info));
93
0
    }
94
0
    if (!marker_order.empty()) {
95
      // Last marker should always be EOI marker.
96
0
      JXL_ENSURE(marker_order.back() == 0xd9);
97
0
    }
98
0
  }
99
100
  // Size of the APP and COM markers.
101
16.9k
  if (visitor->IsReading()) {
102
16.9k
    app_data.resize(info.num_app_markers);
103
16.9k
    app_marker_type.resize(info.num_app_markers);
104
16.9k
    com_data.resize(info.num_com_markers);
105
16.9k
    scan_info.resize(info.num_scans);
106
16.9k
  }
107
16.9k
  JXL_ENSURE(app_data.size() == info.num_app_markers);
108
16.9k
  JXL_ENSURE(app_marker_type.size() == info.num_app_markers);
109
16.9k
  JXL_ENSURE(com_data.size() == info.num_com_markers);
110
16.9k
  JXL_ENSURE(scan_info.size() == info.num_scans);
111
41.6k
  for (size_t i = 0; i < app_data.size(); i++) {
112
25.8k
    auto& app = app_data[i];
113
    // Encodes up to 8 different values.
114
25.8k
    JXL_RETURN_IF_ERROR(
115
25.8k
        visitor->U32(Val(0), Val(1), BitsOffset(1, 2), BitsOffset(2, 4), 0,
116
25.8k
                     reinterpret_cast<uint32_t*>(&app_marker_type[i])));
117
25.7k
    if (app_marker_type[i] != AppMarkerType::kUnknown &&
118
16.3k
        app_marker_type[i] != AppMarkerType::kICC &&
119
8.46k
        app_marker_type[i] != AppMarkerType::kExif &&
120
4.43k
        app_marker_type[i] != AppMarkerType::kXMP) {
121
22
      return JXL_FAILURE("Unknown app marker type %u",
122
22
                         static_cast<uint32_t>(app_marker_type[i]));
123
22
    }
124
25.6k
    uint32_t len = app.size() - 1;
125
25.6k
    JXL_RETURN_IF_ERROR(visitor->Bits(16, 0, &len));
126
24.6k
    if (visitor->IsReading()) app.resize(len + 1);
127
24.6k
    if (app.size() < 3) {
128
3
      return JXL_FAILURE("Invalid marker size: %" PRIuS "\n", app.size());
129
3
    }
130
24.6k
  }
131
15.7k
  for (auto& com : com_data) {
132
6.50k
    uint32_t len = com.size() - 1;
133
6.50k
    JXL_RETURN_IF_ERROR(visitor->Bits(16, 0, &len));
134
6.32k
    if (visitor->IsReading()) com.resize(len + 1);
135
6.32k
    if (com.size() < 3) {
136
2
      return JXL_FAILURE("Invalid marker size: %" PRIuS "\n", com.size());
137
2
    }
138
6.32k
  }
139
140
15.5k
  uint32_t num_quant_tables = quant.size();
141
15.5k
  JXL_RETURN_IF_ERROR(
142
15.5k
      visitor->U32(Val(1), Val(2), Val(3), Val(4), 2, &num_quant_tables));
143
15.3k
  if (num_quant_tables == 4) {
144
15
    return JXL_FAILURE("Invalid number of quant tables");
145
15
  }
146
15.3k
  if (visitor->IsReading()) {
147
15.3k
    quant.resize(num_quant_tables);
148
15.3k
  }
149
40.2k
  for (size_t i = 0; i < num_quant_tables; i++) {
150
25.2k
    if (quant[i].precision > 1) {
151
0
      return JXL_FAILURE(
152
0
          "Quant tables with more than 16 bits are not supported");
153
0
    }
154
25.2k
    JXL_RETURN_IF_ERROR(visitor->Bits(1, 0, &quant[i].precision));
155
25.2k
    JXL_RETURN_IF_ERROR(visitor->Bits(2, i, &quant[i].index));
156
24.9k
    JXL_RETURN_IF_ERROR(visitor->Bool(true, &quant[i].is_last));
157
24.9k
  }
158
159
15.0k
  JPEGComponentType component_type =
160
15.0k
      components.size() == 1 && components[0].id == 1 ? JPEGComponentType::kGray
161
15.0k
      : components.size() == 3 && components[0].id == 1 &&
162
0
              components[1].id == 2 && components[2].id == 3
163
15.0k
          ? JPEGComponentType::kYCbCr
164
15.0k
      : components.size() == 3 && components[0].id == 'R' &&
165
0
              components[1].id == 'G' && components[2].id == 'B'
166
15.0k
          ? JPEGComponentType::kRGB
167
15.0k
          : JPEGComponentType::kCustom;
168
15.0k
  JXL_RETURN_IF_ERROR(
169
15.0k
      visitor->Bits(2, JPEGComponentType::kYCbCr,
170
15.0k
                    reinterpret_cast<uint32_t*>(&component_type)));
171
14.9k
  uint32_t num_components;
172
14.9k
  if (component_type == JPEGComponentType::kGray) {
173
9.27k
    num_components = 1;
174
9.27k
  } else if (component_type != JPEGComponentType::kCustom) {
175
4.45k
    num_components = 3;
176
4.45k
  } else {
177
1.19k
    num_components = components.size();
178
1.19k
    JXL_RETURN_IF_ERROR(
179
1.19k
        visitor->U32(Val(1), Val(2), Val(3), Val(4), 3, &num_components));
180
1.17k
    if (num_components != 1 && num_components != 3) {
181
3
      return JXL_FAILURE("Invalid number of components: %u", num_components);
182
3
    }
183
1.17k
  }
184
14.9k
  if (visitor->IsReading()) {
185
14.9k
    components.resize(num_components);
186
14.9k
  }
187
14.9k
  if (component_type == JPEGComponentType::kCustom) {
188
2.65k
    for (auto& component : components) {
189
2.65k
      JXL_RETURN_IF_ERROR(visitor->Bits(8, 0, &component.id));
190
2.65k
    }
191
13.7k
  } else if (component_type == JPEGComponentType::kGray) {
192
9.27k
    components[0].id = 1;
193
9.27k
  } else if (component_type == JPEGComponentType::kRGB) {
194
2.71k
    components[0].id = 'R';
195
2.71k
    components[1].id = 'G';
196
2.71k
    components[2].id = 'B';
197
2.71k
  } else {
198
1.74k
    components[0].id = 1;
199
1.74k
    components[1].id = 2;
200
1.74k
    components[2].id = 3;
201
1.74k
  }
202
14.8k
  size_t used_tables = 0;
203
39.7k
  for (size_t i = 0; i < components.size(); i++) {
204
25.0k
    JXL_RETURN_IF_ERROR(visitor->Bits(2, 0, &components[i].quant_idx));
205
24.9k
    if (components[i].quant_idx >= quant.size()) {
206
18
      return JXL_FAILURE("Invalid quant table for component %" PRIuS ": %u\n",
207
18
                         i, components[i].quant_idx);
208
18
    }
209
24.9k
    used_tables |= 1U << components[i].quant_idx;
210
24.9k
  }
211
38.8k
  for (size_t i = 0; i < quant.size(); i++) {
212
24.1k
    if (used_tables & (1 << i)) continue;
213
3.48k
    if (i == 0) return JXL_FAILURE("First quant table unused.");
214
    // Unused quant table has to be set to copy of previous quant table
215
226k
    for (size_t j = 0; j < 64; j++) {
216
222k
      if (quant[i].values[j] != quant[i - 1].values[j]) {
217
0
        return JXL_FAILURE("Non-trivial unused quant table");
218
0
      }
219
222k
    }
220
3.48k
  }
221
222
14.6k
  uint32_t num_huff = huffman_code.size();
223
14.6k
  JXL_RETURN_IF_ERROR(visitor->U32(Val(4), BitsOffset(3, 2), BitsOffset(4, 10),
224
14.6k
                                   BitsOffset(6, 26), 4, &num_huff));
225
14.4k
  if (visitor->IsReading()) {
226
14.4k
    huffman_code.resize(num_huff);
227
14.4k
  }
228
58.8k
  for (JPEGHuffmanCode& hc : huffman_code) {
229
58.8k
    bool is_ac = ((hc.slot_id >> 4) != 0);
230
58.8k
    uint32_t id = hc.slot_id & 0xF;
231
58.8k
    JXL_RETURN_IF_ERROR(visitor->Bool(false, &is_ac));
232
58.8k
    JXL_RETURN_IF_ERROR(visitor->Bits(2, 0, &id));
233
58.6k
    hc.slot_id = (static_cast<uint32_t>(is_ac) << 4) | id;
234
58.6k
    JXL_RETURN_IF_ERROR(visitor->Bool(true, &hc.is_last));
235
58.3k
    size_t num_symbols = 0;
236
1.00M
    for (size_t i = 0; i <= 16; i++) {
237
951k
      JXL_RETURN_IF_ERROR(visitor->U32(Val(0), Val(1), BitsOffset(3, 2),
238
951k
                                       Bits(8), 0, &hc.counts[i]));
239
946k
      num_symbols += hc.counts[i];
240
946k
    }
241
53.4k
    if (num_symbols == 0) {
242
      // Actually, at least 2 symbols are required, since one of them is EOI.
243
      // This case is used to represent an empty DHT marker.
244
45.2k
      continue;
245
45.2k
    }
246
8.17k
    if (num_symbols > hc.values.size()) {
247
26
      return JXL_FAILURE("Huffman code too large (%" PRIuS ")", num_symbols);
248
26
    }
249
    // Presence flags for 4 * 64 + 1 values.
250
8.14k
    uint64_t value_slots[5] = {};
251
135k
    for (size_t i = 0; i < num_symbols; i++) {
252
      // Goes up to 256, included. Might have the same symbol appear twice...
253
129k
      JXL_RETURN_IF_ERROR(visitor->U32(Bits(2), BitsOffset(2, 4),
254
129k
                                       BitsOffset(4, 8), BitsOffset(8, 1), 0,
255
129k
                                       &hc.values[i]));
256
127k
      value_slots[hc.values[i] >> 6] |= static_cast<uint64_t>(1)
257
127k
                                        << (hc.values[i] & 0x3F);
258
127k
    }
259
6.31k
    if (hc.values[num_symbols - 1] != kJpegHuffmanAlphabetSize) {
260
19
      return JXL_FAILURE("Missing EOI symbol");
261
19
    }
262
    // Last element, denoting EOI, have to be 1 after the loop.
263
6.29k
    JXL_ENSURE(value_slots[4] == 1);
264
6.29k
    size_t num_values = 1;
265
31.4k
    for (size_t i = 0; i < 4; ++i) num_values += hwy::PopCount(value_slots[i]);
266
6.29k
    if (num_values != num_symbols) {
267
4
      return JXL_FAILURE("Duplicate Huffman symbols");
268
4
    }
269
6.29k
    if (!is_ac) {
270
3.37k
      bool only_dc = ((value_slots[0] >> kJpegDCAlphabetSize) | value_slots[1] |
271
3.37k
                      value_slots[2] | value_slots[3]) == 0;
272
3.37k
      if (!only_dc) return JXL_FAILURE("Huffman symbols out of DC range");
273
3.37k
    }
274
6.29k
  }
275
276
11.8k
  for (auto& scan : scan_info) {
277
11.8k
    JXL_RETURN_IF_ERROR(
278
11.8k
        visitor->U32(Val(1), Val(2), Val(3), Val(4), 1, &scan.num_components));
279
11.7k
    if (scan.num_components >= 4) {
280
3
      return JXL_FAILURE("Invalid number of components in SOS marker");
281
3
    }
282
11.7k
    JXL_RETURN_IF_ERROR(visitor->Bits(6, 0, &scan.Ss));
283
11.5k
    JXL_RETURN_IF_ERROR(visitor->Bits(6, 63, &scan.Se));
284
11.3k
    JXL_RETURN_IF_ERROR(visitor->Bits(4, 0, &scan.Al));
285
11.2k
    JXL_RETURN_IF_ERROR(visitor->Bits(4, 0, &scan.Ah));
286
26.6k
    for (size_t i = 0; i < scan.num_components; i++) {
287
15.7k
      JXL_RETURN_IF_ERROR(visitor->Bits(2, 0, &scan.components[i].comp_idx));
288
15.7k
      if (scan.components[i].comp_idx >= components.size()) {
289
17
        return JXL_FAILURE("Invalid component idx in SOS marker");
290
17
      }
291
15.7k
      JXL_RETURN_IF_ERROR(visitor->Bits(2, 0, &scan.components[i].ac_tbl_idx));
292
15.5k
      JXL_RETURN_IF_ERROR(visitor->Bits(2, 0, &scan.components[i].dc_tbl_idx));
293
15.5k
    }
294
    // TODO(veluca): actually set and use this value.
295
10.8k
    JXL_RETURN_IF_ERROR(visitor->U32(Val(0), Val(1), Val(2), BitsOffset(3, 3),
296
10.8k
                                     kMaxNumPasses - 1,
297
10.8k
                                     &scan.last_needed_pass));
298
10.8k
  }
299
300
  // From here on, this is data that is not strictly necessary to get a valid
301
  // JPEG, but necessary for bit-exact JPEG reconstruction.
302
5.95k
  if (info.has_dri) {
303
1.06k
    JXL_RETURN_IF_ERROR(visitor->Bits(16, 0, &restart_interval));
304
1.06k
  }
305
306
7.14k
  for (auto& scan : scan_info) {
307
7.14k
    uint32_t num_reset_points = scan.reset_points.size();
308
7.14k
    JXL_RETURN_IF_ERROR(visitor->U32(Val(0), BitsOffset(2, 1), BitsOffset(4, 4),
309
7.14k
                                     BitsOffset(16, 20), 0, &num_reset_points));
310
7.05k
    if (visitor->IsReading()) {
311
7.05k
      scan.reset_points.resize(num_reset_points);
312
7.05k
    }
313
7.05k
    int last_block_idx = -1;
314
85.9k
    for (auto& block_idx : scan.reset_points) {
315
85.9k
      block_idx -= last_block_idx + 1;
316
85.9k
      JXL_RETURN_IF_ERROR(visitor->U32(Val(0), BitsOffset(3, 1),
317
85.9k
                                       BitsOffset(5, 9), BitsOffset(28, 41), 0,
318
85.9k
                                       &block_idx));
319
85.2k
      block_idx += last_block_idx + 1;
320
85.2k
      if (block_idx >= (3u << 26)) {
321
        // At most 8K x 8K x num_channels blocks are possible in a JPEG.
322
        // So valid block indices are below 3 * 2^26.
323
9
        return JXL_FAILURE("Invalid block ID: %u", block_idx);
324
9
      }
325
85.2k
      last_block_idx = block_idx;
326
85.2k
    }
327
328
6.43k
    uint32_t num_extra_zero_runs = scan.extra_zero_runs.size();
329
6.43k
    JXL_RETURN_IF_ERROR(visitor->U32(Val(0), BitsOffset(2, 1), BitsOffset(4, 4),
330
6.43k
                                     BitsOffset(16, 20), 0,
331
6.43k
                                     &num_extra_zero_runs));
332
6.33k
    if (visitor->IsReading()) {
333
6.33k
      scan.extra_zero_runs.resize(num_extra_zero_runs);
334
6.33k
    }
335
6.33k
    last_block_idx = -1;
336
40.6k
    for (auto& extra_zero_run : scan.extra_zero_runs) {
337
40.6k
      uint32_t& block_idx = extra_zero_run.block_idx;
338
40.6k
      JXL_RETURN_IF_ERROR(visitor->U32(Val(1), BitsOffset(2, 2),
339
40.6k
                                       BitsOffset(4, 5), BitsOffset(8, 20), 1,
340
40.6k
                                       &extra_zero_run.num_extra_zero_runs));
341
40.3k
      block_idx -= last_block_idx + 1;
342
40.3k
      JXL_RETURN_IF_ERROR(visitor->U32(Val(0), BitsOffset(3, 1),
343
40.3k
                                       BitsOffset(5, 9), BitsOffset(28, 41), 0,
344
40.3k
                                       &block_idx));
345
40.0k
      block_idx += last_block_idx + 1;
346
40.0k
      if (block_idx > (3u << 26)) {
347
9
        return JXL_FAILURE("Invalid block ID: %u", block_idx);
348
9
      }
349
39.9k
      last_block_idx = block_idx;
350
39.9k
    }
351
6.33k
  }
352
4.45k
  std::vector<uint32_t> inter_marker_data_sizes;
353
4.45k
  inter_marker_data_sizes.reserve(info.num_intermarker);
354
160k
  for (size_t i = 0; i < info.num_intermarker; ++i) {
355
157k
    uint32_t len = visitor->IsReading() ? 0 : inter_marker_data[i].size();
356
157k
    JXL_RETURN_IF_ERROR(visitor->Bits(16, 0, &len));
357
156k
    if (visitor->IsReading()) inter_marker_data_sizes.emplace_back(len);
358
156k
  }
359
3.54k
  uint32_t tail_data_len = tail_data.size();
360
3.54k
  if (!visitor->IsReading() && tail_data_len > 4260096) {
361
0
    return JXL_FAILURE("Tail data too large (max size = 4260096, size = %u)",
362
0
                       tail_data_len);
363
0
  }
364
3.54k
  JXL_RETURN_IF_ERROR(visitor->U32(Val(0), BitsOffset(8, 1),
365
3.54k
                                   BitsOffset(16, 257), BitsOffset(22, 65793),
366
3.54k
                                   0, &tail_data_len));
367
368
3.43k
  JXL_RETURN_IF_ERROR(visitor->Bool(false, &has_zero_padding_bit));
369
3.41k
  if (has_zero_padding_bit) {
370
2.63k
    uint32_t nbit = padding_bits.size();
371
2.63k
    JXL_RETURN_IF_ERROR(visitor->Bits(24, 0, &nbit));
372
2.50k
    if (visitor->IsReading()) {
373
2.50k
      JXL_RETURN_IF_ERROR(CheckHasEnoughBits(visitor, nbit));
374
112
      padding_bits.reserve(std::min<uint32_t>(1024u, nbit));
375
21.0M
      for (uint32_t i = 0; i < nbit; i++) {
376
21.0M
        bool bbit = false;
377
21.0M
        JXL_RETURN_IF_ERROR(visitor->Bool(false, &bbit));
378
21.0M
        padding_bits.push_back(TO_JXL_BOOL(bbit));
379
21.0M
      }
380
112
    } else {
381
0
      for (uint8_t& bit : padding_bits) {
382
0
        bool bbit = FROM_JXL_BOOL(bit);
383
0
        JXL_RETURN_IF_ERROR(visitor->Bool(false, &bbit));
384
0
        bit = TO_JXL_BOOL(bbit);
385
0
      }
386
0
    }
387
2.50k
  }
388
389
896
  {
390
896
    size_t dht_index = 0;
391
896
    size_t scan_index = 0;
392
896
    bool is_progressive = false;
393
896
    bool ac_ok[kMaxHuffmanTables] = {false};
394
896
    bool dc_ok[kMaxHuffmanTables] = {false};
395
68.2k
    for (uint8_t marker : marker_order) {
396
68.2k
      if (marker == 0xC2) {
397
789
        is_progressive = true;
398
67.4k
      } else if (marker == 0xC4) {
399
2.40k
        for (; dht_index < huffman_code.size();) {
400
1.55k
          const JPEGHuffmanCode& huff = huffman_code[dht_index++];
401
1.55k
          size_t index = huff.slot_id;
402
1.55k
          if (index & 0x10) {
403
604
            index -= 0x10;
404
604
            ac_ok[index] = true;
405
952
          } else {
406
952
            dc_ok[index] = true;
407
952
          }
408
1.55k
          if (huff.is_last) break;
409
1.55k
        }
410
65.6k
      } else if (marker == 0xDA) {
411
1.33k
        const JPEGScanInfo& si = scan_info[scan_index++];
412
3.29k
        for (size_t i = 0; i < si.num_components; ++i) {
413
2.01k
          const JPEGComponentScanInfo& csi = si.components[i];
414
2.01k
          size_t dc_tbl_idx = csi.dc_tbl_idx;
415
2.01k
          size_t ac_tbl_idx = csi.ac_tbl_idx;
416
2.01k
          bool want_dc = !is_progressive || (si.Ss == 0);
417
2.01k
          if (want_dc && !dc_ok[dc_tbl_idx]) {
418
30
            return JXL_FAILURE("DC Huffman table used before defined");
419
30
          }
420
1.98k
          bool want_ac = !is_progressive || (si.Ss != 0) || (si.Se != 0);
421
1.98k
          if (want_ac && !ac_ok[ac_tbl_idx]) {
422
22
            return JXL_FAILURE("AC Huffman table used before defined");
423
22
          }
424
1.98k
        }
425
1.33k
      }
426
68.2k
    }
427
896
  }
428
429
  // Apply postponed actions.
430
844
  if (visitor->IsReading()) {
431
844
    tail_data.resize(tail_data_len);
432
844
    JXL_ENSURE(inter_marker_data_sizes.size() == info.num_intermarker);
433
844
    inter_marker_data.reserve(info.num_intermarker);
434
58.0k
    for (size_t i = 0; i < info.num_intermarker; ++i) {
435
57.2k
      inter_marker_data.emplace_back(inter_marker_data_sizes[i]);
436
57.2k
    }
437
844
  }
438
439
844
  return true;
440
844
}
441
442
#endif  // JPEGXL_ENABLE_TRANSCODE_JPEG
443
444
void JPEGData::CalculateMcuSize(const JPEGScanInfo& scan, int* MCUs_per_row,
445
337
                                int* MCU_rows) const {
446
337
  const bool is_interleaved = (scan.num_components > 1);
447
337
  const JPEGComponent& base_component = components[scan.components[0].comp_idx];
448
  // h_group / v_group act as numerators for converting number of blocks to
449
  // number of MCU. In interleaved mode it is 1, so MCU is represented with
450
  // max_*_samp_factor blocks. In non-interleaved mode we choose numerator to
451
  // be the sampling factor, consequently MCU is always represented with single
452
  // block.
453
337
  const int h_group = is_interleaved ? 1 : base_component.h_samp_factor;
454
337
  const int v_group = is_interleaved ? 1 : base_component.v_samp_factor;
455
337
  int max_h_samp_factor = 1;
456
337
  int max_v_samp_factor = 1;
457
337
  for (const auto& c : components) {
458
337
    max_h_samp_factor = std::max(c.h_samp_factor, max_h_samp_factor);
459
337
    max_v_samp_factor = std::max(c.v_samp_factor, max_v_samp_factor);
460
337
  }
461
337
  *MCUs_per_row = DivCeil(width * h_group, 8 * max_h_samp_factor);
462
337
  *MCU_rows = DivCeil(height * v_group, 8 * max_v_samp_factor);
463
337
}
464
465
#if JPEGXL_ENABLE_TRANSCODE_JPEG
466
467
Status SetJPEGDataFromICC(const std::vector<uint8_t>& icc,
468
455
                          jpeg::JPEGData* jpeg_data) {
469
455
  size_t icc_pos = 0;
470
909
  for (size_t i = 0; i < jpeg_data->app_data.size(); i++) {
471
454
    if (jpeg_data->app_marker_type[i] != jpeg::AppMarkerType::kICC) {
472
454
      continue;
473
454
    }
474
0
    size_t len = jpeg_data->app_data[i].size() - 17;
475
0
    if (icc_pos + len > icc.size()) {
476
0
      return JXL_FAILURE(
477
0
          "ICC length is less than APP markers: requested %" PRIuS
478
0
          " more bytes, "
479
0
          "%" PRIuS " available",
480
0
          len, icc.size() - icc_pos);
481
0
    }
482
0
    memcpy(&jpeg_data->app_data[i][17], icc.data() + icc_pos, len);
483
0
    icc_pos += len;
484
0
  }
485
455
  if (icc_pos != icc.size() && icc_pos != 0) {
486
0
    return JXL_FAILURE("ICC length is more than APP markers");
487
0
  }
488
455
  return true;
489
455
}
490
491
#endif  // JPEGXL_ENABLE_TRANSCODE_JPEG
492
493
}  // namespace jpeg
494
}  // namespace jxl