// 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.
jpeg_comp_master* m = cinfo->master;
size_t restart_interval = sti->restart_interval; int restarts_to_go = restart_interval;
coeff_t last_dc_coeff[MAX_COMPS_IN_SCAN] = {0};
// "Non-interleaved" means color data comes in separate scans, in other words // each scan can contain only one color component. constbool is_interleaved = (scan_info->comps_in_scan > 1); constbool is_progressive = FROM_JXL_BOOL(cinfo->progressive_mode); constint Ah = scan_info->Ah; constint Al = scan_info->Al;
HWY_ALIGN constexpr coeff_t kSinkBlock[DCTSIZE2] = {0};
void AddHistograms(const Histogram& a, const Histogram& b, Histogram* c) { for (size_t i = 0; i < kJpegHuffmanAlphabetSize; ++i) {
c->count[i] = a.count[i] + b.count[i];
}
}
bool IsEmptyHistogram(const Histogram& histo) { for (int count : histo.count) { if (count) returnfalse;
} returntrue;
}
void ClusterJpegHistograms(j_compress_ptr cinfo, const Histogram* histograms,
size_t num, JpegClusteredHistograms* clusters) {
clusters->histogram_indexes.resize(num);
std::vector<uint32_t> slot_histograms;
std::vector<float> slot_costs; for (size_t i = 0; i < num; ++i) { const Histogram& cur = histograms[i]; if (IsEmptyHistogram(cur)) { continue;
} float best_cost = HistogramCost(cur);
size_t best_slot = slot_histograms.size(); for (size_t j = 0; j < slot_histograms.size(); ++j) {
size_t prev_idx = slot_histograms[j]; const Histogram& prev = clusters->histograms[prev_idx];
Histogram combined;
AddHistograms(prev, cur, &combined); float combined_cost = HistogramCost(combined); float cost = combined_cost - slot_costs[j]; if (cost < best_cost) {
best_cost = cost;
best_slot = j;
}
} if (best_slot == slot_histograms.size()) { // Create new histogram.
size_t histogram_index = clusters->histograms.size();
clusters->histograms.push_back(cur);
clusters->histogram_indexes[i] = histogram_index; if (best_slot < 4) { // We have a free slot, so we put the new histogram there.
slot_histograms.push_back(histogram_index);
slot_costs.push_back(best_cost);
} else { // TODO(szabadka) Find the best histogram to replce.
best_slot = (clusters->slot_ids.back() + 1) % 4;
}
slot_histograms[best_slot] = histogram_index;
slot_costs[best_slot] = best_cost;
clusters->slot_ids.push_back(best_slot);
} else { // Merge this histogram with a previous one.
size_t histogram_index = slot_histograms[best_slot]; const Histogram& prev = clusters->histograms[histogram_index];
AddHistograms(prev, cur, &clusters->histograms[histogram_index]);
clusters->histogram_indexes[i] = histogram_index;
JPEGLI_CHECK(clusters->slot_ids[histogram_index] == best_slot);
slot_costs[best_slot] += best_cost;
}
}
}
void CopyHuffmanTable(j_compress_ptr cinfo, int index, bool is_dc, int* inv_slot_map, uint8_t* slot_id_map,
JHUFF_TBL* huffman_tables, size_t* num_huffman_tables) { constchar* type = is_dc ? "DC" : "AC"; if (index < 0 || index >= NUM_HUFF_TBLS) {
JPEGLI_ERROR("Invalid %s Huffman table index %d", type, index);
} // Check if we have already copied this Huffman table. int slot_idx = index + (is_dc ? 0 : NUM_HUFF_TBLS); if (inv_slot_map[slot_idx] != -1) { return;
}
inv_slot_map[slot_idx] = *num_huffman_tables; // Look up and validate Huffman table.
JHUFF_TBL* table =
is_dc ? cinfo->dc_huff_tbl_ptrs[index] : cinfo->ac_huff_tbl_ptrs[index]; if (table == nullptr) {
JPEGLI_ERROR("Missing %s Huffman table %d", type, index);
}
ValidateHuffmanTable(reinterpret_cast<j_common_ptr>(cinfo), table, is_dc); // Copy Huffman table to the end of the list and save slot id.
slot_id_map[*num_huffman_tables] = index + (is_dc ? 0 : 0x10);
memcpy(&huffman_tables[*num_huffman_tables], table, sizeof(JHUFF_TBL));
++(*num_huffman_tables);
}
void BuildJpegHuffmanTable(const Histogram& histo, JHUFF_TBL* table) {
std::vector<uint32_t> counts(kJpegHuffmanAlphabetSize + 1);
std::vector<uint8_t> depths(kJpegHuffmanAlphabetSize + 1); for (size_t j = 0; j < kJpegHuffmanAlphabetSize; ++j) {
counts[j] = histo.count[j];
}
counts[kJpegHuffmanAlphabetSize] = 1;
CreateHuffmanTree(counts.data(), counts.size(), kJpegHuffmanMaxBitLength,
depths.data());
memset(table, 0, sizeof(JHUFF_TBL)); for (size_t i = 0; i < kJpegHuffmanAlphabetSize; ++i) { if (depths[i] > 0) {
++table->bits[depths[i]];
}
} int offset[kJpegHuffmanMaxBitLength + 1] = {0}; for (size_t i = 1; i <= kJpegHuffmanMaxBitLength; ++i) {
offset[i] = offset[i - 1] + table->bits[i - 1];
} for (size_t i = 0; i < kJpegHuffmanAlphabetSize; ++i) { if (depths[i] > 0) {
table->huffval[offset[depths[i]]++] = i;
}
}
}
} // namespace
void CopyHuffmanTables(j_compress_ptr cinfo) {
jpeg_comp_master* m = cinfo->master;
size_t max_huff_tables = 2 * cinfo->num_components; // Copy Huffman tables and save slot ids.
m->huffman_tables = Allocate<JHUFF_TBL>(cinfo, max_huff_tables, JPOOL_IMAGE);
m->slot_id_map = Allocate<uint8_t>(cinfo, max_huff_tables, JPOOL_IMAGE);
m->num_huffman_tables = 0; int inv_slot_map[8] = {-1, -1, -1, -1, -1, -1, -1, -1}; for (int c = 0; c < cinfo->num_components; ++c) {
jpeg_component_info* comp = &cinfo->comp_info[c];
CopyHuffmanTable(cinfo, comp->dc_tbl_no, /*is_dc=*/true, &inv_slot_map[0],
m->slot_id_map, m->huffman_tables, &m->num_huffman_tables);
CopyHuffmanTable(cinfo, comp->ac_tbl_no, /*is_dc=*/false, &inv_slot_map[0],
m->slot_id_map, m->huffman_tables, &m->num_huffman_tables);
} // Compute context map.
m->context_map = Allocate<uint8_t>(cinfo, 8, JPOOL_IMAGE);
memset(m->context_map, 0, 8); for (int c = 0; c < cinfo->num_components; ++c) {
m->context_map[c] = inv_slot_map[cinfo->comp_info[c].dc_tbl_no];
} int ac_ctx = 4; for (int i = 0; i < cinfo->num_scans; ++i) { const jpeg_scan_info* si = &cinfo->scan_info[i]; if (si->Se > 0) { for (int j = 0; j < si->comps_in_scan; ++j) { int c = si->component_index[j];
jpeg_component_info* comp = &cinfo->comp_info[c];
m->context_map[ac_ctx++] = inv_slot_map[comp->ac_tbl_no + 4];
}
}
}
}
void OptimizeHuffmanCodes(j_compress_ptr cinfo) {
jpeg_comp_master* m = cinfo->master; // Build DC and AC histograms.
std::vector<Histogram> histograms(m->num_contexts);
BuildHistograms(cinfo, histograms.data());
// Cluster DC histograms.
JpegClusteredHistograms dc_clusters;
ClusterJpegHistograms(cinfo, histograms.data(), cinfo->num_components,
&dc_clusters);
void BuildHuffmanCodeTable(const JHUFF_TBL& table, HuffmanCodeTable* code) { int huff_code[kJpegHuffmanAlphabetSize]; // +1 for a sentinel element.
uint32_t huff_size[kJpegHuffmanAlphabetSize + 1]; int p = 0; for (size_t l = 1; l <= kJpegHuffmanMaxBitLength; ++l) { int i = table.bits[l]; while (i--) huff_size[p++] = l;
}
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.