Add support for 16-bit precision JPEG quantization values

Don't force JPEG quantization to be baseline-compatible

Quantization values will not be limited to values 1..255 and may
be 16 bits if needed. This may cause compatibility issues.
This commit is contained in:
gofr 2020-09-12 20:15:33 +02:00
parent 2e029d9a79
commit 6db0843af4
2 changed files with 14 additions and 13 deletions

View File

@ -36,6 +36,7 @@ import io
import os import os
import struct import struct
import subprocess import subprocess
import sys
import tempfile import tempfile
import warnings import warnings
@ -244,15 +245,16 @@ def DQT(self, marker):
n = i16(self.fp.read(2)) - 2 n = i16(self.fp.read(2)) - 2
s = ImageFile._safe_read(self.fp, n) s = ImageFile._safe_read(self.fp, n)
while len(s): while len(s):
if len(s) < 65:
raise SyntaxError("bad quantization table marker")
v = i8(s[0]) v = i8(s[0])
if v // 16 == 0: precision = 1 if (v // 16 == 0) else 2 # in bytes
self.quantization[v & 15] = array.array("B", s[1:65]) qt_length = 1 + precision * 64
s = s[65:] if len(s) < qt_length:
else: raise SyntaxError("bad quantization table marker")
return # FIXME: add code to read 16-bit tables! data = array.array("B" if precision == 1 else "H", s[1:qt_length])
# raise SyntaxError, "bad quantization table element size" if sys.byteorder == "little" and precision > 1:
data.byteswap() # the values are always big-endian
self.quantization[v & 15] = data
s = s[qt_length:]
# #
@ -683,7 +685,7 @@ def _save(im, fp, filename):
try: try:
if len(table) != 64: if len(table) != 64:
raise TypeError raise TypeError
table = array.array("B", table) table = array.array("H", table)
except TypeError as e: except TypeError as e:
raise ValueError("Invalid quantization table") from e raise ValueError("Invalid quantization table") from e
else: else:

View File

@ -159,22 +159,21 @@ ImagingJpegEncode(Imaging im, ImagingCodecState state, UINT8* buf, int bytes)
quality = context->quality; quality = context->quality;
} }
for (i = 0; i < context->qtablesLen; i++) { for (i = 0; i < context->qtablesLen; i++) {
// TODO: Should add support for none baseline
jpeg_add_quant_table(&context->cinfo, i, &context->qtables[i * DCTSIZE2], jpeg_add_quant_table(&context->cinfo, i, &context->qtables[i * DCTSIZE2],
quality, TRUE); quality, FALSE);
context->cinfo.comp_info[i].quant_tbl_no = i; context->cinfo.comp_info[i].quant_tbl_no = i;
last_q = i; last_q = i;
} }
if (context->qtablesLen == 1) { if (context->qtablesLen == 1) {
// jpeg_set_defaults created two qtables internally, but we only wanted one. // jpeg_set_defaults created two qtables internally, but we only wanted one.
jpeg_add_quant_table(&context->cinfo, 1, &context->qtables[0], jpeg_add_quant_table(&context->cinfo, 1, &context->qtables[0],
quality, TRUE); quality, FALSE);
} }
for (i = last_q; i < context->cinfo.num_components; i++) { for (i = last_q; i < context->cinfo.num_components; i++) {
context->cinfo.comp_info[i].quant_tbl_no = last_q; context->cinfo.comp_info[i].quant_tbl_no = last_q;
} }
} else if (context->quality != -1) { } else if (context->quality != -1) {
jpeg_set_quality(&context->cinfo, context->quality, 1); jpeg_set_quality(&context->cinfo, context->quality, FALSE);
} }
/* Set subsampling options */ /* Set subsampling options */