Skip to content

Commit

Permalink
fix: handle empty dht in jpegli (#128)
Browse files Browse the repository at this point in the history
handle empty dht in jpegli
  • Loading branch information
mertalev authored Oct 15, 2024
1 parent e2f13f5 commit 7fa0413
Show file tree
Hide file tree
Showing 2 changed files with 100 additions and 0 deletions.
1 change: 1 addition & 0 deletions server/bin/build-libjxl.sh
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ git clone https://github.com/libjxl/libjxl.git
cd libjxl
git reset --hard "$LIBJXL_REVISION"
git submodule update --init --recursive --depth 1 --recommend-shallow
git apply ../jpegli-empty-dht-marker.patch # adapted from https://github.com/libjxl/libjxl/pull/2704

mkdir build
cd build
Expand Down
99 changes: 99 additions & 0 deletions server/bin/jpegli-empty-dht-marker.patch
Original file line number Diff line number Diff line change
@@ -0,0 +1,99 @@
diff --git a/lib/jpegli/decode_marker.cc b/lib/jpegli/decode_marker.cc
index 2621ed08..933210c5 100644
--- a/lib/jpegli/decode_marker.cc
+++ b/lib/jpegli/decode_marker.cc
@@ -282,7 +282,7 @@ void ProcessSOS(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
void ProcessDHT(j_decompress_ptr cinfo, const uint8_t* data, size_t len) {
size_t pos = 2;
if (pos == len) {
- JPEGLI_ERROR("DHT marker: no Huffman table found");
+ return;
}
while (pos < len) {
JPEG_VERIFY_LEN(1 + kJpegHuffmanMaxBitLength);
diff --git a/lib/jxl/jpeg/dec_jpeg_data_writer.cc b/lib/jxl/jpeg/dec_jpeg_data_writer.cc
index 9fb664d3..e055ef9a 100644
--- a/lib/jxl/jpeg/dec_jpeg_data_writer.cc
+++ b/lib/jxl/jpeg/dec_jpeg_data_writer.cc
@@ -384,10 +384,12 @@ bool EncodeDHT(const JPEGData& jpg, SerializationState* state) {
size_t marker_len = 2;
for (size_t i = state->dht_index; i < huffman_code.size(); ++i) {
const JPEGHuffmanCode& huff = huffman_code[i];
- marker_len += kJpegHuffmanMaxBitLength;
for (uint32_t count : huff.counts) {
marker_len += count;
}
+ // special case: empty DHT marker
+ if (marker_len == 2) break;
+ marker_len += kJpegHuffmanMaxBitLength;
if (huff.is_last) break;
}
state->output_queue.emplace_back(marker_len + 2);
@@ -405,6 +407,17 @@ bool EncodeDHT(const JPEGData& jpg, SerializationState* state) {
const JPEGHuffmanCode& huff = huffman_code[huffman_code_index];
size_t index = huff.slot_id;
HuffmanCodeTable* huff_table;
+ size_t total_count = 0;
+ size_t max_length = 0;
+ for (size_t i = 0; i < huff.counts.size(); ++i) {
+ if (huff.counts[i] != 0) {
+ max_length = i;
+ }
+ total_count += huff.counts[i];
+ }
+ // Empty DHT marker
+ if (total_count == 0) break;
+
if (index & 0x10) {
index -= 0x10;
huff_table = &state->ac_huff_table[index];
@@ -417,14 +430,6 @@ bool EncodeDHT(const JPEGData& jpg, SerializationState* state) {
return false;
}
huff_table->initialized = true;
- size_t total_count = 0;
- size_t max_length = 0;
- for (size_t i = 0; i < huff.counts.size(); ++i) {
- if (huff.counts[i] != 0) {
- max_length = i;
- }
- total_count += huff.counts[i];
- }
--total_count;
data[pos++] = huff.slot_id;
for (size_t i = 1; i <= kJpegHuffmanMaxBitLength; ++i) {
diff --git a/lib/jxl/jpeg/enc_jpeg_data_reader.cc b/lib/jxl/jpeg/enc_jpeg_data_reader.cc
index 149bde1c..70ad6a30 100644
--- a/lib/jxl/jpeg/enc_jpeg_data_reader.cc
+++ b/lib/jxl/jpeg/enc_jpeg_data_reader.cc
@@ -226,7 +226,12 @@ bool ProcessDHT(const uint8_t* data, const size_t len, JpegReadMode mode,
JXL_JPEG_VERIFY_LEN(2);
size_t marker_len = ReadUint16(data, pos);
if (marker_len == 2) {
- return JXL_FAILURE("DHT marker: no Huffman table found");
+ // Empty DHT marker. Useless but does seem to occur in the wild.
+ // We represent this situation with a dummy all-zeroes Huffman table.
+ JPEGHuffmanCode huff;
+ huff.is_last = true;
+ jpg->huffman_code.push_back(huff);
+ return true;
}
while (*pos < start_pos + marker_len) {
JXL_JPEG_VERIFY_LEN(1 + kJpegHuffmanMaxBitLength);
diff --git a/lib/jxl/jpeg/jpeg_data.cc b/lib/jxl/jpeg/jpeg_data.cc
index f3144dd6..1ae50a77 100644
--- a/lib/jxl/jpeg/jpeg_data.cc
+++ b/lib/jxl/jpeg/jpeg_data.cc
@@ -228,9 +228,10 @@ Status JPEGData::VisitFields(Visitor* visitor) {
Bits(8), 0, &hc.counts[i]));
num_symbols += hc.counts[i];
}
- if (num_symbols < 1) {
+ if (num_symbols == 0) {
// Actually, at least 2 symbols are required, since one of them is EOI.
- return JXL_FAILURE("Empty Huffman table");
+ // This case is used to represent an empty DHT marker.
+ continue;
}
if (num_symbols > hc.values.size()) {
return JXL_FAILURE("Huffman code too large (%" PRIuS ")", num_symbols);

0 comments on commit 7fa0413

Please sign in to comment.