// Copyright (c) the JPEG XL Project Authors. All rights reserved. // // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file.
int send_table[NUM_QUANT_TBLS] = {}; if (write_all_tables) { for (int i = 0; i < NUM_QUANT_TBLS; ++i) { if (cinfo->quant_tbl_ptrs[i]) send_table[i] = 1;
}
} else { for (int c = 0; c < cinfo->num_components; ++c) {
send_table[cinfo->comp_info[c].quant_tbl_no] = 1;
}
}
bool is_baseline = true; for (int i = 0; i < NUM_QUANT_TBLS; ++i) { if (!send_table[i]) continue;
JQUANT_TBL* quant_table = cinfo->quant_tbl_ptrs[i]; if (quant_table == nullptr) {
JPEGLI_ERROR("Missing quant table %d", i);
} int precision = 0; for (UINT16 q : quant_table->quantval) { if (q > 255) {
precision = 1;
is_baseline = false;
}
} if (quant_table->sent_table) { continue;
}
data[pos++] = (precision << 4) + i; for (size_t j = 0; j < DCTSIZE2; ++j) { int val_idx = kJPEGNaturalOrder[j]; int val = quant_table->quantval[val_idx]; if (val == 0) {
JPEGLI_ERROR("Invalid quantval 0.");
} if (precision) {
data[pos++] = val >> 8;
}
data[pos++] = val & 0xFFu;
}
quant_table->sent_table = TRUE;
} if (pos > 4) {
data[2] = (pos - 2) >> 8u;
data[3] = (pos - 2) & 0xFFu;
WriteOutput(cinfo, data, pos);
} return is_baseline;
}
void WriteScanHeader(j_compress_ptr cinfo, int scan_index) {
jpeg_comp_master* m = cinfo->master; const jpeg_scan_info* scan_info = &cinfo->scan_info[scan_index];
cinfo->restart_interval = m->scan_token_info[scan_index].restart_interval; if (cinfo->restart_interval != m->last_restart_interval) {
EncodeDRI(cinfo);
m->last_restart_interval = cinfo->restart_interval;
}
size_t num_dht = 0; if (scan_index == 0) { // For the first scan we emit all DC and at most 4 AC Huffman codes. for (size_t i = 0, num_ac = 0; i < m->num_huffman_tables; ++i) { if (m->slot_id_map[i] >= 16 && num_ac++ >= 4) break;
++num_dht;
}
} elseif (scan_info->Ss > 0) { // For multi-scan sequential and progressive DC scans we have already // emitted all Huffman codes that we need before the first scan. For // progressive AC scans we only need at most one new Huffman code. if (m->context_map[m->ac_ctx_offset[scan_index]] == m->next_dht_index) {
num_dht = 1;
}
} if (num_dht > 0) {
EncodeDHT(cinfo, m->next_dht_index, num_dht);
m->next_dht_index += num_dht;
}
EncodeSOS(cinfo, scan_index);
}
void WriteBlock(const int32_t* JXL_RESTRICT symbols, const int32_t* JXL_RESTRICT extra_bits, constint num_nonzeros, constbool emit_eob, const HuffmanCodeTable* JXL_RESTRICT dc_code, const HuffmanCodeTable* JXL_RESTRICT ac_code,
JpegBitWriter* JXL_RESTRICT bw) { int symbol = symbols[0];
WriteBits(bw, dc_code->depth[symbol], dc_code->code[symbol] | extra_bits[0]); for (int i = 1; i < num_nonzeros; ++i) {
symbol = symbols[i]; if (symbol > 255) {
WriteBits(bw, ac_code->depth[0xf0], ac_code->code[0xf0]);
symbol -= 256; if (symbol > 255) {
WriteBits(bw, ac_code->depth[0xf0], ac_code->code[0xf0]);
symbol -= 256; if (symbol > 255) {
WriteBits(bw, ac_code->depth[0xf0], ac_code->code[0xf0]);
symbol -= 256;
}
}
}
WriteBits(bw, ac_code->depth[symbol],
ac_code->code[symbol] | extra_bits[i]);
} if (emit_eob) {
WriteBits(bw, ac_code->depth[0], ac_code->code[0]);
}
}
void WriteTokens(j_compress_ptr cinfo, int scan_index, JpegBitWriter* bw) {
jpeg_comp_master* m = cinfo->master;
HuffmanCodeTable* coding_tables = &m->coding_tables[0]; int next_restart_marker = 0; const ScanTokenInfo& sti = m->scan_token_info[scan_index];
size_t num_token_arrays = m->cur_token_array + 1;
size_t total_tokens = 0;
size_t restart_idx = 0;
size_t next_restart = sti.restarts[restart_idx];
uint8_t* context_map = m->context_map; for (size_t i = 0; i < num_token_arrays; ++i) {
Token* tokens = m->token_arrays[i].tokens;
size_t num_tokens = m->token_arrays[i].num_tokens; if (sti.token_offset < total_tokens + num_tokens &&
total_tokens < sti.token_offset + sti.num_tokens) {
size_t start_ix =
total_tokens < sti.token_offset ? sti.token_offset - total_tokens : 0;
size_t end_ix = std::min(sti.token_offset + sti.num_tokens - total_tokens,
num_tokens);
size_t cycle_len = bw->len / 8;
size_t next_cycle = cycle_len; for (size_t i = start_ix; i < end_ix; ++i) { if (total_tokens + i == next_restart) {
JumpToByteBoundary(bw);
EmitMarker(bw, 0xD0 + next_restart_marker);
next_restart_marker += 1;
next_restart_marker &= 0x7;
next_restart = sti.restarts[++restart_idx];
}
Token t = tokens[i]; const HuffmanCodeTable* code = &coding_tables[context_map[t.context]];
WriteBits(bw, code->depth[t.symbol], code->code[t.symbol] | t.bits); if (--next_cycle == 0) { if (!EmptyBitWriterBuffer(bw)) {
JPEGLI_ERROR( "Output suspension is not supported in " "finish_compress");
}
next_cycle = cycle_len;
}
}
}
total_tokens += num_tokens;
}
}
void WriteACRefinementTokens(j_compress_ptr cinfo, int scan_index,
JpegBitWriter* bw) {
jpeg_comp_master* m = cinfo->master; const ScanTokenInfo& sti = m->scan_token_info[scan_index]; const uint8_t context = m->ac_ctx_offset[scan_index]; const HuffmanCodeTable* code = &m->coding_tables[m->context_map[context]];
size_t cycle_len = bw->len / 64;
size_t next_cycle = cycle_len;
size_t refbit_idx = 0;
size_t eobrun_idx = 0;
size_t restart_idx = 0;
size_t next_restart = sti.restarts[restart_idx]; int next_restart_marker = 0; for (size_t i = 0; i < sti.num_tokens; ++i) { if (i == next_restart) {
JumpToByteBoundary(bw);
EmitMarker(bw, 0xD0 + next_restart_marker);
next_restart_marker += 1;
next_restart_marker &= 0x7;
next_restart = sti.restarts[++restart_idx];
}
RefToken t = sti.tokens[i]; int symbol = t.symbol & 253;
uint16_t bits = 0; if ((symbol & 1) == 0) { int r = symbol >> 4; if (r > 0 && r < 15) {
bits = sti.eobruns[eobrun_idx++];
}
} else {
bits = (t.symbol >> 1) & 1;
}
WriteBits(bw, code->depth[symbol], code->code[symbol] | bits); for (int j = 0; j < t.refbits; ++j) {
WriteBits(bw, 1, sti.refbits[refbit_idx++]);
} if (--next_cycle == 0) { if (!EmptyBitWriterBuffer(bw)) {
JPEGLI_ERROR("Output suspension is not supported in finish_compress");
}
next_cycle = cycle_len;
}
}
}
void WriteDCRefinementBits(j_compress_ptr cinfo, int scan_index,
JpegBitWriter* bw) {
jpeg_comp_master* m = cinfo->master; const ScanTokenInfo& sti = m->scan_token_info[scan_index];
size_t restart_idx = 0;
size_t next_restart = sti.restarts[restart_idx]; int next_restart_marker = 0;
size_t cycle_len = bw->len * 4;
size_t next_cycle = cycle_len;
size_t refbit_idx = 0; for (size_t i = 0; i < sti.num_tokens; ++i) { if (i == next_restart) {
JumpToByteBoundary(bw);
EmitMarker(bw, 0xD0 + next_restart_marker);
next_restart_marker += 1;
next_restart_marker &= 0x7;
next_restart = sti.restarts[++restart_idx];
}
WriteBits(bw, 1, sti.refbits[refbit_idx++]); if (--next_cycle == 0) { if (!EmptyBitWriterBuffer(bw)) {
JPEGLI_ERROR( "Output suspension is not supported in " "finish_compress");
}
next_cycle = cycle_len;
}
}
}
} // namespace
void WriteScanData(j_compress_ptr cinfo, int scan_index) { const jpeg_scan_info* scan_info = &cinfo->scan_info[scan_index];
JpegBitWriter* bw = &cinfo->master->bw; if (scan_info->Ah == 0) {
WriteTokens(cinfo, scan_index, bw);
} elseif (scan_info->Ss > 0) {
WriteACRefinementTokens(cinfo, scan_index, bw);
} else {
WriteDCRefinementBits(cinfo, scan_index, bw);
} if (!bw->healthy) {
JPEGLI_ERROR("Unknown Huffman coded symbol found in scan %d", scan_index);
}
JumpToByteBoundary(bw); if (!EmptyBitWriterBuffer(bw)) {
JPEGLI_ERROR("Output suspension is not supported in finish_compress");
}
}
} // namespace jpegli
Messung V0.5 in Prozent
¤ Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.0.13Bemerkung:
(vorverarbeitet am 2026-06-05)
¤
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.