jpeg: use the Huffman tables the scan header selects

Both JPEG decoders ignored the DC/AC table selectors in the SOS header
and always decoded luma with tables 0 and chroma with tables 1, the
layout libjpeg writes by default. Files where all components share
table 0, or where the slots are assigned differently, decoded to noise.

Look up each component's tables from its selectors instead. Baseline
JPEG only allows tables 0 and 1, which both decoders already hold, so
this needs no extra memory; selectors above 1 are rejected. In the core
loader tab_membership is no longer used and is removed.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Change-Id: Ie1ec407ddecf1256fef410b1256b97af412fb194
This commit is contained in:
Michael Giacomelli 2026-09-28 23:19:50 -04:00 • committed by Solomon Peachy
parent c12f6ebacd
commit b897766a7a
3 changed files with 24 additions and 27 deletions

View file

@ -638,6 +638,11 @@ int process_markers(unsigned char* p_src, long size, struct jpeg* p_jpeg)
p_jpeg->scanheader[i].ID = *p_src++;
p_jpeg->scanheader[i].DC_select = *p_src >> 4;
p_jpeg->scanheader[i].AC_select = *p_src++ & 0x0F;
if (p_jpeg->scanheader[i].DC_select > 1
|| p_jpeg->scanheader[i].AC_select > 1)
{
return (-5); /* Huffman table index out of range */
}
}
p_src += 3; /* skip spectral information */
p_jpeg->p_entropy_data = p_src;
@ -1282,8 +1287,10 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel[3],
int s, r; /* huffman values */
int ci = p_jpeg->mcu_membership[blkn]; /* component index */
int ti = p_jpeg->tab_membership[blkn]; /* table index */
struct derived_tbl* dctbl = &p_jpeg->dc_derived_tbls[ti];
struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti];
struct derived_tbl* dctbl =
&p_jpeg->dc_derived_tbls[p_jpeg->scanheader[ci].DC_select];
struct derived_tbl* actbl =
&p_jpeg->ac_derived_tbls[p_jpeg->scanheader[ci].AC_select];
/* Section F.2.2.1: decode the DC coefficient difference */
s = huff_decode_dc(&bs, dctbl);
@ -1453,8 +1460,10 @@ int jpeg_decode(struct jpeg* p_jpeg, unsigned char* p_pixel[1], int downscale,
int s, r; /* huffman values */
int ci = p_jpeg->mcu_membership[blkn]; /* component index */
int ti = p_jpeg->tab_membership[blkn]; /* table index */
struct derived_tbl* dctbl = &p_jpeg->dc_derived_tbls[ti];
struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti];
struct derived_tbl* dctbl =
&p_jpeg->dc_derived_tbls[p_jpeg->scanheader[ci].DC_select];
struct derived_tbl* actbl =
&p_jpeg->ac_derived_tbls[p_jpeg->scanheader[ci].AC_select];
/* Section F.2.2.1: decode the DC coefficient difference */
s = huff_decode_dc(&bs, dctbl);

View file

@ -49,7 +49,7 @@ struct jpeg
struct derived_tbl ac_derived_tbls[2];
struct frame_component frameheader[3]; /* Component descriptor */
struct scan_component scanheader[3]; /* currently not used */
struct scan_component scanheader[3]; /* Huffman tables per component */
int mcu_membership[6]; /* info per block */
int tab_membership[6];

View file

@ -128,10 +128,9 @@ struct jpeg
struct derived_tbl ac_derived_tbls[2];
struct frame_component frameheader[3]; /* Component descriptor */
struct scan_component scanheader[3]; /* currently not used */
struct scan_component scanheader[3]; /* Huffman tables per component */
int mcu_membership[6]; /* info per block */
int tab_membership[6];
int subsample_x[3]; /* info per component */
int subsample_y[3];
bool resize;
@ -1171,6 +1170,11 @@ static int process_markers(struct jpeg* p_jpeg)
>> 4;
p_jpeg->scanheader[i].AC_select = c & 0x0F;
marker_size -= 2;
if (p_jpeg->scanheader[i].DC_select > 1
|| p_jpeg->scanheader[i].AC_select > 1)
{
return (-5); /* Huffman table index out of range */
}
}
/* skip spectral information */
e_skip_bytes(p_jpeg, marker_size);
@ -1472,10 +1476,6 @@ INLINE void fix_headers(struct jpeg* p_jpeg)
p_jpeg->mcu_membership[1] = 0;
p_jpeg->mcu_membership[2] = 1;
p_jpeg->mcu_membership[3] = 2;
p_jpeg->tab_membership[0] = 0; /* DC, DC, AC, AC */
p_jpeg->tab_membership[1] = 0;
p_jpeg->tab_membership[2] = 1;
p_jpeg->tab_membership[3] = 1;
p_jpeg->subsample_x[0] = 1;
p_jpeg->subsample_x[1] = 2;
p_jpeg->subsample_x[2] = 2;
@ -1497,10 +1497,6 @@ INLINE void fix_headers(struct jpeg* p_jpeg)
p_jpeg->mcu_membership[1] = 0;
p_jpeg->mcu_membership[2] = 1;
p_jpeg->mcu_membership[3] = 2;
p_jpeg->tab_membership[0] = 0; /* DC, DC, AC, AC */
p_jpeg->tab_membership[1] = 0;
p_jpeg->tab_membership[2] = 1;
p_jpeg->tab_membership[3] = 1;
p_jpeg->subsample_x[0] = 1;
p_jpeg->subsample_x[1] = 1;
p_jpeg->subsample_x[2] = 1;
@ -1522,12 +1518,6 @@ INLINE void fix_headers(struct jpeg* p_jpeg)
p_jpeg->mcu_membership[3] = 0;
p_jpeg->mcu_membership[4] = 1;
p_jpeg->mcu_membership[5] = 2;
p_jpeg->tab_membership[0] = 0;
p_jpeg->tab_membership[1] = 0;
p_jpeg->tab_membership[2] = 0;
p_jpeg->tab_membership[3] = 0;
p_jpeg->tab_membership[4] = 1;
p_jpeg->tab_membership[5] = 1;
p_jpeg->subsample_x[0] = 1;
p_jpeg->subsample_x[1] = 2;
p_jpeg->subsample_x[2] = 2;
@ -1546,9 +1536,6 @@ INLINE void fix_headers(struct jpeg* p_jpeg)
p_jpeg->mcu_membership[0] = 0;
p_jpeg->mcu_membership[1] = 1;
p_jpeg->mcu_membership[2] = 2;
p_jpeg->tab_membership[0] = 0;
p_jpeg->tab_membership[1] = 1;
p_jpeg->tab_membership[2] = 1;
p_jpeg->subsample_x[0] = 1;
p_jpeg->subsample_x[1] = 1;
p_jpeg->subsample_x[2] = 1;
@ -1845,14 +1832,15 @@ static struct img_part *store_row_jpeg(void *jpeg_args)
for (blkn = 0; blkn < p_jpeg->blocks; blkn++)
{
int ci = p_jpeg->mcu_membership[blkn]; /* component index */
int ti = p_jpeg->tab_membership[blkn]; /* table index */
#ifdef JPEG_IDCT_TRANSPOSE
bool transpose = p_jpeg->v_scale[!!ci] > 2;
#endif
int k = 1; /* coefficient index */
int s, r; /* huffman values */
struct derived_tbl* dctbl = &p_jpeg->dc_derived_tbls[ti];
struct derived_tbl* actbl = &p_jpeg->ac_derived_tbls[ti];
struct derived_tbl* dctbl =
&p_jpeg->dc_derived_tbls[p_jpeg->scanheader[ci].DC_select];
struct derived_tbl* actbl =
&p_jpeg->ac_derived_tbls[p_jpeg->scanheader[ci].AC_select];
/* Section F.2.2.1: decode the DC coefficient difference */
huff_decode_dc(p_jpeg, dctbl, s, r);