From 96bc40c1b36775afdbad4ae05a6b3f48e2eebeb9 Mon Sep 17 00:00:00 2001 From: DRC Date: Thu, 26 Jan 2023 13:11:58 -0600 Subject: [PATCH] Implement arithmetic coding with 12-bit precision This actually works and apparently always has worked. It only failed because the libjpeg code, which did not originally support arithmetic coding, assumed that optimize_coding should always be TRUE for 12-bit data precision. --- cmakescripts/tjbenchtest.cmake | 10 +++++++++ doc/html/group___turbo_j_p_e_g.html | 10 ++++----- fuzz/compress12.cc | 1 + java/TJBench.java | 8 +++----- java/doc/member-search-index.zip | Bin 1927 -> 1927 bytes java/doc/org/libjpegturbo/turbojpeg/TJ.html | 11 +++++----- .../libjpegturbo/turbojpeg/TJTransform.html | 4 ++-- java/doc/package-search-index.zip | Bin 237 -> 237 bytes java/doc/type-search-index.zip | Bin 311 -> 311 bytes java/org/libjpegturbo/turbojpeg/TJ.java | 11 +++++----- .../libjpegturbo/turbojpeg/TJTransform.java | 4 ++-- jcarith.c | 3 --- jcmaster.c | 4 ++-- jcparam.c | 4 ++-- jdarith.c | 3 --- tjbench.c | 10 +++------ tjbenchtest.in | 19 +++++++++++++++--- turbojpeg.c | 4 +++- turbojpeg.h | 14 ++++++------- 19 files changed, 68 insertions(+), 52 deletions(-) diff --git a/cmakescripts/tjbenchtest.cmake b/cmakescripts/tjbenchtest.cmake index 1f28b8a6..facb2030 100644 --- a/cmakescripts/tjbenchtest.cmake +++ b/cmakescripts/tjbenchtest.cmake @@ -35,7 +35,12 @@ if(NOT PRECISION EQUAL 16) endif() if(PRECISION EQUAL 8) run_test(tjbenchtest "-precision;${PRECISION};-progressive;-yuv") +endif() +if(NOT PRECISION EQUAL 16) run_test(tjbenchtest "-precision;${PRECISION};-arithmetic") + run_test(tjbenchtest "-precision;${PRECISION};-progressive;-arithmetic") +endif() +if(PRECISION EQUAL 8) run_test(tjbenchtest "-precision;${PRECISION};-arithmetic;-yuv") endif() run_test(tjbenchtest "-precision;${PRECISION};-lossless") @@ -57,7 +62,12 @@ if(WITH_JAVA) endif() if(PRECISION EQUAL 8) run_test(tjbenchtest "-java;-precision;${PRECISION};-progressive;-yuv") + endif() + if(NOT PRECISION EQUAL 16) run_test(tjbenchtest "-java;-precision;${PRECISION};-arithmetic") + run_test(tjbenchtest "-java;-precision;${PRECISION};-progressive;-arithmetic") + endif() + if(PRECISION EQUAL 8) run_test(tjbenchtest "-java;-precision;${PRECISION};-arithmetic;-yuv") endif() run_test(tjbenchtest "-java;-precision;${PRECISION};-lossless") diff --git a/doc/html/group___turbo_j_p_e_g.html b/doc/html/group___turbo_j_p_e_g.html index 1e96c474..1d0507f7 100644 --- a/doc/html/group___turbo_j_p_e_g.html +++ b/doc/html/group___turbo_j_p_e_g.html @@ -572,7 +572,7 @@ YUV Image Format Notes

This option will enable arithmetic entropy coding in the JPEG image generated by this particular transform.

-

Arithmetic entropy coding will generally improve compression relative to Huffman entropy coding (the default), but it will reduce decompression performance considerably. Can be combined with TJXOPT_PROGRESSIVE. Arithmetic entropy coding is currently only implemented for 8-bit samples.

+

Arithmetic entropy coding will generally improve compression relative to Huffman entropy coding (the default), but it will reduce decompression performance considerably. Can be combined with TJXOPT_PROGRESSIVE.

@@ -689,7 +689,7 @@ YUV Image Format Notes

This option will enable progressive entropy coding in the JPEG image generated by this particular transform.

-

Progressive entropy coding will generally improve compression relative to baseline entropy coding (the default), but it will reduce decompression performance considerably. Implies TJXOPT_OPTIMIZE. Can be combined with TJXOPT_ARITHMETIC.

+

Progressive entropy coding will generally improve compression relative to baseline entropy coding (the default), but it will reduce decompression performance considerably. Can be combined with TJXOPT_ARITHMETIC. Implies TJXOPT_OPTIMIZE unless TJXOPT_ARITHMETIC is also specified.

@@ -874,7 +874,7 @@ YUV Image Format Notes

Value

-

12-bit data precision implies TJPARAM_OPTIMIZE.

+

12-bit data precision implies TJPARAM_OPTIMIZE unless TJPARAM_ARITHMETIC is set.

TJPARAM_COLORSPACE 

JPEG colorspace.

The JPEG image uses (decompression) or will use (lossy compression) the specified colorspace.

@@ -912,7 +912,7 @@ YUV Image Format Notes
  • 0 [default for compression, lossless transformation] The lossy JPEG image uses (decompression) or will use (compression, lossless transformation) baseline entropy coding.
  • 1 The lossy JPEG image uses (decompression) or will use (compression, lossless transformation) progressive entropy coding. For lossless transformation, this can also be specified using TJXOPT_PROGRESSIVE.
  • -

    Progressive entropy coding will generally improve compression relative to baseline entropy coding, but it will reduce compression and decompression performance considerably. Implies TJPARAM_OPTIMIZE. Can be combined with TJPARAM_ARITHMETIC.

    +

    Progressive entropy coding will generally improve compression relative to baseline entropy coding, but it will reduce compression and decompression performance considerably. Can be combined with TJPARAM_ARITHMETIC. Implies TJPARAM_OPTIMIZE unless TJPARAM_ARITHMETIC is also set.

    TJPARAM_SCANLIMIT 

    Progressive JPEG scan limit for lossy JPEG images [decompression, lossless transformation].

    Setting this parameter will cause the decompression and transform functions to return an error if the number of scans in a progressive JPEG image exceeds the specified limit. The primary purpose of this is to allow security-critical applications to guard against an exploit of the progressive JPEG format described in this report.

    @@ -926,7 +926,7 @@ YUV Image Format Notes
  • 0 [default for compression, lossless transformation] The lossy JPEG image uses (decompression) or will use (compression, lossless transformation) Huffman entropy coding.
  • 1 The lossy JPEG image uses (decompression) or will use (compression, lossless transformation) arithmetic entropy coding. For lossless transformation, this can also be specified using TJXOPT_ARITHMETIC.
  • -

    Arithmetic entropy coding will generally improve compression relative to Huffman entropy coding, but it will reduce compression and decompression performance considerably. Can be combined with TJPARAM_PROGRESSIVE. Arithmetic entropy coding is currently only implemented for 8-bit samples.

    +

    Arithmetic entropy coding will generally improve compression relative to Huffman entropy coding, but it will reduce compression and decompression performance considerably. Can be combined with TJPARAM_PROGRESSIVE.

    TJPARAM_LOSSLESS 

    Lossless JPEG.

    Value

    -

    12-bit data precision implies PARAM_OPTIMIZE. +

    12-bit data precision implies PARAM_OPTIMIZE unless + PARAM_ARITHMETIC is set.

    See Also:
    Constant Field Values
    @@ -1511,8 +1512,9 @@ extends java.lang.Object

    Progressive entropy coding will generally improve compression relative to baseline entropy coding, but it will reduce compression and - decompression performance considerably. Implies PARAM_OPTIMIZE. - Can be combined with PARAM_ARITHMETIC. + decompression performance considerably. Can be combined with + PARAM_ARITHMETIC. Implies PARAM_OPTIMIZE unless + PARAM_ARITHMETIC is also set.

    See Also:
    Constant Field Values
    @@ -1572,8 +1574,7 @@ extends java.lang.Object

    Arithmetic entropy coding will generally improve compression relative to Huffman entropy coding, but it will reduce compression and decompression performance considerably. Can be combined with - PARAM_PROGRESSIVE. Arithmetic entropy coding is currently only - implemented for 8-bit samples. + PARAM_PROGRESSIVE.

    See Also:
    Constant Field Values
    diff --git a/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html b/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html index fbe0dd8b..0c2f5cc6 100644 --- a/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html +++ b/java/doc/org/libjpegturbo/turbojpeg/TJTransform.html @@ -700,8 +700,8 @@ extends java.awt.Rectangle generated by this particular transform. Progressive entropy coding will generally improve compression relative to baseline entropy coding (the default), but it will reduce decompression performance considerably. - Implies OPT_OPTIMIZE. Can be combined with - OPT_ARITHMETIC. + Can be combined with OPT_ARITHMETIC. Implies + OPT_OPTIMIZE unless OPT_ARITHMETIC is also specified.
    See Also:
    Constant Field Values
    diff --git a/java/doc/package-search-index.zip b/java/doc/package-search-index.zip index 453ee4a263aca02b3e9117b9ed141044b624b466..e6c959be2db77fde6b061acc44969fec7d16dc2a 100644 GIT binary patch delta 28 hcmaFM_?D43z?+#xgn@&DgTW`=Y9enxGl-h+2LNJ!2S5M- delta 28 hcmaFM_?D43z?+#xgn@&DgQ0!4#YEnIW)L;s4*+U52pRwY diff --git a/java/doc/type-search-index.zip b/java/doc/type-search-index.zip index 81bcf27aa0044f80079cf65d7fd56b05578ee707..93006846a794bac2ccb9450ec5748ca50e64b3c8 100644 GIT binary patch delta 28 hcmdnaw4I4Jz?+#xgn@&DgTW`=Y9j9)W)Stp8vt5P2W 8, 12, or 16 * * - *

    12-bit data precision implies {@link #PARAM_OPTIMIZE}. + *

    12-bit data precision implies {@link #PARAM_OPTIMIZE} unless + * {@link #PARAM_ARITHMETIC} is set. */ public static final int PARAM_PRECISION = 7; /** @@ -559,8 +560,9 @@ public final class TJ { * *

    Progressive entropy coding will generally improve compression relative * to baseline entropy coding, but it will reduce compression and - * decompression performance considerably. Implies {@link #PARAM_OPTIMIZE}. - * Can be combined with {@link #PARAM_ARITHMETIC}. + * decompression performance considerably. Can be combined with + * {@link #PARAM_ARITHMETIC}. Implies {@link #PARAM_OPTIMIZE} unless + * {@link #PARAM_ARITHMETIC} is also set. */ public static final int PARAM_PROGRESSIVE = 12; /** @@ -601,8 +603,7 @@ public final class TJ { *

    Arithmetic entropy coding will generally improve compression relative * to Huffman entropy coding, but it will reduce compression and * decompression performance considerably. Can be combined with - * {@link #PARAM_PROGRESSIVE}. Arithmetic entropy coding is currently only - * implemented for 8-bit samples. + * {@link #PARAM_PROGRESSIVE}. */ public static final int PARAM_ARITHMETIC = 14; /** diff --git a/java/org/libjpegturbo/turbojpeg/TJTransform.java b/java/org/libjpegturbo/turbojpeg/TJTransform.java index dae0c164..7c32cce7 100644 --- a/java/org/libjpegturbo/turbojpeg/TJTransform.java +++ b/java/org/libjpegturbo/turbojpeg/TJTransform.java @@ -133,8 +133,8 @@ public class TJTransform extends Rectangle { * generated by this particular transform. Progressive entropy coding will * generally improve compression relative to baseline entropy coding (the * default), but it will reduce decompression performance considerably. - * Implies {@link #OPT_OPTIMIZE}. Can be combined with - * {@link #OPT_ARITHMETIC}. + * Can be combined with {@link #OPT_ARITHMETIC}. Implies + * {@link #OPT_OPTIMIZE} unless {@link #OPT_ARITHMETIC} is also specified. */ public static final int OPT_PROGRESSIVE = (1 << 5); /** diff --git a/jcarith.c b/jcarith.c index 054c7c12..b1720521 100644 --- a/jcarith.c +++ b/jcarith.c @@ -914,9 +914,6 @@ jinit_arith_encoder(j_compress_ptr cinfo) arith_entropy_ptr entropy; int i; - if (cinfo->data_precision != 8) - ERREXIT(cinfo, JERR_NOTIMPL); - entropy = (arith_entropy_ptr) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, sizeof(arith_entropy_encoder)); diff --git a/jcmaster.c b/jcmaster.c index 68492e93..7e1408fc 100644 --- a/jcmaster.c +++ b/jcmaster.c @@ -7,7 +7,7 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2010, 2016, 2018, 2022, D. R. Commander. + * Copyright (C) 2010, 2016, 2018, 2022-2023, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -646,7 +646,7 @@ jinit_c_master_control(j_compress_ptr cinfo, boolean transcode_only) (cinfo->progressive_mode && !cinfo->arith_code)) cinfo->optimize_coding = TRUE; /* assume default tables no good for progressive mode or lossless mode */ - if (cinfo->data_precision == 12) + if (cinfo->data_precision == 12 && !cinfo->arith_code) cinfo->optimize_coding = TRUE; /* assume default tables no good for 12-bit data precision */ diff --git a/jcparam.c b/jcparam.c index 30bb23b7..d1dee4da 100644 --- a/jcparam.c +++ b/jcparam.c @@ -7,7 +7,7 @@ * Lossless JPEG Modifications: * Copyright (C) 1999, Ken Murchison. * libjpeg-turbo Modifications: - * Copyright (C) 2009-2011, 2018, D. R. Commander. + * Copyright (C) 2009-2011, 2018, 2023, D. R. Commander. * For conditions of distribution and use, see the accompanying README.ijg * file. * @@ -233,7 +233,7 @@ jpeg_set_defaults(j_compress_ptr cinfo) * tables will be computed. This test can be removed if default tables * are supplied that are valid for the desired precision. */ - if (cinfo->data_precision > 8) + if (cinfo->data_precision == 12 && !cinfo->arith_code) cinfo->optimize_coding = TRUE; /* By default, use the simpler non-cosited sampling alignment */ diff --git a/jdarith.c b/jdarith.c index 626f8cb6..21575e80 100644 --- a/jdarith.c +++ b/jdarith.c @@ -752,9 +752,6 @@ jinit_arith_decoder(j_decompress_ptr cinfo) arith_entropy_ptr entropy; int i; - if (cinfo->data_precision != 8) - ERREXIT(cinfo, JERR_NOTIMPL); - entropy = (arith_entropy_ptr) (*cinfo->mem->alloc_small) ((j_common_ptr)cinfo, JPOOL_IMAGE, sizeof(arith_entropy_decoder)); diff --git a/tjbench.c b/tjbench.c index 8d09340a..84fea32b 100644 --- a/tjbench.c +++ b/tjbench.c @@ -901,6 +901,7 @@ static void usage(char *progName) printf(" (use the CMYK pixel format for packed-pixel source/destination buffers)\n"); printf("-precision N = Use N-bit data precision when compressing [N is 8, 12, or 16;\n"); printf(" default = 8; if N is 16, then -lossless must also be specified]\n"); + printf(" (-precision 12 implies -optimize unless -arithmetic is also specified)\n"); printf("-quiet = Output results in tabular rather than verbose format\n"); printf("-restart N = When compressing, add a restart marker every N MCU rows (lossy) or\n"); printf(" N sample rows (lossless) [default = 0 (no restart markers)]. Append 'B'\n"); @@ -919,7 +920,6 @@ static void usage(char *progName) printf("------------------\n"); printf("-arithmetic = Use arithmetic entropy coding in JPEG images generated by\n"); printf(" compression and transform operations (can be combined with -progressive)\n"); - printf(" ** 8-bit data precision only **\n"); printf("-crop WxH+X+Y = Decompress only the specified region of the JPEG image, where W\n"); printf(" and H are the width and height of the region (0 = maximum possible width\n"); printf(" or height) and X and Y are the left and upper boundary of the region, all\n"); @@ -930,8 +930,8 @@ static void usage(char *progName) printf("-optimize = Use optimized baseline entropy coding in JPEG images generated by\n"); printf(" compession and transform operations\n"); printf("-progressive = Use progressive entropy coding in JPEG images generated by\n"); - printf(" compression and transform operations (implies -optimize; can be combined\n"); - printf(" with -arithmetic)\n"); + printf(" compression and transform operations (can be combined with -arithmetic;\n"); + printf(" implies -optimize unless -arithmetic is also specified)\n"); printf("-limitscans = Refuse to decompress or transform progressive JPEG images that\n"); printf(" have an unreasonably large number of scans\n"); printf("-scale M/N = When decompressing, scale the width/height of the JPEG image by a\n"); @@ -1159,10 +1159,6 @@ int main(int argc, char *argv[]) printf("ERROR: -lossless must be specified along with -precision 16\n"); retval = -1; goto bailout; } - if (precision != 8 && arithmetic) { - printf("ERROR: -arithmetic requires 8-bit data precision\n"); - retval = -1; goto bailout; - } if (precision != 8 && doYUV) { printf("ERROR: -yuv requires 8-bit data precision\n"); retval = -1; goto bailout; diff --git a/tjbenchtest.in b/tjbenchtest.in index 7862906c..c0f5b891 100755 --- a/tjbenchtest.in +++ b/tjbenchtest.in @@ -84,10 +84,18 @@ while [ $# -gt 0 ]; do ENTROPYARG=-optimize ;; -progressive) - ENTROPYARG=-progressive + if [ "$ENTROPYARG" = "-arithmetic" ]; then + ENTROPYARG=-progressive-arithmetic + else + ENTROPYARG=-progressive + fi ;; -arithmetic) - ENTROPYARG=-arithmetic + if [ "$ENTROPYARG" = "-progressive" ]; then + ENTROPYARG=-progressive-arithmetic + else + ENTROPYARG=-arithmetic + fi ;; -lossless) LOSSLSARG="-lossless" @@ -115,13 +123,18 @@ if [ $PRECISION = 8 -a "$YUVARG" = "" ]; then IMAGES="vgl_6434_0018a.${EXT}" elif [ "$ENTROPYARG" = "-progressive" ]; then IMAGES="vgl_6548_0026a.${EXT}" - elif [ "$ENTROPYARG" = "-arithmetic" ]; then + elif [ "$ENTROPYARG" = "-arithmetic" -o \ + "$ENTROPYARG" = "-progressive-arithmetic" ]; then IMAGES="big_tree8.${EXT}" fi fi exec >$EXEDIR/tjbenchtest$JAVAARG$YUVARG$ALLOCARG$ENTROPYARG$LOSSLSARG-$PRECISION.log +if [ "$ENTROPYARG" = "-progressive-arithmetic" ]; then + ENTROPYARG="-progressive -arithmetic" +fi + # Standard tests for image in $IMAGES; do diff --git a/turbojpeg.c b/turbojpeg.c index 3c235861..f77c8688 100644 --- a/turbojpeg.c +++ b/turbojpeg.c @@ -2728,8 +2728,10 @@ DLLEXPORT int tj3Transform(tjhandle handle, const unsigned char *jpegBuf, if (this->progressive || t[i].options & TJXOPT_PROGRESSIVE) jpeg_simple_progression(cinfo); #endif - if (this->arithmetic || t[i].options & TJXOPT_ARITHMETIC) + if (this->arithmetic || t[i].options & TJXOPT_ARITHMETIC) { cinfo->arith_code = TRUE; + cinfo->optimize_coding = FALSE; + } if (!(t[i].options & TJXOPT_NOOUTPUT)) { jpeg_write_coefficients(cinfo, dstcoefs); jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ? diff --git a/turbojpeg.h b/turbojpeg.h index 475282a5..ed2f488d 100644 --- a/turbojpeg.h +++ b/turbojpeg.h @@ -490,7 +490,8 @@ enum TJPARAM { * **Value** * - `8`, `12`, or `16` * - * 12-bit data precision implies #TJPARAM_OPTIMIZE. + * 12-bit data precision implies #TJPARAM_OPTIMIZE unless #TJPARAM_ARITHMETIC + * is set. */ TJPARAM_PRECISION, /** @@ -566,8 +567,8 @@ enum TJPARAM { * * Progressive entropy coding will generally improve compression relative to * baseline entropy coding, but it will reduce compression and decompression - * performance considerably. Implies #TJPARAM_OPTIMIZE. Can be combined - * with #TJPARAM_ARITHMETIC. + * performance considerably. Can be combined with #TJPARAM_ARITHMETIC. + * Implies #TJPARAM_OPTIMIZE unless #TJPARAM_ARITHMETIC is also set. */ TJPARAM_PROGRESSIVE, /** @@ -602,7 +603,6 @@ enum TJPARAM { * Arithmetic entropy coding will generally improve compression relative to * Huffman entropy coding, but it will reduce compression and decompression * performance considerably. Can be combined with #TJPARAM_PROGRESSIVE. - * Arithmetic entropy coding is currently only implemented for 8-bit samples. */ TJPARAM_ARITHMETIC, /** @@ -863,7 +863,8 @@ enum TJXOP { * generated by this particular transform. Progressive entropy coding will * generally improve compression relative to baseline entropy coding (the * default), but it will reduce decompression performance considerably. - * Implies #TJXOPT_OPTIMIZE. Can be combined with #TJXOPT_ARITHMETIC. + * Can be combined with #TJXOPT_ARITHMETIC. Implies #TJXOPT_OPTIMIZE unless + * #TJXOPT_ARITHMETIC is also specified. */ #define TJXOPT_PROGRESSIVE (1 << 5) /** @@ -877,8 +878,7 @@ enum TJXOP { * generated by this particular transform. Arithmetic entropy coding will * generally improve compression relative to Huffman entropy coding (the * default), but it will reduce decompression performance considerably. Can be - * combined with #TJXOPT_PROGRESSIVE. Arithmetic entropy coding is currently - * only implemented for 8-bit samples. + * combined with #TJXOPT_PROGRESSIVE. */ #define TJXOPT_ARITHMETIC (1 << 7) /**