aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJake Weinstein <jake@aospa.co>2023-02-01 22:56:50 -0600
committerJake Weinstein <jake@aospa.co>2023-02-28 22:06:19 +0000
commitb39ac8fb75e9141a5141fcc0a9ef68ac1ef4f7b8 (patch)
tree8fa387b196e632042d153b9c4c66999b1ec9d897
parented683925e4897a84b3bffc5c1414c85b97a129a3 (diff)
downloadlibjpeg-turbo-b39ac8fb75e9141a5141fcc0a9ef68ac1ef4f7b8.tar.gz
Update libjpeg-turbo to upstream stable release 2.1.5.1
This release consists mostly of bug fixes. Change-Id: Ic1b7ea6c10c9c92125eaf31345991d9096b19fb4
-rw-r--r--BUILDING.md18
-rw-r--r--ChangeLog.md104
-rw-r--r--LICENSE.md2
-rw-r--r--README.chromium12
-rw-r--r--cmyk.h1
-rw-r--r--djpeg.c2
-rw-r--r--jccolext.c14
-rw-r--r--jccolor.c21
-rw-r--r--jchuff.c1
-rw-r--r--jchuff.h12
-rw-r--r--jcmaster.c1
-rw-r--r--jconfig.h4
-rw-r--r--jconfigint.h2
-rw-r--r--jcphuff.c37
-rw-r--r--jdapimin.c1
-rw-r--r--jdcolext.c14
-rw-r--r--jdcolor.c1
-rw-r--r--jdmainct.c1
-rw-r--r--jdmerge.c1
-rw-r--r--jdmrgext.c20
-rw-r--r--jsimd.h8
-rw-r--r--jsimd_none.c8
-rw-r--r--jversion.h4
-rw-r--r--rdppm.c20
-rw-r--r--simd/arm/aarch32/jsimd.c12
-rw-r--r--simd/arm/aarch64/jsimd.c17
-rw-r--r--simd/arm/jcphuff-neon.c187
-rw-r--r--simd/arm/jdcolor-neon.c1
-rw-r--r--simd/arm/jdmerge-neon.c1
-rw-r--r--simd/arm/jidctint-neon.c1
-rw-r--r--simd/i386/jsimd.c84
-rw-r--r--simd/jsimd.h12
-rw-r--r--simd/x86_64/jsimd.c60
-rw-r--r--tjbench.c117
-rw-r--r--tjunittest.c75
-rw-r--r--transupp.c2
-rw-r--r--turbojpeg-jni.c31
-rw-r--r--turbojpeg-mapfile8
-rw-r--r--turbojpeg-mapfile.jni8
-rw-r--r--turbojpeg.c164
-rw-r--r--turbojpeg.h962
-rw-r--r--wizard.txt10
42 files changed, 1182 insertions, 879 deletions
diff --git a/BUILDING.md b/BUILDING.md
index 2ce65d61..b965b5e7 100644
--- a/BUILDING.md
+++ b/BUILDING.md
@@ -25,9 +25,9 @@ Build Requirements
variable or the `ASM_NASM` environment variable. On Windows, use forward
slashes rather than backslashes in the path (for example,
**c:/nasm/nasm.exe**).
- * NASM and Yasm are located in the CRB (Code Ready Builder) repository on
- Red Hat Enterprise Linux 8 and in the PowerTools repository on RHEL
- derivatives, which is not enabled by default.
+ * NASM and Yasm are located in the CRB (Code Ready Builder) or PowerTools
+ repository on Red Hat Enterprise Linux 8+ and derivatives, which is not
+ enabled by default.
### Un*x Platforms (including Linux, Mac, FreeBSD, Solaris, and Cygwin)
@@ -372,9 +372,13 @@ located (usually **/usr/bin**.) Next, execute the following commands:
cd {build_directory}
cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \
+ -DCMAKE_INSTALL_PREFIX={install_path} \
[additional CMake flags] {source_directory}
make
+*{install\_path}* is the path under which the libjpeg-turbo binaries should be
+installed.
+
### 64-bit MinGW Build on Un*x (including Mac and Cygwin)
@@ -391,9 +395,13 @@ located (usually **/usr/bin**.) Next, execute the following commands:
cd {build_directory}
cmake -G"Unix Makefiles" -DCMAKE_TOOLCHAIN_FILE=toolchain.cmake \
+ -DCMAKE_INSTALL_PREFIX={install_path} \
[additional CMake flags] {source_directory}
make
+*{install\_path}* is the path under which the libjpeg-turbo binaries should be
+installed.
+
Building libjpeg-turbo for iOS
------------------------------
@@ -429,6 +437,10 @@ iPhone 5S/iPad Mini 2/iPad Air and newer.
[additional CMake flags] {source_directory}
make
+Replace `iPhoneOS` with `iPhoneSimulator` and `-miphoneos-version-min` with
+`-miphonesimulator-version-min` to build libjpeg-turbo for the iOS simulator on
+Macs with Apple silicon CPUs.
+
Building libjpeg-turbo for Android
----------------------------------
diff --git a/ChangeLog.md b/ChangeLog.md
index b0d166ea..1c1e6538 100644
--- a/ChangeLog.md
+++ b/ChangeLog.md
@@ -1,7 +1,83 @@
+2.1.5.1
+=======
+
+### Significant changes relative to 2.1.5:
+
+1. The SIMD dispatchers in libjpeg-turbo 2.1.4 and prior stored the list of
+supported SIMD instruction sets in a global variable, which caused an innocuous
+race condition whereby the variable could have been initialized multiple times
+if `jpeg_start_*compress()` was called simultaneously in multiple threads.
+libjpeg-turbo 2.1.5 included an undocumented attempt to fix this race condition
+by making the SIMD support variable thread-local. However, that caused another
+issue whereby, if `jpeg_start_*compress()` was called in one thread and
+`jpeg_read_*()` or `jpeg_write_*()` was called in a second thread, the SIMD
+support variable was never initialized in the second thread. On x86 systems,
+this led the second thread to incorrectly assume that AVX2 instructions were
+always available, and when it attempted to use those instructions on older x86
+CPUs that do not support them, an illegal instruction error occurred. The SIMD
+dispatchers now ensure that the SIMD support variable is initialized before
+dispatching based on its value.
+
+
+2.1.5
+=====
+
+### Significant changes relative to 2.1.4:
+
+1. Fixed issues in the build system whereby, when using the Ninja Multi-Config
+CMake generator, a static build of libjpeg-turbo (a build in which
+`ENABLE_SHARED` is `0`) could not be installed, a Windows installer could not
+be built, and the Java regression tests failed.
+
+2. Fixed a regression introduced by 2.0 beta1[15] that caused a buffer overrun
+in the progressive Huffman encoder when attempting to transform a
+specially-crafted malformed 12-bit-per-component JPEG image into a progressive
+12-bit-per-component JPEG image using a 12-bit-per-component build of
+libjpeg-turbo (`-DWITH_12BIT=1`.) Given that the buffer overrun was fully
+contained within the progressive Huffman encoder structure and did not cause a
+segfault or other user-visible errant behavior, given that the lossless
+transformer (unlike the decompressor) is not generally exposed to arbitrary
+data exploits, and given that 12-bit-per-component builds of libjpeg-turbo are
+uncommon, this issue did not likely pose a security risk.
+
+3. Fixed an issue whereby, when using a 12-bit-per-component build of
+libjpeg-turbo (`-DWITH_12BIT=1`), passing samples with values greater than 4095
+or less than 0 to `jpeg_write_scanlines()` caused a buffer overrun or underrun
+in the RGB-to-YCbCr color converter.
+
+4. Fixed a floating point exception that occurred when attempting to use the
+jpegtran `-drop` and `-trim` options to losslessly transform a
+specially-crafted malformed JPEG image.
+
+5. Fixed an issue in `tjBufSizeYUV2()` whereby it returned a bogus result,
+rather than throwing an error, if the `align` parameter was not a power of 2.
+Fixed a similar issue in `tjCompressFromYUV()` whereby it generated a corrupt
+JPEG image in certain cases, rather than throwing an error, if the `align`
+parameter was not a power of 2.
+
+6. Fixed an issue whereby `tjDecompressToYUV2()`, which is a wrapper for
+`tjDecompressToYUVPlanes()`, used the desired YUV image dimensions rather than
+the actual scaled image dimensions when computing the plane pointers and
+strides to pass to `tjDecompressToYUVPlanes()`. This caused a buffer overrun
+and subsequent segfault if the desired image dimensions exceeded the scaled
+image dimensions.
+
+7. Fixed an issue whereby, when decompressing a 12-bit-per-component JPEG image
+(`-DWITH_12BIT=1`) using an alpha-enabled output color space such as
+`JCS_EXT_RGBA`, the alpha channel was set to 255 rather than 4095.
+
+8. Fixed an issue whereby the Java version of TJBench did not accept a range of
+quality values.
+
+9. Fixed an issue whereby, when `-progressive` was passed to TJBench, the JPEG
+input image was not transformed into a progressive JPEG image prior to
+decompression.
+
+
2.1.4
=====
-### Significant changes relative to 2.1.3
+### Significant changes relative to 2.1.3:
1. Fixed a regression introduced in 2.1.3 that caused build failures with
Visual Studio 2010.
@@ -36,7 +112,7 @@ virtual array access") under certain circumstances.
2.1.3
=====
-### Significant changes relative to 2.1.2
+### Significant changes relative to 2.1.2:
1. Fixed a regression introduced by 2.0 beta1[7] whereby cjpeg compressed PGM
input files into full-color JPEG images unless the `-grayscale` option was
@@ -60,7 +136,7 @@ be reproduced using the libjpeg API, not using djpeg.
2.1.2
=====
-### Significant changes relative to 2.1.1
+### Significant changes relative to 2.1.1:
1. Fixed a regression introduced by 2.1 beta1[13] that caused the remaining
GAS implementations of AArch64 (Arm 64-bit) Neon SIMD functions (which are used
@@ -92,7 +168,7 @@ image contains incomplete or corrupt image data.
2.1.1
=====
-### Significant changes relative to 2.1.0
+### Significant changes relative to 2.1.0:
1. Fixed a regression introduced in 2.1.0 that caused build failures with
non-GCC-compatible compilers for Un*x/Arm platforms.
@@ -121,7 +197,7 @@ transform a specially-crafted malformed JPEG image.
2.1.0
=====
-### Significant changes relative to 2.1 beta1
+### Significant changes relative to 2.1 beta1:
1. Fixed a regression introduced by 2.1 beta1[6(b)] whereby attempting to
decompress certain progressive JPEG images with one or more component planes of
@@ -156,10 +232,10 @@ progressive JPEG format described in the report
["Two Issues with the JPEG Standard"](https://libjpeg-turbo.org/pmwiki/uploads/About/TwoIssueswiththeJPEGStandard.pdf).
7. The PPM reader now throws an error, rather than segfaulting (due to a buffer
-overrun) or generating incorrect pixels, if an application attempts to use the
-`tjLoadImage()` function to load a 16-bit binary PPM file (a binary PPM file
-with a maximum value greater than 255) into a grayscale image buffer or to load
-a 16-bit binary PGM file into an RGB image buffer.
+overrun, CVE-2021-46822) or generating incorrect pixels, if an application
+attempts to use the `tjLoadImage()` function to load a 16-bit binary PPM file
+(a binary PPM file with a maximum value greater than 255) into a grayscale
+image buffer or to load a 16-bit binary PGM file into an RGB image buffer.
8. Fixed an issue in the PPM reader that caused incorrect pixels to be
generated when using the `tjLoadImage()` function to load a 16-bit binary PPM
@@ -325,11 +401,11 @@ methods in the TurboJPEG Java API.
2. Fixed or worked around multiple issues with `jpeg_skip_scanlines()`:
- - Fixed segfaults or "Corrupt JPEG data: premature end of data segment"
-errors in `jpeg_skip_scanlines()` that occurred when decompressing 4:2:2 or
-4:2:0 JPEG images using merged (non-fancy) upsampling/color conversion (that
-is, when setting `cinfo.do_fancy_upsampling` to `FALSE`.) 2.0.0[6] was a
-similar fix, but it did not cover all cases.
+ - Fixed segfaults (CVE-2020-35538) or "Corrupt JPEG data: premature end of
+data segment" errors in `jpeg_skip_scanlines()` that occurred when
+decompressing 4:2:2 or 4:2:0 JPEG images using merged (non-fancy)
+upsampling/color conversion (that is, when setting `cinfo.do_fancy_upsampling`
+to `FALSE`.) 2.0.0[6] was a similar fix, but it did not cover all cases.
- `jpeg_skip_scanlines()` now throws an error if two-pass color
quantization is enabled. Two-pass color quantization never worked properly
with `jpeg_skip_scanlines()`, and the issues could not readily be fixed.
diff --git a/LICENSE.md b/LICENSE.md
index d753e1d7..bf8a7fda 100644
--- a/LICENSE.md
+++ b/LICENSE.md
@@ -91,7 +91,7 @@ best of our understanding.
The Modified (3-clause) BSD License
===================================
-Copyright (C)2009-2022 D. R. Commander. All Rights Reserved.<br>
+Copyright (C)2009-2023 D. R. Commander. All Rights Reserved.<br>
Copyright (C)2015 Viktor Szathmáry. All Rights Reserved.
Redistribution and use in source and binary forms, with or without
diff --git a/README.chromium b/README.chromium
index f0159a0d..e94ed285 100644
--- a/README.chromium
+++ b/README.chromium
@@ -1,6 +1,6 @@
Name: libjpeg-turbo
URL: https://github.com/libjpeg-turbo/libjpeg-turbo/
-Version: 2.1.4
+Version: 2.1.5.1
License: Custom license
License File: LICENSE.md
Security Critical: yes
@@ -8,19 +8,19 @@ License Android Compatible: yes
Description:
This consists of the components:
-* libjpeg-turbo 2.1.4
+* libjpeg-turbo 2.1.5.1
* This file (README.chromium)
* A build file (BUILD.gn)
* An OWNERS file
* A codereview.settings file
* A DIR_METADATA file
* Patched header files used by Chromium
-* Deleted unused directories: cmakescripts, doc, fuzz, java, release,
+* Deleted unused directories: .github, cmakescripts, doc, fuzz, java, release,
sharedlib, simd/mips, simd/mips64, simd/powerpc, and win
* Deleted unused files: appveyor.yml, CMakeLists.txt, cjpeg.1, croptest.in,
- djpeg.1, doxygen.config, doxygen-extra.css, .gitattributes, jpegtran.1,
- md5/CMakeLists.txt, md5/md5cmp.c, rdjpgcom.1, simd/CMakeLists.txt, strtest.c,
- tjbenchtest.in, tjbenchtest.java.in, tjexample.c, tjexampletest.in,
+ djpeg.1, doxygen.config, doxygen-extra.css, example.txt, .gitattributes,
+ jpegtran.1, md5/CMakeLists.txt, md5/md5cmp.c, rdjpgcom.1, simd/CMakeLists.txt,
+ strtest.c, tjbenchtest.in, tjbenchtest.java.in, tjexample.c, tjexampletest.in,
tjexampletest.java.in and wrjpgcom.1
* Deleted legacy Arm Neon assembly files (supporting old compiler versions that
do not generate performant code from intrinsics):
diff --git a/cmyk.h b/cmyk.h
index 48187a8f..b6ca20f2 100644
--- a/cmyk.h
+++ b/cmyk.h
@@ -17,7 +17,6 @@
#include <jinclude.h>
#define JPEG_INTERNALS
#include <jpeglib.h>
-#include "jconfigint.h"
/* Fully reversible */
diff --git a/djpeg.c b/djpeg.c
index 68ffed26..7be67563 100644
--- a/djpeg.c
+++ b/djpeg.c
@@ -316,7 +316,9 @@ parse_switches(j_decompress_ptr cinfo, int argc, char **argv,
if (++argn >= argc) /* advance to next argument */
usage();
icc_filename = argv[argn];
+#ifdef SAVE_MARKERS_SUPPORTED
jpeg_save_markers(cinfo, JPEG_APP0 + 2, 0xFFFF);
+#endif
} else if (keymatch(arg, "map", 3)) {
/* Quantize to a color map taken from an input file. */
diff --git a/jccolext.c b/jccolext.c
index 303b322c..20f891a6 100644
--- a/jccolext.c
+++ b/jccolext.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009-2012, 2015, D. R. Commander.
+ * Copyright (C) 2009-2012, 2015, 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -48,9 +48,9 @@ rgb_ycc_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
outptr2 = output_buf[2][output_row];
output_row++;
for (col = 0; col < num_cols; col++) {
- r = inptr[RGB_RED];
- g = inptr[RGB_GREEN];
- b = inptr[RGB_BLUE];
+ r = RANGE_LIMIT(inptr[RGB_RED]);
+ g = RANGE_LIMIT(inptr[RGB_GREEN]);
+ b = RANGE_LIMIT(inptr[RGB_BLUE]);
inptr += RGB_PIXELSIZE;
/* If the inputs are 0..MAXJSAMPLE, the outputs of these equations
* must be too; we do not need an explicit range-limiting operation.
@@ -100,9 +100,9 @@ rgb_gray_convert_internal(j_compress_ptr cinfo, JSAMPARRAY input_buf,
outptr = output_buf[0][output_row];
output_row++;
for (col = 0; col < num_cols; col++) {
- r = inptr[RGB_RED];
- g = inptr[RGB_GREEN];
- b = inptr[RGB_BLUE];
+ r = RANGE_LIMIT(inptr[RGB_RED]);
+ g = RANGE_LIMIT(inptr[RGB_GREEN]);
+ b = RANGE_LIMIT(inptr[RGB_BLUE]);
inptr += RGB_PIXELSIZE;
/* Y */
outptr[col] = (JSAMPLE)((ctab[r + R_Y_OFF] + ctab[g + G_Y_OFF] +
diff --git a/jccolor.c b/jccolor.c
index bdc563c7..fb9f1cc1 100644
--- a/jccolor.c
+++ b/jccolor.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2012, 2015, D. R. Commander.
+ * Copyright (C) 2009-2012, 2015, 2022, D. R. Commander.
* Copyright (C) 2014, MIPS Technologies, Inc., California.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
@@ -17,7 +17,6 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jsimd.h"
-#include "jconfigint.h"
/* Private subobject */
@@ -84,6 +83,18 @@ typedef my_color_converter *my_cconvert_ptr;
#define B_CR_OFF (7 * (MAXJSAMPLE + 1))
#define TABLE_SIZE (8 * (MAXJSAMPLE + 1))
+/* 12-bit samples use a 16-bit data type, so it is possible to pass
+ * out-of-range sample values (< 0 or > 4095) to jpeg_write_scanlines().
+ * Thus, we mask the incoming 12-bit samples to guard against overrunning
+ * or underrunning the conversion tables.
+ */
+
+#if BITS_IN_JSAMPLE == 12
+#define RANGE_LIMIT(value) ((value) & 0xFFF)
+#else
+#define RANGE_LIMIT(value) (value)
+#endif
+
/* Include inline routines for colorspace extensions */
@@ -392,9 +403,9 @@ cmyk_ycck_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
outptr3 = output_buf[3][output_row];
output_row++;
for (col = 0; col < num_cols; col++) {
- r = MAXJSAMPLE - inptr[0];
- g = MAXJSAMPLE - inptr[1];
- b = MAXJSAMPLE - inptr[2];
+ r = MAXJSAMPLE - RANGE_LIMIT(inptr[0]);
+ g = MAXJSAMPLE - RANGE_LIMIT(inptr[1]);
+ b = MAXJSAMPLE - RANGE_LIMIT(inptr[2]);
/* K passes through as-is */
outptr3[col] = inptr[3];
inptr += 4;
diff --git a/jchuff.c b/jchuff.c
index f4dfa1cb..5d0276ad 100644
--- a/jchuff.c
+++ b/jchuff.c
@@ -27,7 +27,6 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jsimd.h"
-#include "jconfigint.h"
#include <limits.h>
/*
diff --git a/jchuff.h b/jchuff.h
index 314a2325..da7809a9 100644
--- a/jchuff.h
+++ b/jchuff.h
@@ -3,8 +3,8 @@
*
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
- * It was modified by The libjpeg-turbo Project to include only code relevant
- * to libjpeg-turbo.
+ * libjpeg-turbo Modifications:
+ * Copyright (C) 2022, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -25,6 +25,14 @@
#define MAX_COEF_BITS 14
#endif
+/* The progressive Huffman encoder uses an unsigned 16-bit data type to store
+ * absolute values of coefficients, because it is possible to inject a
+ * coefficient value of -32768 into the encoder by attempting to transform a
+ * malformed 12-bit JPEG image, and the absolute value of -32768 would overflow
+ * a signed 16-bit integer.
+ */
+typedef unsigned short UJCOEF;
+
/* Derived data constructed for each Huffman table */
typedef struct {
diff --git a/jcmaster.c b/jcmaster.c
index c2b26000..b821710a 100644
--- a/jcmaster.c
+++ b/jcmaster.c
@@ -19,7 +19,6 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jpegcomp.h"
-#include "jconfigint.h"
/* Private state */
diff --git a/jconfig.h b/jconfig.h
index 2366cf12..b33cc955 100644
--- a/jconfig.h
+++ b/jconfig.h
@@ -4,10 +4,10 @@
#define JPEG_LIB_VERSION 62
/* libjpeg-turbo version */
-#define LIBJPEG_TURBO_VERSION 2.1.4
+#define LIBJPEG_TURBO_VERSION 2.1.5.1
/* libjpeg-turbo version in integer form */
-#define LIBJPEG_TURBO_VERSION_NUMBER 2001004
+#define LIBJPEG_TURBO_VERSION_NUMBER 2001005
/* Support arithmetic encoding */
/* #define C_ARITH_CODING_SUPPORTED 1 */
diff --git a/jconfigint.h b/jconfigint.h
index 093659b5..3af3adec 100644
--- a/jconfigint.h
+++ b/jconfigint.h
@@ -26,7 +26,7 @@
#define PACKAGE_NAME "libjpeg-turbo"
/* Version number of package */
-#define VERSION "2.1.4"
+#define VERSION "2.1.5.1"
/* The size of `size_t', as computed by sizeof. */
#include <stdint.h>
diff --git a/jcphuff.c b/jcphuff.c
index 872e570b..5006b670 100644
--- a/jcphuff.c
+++ b/jcphuff.c
@@ -5,7 +5,7 @@
* Copyright (C) 1995-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
* Copyright (C) 2011, 2015, 2018, 2021-2022, D. R. Commander.
- * Copyright (C) 2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2016, 2018, 2022, Matthieu Darbois.
* Copyright (C) 2020, Arm Limited.
* Copyright (C) 2021, Alex Richardson.
* For conditions of distribution and use, see the accompanying README.ijg
@@ -22,7 +22,6 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jsimd.h"
-#include "jconfigint.h"
#include <limits.h>
#ifdef HAVE_INTRIN_H
@@ -83,11 +82,11 @@ typedef struct {
/* Pointer to routine to prepare data for encode_mcu_AC_first() */
void (*AC_first_prepare) (const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *values, size_t *zerobits);
+ int Al, UJCOEF *values, size_t *zerobits);
/* Pointer to routine to prepare data for encode_mcu_AC_refine() */
int (*AC_refine_prepare) (const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *absvalues, size_t *bits);
+ int Al, UJCOEF *absvalues, size_t *bits);
/* Mode flag: TRUE for optimization, FALSE for actual data output */
boolean gather_statistics;
@@ -157,14 +156,14 @@ METHODDEF(boolean) encode_mcu_DC_first(j_compress_ptr cinfo,
JBLOCKROW *MCU_data);
METHODDEF(void) encode_mcu_AC_first_prepare
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
- JCOEF *values, size_t *zerobits);
+ UJCOEF *values, size_t *zerobits);
METHODDEF(boolean) encode_mcu_AC_first(j_compress_ptr cinfo,
JBLOCKROW *MCU_data);
METHODDEF(boolean) encode_mcu_DC_refine(j_compress_ptr cinfo,
JBLOCKROW *MCU_data);
METHODDEF(int) encode_mcu_AC_refine_prepare
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
- JCOEF *absvalues, size_t *bits);
+ UJCOEF *absvalues, size_t *bits);
METHODDEF(boolean) encode_mcu_AC_refine(j_compress_ptr cinfo,
JBLOCKROW *MCU_data);
METHODDEF(void) finish_pass_phuff(j_compress_ptr cinfo);
@@ -584,8 +583,8 @@ encode_mcu_DC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
continue; \
/* For a negative coef, want temp2 = bitwise complement of abs(coef) */ \
temp2 ^= temp; \
- values[k] = (JCOEF)temp; \
- values[k + DCTSIZE2] = (JCOEF)temp2; \
+ values[k] = (UJCOEF)temp; \
+ values[k + DCTSIZE2] = (UJCOEF)temp2; \
zerobits |= ((size_t)1U) << k; \
} \
}
@@ -593,7 +592,7 @@ encode_mcu_DC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
METHODDEF(void)
encode_mcu_AC_first_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *values, size_t *bits)
+ int Al, UJCOEF *values, size_t *bits)
{
register int k, temp, temp2;
size_t zerobits = 0U;
@@ -666,9 +665,9 @@ encode_mcu_AC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
register int nbits, r;
int Sl = cinfo->Se - cinfo->Ss + 1;
int Al = cinfo->Al;
- JCOEF values_unaligned[2 * DCTSIZE2 + 15];
- JCOEF *values;
- const JCOEF *cvalue;
+ UJCOEF values_unaligned[2 * DCTSIZE2 + 15];
+ UJCOEF *values;
+ const UJCOEF *cvalue;
size_t zerobits;
size_t bits[8 / SIZEOF_SIZE_T];
@@ -681,7 +680,7 @@ encode_mcu_AC_first(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
emit_restart(entropy, entropy->next_restart_num);
#ifdef WITH_SIMD
- cvalue = values = (JCOEF *)PAD((JUINTPTR)values_unaligned, 16);
+ cvalue = values = (UJCOEF *)PAD((JUINTPTR)values_unaligned, 16);
#else
/* Not using SIMD, so alignment is not needed */
cvalue = values = values_unaligned;
@@ -815,7 +814,7 @@ encode_mcu_DC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
zerobits |= ((size_t)1U) << k; \
signbits |= ((size_t)(temp2 + 1)) << k; \
} \
- absvalues[k] = (JCOEF)temp; /* save abs value for main pass */ \
+ absvalues[k] = (UJCOEF)temp; /* save abs value for main pass */ \
if (temp == 1) \
EOB = k + koffset; /* EOB = index of last newly-nonzero coef */ \
} \
@@ -824,7 +823,7 @@ encode_mcu_DC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
METHODDEF(int)
encode_mcu_AC_refine_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *absvalues, size_t *bits)
+ int Al, UJCOEF *absvalues, size_t *bits)
{
register int k, temp, temp2;
int EOB = 0;
@@ -931,9 +930,9 @@ encode_mcu_AC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
unsigned int BR;
int Sl = cinfo->Se - cinfo->Ss + 1;
int Al = cinfo->Al;
- JCOEF absvalues_unaligned[DCTSIZE2 + 15];
- JCOEF *absvalues;
- const JCOEF *cabsvalue, *EOBPTR;
+ UJCOEF absvalues_unaligned[DCTSIZE2 + 15];
+ UJCOEF *absvalues;
+ const UJCOEF *cabsvalue, *EOBPTR;
size_t zerobits, signbits;
size_t bits[16 / SIZEOF_SIZE_T];
@@ -946,7 +945,7 @@ encode_mcu_AC_refine(j_compress_ptr cinfo, JBLOCKROW *MCU_data)
emit_restart(entropy, entropy->next_restart_num);
#ifdef WITH_SIMD
- cabsvalue = absvalues = (JCOEF *)PAD((JUINTPTR)absvalues_unaligned, 16);
+ cabsvalue = absvalues = (UJCOEF *)PAD((JUINTPTR)absvalues_unaligned, 16);
#else
/* Not using SIMD, so alignment is not needed */
cabsvalue = absvalues = absvalues_unaligned;
diff --git a/jdapimin.c b/jdapimin.c
index f50c27ed..30126a04 100644
--- a/jdapimin.c
+++ b/jdapimin.c
@@ -23,7 +23,6 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jdmaster.h"
-#include "jconfigint.h"
/*
diff --git a/jdcolext.c b/jdcolext.c
index 863c7a2f..fc7e7b8f 100644
--- a/jdcolext.c
+++ b/jdcolext.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2009, 2011, 2015, D. R. Commander.
+ * Copyright (C) 2009, 2011, 2015, 2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -62,10 +62,10 @@ ycc_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
((int)RIGHT_SHIFT(Cbgtab[cb] + Crgtab[cr],
SCALEBITS))];
outptr[RGB_BLUE] = range_limit[y + Cbbtab[cb]];
- /* Set unused byte to 0xFF so it can be interpreted as an opaque */
+ /* Set unused byte to MAXJSAMPLE so it can be interpreted as an opaque */
/* alpha channel value */
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = 0xFF;
+ outptr[RGB_ALPHA] = MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
@@ -94,10 +94,10 @@ gray_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr = *output_buf++;
for (col = 0; col < num_cols; col++) {
outptr[RGB_RED] = outptr[RGB_GREEN] = outptr[RGB_BLUE] = inptr[col];
- /* Set unused byte to 0xFF so it can be interpreted as an opaque */
+ /* Set unused byte to MAXJSAMPLE so it can be interpreted as an opaque */
/* alpha channel value */
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = 0xFF;
+ outptr[RGB_ALPHA] = MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
@@ -130,10 +130,10 @@ rgb_rgb_convert_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr[RGB_RED] = inptr0[col];
outptr[RGB_GREEN] = inptr1[col];
outptr[RGB_BLUE] = inptr2[col];
- /* Set unused byte to 0xFF so it can be interpreted as an opaque */
+ /* Set unused byte to MAXJSAMPLE so it can be interpreted as an opaque */
/* alpha channel value */
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = 0xFF;
+ outptr[RGB_ALPHA] = MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
diff --git a/jdcolor.c b/jdcolor.c
index 8da2b4ea..735190b7 100644
--- a/jdcolor.c
+++ b/jdcolor.c
@@ -18,7 +18,6 @@
#include "jinclude.h"
#include "jpeglib.h"
#include "jsimd.h"
-#include "jconfigint.h"
/* Private subobject */
diff --git a/jdmainct.c b/jdmainct.c
index f466b259..d332e6b2 100644
--- a/jdmainct.c
+++ b/jdmainct.c
@@ -18,7 +18,6 @@
#include "jinclude.h"
#include "jdmainct.h"
-#include "jconfigint.h"
/*
diff --git a/jdmerge.c b/jdmerge.c
index 3a456d65..38b00272 100644
--- a/jdmerge.c
+++ b/jdmerge.c
@@ -42,7 +42,6 @@
#include "jpeglib.h"
#include "jdmerge.h"
#include "jsimd.h"
-#include "jconfigint.h"
#ifdef UPSAMPLE_MERGING_SUPPORTED
diff --git a/jdmrgext.c b/jdmrgext.c
index 9bf4f1a3..038abc75 100644
--- a/jdmrgext.c
+++ b/jdmrgext.c
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications:
- * Copyright (C) 2011, 2015, 2020, D. R. Commander.
+ * Copyright (C) 2011, 2015, 2020, 2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -57,7 +57,7 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr[RGB_GREEN] = range_limit[y + cgreen];
outptr[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = 0xFF;
+ outptr[RGB_ALPHA] = MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
y = *inptr0++;
@@ -65,7 +65,7 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr[RGB_GREEN] = range_limit[y + cgreen];
outptr[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = 0xFF;
+ outptr[RGB_ALPHA] = MAXJSAMPLE;
#endif
outptr += RGB_PIXELSIZE;
}
@@ -81,7 +81,7 @@ h2v1_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr[RGB_GREEN] = range_limit[y + cgreen];
outptr[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr[RGB_ALPHA] = 0xFF;
+ outptr[RGB_ALPHA] = MAXJSAMPLE;
#endif
}
}
@@ -131,7 +131,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr0[RGB_GREEN] = range_limit[y + cgreen];
outptr0[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr0[RGB_ALPHA] = 0xFF;
+ outptr0[RGB_ALPHA] = MAXJSAMPLE;
#endif
outptr0 += RGB_PIXELSIZE;
y = *inptr00++;
@@ -139,7 +139,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr0[RGB_GREEN] = range_limit[y + cgreen];
outptr0[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr0[RGB_ALPHA] = 0xFF;
+ outptr0[RGB_ALPHA] = MAXJSAMPLE;
#endif
outptr0 += RGB_PIXELSIZE;
y = *inptr01++;
@@ -147,7 +147,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr1[RGB_GREEN] = range_limit[y + cgreen];
outptr1[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr1[RGB_ALPHA] = 0xFF;
+ outptr1[RGB_ALPHA] = MAXJSAMPLE;
#endif
outptr1 += RGB_PIXELSIZE;
y = *inptr01++;
@@ -155,7 +155,7 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr1[RGB_GREEN] = range_limit[y + cgreen];
outptr1[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr1[RGB_ALPHA] = 0xFF;
+ outptr1[RGB_ALPHA] = MAXJSAMPLE;
#endif
outptr1 += RGB_PIXELSIZE;
}
@@ -171,14 +171,14 @@ h2v2_merged_upsample_internal(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
outptr0[RGB_GREEN] = range_limit[y + cgreen];
outptr0[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr0[RGB_ALPHA] = 0xFF;
+ outptr0[RGB_ALPHA] = MAXJSAMPLE;
#endif
y = *inptr01;
outptr1[RGB_RED] = range_limit[y + cred];
outptr1[RGB_GREEN] = range_limit[y + cgreen];
outptr1[RGB_BLUE] = range_limit[y + cblue];
#ifdef RGB_ALPHA
- outptr1[RGB_ALPHA] = 0xFF;
+ outptr1[RGB_ALPHA] = MAXJSAMPLE;
#endif
}
}
diff --git a/jsimd.h b/jsimd.h
index 6c203655..74d480aa 100644
--- a/jsimd.h
+++ b/jsimd.h
@@ -2,8 +2,8 @@
* jsimd.h
*
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2011, 2014, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2011, 2014, 2022, D. R. Commander.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
* Copyright (C) 2020, Arm Limited.
*
* Based on the x86 SIMD extension for IJG JPEG library,
@@ -114,10 +114,10 @@ EXTERN(int) jsimd_can_encode_mcu_AC_first_prepare(void);
EXTERN(void) jsimd_encode_mcu_AC_first_prepare
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
- JCOEF *values, size_t *zerobits);
+ UJCOEF *values, size_t *zerobits);
EXTERN(int) jsimd_can_encode_mcu_AC_refine_prepare(void);
EXTERN(int) jsimd_encode_mcu_AC_refine_prepare
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
- JCOEF *absvalues, size_t *bits);
+ UJCOEF *absvalues, size_t *bits);
diff --git a/jsimd_none.c b/jsimd_none.c
index 5b38a9fb..a25db738 100644
--- a/jsimd_none.c
+++ b/jsimd_none.c
@@ -2,8 +2,8 @@
* jsimd_none.c
*
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2009-2011, 2014, 2022, D. R. Commander.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
* Copyright (C) 2020, Arm Limited.
*
* Based on the x86 SIMD extension for IJG JPEG library,
@@ -412,7 +412,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
GLOBAL(void)
jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *values, size_t *zerobits)
+ int Al, UJCOEF *values, size_t *zerobits)
{
}
@@ -425,7 +425,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
GLOBAL(int)
jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *absvalues, size_t *bits)
+ int Al, UJCOEF *absvalues, size_t *bits)
{
return 0;
}
diff --git a/jversion.h b/jversion.h
index 63db95b9..3d1c61a4 100644
--- a/jversion.h
+++ b/jversion.h
@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-2020, Thomas G. Lane, Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2010, 2012-2022, D. R. Commander.
+ * Copyright (C) 2010, 2012-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -37,7 +37,7 @@
*/
#define JCOPYRIGHT \
- "Copyright (C) 2009-2022 D. R. Commander\n" \
+ "Copyright (C) 2009-2023 D. R. Commander\n" \
"Copyright (C) 2015, 2020 Google, Inc.\n" \
"Copyright (C) 2019-2020 Arm Limited\n" \
"Copyright (C) 2015-2016, 2018 Matthieu Darbois\n" \
diff --git a/rdppm.c b/rdppm.c
index 294749a4..883641d8 100644
--- a/rdppm.c
+++ b/rdppm.c
@@ -5,7 +5,7 @@
* Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2009 by Bill Allombert, Guido Vollbeding.
* libjpeg-turbo Modifications:
- * Copyright (C) 2015-2017, 2020-2022, D. R. Commander.
+ * Copyright (C) 2015-2017, 2020-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg
* file.
*
@@ -179,13 +179,13 @@ get_text_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
if (maxval == MAXJSAMPLE) {
if (aindex >= 0)
GRAY_RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
- ptr[aindex] = 0xFF;)
+ ptr[aindex] = MAXJSAMPLE;)
else
GRAY_RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {})
} else {
if (aindex >= 0)
GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],
- ptr[aindex] = 0xFF;)
+ ptr[aindex] = MAXJSAMPLE;)
else
GRAY_RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {})
}
@@ -253,13 +253,13 @@ get_text_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
if (maxval == MAXJSAMPLE) {
if (aindex >= 0)
RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval),
- ptr[aindex] = 0xFF;)
+ ptr[aindex] = MAXJSAMPLE;)
else
RGB_READ_LOOP((JSAMPLE)read_pbm_integer(cinfo, infile, maxval), {})
} else {
if (aindex >= 0)
RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)],
- ptr[aindex] = 0xFF;)
+ ptr[aindex] = MAXJSAMPLE;)
else
RGB_READ_LOOP(rescale[read_pbm_integer(cinfo, infile, maxval)], {})
}
@@ -345,12 +345,12 @@ get_gray_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
bufferptr = source->iobuffer;
if (maxval == MAXJSAMPLE) {
if (aindex >= 0)
- GRAY_RGB_READ_LOOP(*bufferptr++, ptr[aindex] = 0xFF;)
+ GRAY_RGB_READ_LOOP(*bufferptr++, ptr[aindex] = MAXJSAMPLE;)
else
GRAY_RGB_READ_LOOP(*bufferptr++, {})
} else {
if (aindex >= 0)
- GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = 0xFF;)
+ GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = MAXJSAMPLE;)
else
GRAY_RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {})
}
@@ -413,12 +413,12 @@ get_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
bufferptr = source->iobuffer;
if (maxval == MAXJSAMPLE) {
if (aindex >= 0)
- RGB_READ_LOOP(*bufferptr++, ptr[aindex] = 0xFF;)
+ RGB_READ_LOOP(*bufferptr++, ptr[aindex] = MAXJSAMPLE;)
else
RGB_READ_LOOP(*bufferptr++, {})
} else {
if (aindex >= 0)
- RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = 0xFF;)
+ RGB_READ_LOOP(rescale[UCH(*bufferptr++)], ptr[aindex] = MAXJSAMPLE;)
else
RGB_READ_LOOP(rescale[UCH(*bufferptr++)], {})
}
@@ -543,7 +543,7 @@ get_word_rgb_row(j_compress_ptr cinfo, cjpeg_source_ptr sinfo)
ERREXIT(cinfo, JERR_PPM_OUTOFRANGE);
ptr[bindex] = rescale[temp];
if (aindex >= 0)
- ptr[aindex] = 0xFF;
+ ptr[aindex] = MAXJSAMPLE;
ptr += ps;
}
return 1;
diff --git a/simd/arm/aarch32/jsimd.c b/simd/arm/aarch32/jsimd.c
index 920f7656..04d64526 100644
--- a/simd/arm/aarch32/jsimd.c
+++ b/simd/arm/aarch32/jsimd.c
@@ -4,7 +4,7 @@
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
* Copyright (C) 2019, Google LLC.
* Copyright (C) 2020, Arm Limited.
*
@@ -27,8 +27,8 @@
#include <ctype.h>
-static unsigned int simd_support = ~0;
-static unsigned int simd_huffman = 1;
+static THREAD_LOCAL unsigned int simd_support = ~0;
+static THREAD_LOCAL unsigned int simd_huffman = 1;
#if !defined(__ARM_NEON__) && (defined(__linux__) || defined(ANDROID) || defined(__ANDROID__))
@@ -96,8 +96,6 @@ parse_proc_cpuinfo(int bufsize)
/*
* Check what SIMD accelerations are supported.
- *
- * FIXME: This code is racy under a multi-threaded environment.
*/
LOCAL(void)
init_simd(void)
@@ -945,7 +943,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
GLOBAL(void)
jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *values, size_t *zerobits)
+ int Al, UJCOEF *values, size_t *zerobits)
{
jsimd_encode_mcu_AC_first_prepare_neon(block, jpeg_natural_order_start,
Sl, Al, values, zerobits);
@@ -970,7 +968,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
GLOBAL(int)
jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *absvalues, size_t *bits)
+ int Al, UJCOEF *absvalues, size_t *bits)
{
return jsimd_encode_mcu_AC_refine_prepare_neon(block,
jpeg_natural_order_start, Sl,
diff --git a/simd/arm/aarch64/jsimd.c b/simd/arm/aarch64/jsimd.c
index 41c06d31..358e1597 100644
--- a/simd/arm/aarch64/jsimd.c
+++ b/simd/arm/aarch64/jsimd.c
@@ -4,7 +4,7 @@
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2011, Nokia Corporation and/or its subsidiary(-ies).
* Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2020, 2022, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
* Copyright (C) 2020, Arm Limited.
*
* Based on the x86 SIMD extension for IJG JPEG library,
@@ -23,7 +23,6 @@
#include "../../../jdct.h"
#include "../../../jsimddct.h"
#include "../../jsimd.h"
-#include "jconfigint.h"
#include <ctype.h>
@@ -31,10 +30,10 @@
#define JSIMD_FASTST3 2
#define JSIMD_FASTTBL 4
-static unsigned int simd_support = ~0;
-static unsigned int simd_huffman = 1;
-static unsigned int simd_features = JSIMD_FASTLD3 | JSIMD_FASTST3 |
- JSIMD_FASTTBL;
+static THREAD_LOCAL unsigned int simd_support = ~0;
+static THREAD_LOCAL unsigned int simd_huffman = 1;
+static THREAD_LOCAL unsigned int simd_features = JSIMD_FASTLD3 |
+ JSIMD_FASTST3 | JSIMD_FASTTBL;
#if defined(__linux__) || defined(ANDROID) || defined(__ANDROID__)
@@ -109,8 +108,6 @@ parse_proc_cpuinfo(int bufsize)
/*
* Check what SIMD accelerations are supported.
- *
- * FIXME: This code is racy under a multi-threaded environment.
*/
/*
@@ -1021,7 +1018,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
GLOBAL(void)
jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *values, size_t *zerobits)
+ int Al, UJCOEF *values, size_t *zerobits)
{
jsimd_encode_mcu_AC_first_prepare_neon(block, jpeg_natural_order_start,
Sl, Al, values, zerobits);
@@ -1048,7 +1045,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
GLOBAL(int)
jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *absvalues, size_t *bits)
+ int Al, UJCOEF *absvalues, size_t *bits)
{
return jsimd_encode_mcu_AC_refine_prepare_neon(block,
jpeg_natural_order_start,
diff --git a/simd/arm/jcphuff-neon.c b/simd/arm/jcphuff-neon.c
index b91c5db4..51db3c5f 100644
--- a/simd/arm/jcphuff-neon.c
+++ b/simd/arm/jcphuff-neon.c
@@ -2,6 +2,8 @@
* jcphuff-neon.c - prepare data for progressive Huffman encoding (Arm Neon)
*
* Copyright (C) 2020-2021, Arm Limited. All Rights Reserved.
+ * Copyright (C) 2022, Matthieu Darbois. All Rights Reserved.
+ * Copyright (C) 2022, D. R. Commander. All Rights Reserved.
*
* This software is provided 'as-is', without any express or implied
* warranty. In no event will the authors be held liable for any damages
@@ -21,7 +23,6 @@
*/
#define JPEG_INTERNALS
-#include "jconfigint.h"
#include "../../jinclude.h"
#include "../../jpeglib.h"
#include "../../jsimd.h"
@@ -41,10 +42,10 @@
void jsimd_encode_mcu_AC_first_prepare_neon
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
- JCOEF *values, size_t *zerobits)
+ UJCOEF *values, size_t *zerobits)
{
- JCOEF *values_ptr = values;
- JCOEF *diff_values_ptr = values + DCTSIZE2;
+ UJCOEF *values_ptr = values;
+ UJCOEF *diff_values_ptr = values + DCTSIZE2;
/* Rows of coefficients to zero (since they haven't been processed) */
int i, rows_to_zero = 8;
@@ -68,23 +69,23 @@ void jsimd_encode_mcu_AC_first_prepare_neon
coefs2 = vld1q_lane_s16(block + jpeg_natural_order_start[15], coefs2, 7);
/* Isolate sign of coefficients. */
- int16x8_t sign_coefs1 = vshrq_n_s16(coefs1, 15);
- int16x8_t sign_coefs2 = vshrq_n_s16(coefs2, 15);
+ uint16x8_t sign_coefs1 = vreinterpretq_u16_s16(vshrq_n_s16(coefs1, 15));
+ uint16x8_t sign_coefs2 = vreinterpretq_u16_s16(vshrq_n_s16(coefs2, 15));
/* Compute absolute value of coefficients and apply point transform Al. */
- int16x8_t abs_coefs1 = vabsq_s16(coefs1);
- int16x8_t abs_coefs2 = vabsq_s16(coefs2);
- coefs1 = vshlq_s16(abs_coefs1, vdupq_n_s16(-Al));
- coefs2 = vshlq_s16(abs_coefs2, vdupq_n_s16(-Al));
+ uint16x8_t abs_coefs1 = vreinterpretq_u16_s16(vabsq_s16(coefs1));
+ uint16x8_t abs_coefs2 = vreinterpretq_u16_s16(vabsq_s16(coefs2));
+ abs_coefs1 = vshlq_u16(abs_coefs1, vdupq_n_s16(-Al));
+ abs_coefs2 = vshlq_u16(abs_coefs2, vdupq_n_s16(-Al));
/* Compute diff values. */
- int16x8_t diff1 = veorq_s16(coefs1, sign_coefs1);
- int16x8_t diff2 = veorq_s16(coefs2, sign_coefs2);
+ uint16x8_t diff1 = veorq_u16(abs_coefs1, sign_coefs1);
+ uint16x8_t diff2 = veorq_u16(abs_coefs2, sign_coefs2);
/* Store transformed coefficients and diff values. */
- vst1q_s16(values_ptr, coefs1);
- vst1q_s16(values_ptr + DCTSIZE, coefs2);
- vst1q_s16(diff_values_ptr, diff1);
- vst1q_s16(diff_values_ptr + DCTSIZE, diff2);
+ vst1q_u16(values_ptr, abs_coefs1);
+ vst1q_u16(values_ptr + DCTSIZE, abs_coefs2);
+ vst1q_u16(diff_values_ptr, diff1);
+ vst1q_u16(diff_values_ptr + DCTSIZE, diff2);
values_ptr += 16;
diff_values_ptr += 16;
jpeg_natural_order_start += 16;
@@ -130,23 +131,23 @@ void jsimd_encode_mcu_AC_first_prepare_neon
}
/* Isolate sign of coefficients. */
- int16x8_t sign_coefs1 = vshrq_n_s16(coefs1, 15);
- int16x8_t sign_coefs2 = vshrq_n_s16(coefs2, 15);
+ uint16x8_t sign_coefs1 = vreinterpretq_u16_s16(vshrq_n_s16(coefs1, 15));
+ uint16x8_t sign_coefs2 = vreinterpretq_u16_s16(vshrq_n_s16(coefs2, 15));
/* Compute absolute value of coefficients and apply point transform Al. */
- int16x8_t abs_coefs1 = vabsq_s16(coefs1);
- int16x8_t abs_coefs2 = vabsq_s16(coefs2);
- coefs1 = vshlq_s16(abs_coefs1, vdupq_n_s16(-Al));
- coefs2 = vshlq_s16(abs_coefs2, vdupq_n_s16(-Al));
+ uint16x8_t abs_coefs1 = vreinterpretq_u16_s16(vabsq_s16(coefs1));
+ uint16x8_t abs_coefs2 = vreinterpretq_u16_s16(vabsq_s16(coefs2));
+ abs_coefs1 = vshlq_u16(abs_coefs1, vdupq_n_s16(-Al));
+ abs_coefs2 = vshlq_u16(abs_coefs2, vdupq_n_s16(-Al));
/* Compute diff values. */
- int16x8_t diff1 = veorq_s16(coefs1, sign_coefs1);
- int16x8_t diff2 = veorq_s16(coefs2, sign_coefs2);
+ uint16x8_t diff1 = veorq_u16(abs_coefs1, sign_coefs1);
+ uint16x8_t diff2 = veorq_u16(abs_coefs2, sign_coefs2);
/* Store transformed coefficients and diff values. */
- vst1q_s16(values_ptr, coefs1);
- vst1q_s16(values_ptr + DCTSIZE, coefs2);
- vst1q_s16(diff_values_ptr, diff1);
- vst1q_s16(diff_values_ptr + DCTSIZE, diff2);
+ vst1q_u16(values_ptr, abs_coefs1);
+ vst1q_u16(values_ptr + DCTSIZE, abs_coefs2);
+ vst1q_u16(diff_values_ptr, diff1);
+ vst1q_u16(diff_values_ptr + DCTSIZE, diff2);
values_ptr += 16;
diff_values_ptr += 16;
rows_to_zero -= 2;
@@ -184,17 +185,17 @@ void jsimd_encode_mcu_AC_first_prepare_neon
}
/* Isolate sign of coefficients. */
- int16x8_t sign_coefs = vshrq_n_s16(coefs, 15);
+ uint16x8_t sign_coefs = vreinterpretq_u16_s16(vshrq_n_s16(coefs, 15));
/* Compute absolute value of coefficients and apply point transform Al. */
- int16x8_t abs_coefs = vabsq_s16(coefs);
- coefs = vshlq_s16(abs_coefs, vdupq_n_s16(-Al));
+ uint16x8_t abs_coefs = vreinterpretq_u16_s16(vabsq_s16(coefs));
+ abs_coefs = vshlq_u16(abs_coefs, vdupq_n_s16(-Al));
/* Compute diff values. */
- int16x8_t diff = veorq_s16(coefs, sign_coefs);
+ uint16x8_t diff = veorq_u16(abs_coefs, sign_coefs);
/* Store transformed coefficients and diff values. */
- vst1q_s16(values_ptr, coefs);
- vst1q_s16(diff_values_ptr, diff);
+ vst1q_u16(values_ptr, abs_coefs);
+ vst1q_u16(diff_values_ptr, diff);
values_ptr += 8;
diff_values_ptr += 8;
rows_to_zero--;
@@ -202,8 +203,8 @@ void jsimd_encode_mcu_AC_first_prepare_neon
/* Zero remaining memory in the values and diff_values blocks. */
for (i = 0; i < rows_to_zero; i++) {
- vst1q_s16(values_ptr, vdupq_n_s16(0));
- vst1q_s16(diff_values_ptr, vdupq_n_s16(0));
+ vst1q_u16(values_ptr, vdupq_n_u16(0));
+ vst1q_u16(diff_values_ptr, vdupq_n_u16(0));
values_ptr += 8;
diff_values_ptr += 8;
}
@@ -211,23 +212,23 @@ void jsimd_encode_mcu_AC_first_prepare_neon
/* Construct zerobits bitmap. A set bit means that the corresponding
* coefficient != 0.
*/
- int16x8_t row0 = vld1q_s16(values + 0 * DCTSIZE);
- int16x8_t row1 = vld1q_s16(values + 1 * DCTSIZE);
- int16x8_t row2 = vld1q_s16(values + 2 * DCTSIZE);
- int16x8_t row3 = vld1q_s16(values + 3 * DCTSIZE);
- int16x8_t row4 = vld1q_s16(values + 4 * DCTSIZE);
- int16x8_t row5 = vld1q_s16(values + 5 * DCTSIZE);
- int16x8_t row6 = vld1q_s16(values + 6 * DCTSIZE);
- int16x8_t row7 = vld1q_s16(values + 7 * DCTSIZE);
-
- uint8x8_t row0_eq0 = vmovn_u16(vceqq_s16(row0, vdupq_n_s16(0)));
- uint8x8_t row1_eq0 = vmovn_u16(vceqq_s16(row1, vdupq_n_s16(0)));
- uint8x8_t row2_eq0 = vmovn_u16(vceqq_s16(row2, vdupq_n_s16(0)));
- uint8x8_t row3_eq0 = vmovn_u16(vceqq_s16(row3, vdupq_n_s16(0)));
- uint8x8_t row4_eq0 = vmovn_u16(vceqq_s16(row4, vdupq_n_s16(0)));
- uint8x8_t row5_eq0 = vmovn_u16(vceqq_s16(row5, vdupq_n_s16(0)));
- uint8x8_t row6_eq0 = vmovn_u16(vceqq_s16(row6, vdupq_n_s16(0)));
- uint8x8_t row7_eq0 = vmovn_u16(vceqq_s16(row7, vdupq_n_s16(0)));
+ uint16x8_t row0 = vld1q_u16(values + 0 * DCTSIZE);
+ uint16x8_t row1 = vld1q_u16(values + 1 * DCTSIZE);
+ uint16x8_t row2 = vld1q_u16(values + 2 * DCTSIZE);
+ uint16x8_t row3 = vld1q_u16(values + 3 * DCTSIZE);
+ uint16x8_t row4 = vld1q_u16(values + 4 * DCTSIZE);
+ uint16x8_t row5 = vld1q_u16(values + 5 * DCTSIZE);
+ uint16x8_t row6 = vld1q_u16(values + 6 * DCTSIZE);
+ uint16x8_t row7 = vld1q_u16(values + 7 * DCTSIZE);
+
+ uint8x8_t row0_eq0 = vmovn_u16(vceqq_u16(row0, vdupq_n_u16(0)));
+ uint8x8_t row1_eq0 = vmovn_u16(vceqq_u16(row1, vdupq_n_u16(0)));
+ uint8x8_t row2_eq0 = vmovn_u16(vceqq_u16(row2, vdupq_n_u16(0)));
+ uint8x8_t row3_eq0 = vmovn_u16(vceqq_u16(row3, vdupq_n_u16(0)));
+ uint8x8_t row4_eq0 = vmovn_u16(vceqq_u16(row4, vdupq_n_u16(0)));
+ uint8x8_t row5_eq0 = vmovn_u16(vceqq_u16(row5, vdupq_n_u16(0)));
+ uint8x8_t row6_eq0 = vmovn_u16(vceqq_u16(row6, vdupq_n_u16(0)));
+ uint8x8_t row7_eq0 = vmovn_u16(vceqq_u16(row7, vdupq_n_u16(0)));
/* { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 } */
const uint8x8_t bitmap_mask =
@@ -274,7 +275,7 @@ void jsimd_encode_mcu_AC_first_prepare_neon
int jsimd_encode_mcu_AC_refine_prepare_neon
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
- JCOEF *absvalues, size_t *bits)
+ UJCOEF *absvalues, size_t *bits)
{
/* Temporary storage buffers for data used to compute the signbits bitmap and
* the end-of-block (EOB) position
@@ -282,7 +283,7 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
uint8_t coef_sign_bits[64];
uint8_t coef_eq1_bits[64];
- JCOEF *absvalues_ptr = absvalues;
+ UJCOEF *absvalues_ptr = absvalues;
uint8_t *coef_sign_bits_ptr = coef_sign_bits;
uint8_t *eq1_bits_ptr = coef_eq1_bits;
@@ -316,18 +317,18 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
vst1_u8(coef_sign_bits_ptr + DCTSIZE, sign_coefs2);
/* Compute absolute value of coefficients and apply point transform Al. */
- int16x8_t abs_coefs1 = vabsq_s16(coefs1);
- int16x8_t abs_coefs2 = vabsq_s16(coefs2);
- coefs1 = vshlq_s16(abs_coefs1, vdupq_n_s16(-Al));
- coefs2 = vshlq_s16(abs_coefs2, vdupq_n_s16(-Al));
- vst1q_s16(absvalues_ptr, coefs1);
- vst1q_s16(absvalues_ptr + DCTSIZE, coefs2);
+ uint16x8_t abs_coefs1 = vreinterpretq_u16_s16(vabsq_s16(coefs1));
+ uint16x8_t abs_coefs2 = vreinterpretq_u16_s16(vabsq_s16(coefs2));
+ abs_coefs1 = vshlq_u16(abs_coefs1, vdupq_n_s16(-Al));
+ abs_coefs2 = vshlq_u16(abs_coefs2, vdupq_n_s16(-Al));
+ vst1q_u16(absvalues_ptr, abs_coefs1);
+ vst1q_u16(absvalues_ptr + DCTSIZE, abs_coefs2);
/* Test whether transformed coefficient values == 1 (used to find EOB
* position.)
*/
- uint8x8_t coefs_eq11 = vmovn_u16(vceqq_s16(coefs1, vdupq_n_s16(1)));
- uint8x8_t coefs_eq12 = vmovn_u16(vceqq_s16(coefs2, vdupq_n_s16(1)));
+ uint8x8_t coefs_eq11 = vmovn_u16(vceqq_u16(abs_coefs1, vdupq_n_u16(1)));
+ uint8x8_t coefs_eq12 = vmovn_u16(vceqq_u16(abs_coefs2, vdupq_n_u16(1)));
vst1_u8(eq1_bits_ptr, coefs_eq11);
vst1_u8(eq1_bits_ptr + DCTSIZE, coefs_eq12);
@@ -385,18 +386,18 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
vst1_u8(coef_sign_bits_ptr + DCTSIZE, sign_coefs2);
/* Compute absolute value of coefficients and apply point transform Al. */
- int16x8_t abs_coefs1 = vabsq_s16(coefs1);
- int16x8_t abs_coefs2 = vabsq_s16(coefs2);
- coefs1 = vshlq_s16(abs_coefs1, vdupq_n_s16(-Al));
- coefs2 = vshlq_s16(abs_coefs2, vdupq_n_s16(-Al));
- vst1q_s16(absvalues_ptr, coefs1);
- vst1q_s16(absvalues_ptr + DCTSIZE, coefs2);
+ uint16x8_t abs_coefs1 = vreinterpretq_u16_s16(vabsq_s16(coefs1));
+ uint16x8_t abs_coefs2 = vreinterpretq_u16_s16(vabsq_s16(coefs2));
+ abs_coefs1 = vshlq_u16(abs_coefs1, vdupq_n_s16(-Al));
+ abs_coefs2 = vshlq_u16(abs_coefs2, vdupq_n_s16(-Al));
+ vst1q_u16(absvalues_ptr, abs_coefs1);
+ vst1q_u16(absvalues_ptr + DCTSIZE, abs_coefs2);
/* Test whether transformed coefficient values == 1 (used to find EOB
* position.)
*/
- uint8x8_t coefs_eq11 = vmovn_u16(vceqq_s16(coefs1, vdupq_n_s16(1)));
- uint8x8_t coefs_eq12 = vmovn_u16(vceqq_s16(coefs2, vdupq_n_s16(1)));
+ uint8x8_t coefs_eq11 = vmovn_u16(vceqq_u16(abs_coefs1, vdupq_n_u16(1)));
+ uint8x8_t coefs_eq12 = vmovn_u16(vceqq_u16(abs_coefs2, vdupq_n_u16(1)));
vst1_u8(eq1_bits_ptr, coefs_eq11);
vst1_u8(eq1_bits_ptr + DCTSIZE, coefs_eq12);
@@ -444,14 +445,14 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
vst1_u8(coef_sign_bits_ptr, sign_coefs);
/* Compute absolute value of coefficients and apply point transform Al. */
- int16x8_t abs_coefs = vabsq_s16(coefs);
- coefs = vshlq_s16(abs_coefs, vdupq_n_s16(-Al));
- vst1q_s16(absvalues_ptr, coefs);
+ uint16x8_t abs_coefs = vreinterpretq_u16_s16(vabsq_s16(coefs));
+ abs_coefs = vshlq_u16(abs_coefs, vdupq_n_s16(-Al));
+ vst1q_u16(absvalues_ptr, abs_coefs);
/* Test whether transformed coefficient values == 1 (used to find EOB
* position.)
*/
- uint8x8_t coefs_eq1 = vmovn_u16(vceqq_s16(coefs, vdupq_n_s16(1)));
+ uint8x8_t coefs_eq1 = vmovn_u16(vceqq_u16(abs_coefs, vdupq_n_u16(1)));
vst1_u8(eq1_bits_ptr, coefs_eq1);
absvalues_ptr += 8;
@@ -462,7 +463,7 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
/* Zero remaining memory in blocks. */
for (i = 0; i < rows_to_zero; i++) {
- vst1q_s16(absvalues_ptr, vdupq_n_s16(0));
+ vst1q_u16(absvalues_ptr, vdupq_n_u16(0));
vst1_u8(coef_sign_bits_ptr, vdup_n_u8(0));
vst1_u8(eq1_bits_ptr, vdup_n_u8(0));
absvalues_ptr += 8;
@@ -471,23 +472,23 @@ int jsimd_encode_mcu_AC_refine_prepare_neon
}
/* Construct zerobits bitmap. */
- int16x8_t abs_row0 = vld1q_s16(absvalues + 0 * DCTSIZE);
- int16x8_t abs_row1 = vld1q_s16(absvalues + 1 * DCTSIZE);
- int16x8_t abs_row2 = vld1q_s16(absvalues + 2 * DCTSIZE);
- int16x8_t abs_row3 = vld1q_s16(absvalues + 3 * DCTSIZE);
- int16x8_t abs_row4 = vld1q_s16(absvalues + 4 * DCTSIZE);
- int16x8_t abs_row5 = vld1q_s16(absvalues + 5 * DCTSIZE);
- int16x8_t abs_row6 = vld1q_s16(absvalues + 6 * DCTSIZE);
- int16x8_t abs_row7 = vld1q_s16(absvalues + 7 * DCTSIZE);
-
- uint8x8_t abs_row0_eq0 = vmovn_u16(vceqq_s16(abs_row0, vdupq_n_s16(0)));
- uint8x8_t abs_row1_eq0 = vmovn_u16(vceqq_s16(abs_row1, vdupq_n_s16(0)));
- uint8x8_t abs_row2_eq0 = vmovn_u16(vceqq_s16(abs_row2, vdupq_n_s16(0)));
- uint8x8_t abs_row3_eq0 = vmovn_u16(vceqq_s16(abs_row3, vdupq_n_s16(0)));
- uint8x8_t abs_row4_eq0 = vmovn_u16(vceqq_s16(abs_row4, vdupq_n_s16(0)));
- uint8x8_t abs_row5_eq0 = vmovn_u16(vceqq_s16(abs_row5, vdupq_n_s16(0)));
- uint8x8_t abs_row6_eq0 = vmovn_u16(vceqq_s16(abs_row6, vdupq_n_s16(0)));
- uint8x8_t abs_row7_eq0 = vmovn_u16(vceqq_s16(abs_row7, vdupq_n_s16(0)));
+ uint16x8_t abs_row0 = vld1q_u16(absvalues + 0 * DCTSIZE);
+ uint16x8_t abs_row1 = vld1q_u16(absvalues + 1 * DCTSIZE);
+ uint16x8_t abs_row2 = vld1q_u16(absvalues + 2 * DCTSIZE);
+ uint16x8_t abs_row3 = vld1q_u16(absvalues + 3 * DCTSIZE);
+ uint16x8_t abs_row4 = vld1q_u16(absvalues + 4 * DCTSIZE);
+ uint16x8_t abs_row5 = vld1q_u16(absvalues + 5 * DCTSIZE);
+ uint16x8_t abs_row6 = vld1q_u16(absvalues + 6 * DCTSIZE);
+ uint16x8_t abs_row7 = vld1q_u16(absvalues + 7 * DCTSIZE);
+
+ uint8x8_t abs_row0_eq0 = vmovn_u16(vceqq_u16(abs_row0, vdupq_n_u16(0)));
+ uint8x8_t abs_row1_eq0 = vmovn_u16(vceqq_u16(abs_row1, vdupq_n_u16(0)));
+ uint8x8_t abs_row2_eq0 = vmovn_u16(vceqq_u16(abs_row2, vdupq_n_u16(0)));
+ uint8x8_t abs_row3_eq0 = vmovn_u16(vceqq_u16(abs_row3, vdupq_n_u16(0)));
+ uint8x8_t abs_row4_eq0 = vmovn_u16(vceqq_u16(abs_row4, vdupq_n_u16(0)));
+ uint8x8_t abs_row5_eq0 = vmovn_u16(vceqq_u16(abs_row5, vdupq_n_u16(0)));
+ uint8x8_t abs_row6_eq0 = vmovn_u16(vceqq_u16(abs_row6, vdupq_n_u16(0)));
+ uint8x8_t abs_row7_eq0 = vmovn_u16(vceqq_u16(abs_row7, vdupq_n_u16(0)));
/* { 0x01, 0x02, 0x04, 0x08, 0x10, 0x20, 0x40, 0x80 } */
const uint8x8_t bitmap_mask =
diff --git a/simd/arm/jdcolor-neon.c b/simd/arm/jdcolor-neon.c
index ea4668f1..28dbc572 100644
--- a/simd/arm/jdcolor-neon.c
+++ b/simd/arm/jdcolor-neon.c
@@ -21,7 +21,6 @@
*/
#define JPEG_INTERNALS
-#include "jconfigint.h"
#include "../../jinclude.h"
#include "../../jpeglib.h"
#include "../../jsimd.h"
diff --git a/simd/arm/jdmerge-neon.c b/simd/arm/jdmerge-neon.c
index e4f91fdc..18fb9d8a 100644
--- a/simd/arm/jdmerge-neon.c
+++ b/simd/arm/jdmerge-neon.c
@@ -21,7 +21,6 @@
*/
#define JPEG_INTERNALS
-#include "jconfigint.h"
#include "../../jinclude.h"
#include "../../jpeglib.h"
#include "../../jsimd.h"
diff --git a/simd/arm/jidctint-neon.c b/simd/arm/jidctint-neon.c
index 043b652e..d25112ef 100644
--- a/simd/arm/jidctint-neon.c
+++ b/simd/arm/jidctint-neon.c
@@ -22,7 +22,6 @@
*/
#define JPEG_INTERNALS
-#include "jconfigint.h"
#include "../../jinclude.h"
#include "../../jpeglib.h"
#include "../../jsimd.h"
diff --git a/simd/i386/jsimd.c b/simd/i386/jsimd.c
index 80bc821f..b429b0a5 100644
--- a/simd/i386/jsimd.c
+++ b/simd/i386/jsimd.c
@@ -2,8 +2,8 @@
* jsimd_i386.c
*
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022-2023, D. R. Commander.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
*
* Based on the x86 SIMD extension for IJG JPEG library,
* Copyright (C) 1999-2006, MIYASAKA Masaru.
@@ -21,7 +21,6 @@
#include "../../jdct.h"
#include "../../jsimddct.h"
#include "../jsimd.h"
-#include "jconfigint.h"
/*
* In the PIC cases, we have no guarantee that constants will keep
@@ -32,13 +31,11 @@
#define IS_ALIGNED_SSE(ptr) (IS_ALIGNED(ptr, 4)) /* 16 byte alignment */
#define IS_ALIGNED_AVX(ptr) (IS_ALIGNED(ptr, 5)) /* 32 byte alignment */
-static unsigned int simd_support = (unsigned int)(~0);
-static unsigned int simd_huffman = 1;
+static THREAD_LOCAL unsigned int simd_support = (unsigned int)(~0);
+static THREAD_LOCAL unsigned int simd_huffman = 1;
/*
* Check what SIMD accelerations are supported.
- *
- * FIXME: This code is racy under a multi-threaded environment.
*/
LOCAL(void)
init_simd(void)
@@ -161,6 +158,9 @@ jsimd_rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
void (*mmxfct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
+ if (simd_support == ~0U)
+ init_simd();
+
switch (cinfo->in_color_space) {
case JCS_EXT_RGB:
avx2fct = jsimd_extrgb_ycc_convert_avx2;
@@ -220,6 +220,9 @@ jsimd_rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
void (*mmxfct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
+ if (simd_support == ~0U)
+ init_simd();
+
switch (cinfo->in_color_space) {
case JCS_EXT_RGB:
avx2fct = jsimd_extrgb_gray_convert_avx2;
@@ -279,6 +282,9 @@ jsimd_ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
+ if (simd_support == ~0U)
+ init_simd();
+
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
avx2fct = jsimd_ycc_extrgb_convert_avx2;
@@ -382,6 +388,9 @@ GLOBAL(void)
jsimd_h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v2_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
compptr->v_samp_factor,
@@ -402,6 +411,9 @@ GLOBAL(void)
jsimd_h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v1_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
compptr->v_samp_factor,
@@ -464,6 +476,9 @@ GLOBAL(void)
jsimd_h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v2_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
input_data, output_data_ptr);
@@ -479,6 +494,9 @@ GLOBAL(void)
jsimd_h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v1_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
input_data, output_data_ptr);
@@ -540,6 +558,9 @@ GLOBAL(void)
jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v2_fancy_upsample_avx2(cinfo->max_v_samp_factor,
compptr->downsampled_width, input_data,
@@ -558,6 +579,9 @@ GLOBAL(void)
jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v1_fancy_upsample_avx2(cinfo->max_v_samp_factor,
compptr->downsampled_width, input_data,
@@ -626,6 +650,9 @@ jsimd_h2v2_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
+ if (simd_support == ~0U)
+ init_simd();
+
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
avx2fct = jsimd_h2v2_extrgb_merged_upsample_avx2;
@@ -684,6 +711,9 @@ jsimd_h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
+ if (simd_support == ~0U)
+ init_simd();
+
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
avx2fct = jsimd_h2v1_extrgb_merged_upsample_avx2;
@@ -788,6 +818,9 @@ GLOBAL(void)
jsimd_convsamp(JSAMPARRAY sample_data, JDIMENSION start_col,
DCTELEM *workspace)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_convsamp_avx2(sample_data, start_col, workspace);
else if (simd_support & JSIMD_SSE2)
@@ -800,6 +833,9 @@ GLOBAL(void)
jsimd_convsamp_float(JSAMPARRAY sample_data, JDIMENSION start_col,
FAST_FLOAT *workspace)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_SSE2)
jsimd_convsamp_float_sse2(sample_data, start_col, workspace);
else if (simd_support & JSIMD_SSE)
@@ -870,6 +906,9 @@ jsimd_can_fdct_float(void)
GLOBAL(void)
jsimd_fdct_islow(DCTELEM *data)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_fdct_islow_avx2(data);
else if (simd_support & JSIMD_SSE2)
@@ -881,6 +920,9 @@ jsimd_fdct_islow(DCTELEM *data)
GLOBAL(void)
jsimd_fdct_ifast(DCTELEM *data)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_fdct_islow_sse2))
jsimd_fdct_ifast_sse2(data);
else
@@ -890,6 +932,9 @@ jsimd_fdct_ifast(DCTELEM *data)
GLOBAL(void)
jsimd_fdct_float(FAST_FLOAT *data)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if ((simd_support & JSIMD_SSE) && IS_ALIGNED_SSE(jconst_fdct_float_sse))
jsimd_fdct_float_sse(data);
else if (simd_support & JSIMD_3DNOW)
@@ -945,6 +990,9 @@ jsimd_can_quantize_float(void)
GLOBAL(void)
jsimd_quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_quantize_avx2(coef_block, divisors, workspace);
else if (simd_support & JSIMD_SSE2)
@@ -957,6 +1005,9 @@ GLOBAL(void)
jsimd_quantize_float(JCOEFPTR coef_block, FAST_FLOAT *divisors,
FAST_FLOAT *workspace)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_SSE2)
jsimd_quantize_float_sse2(coef_block, divisors, workspace);
else if (simd_support & JSIMD_SSE)
@@ -1020,6 +1071,9 @@ jsimd_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_red_sse2))
jsimd_idct_2x2_sse2(compptr->dct_table, coef_block, output_buf,
output_col);
@@ -1032,6 +1086,9 @@ jsimd_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_red_sse2))
jsimd_idct_4x4_sse2(compptr->dct_table, coef_block, output_buf,
output_col);
@@ -1126,6 +1183,9 @@ jsimd_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_idct_islow_avx2(compptr->dct_table, coef_block, output_buf,
output_col);
@@ -1142,6 +1202,9 @@ jsimd_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_ifast_sse2))
jsimd_idct_ifast_sse2(compptr->dct_table, coef_block, output_buf,
output_col);
@@ -1155,6 +1218,9 @@ jsimd_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_float_sse2))
jsimd_idct_float_sse2(compptr->dct_table, coef_block, output_buf,
output_col);
@@ -1212,7 +1278,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
GLOBAL(void)
jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *values, size_t *zerobits)
+ int Al, UJCOEF *values, size_t *zerobits)
{
jsimd_encode_mcu_AC_first_prepare_sse2(block, jpeg_natural_order_start,
Sl, Al, values, zerobits);
@@ -1238,7 +1304,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
GLOBAL(int)
jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *absvalues, size_t *bits)
+ int Al, UJCOEF *absvalues, size_t *bits)
{
return jsimd_encode_mcu_AC_refine_prepare_sse2(block,
jpeg_natural_order_start,
diff --git a/simd/jsimd.h b/simd/jsimd.h
index 64747c63..a28754ad 100644
--- a/simd/jsimd.h
+++ b/simd/jsimd.h
@@ -2,10 +2,10 @@
* simd/jsimd.h
*
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2011, 2014-2016, 2018, 2020, D. R. Commander.
+ * Copyright (C) 2011, 2014-2016, 2018, 2020, 2022, D. R. Commander.
* Copyright (C) 2013-2014, MIPS Technologies, Inc., California.
* Copyright (C) 2014, Linaro Limited.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
* Copyright (C) 2016-2018, Loongson Technology Corporation Limited, BeiJing.
* Copyright (C) 2020, Arm Limited.
*
@@ -1243,16 +1243,16 @@ EXTERN(JOCTET *) jsimd_huff_encode_one_block_neon_slowtbl
/* Progressive Huffman encoding */
EXTERN(void) jsimd_encode_mcu_AC_first_prepare_sse2
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
- JCOEF *values, size_t *zerobits);
+ UJCOEF *values, size_t *zerobits);
EXTERN(void) jsimd_encode_mcu_AC_first_prepare_neon
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
- JCOEF *values, size_t *zerobits);
+ UJCOEF *values, size_t *zerobits);
EXTERN(int) jsimd_encode_mcu_AC_refine_prepare_sse2
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
- JCOEF *absvalues, size_t *bits);
+ UJCOEF *absvalues, size_t *bits);
EXTERN(int) jsimd_encode_mcu_AC_refine_prepare_neon
(const JCOEF *block, const int *jpeg_natural_order_start, int Sl, int Al,
- JCOEF *absvalues, size_t *bits);
+ UJCOEF *absvalues, size_t *bits);
diff --git a/simd/x86_64/jsimd.c b/simd/x86_64/jsimd.c
index 584a010a..3f5ee77e 100644
--- a/simd/x86_64/jsimd.c
+++ b/simd/x86_64/jsimd.c
@@ -2,8 +2,8 @@
* jsimd_x86_64.c
*
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
- * Copyright (C) 2009-2011, 2014, 2016, 2018, 2022, D. R. Commander.
- * Copyright (C) 2015-2016, 2018, Matthieu Darbois.
+ * Copyright (C) 2009-2011, 2014, 2016, 2018, 2022-2023, D. R. Commander.
+ * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
*
* Based on the x86 SIMD extension for IJG JPEG library,
* Copyright (C) 1999-2006, MIYASAKA Masaru.
@@ -21,7 +21,6 @@
#include "../../jdct.h"
#include "../../jsimddct.h"
#include "../jsimd.h"
-#include "jconfigint.h"
/*
* In the PIC cases, we have no guarantee that constants will keep
@@ -32,13 +31,11 @@
#define IS_ALIGNED_SSE(ptr) (IS_ALIGNED(ptr, 4)) /* 16 byte alignment */
#define IS_ALIGNED_AVX(ptr) (IS_ALIGNED(ptr, 5)) /* 32 byte alignment */
-static unsigned int simd_support = (unsigned int)(~0);
-static unsigned int simd_huffman = 1;
+static THREAD_LOCAL unsigned int simd_support = (unsigned int)(~0);
+static THREAD_LOCAL unsigned int simd_huffman = 1;
/*
* Check what SIMD accelerations are supported.
- *
- * FIXME: This code is racy under a multi-threaded environment.
*/
LOCAL(void)
init_simd(void)
@@ -148,6 +145,9 @@ jsimd_rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
void (*avx2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
+ if (simd_support == ~0U)
+ init_simd();
+
switch (cinfo->in_color_space) {
case JCS_EXT_RGB:
avx2fct = jsimd_extrgb_ycc_convert_avx2;
@@ -197,6 +197,9 @@ jsimd_rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
void (*avx2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
+ if (simd_support == ~0U)
+ init_simd();
+
switch (cinfo->in_color_space) {
case JCS_EXT_RGB:
avx2fct = jsimd_extrgb_gray_convert_avx2;
@@ -246,6 +249,9 @@ jsimd_ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
+ if (simd_support == ~0U)
+ init_simd();
+
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
avx2fct = jsimd_ycc_extrgb_convert_avx2;
@@ -336,6 +342,9 @@ GLOBAL(void)
jsimd_h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v2_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
compptr->v_samp_factor,
@@ -352,6 +361,9 @@ GLOBAL(void)
jsimd_h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v1_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
compptr->v_samp_factor,
@@ -406,6 +418,9 @@ GLOBAL(void)
jsimd_h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v2_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
input_data, output_data_ptr);
@@ -418,6 +433,9 @@ GLOBAL(void)
jsimd_h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v1_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
input_data, output_data_ptr);
@@ -472,6 +490,9 @@ GLOBAL(void)
jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v2_fancy_upsample_avx2(cinfo->max_v_samp_factor,
compptr->downsampled_width, input_data,
@@ -486,6 +507,9 @@ GLOBAL(void)
jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_h2v1_fancy_upsample_avx2(cinfo->max_v_samp_factor,
compptr->downsampled_width, input_data,
@@ -545,6 +569,9 @@ jsimd_h2v2_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
+ if (simd_support == ~0U)
+ init_simd();
+
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
avx2fct = jsimd_h2v2_extrgb_merged_upsample_avx2;
@@ -593,6 +620,9 @@ jsimd_h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
+ if (simd_support == ~0U)
+ init_simd();
+
switch (cinfo->out_color_space) {
case JCS_EXT_RGB:
avx2fct = jsimd_h2v1_extrgb_merged_upsample_avx2;
@@ -682,6 +712,9 @@ GLOBAL(void)
jsimd_convsamp(JSAMPARRAY sample_data, JDIMENSION start_col,
DCTELEM *workspace)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_convsamp_avx2(sample_data, start_col, workspace);
else
@@ -751,6 +784,9 @@ jsimd_can_fdct_float(void)
GLOBAL(void)
jsimd_fdct_islow(DCTELEM *data)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_fdct_islow_avx2(data);
else
@@ -812,6 +848,9 @@ jsimd_can_quantize_float(void)
GLOBAL(void)
jsimd_quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_quantize_avx2(coef_block, divisors, workspace);
else
@@ -966,6 +1005,9 @@ jsimd_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col)
{
+ if (simd_support == ~0U)
+ init_simd();
+
if (simd_support & JSIMD_AVX2)
jsimd_idct_islow_avx2(compptr->dct_table, coef_block, output_buf,
output_col);
@@ -1036,7 +1078,7 @@ jsimd_can_encode_mcu_AC_first_prepare(void)
GLOBAL(void)
jsimd_encode_mcu_AC_first_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *values, size_t *zerobits)
+ int Al, UJCOEF *values, size_t *zerobits)
{
jsimd_encode_mcu_AC_first_prepare_sse2(block, jpeg_natural_order_start,
Sl, Al, values, zerobits);
@@ -1060,7 +1102,7 @@ jsimd_can_encode_mcu_AC_refine_prepare(void)
GLOBAL(int)
jsimd_encode_mcu_AC_refine_prepare(const JCOEF *block,
const int *jpeg_natural_order_start, int Sl,
- int Al, JCOEF *absvalues, size_t *bits)
+ int Al, UJCOEF *absvalues, size_t *bits)
{
return jsimd_encode_mcu_AC_refine_prepare_sse2(block,
jpeg_natural_order_start,
diff --git a/tjbench.c b/tjbench.c
index b8d41c66..7291723f 100644
--- a/tjbench.c
+++ b/tjbench.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C)2009-2019, 2021 D. R. Commander. All Rights Reserved.
+ * Copyright (C)2009-2019, 2021-2023 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -84,7 +84,7 @@ static int tjErrorLine = -1, tjErrorCode = -1;
}
static int flags = TJFLAG_NOREALLOC, compOnly = 0, decompOnly = 0, doYUV = 0,
- quiet = 0, doTile = 0, pf = TJPF_BGR, yuvPad = 1, doWrite = 1;
+ quiet = 0, doTile = 0, pf = TJPF_BGR, yuvAlign = 1, doWrite = 1;
static char *ext = "ppm";
static const char *pixFormatStr[TJ_NUMPF] = {
"RGB", "BGR", "RGBX", "BGRX", "XBGR", "XRGB", "GRAY", "", "", "", "", "CMYK"
@@ -185,7 +185,7 @@ static int decomp(unsigned char *srcBuf, unsigned char **jpegBuf,
if (doYUV) {
int width = doTile ? tilew : scaledw;
int height = doTile ? tileh : scaledh;
- unsigned long yuvSize = tjBufSizeYUV2(width, yuvPad, height, subsamp);
+ unsigned long yuvSize = tjBufSizeYUV2(width, yuvAlign, height, subsamp);
if (yuvSize == (unsigned long)-1)
THROW_TJ("allocating YUV buffer");
@@ -212,10 +212,10 @@ static int decomp(unsigned char *srcBuf, unsigned char **jpegBuf,
double startDecode;
if (tjDecompressToYUV2(handle, jpegBuf[tile], jpegSize[tile], yuvBuf,
- width, yuvPad, height, flags) == -1)
+ width, yuvAlign, height, flags) == -1)
THROW_TJ("executing tjDecompressToYUV2()");
startDecode = getTime();
- if (tjDecodeYUV(handle, yuvBuf, yuvPad, subsamp, dstPtr2, width,
+ if (tjDecodeYUV(handle, yuvBuf, yuvAlign, subsamp, dstPtr2, width,
pitch, height, pf, flags) == -1)
THROW_TJ("executing tjDecodeYUV()");
if (iter >= 0) elapsedDecode += getTime() - startDecode;
@@ -278,12 +278,12 @@ static int decomp(unsigned char *srcBuf, unsigned char **jpegBuf,
qualStr, sizeStr, ext);
if (tjSaveImage(tempStr, dstBuf, scaledw, 0, scaledh, pf, flags) == -1)
- THROW_TJG("saving bitmap");
+ THROW_TJG("saving output image");
ptr = strrchr(tempStr, '.');
SNPRINTF(ptr, 1024 - (ptr - tempStr), "-err.%s", ext);
if (srcBuf && sf.num == 1 && sf.denom == 1) {
if (!quiet) fprintf(stderr, "Compression error written to %s.\n", tempStr);
- if (subsamp == TJ_GRAYSCALE) {
+ if (subsamp == TJSAMP_GRAY) {
unsigned long index, index2;
for (row = 0, index = 0; row < h; row++, index += pitch) {
@@ -310,7 +310,7 @@ static int decomp(unsigned char *srcBuf, unsigned char **jpegBuf,
srcBuf[pitch * row + col]);
}
if (tjSaveImage(tempStr, dstBuf, w, 0, h, pf, flags) == -1)
- THROW_TJG("saving bitmap");
+ THROW_TJG("saving output image");
}
bailout:
@@ -385,7 +385,7 @@ static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
THROW_TJ("executing tjInitCompress()");
if (doYUV) {
- yuvSize = tjBufSizeYUV2(tilew, yuvPad, tileh, subsamp);
+ yuvSize = tjBufSizeYUV2(tilew, yuvAlign, tileh, subsamp);
if (yuvSize == (unsigned long)-1)
THROW_TJ("allocating YUV buffer");
if ((yuvBuf = (unsigned char *)malloc(yuvSize)) == NULL)
@@ -412,10 +412,10 @@ static int fullTest(unsigned char *srcBuf, int w, int h, int subsamp,
double startEncode = getTime();
if (tjEncodeYUV3(handle, srcPtr2, width, pitch, height, pf, yuvBuf,
- yuvPad, subsamp, flags) == -1)
+ yuvAlign, subsamp, flags) == -1)
THROW_TJ("executing tjEncodeYUV3()");
if (iter >= 0) elapsedEncode += getTime() - startEncode;
- if (tjCompressFromYUV(handle, yuvBuf, width, yuvPad, height,
+ if (tjCompressFromYUV(handle, yuvBuf, width, yuvAlign, height,
subsamp, &jpegBuf[tile], &jpegSize[tile],
jpegQual, flags) == -1)
THROW_TJ("executing tjCompressFromYUV()");
@@ -580,7 +580,7 @@ static int decompTest(char *fileName)
if (quiet == 1) {
fprintf(stderr, "All performance values in Mpixels/sec\n\n");
fprintf(stderr,
- "Bitmap JPEG JPEG %s %s Xform Comp Decomp ",
+ "Pixel JPEG JPEG %s %s Xform Comp Decomp ",
doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
if (doYUV) fprintf(stderr, "Decode");
fprintf(stderr, "\n");
@@ -644,7 +644,7 @@ static int decompTest(char *fileName)
tw = h; th = w; ttilew = tileh; ttileh = tilew;
}
- if (xformOpt & TJXOPT_GRAY) tsubsamp = TJ_GRAYSCALE;
+ if (xformOpt & TJXOPT_GRAY) tsubsamp = TJSAMP_GRAY;
if (xformOp == TJXOP_HFLIP || xformOp == TJXOP_ROT180)
tw = tw - (tw % tjMCUWidth[tsubsamp]);
if (xformOp == TJXOP_VFLIP || xformOp == TJXOP_ROT180)
@@ -766,38 +766,34 @@ static void usage(char *progName)
int i;
printf("USAGE: %s\n", progName);
- printf(" <Inputfile (BMP|PPM)> <Quality> [options]\n\n");
+ printf(" <Inputimage (BMP|PPM)> <Quality> [options]\n\n");
printf(" %s\n", progName);
- printf(" <Inputfile (JPG)> [options]\n\n");
+ printf(" <Inputimage (JPG)> [options]\n\n");
printf("Options:\n\n");
- printf("-alloc = Dynamically allocate JPEG image buffers\n");
- printf("-bmp = Generate output images in Windows Bitmap format (default = PPM)\n");
- printf("-bottomup = Test bottom-up compression/decompression\n");
- printf("-tile = Test performance of the codec when the image is encoded as separate\n");
- printf(" tiles of varying sizes.\n");
+ printf("-alloc = Dynamically allocate JPEG buffers\n");
+ printf("-bmp = Use Windows Bitmap format for output images [default = PPM]\n");
+ printf("-bottomup = Use bottom-up row order for packed-pixel source/destination buffers\n");
+ printf("-tile = Compress/transform the input image into separate JPEG tiles of varying\n");
+ printf(" sizes (useful for measuring JPEG overhead)\n");
printf("-rgb, -bgr, -rgbx, -bgrx, -xbgr, -xrgb =\n");
- printf(" Test the specified color conversion path in the codec (default = BGR)\n");
- printf("-cmyk = Indirectly test YCCK JPEG compression/decompression (the source\n");
- printf(" and destination bitmaps are still RGB. The conversion is done\n");
- printf(" internally prior to compression or after decompression.)\n");
- printf("-fastupsample = Use the fastest chrominance upsampling algorithm available in\n");
- printf(" the underlying codec\n");
- printf("-fastdct = Use the fastest DCT/IDCT algorithms available in the underlying\n");
- printf(" codec\n");
- printf("-accuratedct = Use the most accurate DCT/IDCT algorithms available in the\n");
- printf(" underlying codec\n");
+ printf(" Use the specified pixel format for packed-pixel source/destination buffers\n");
+ printf(" [default = BGR]\n");
+ printf("-cmyk = Indirectly test YCCK JPEG compression/decompression\n");
+ printf(" (use the CMYK pixel format for packed-pixel source/destination buffers)\n");
+ printf("-fastupsample = Use the fastest chrominance upsampling algorithm available\n");
+ printf("-fastdct = Use the fastest DCT/IDCT algorithm available\n");
+ printf("-accuratedct = Use the most accurate DCT/IDCT algorithm available\n");
printf("-progressive = Use progressive entropy coding in JPEG images generated by\n");
- printf(" compression and transform operations.\n");
- printf("-subsamp <s> = When testing JPEG compression, this option specifies the level\n");
- printf(" of chrominance subsampling to use (<s> = 444, 422, 440, 420, 411, or\n");
- printf(" GRAY). The default is to test Grayscale, 4:2:0, 4:2:2, and 4:4:4 in\n");
- printf(" sequence.\n");
+ printf(" compression and transform operations\n");
+ printf("-subsamp <s> = When compressing, use the specified level of chrominance\n");
+ printf(" subsampling (<s> = 444, 422, 440, 420, 411, or GRAY) [default = test\n");
+ printf(" Grayscale, 4:2:0, 4:2:2, and 4:4:4 in sequence]\n");
printf("-quiet = Output results in tabular rather than verbose format\n");
- printf("-yuv = Test YUV encoding/decoding functions\n");
- printf("-yuvpad <p> = If testing YUV encoding/decoding, this specifies the number of\n");
- printf(" bytes to which each row of each plane in the intermediate YUV image is\n");
- printf(" padded (default = 1)\n");
- printf("-scale M/N = Scale down the width/height of the decompressed JPEG image by a\n");
+ printf("-yuv = Compress from/decompress to intermediate planar YUV images\n");
+ printf("-yuvpad <p> = The number of bytes by which each row in each plane of an\n");
+ printf(" intermediate YUV image is evenly divisible (must be a power of 2)\n");
+ printf(" [default = 1]\n");
+ printf("-scale M/N = When decompressing, scale the width/height of the JPEG image by a\n");
printf(" factor of M/N (M/N = ");
for (i = 0; i < nsf; i++) {
printf("%d/%d", scalingFactors[i].num, scalingFactors[i].denom);
@@ -810,24 +806,24 @@ static void usage(char *progName)
}
printf(")\n");
printf("-hflip, -vflip, -transpose, -transverse, -rot90, -rot180, -rot270 =\n");
- printf(" Perform the corresponding lossless transform prior to\n");
- printf(" decompression (these options are mutually exclusive)\n");
- printf("-grayscale = Perform lossless grayscale conversion prior to decompression\n");
- printf(" test (can be combined with the other transforms above)\n");
+ printf(" Perform the specified lossless transform operation on the input image\n");
+ printf(" prior to decompression (these operations are mutually exclusive)\n");
+ printf("-grayscale = Transform the input image into a grayscale JPEG image prior to\n");
+ printf(" decompression (can be combined with the other transform operations above)\n");
printf("-copynone = Do not copy any extra markers (including EXIF and ICC profile data)\n");
- printf(" when transforming the image.\n");
- printf("-benchtime <t> = Run each benchmark for at least <t> seconds (default = 5.0)\n");
- printf("-warmup <t> = Run each benchmark for <t> seconds (default = 1.0) prior to\n");
+ printf(" when transforming the input image\n");
+ printf("-benchtime <t> = Run each benchmark for at least <t> seconds [default = 5.0]\n");
+ printf("-warmup <t> = Run each benchmark for <t> seconds [default = 1.0] prior to\n");
printf(" starting the timer, in order to prime the caches and thus improve the\n");
- printf(" consistency of the results.\n");
+ printf(" consistency of the benchmark results\n");
printf("-componly = Stop after running compression tests. Do not test decompression.\n");
printf("-nowrite = Do not write reference or output images (improves consistency of\n");
- printf(" performance measurements.)\n");
+ printf(" benchmark results)\n");
printf("-limitscans = Refuse to decompress or transform progressive JPEG images that\n");
printf(" have an unreasonably large number of scans\n");
printf("-stoponwarning = Immediately discontinue the current\n");
- printf(" compression/decompression/transform operation if the underlying codec\n");
- printf(" throws a warning (non-fatal error)\n\n");
+ printf(" compression/decompression/transform operation if a warning (non-fatal\n");
+ printf(" error) occurs\n\n");
printf("NOTE: If the quality is specified as a range (e.g. 90-100), a separate\n");
printf("test will be performed for all quality values in the range.\n\n");
exit(1);
@@ -876,7 +872,7 @@ int tjbench(int argc, char *argv[])
if (!strcasecmp(argv[i], "-tile")) {
doTile = 1; xformOpt |= TJXOPT_CROP;
} else if (!strcasecmp(argv[i], "-fastupsample")) {
- fprintf(stderr, "Using fast upsampling code\n\n");
+ fprintf(stderr, "Using fastest upsampling algorithm\n\n");
flags |= TJFLAG_FASTUPSAMPLE;
} else if (!strcasecmp(argv[i], "-fastdct")) {
fprintf(stderr, "Using fastest DCT/IDCT algorithm\n\n");
@@ -887,6 +883,7 @@ int tjbench(int argc, char *argv[])
} else if (!strcasecmp(argv[i], "-progressive")) {
fprintf(stderr, "Using progressive entropy coding\n\n");
flags |= TJFLAG_PROGRESSIVE;
+ xformOpt |= TJXOPT_PROGRESSIVE;
} else if (!strcasecmp(argv[i], "-rgb"))
pf = TJPF_RGB;
else if (!strcasecmp(argv[i], "-rgbx"))
@@ -959,12 +956,13 @@ int tjbench(int argc, char *argv[])
else if (!strcasecmp(argv[i], "-bmp"))
ext = "bmp";
else if (!strcasecmp(argv[i], "-yuv")) {
- fprintf(stderr, "Testing YUV planar encoding/decoding\n\n");
+ fprintf(stderr, "Testing planar YUV encoding/decoding\n\n");
doYUV = 1;
} else if (!strcasecmp(argv[i], "-yuvpad") && i < argc - 1) {
int tempi = atoi(argv[++i]);
- if (tempi >= 1) yuvPad = tempi;
+ if (tempi >= 1 && (tempi & (tempi - 1)) == 0) yuvAlign = tempi;
+ else usage(argv[0]);
} else if (!strcasecmp(argv[i], "-subsamp") && i < argc - 1) {
i++;
if (toupper(argv[i][0]) == 'G') subsamp = TJSAMP_GRAY;
@@ -977,6 +975,7 @@ int tjbench(int argc, char *argv[])
case 440: subsamp = TJSAMP_440; break;
case 420: subsamp = TJSAMP_420; break;
case 411: subsamp = TJSAMP_411; break;
+ default: usage(argv[0]);
}
}
} else if (!strcasecmp(argv[i], "-componly"))
@@ -993,26 +992,26 @@ int tjbench(int argc, char *argv[])
if ((sf.num != 1 || sf.denom != 1) && doTile) {
fprintf(stderr, "Disabling tiled compression/decompression tests, because those tests do not\n");
- fprintf(stderr, "work when scaled decompression is enabled.\n");
- doTile = 0;
+ fprintf(stderr, "work when scaled decompression is enabled.\n\n");
+ doTile = 0; xformOpt &= (~TJXOPT_CROP);
}
if ((flags & TJFLAG_NOREALLOC) == 0 && doTile) {
fprintf(stderr, "Disabling tiled compression/decompression tests, because those tests do not\n");
fprintf(stderr, "work when dynamic JPEG buffer allocation is enabled.\n\n");
- doTile = 0;
+ doTile = 0; xformOpt &= (~TJXOPT_CROP);
}
if (!decompOnly) {
if ((srcBuf = tjLoadImage(argv[1], &w, 1, &h, &pf, flags)) == NULL)
- THROW_TJG("loading bitmap");
+ THROW_TJG("loading input image");
temp = strrchr(argv[1], '.');
if (temp != NULL) *temp = '\0';
}
if (quiet == 1 && !decompOnly) {
fprintf(stderr, "All performance values in Mpixels/sec\n\n");
- fprintf(stderr, "Bitmap JPEG JPEG %s %s ",
+ fprintf(stderr, "Pixel JPEG JPEG %s %s ",
doTile ? "Tile " : "Image", doTile ? "Tile " : "Image");
if (doYUV) fprintf(stderr, "Encode ");
fprintf(stderr, "Comp Comp Decomp ");
diff --git a/tjunittest.c b/tjunittest.c
index 04be30d4..d5211f15 100644
--- a/tjunittest.c
+++ b/tjunittest.c
@@ -1,6 +1,6 @@
/*
- * Copyright (C)2009-2014, 2017-2019, 2022 D. R. Commander.
- * All Rights Reserved.
+ * Copyright (C)2009-2014, 2017-2019, 2022-2023 D. R. Commander.
+ * All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -38,6 +38,7 @@
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
+#include <limits.h>
#include <errno.h>
#include "tjutil.h"
#include "turbojpeg.h"
@@ -56,11 +57,11 @@ static void usage(char *progName)
{
printf("\nUSAGE: %s [options]\n\n", progName);
printf("Options:\n");
- printf("-yuv = test YUV encoding/decoding support\n");
- printf("-noyuvpad = do not pad each line of each Y, U, and V plane to the nearest\n");
- printf(" 4-byte boundary\n");
- printf("-alloc = test automatic buffer allocation\n");
- printf("-bmp = tjLoadImage()/tjSaveImage() unit test\n\n");
+ printf("-yuv = test YUV encoding/compression/decompression/decoding\n");
+ printf("-noyuvpad = do not pad each row in each Y, U, and V plane to the nearest\n");
+ printf(" multiple of 4 bytes\n");
+ printf("-alloc = test automatic JPEG buffer allocation\n");
+ printf("-bmp = test packed-pixel image I/O\n");
exit(1);
}
#endif
@@ -97,7 +98,7 @@ static const int _4byteFormats[] = {
static const int _onlyGray[] = { TJPF_GRAY };
static const int _onlyRGB[] = { TJPF_RGB };
-static int doYUV = 0, alloc = 0, pad = 4;
+static int doYUV = 0, alloc = 0, yuvAlign = 4;
static int exitStatus = 0;
#define BAILOUT() { exitStatus = -1; goto bailout; }
@@ -289,7 +290,7 @@ static int checkBufYUV(unsigned char *buf, int w, int h, int subsamp,
int hsf = tjMCUWidth[subsamp] / 8, vsf = tjMCUHeight[subsamp] / 8;
int pw = PAD(w, hsf), ph = PAD(h, vsf);
int cw = pw / hsf, ch = ph / vsf;
- int ypitch = PAD(pw, pad), uvpitch = PAD(cw, pad);
+ int ypitch = PAD(pw, yuvAlign), uvpitch = PAD(cw, yuvAlign);
int retval = 1;
int halfway = 16 * sf.num / sf.denom;
int blocksize = 8 * sf.num / sf.denom;
@@ -394,7 +395,7 @@ static void compTest(tjhandle handle, unsigned char **dstBuf,
if (!alloc) flags |= TJFLAG_NOREALLOC;
if (doYUV) {
- unsigned long yuvSize = tjBufSizeYUV2(w, pad, h, subsamp);
+ unsigned long yuvSize = tjBufSizeYUV2(w, yuvAlign, h, subsamp);
tjscalingfactor sf = { 1, 1 };
tjhandle handle2 = tjInitCompress();
@@ -406,15 +407,15 @@ static void compTest(tjhandle handle, unsigned char **dstBuf,
fprintf(stderr, "%s %s -> YUV %s ... ", pfStr, buStrLong,
subNameLong[subsamp]);
- TRY_TJ(tjEncodeYUV3(handle2, srcBuf, w, 0, h, pf, yuvBuf, pad, subsamp,
- flags));
+ TRY_TJ(tjEncodeYUV3(handle2, srcBuf, w, 0, h, pf, yuvBuf, yuvAlign,
+ subsamp, flags));
tjDestroy(handle2);
if (checkBufYUV(yuvBuf, w, h, subsamp, sf)) fprintf(stderr, "Passed.\n");
else fprintf(stderr, "FAILED!\n");
fprintf(stderr, "YUV %s %s -> JPEG Q%d ... ", subNameLong[subsamp],
buStrLong, jpegQual);
- TRY_TJ(tjCompressFromYUV(handle, yuvBuf, w, pad, h, subsamp, dstBuf,
+ TRY_TJ(tjCompressFromYUV(handle, yuvBuf, w, yuvAlign, h, subsamp, dstBuf,
dstSize, jpegQual, flags));
} else {
fprintf(stderr, "%s %s -> %s Q%d ... ", pfStr, buStrLong,
@@ -456,7 +457,7 @@ static void _decompTest(tjhandle handle, unsigned char *jpegBuf,
memset(dstBuf, 0, dstSize);
if (doYUV) {
- unsigned long yuvSize = tjBufSizeYUV2(scaledWidth, pad, scaledHeight,
+ unsigned long yuvSize = tjBufSizeYUV2(scaledWidth, yuvAlign, scaledHeight,
subsamp);
tjhandle handle2 = tjInitDecompress();
@@ -470,8 +471,12 @@ static void _decompTest(tjhandle handle, unsigned char *jpegBuf,
if (sf.num != 1 || sf.denom != 1)
fprintf(stderr, "%d/%d ... ", sf.num, sf.denom);
else fprintf(stderr, "... ");
- TRY_TJ(tjDecompressToYUV2(handle, jpegBuf, jpegSize, yuvBuf, scaledWidth,
- pad, scaledHeight, flags));
+ /* We pass scaledWidth + 1 and scaledHeight + 1 to validate that
+ tjDecompressToYUV2() generates the largest possible scaled image that
+ fits within the desired dimensions, as documented. */
+ TRY_TJ(tjDecompressToYUV2(handle, jpegBuf, jpegSize, yuvBuf,
+ scaledWidth + 1, yuvAlign, scaledHeight + 1,
+ flags));
if (checkBufYUV(yuvBuf, scaledWidth, scaledHeight, subsamp, sf))
fprintf(stderr, "Passed.\n");
else fprintf(stderr, "FAILED!\n");
@@ -479,7 +484,7 @@ static void _decompTest(tjhandle handle, unsigned char *jpegBuf,
fprintf(stderr, "YUV %s -> %s %s ... ", subNameLong[subsamp],
pixFormatStr[pf],
(flags & TJFLAG_BOTTOMUP) ? "Bottom-Up" : "Top-Down ");
- TRY_TJ(tjDecodeYUV(handle2, yuvBuf, pad, subsamp, dstBuf, scaledWidth, 0,
+ TRY_TJ(tjDecodeYUV(handle2, yuvBuf, yuvAlign, subsamp, dstBuf, scaledWidth, 0,
scaledHeight, pf, flags));
tjDestroy(handle2);
} else {
@@ -488,8 +493,11 @@ static void _decompTest(tjhandle handle, unsigned char *jpegBuf,
if (sf.num != 1 || sf.denom != 1)
fprintf(stderr, "%d/%d ... ", sf.num, sf.denom);
else fprintf(stderr, "... ");
- TRY_TJ(tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, scaledWidth, 0,
- scaledHeight, pf, flags));
+ /* We pass scaledWidth + 1 and scaledHeight + 1 to validate that
+ tjDecompress2() generates the largest possible scaled image that fits
+ within the desired dimensions, as documented. */
+ TRY_TJ(tjDecompress2(handle, jpegBuf, jpegSize, dstBuf, scaledWidth + 1, 0,
+ scaledHeight + 1, pf, flags));
}
if (checkBuf(dstBuf, scaledWidth, scaledHeight, pf, subsamp, sf, flags))
@@ -586,12 +594,17 @@ bailout:
THROW(#function " overflow"); \
}
#endif
+#define CHECKSIZEINT(function) { \
+ if (intsize != -1 || !strcmp(tjGetErrorStr2(NULL), "No error")) \
+ THROW(#function " overflow"); \
+}
#ifndef GTEST
static void overflowTest(void)
{
/* Ensure that the various buffer size functions don't overflow */
unsigned long size;
+ int intsize;
size = tjBufSize(26755, 26755, TJSAMP_444);
CHECKSIZE(tjBufSize());
@@ -599,12 +612,20 @@ static void overflowTest(void)
CHECKSIZE(TJBUFSIZE());
size = tjBufSizeYUV2(37838, 1, 37838, TJSAMP_444);
CHECKSIZE(tjBufSizeYUV2());
+ size = tjBufSizeYUV2(37837, 3, 37837, TJSAMP_444);
+ CHECKSIZE(tjBufSizeYUV2());
+ size = tjBufSizeYUV2(37837, -1, 37837, TJSAMP_444);
+ CHECKSIZE(tjBufSizeYUV2());
size = TJBUFSIZEYUV(37838, 37838, TJSAMP_444);
CHECKSIZE(TJBUFSIZEYUV());
size = tjBufSizeYUV(37838, 37838, TJSAMP_444);
CHECKSIZE(tjBufSizeYUV());
size = tjPlaneSizeYUV(0, 65536, 0, 65536, TJSAMP_444);
CHECKSIZE(tjPlaneSizeYUV());
+ intsize = tjPlaneWidth(0, INT_MAX, TJSAMP_420);
+ CHECKSIZEINT(tjPlaneWidth());
+ intsize = tjPlaneHeight(0, INT_MAX, TJSAMP_420);
+ CHECKSIZEINT(tjPlaneHeight());
bailout:
return;
@@ -632,7 +653,7 @@ static void bufSizeTest(void)
if ((srcBuf = (unsigned char *)malloc(w * h * 4)) == NULL)
THROW("Memory allocation failure");
if (!alloc || doYUV) {
- if (doYUV) dstSize = tjBufSizeYUV2(w, pad, h, subsamp);
+ if (doYUV) dstSize = tjBufSizeYUV2(w, yuvAlign, h, subsamp);
else dstSize = tjBufSize(w, h, subsamp);
if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
THROW("Memory allocation failure");
@@ -644,8 +665,8 @@ static void bufSizeTest(void)
}
if (doYUV) {
- TRY_TJ(tjEncodeYUV3(handle, srcBuf, w, 0, h, TJPF_BGRX, dstBuf, pad,
- subsamp, 0));
+ TRY_TJ(tjEncodeYUV3(handle, srcBuf, w, 0, h, TJPF_BGRX, dstBuf,
+ yuvAlign, subsamp, 0));
} else {
TRY_TJ(tjCompress2(handle, srcBuf, w, 0, h, TJPF_BGRX, &dstBuf,
&dstSize, subsamp, 100,
@@ -659,7 +680,7 @@ static void bufSizeTest(void)
if ((srcBuf = (unsigned char *)malloc(h * w * 4)) == NULL)
THROW("Memory allocation failure");
if (!alloc || doYUV) {
- if (doYUV) dstSize = tjBufSizeYUV2(h, pad, w, subsamp);
+ if (doYUV) dstSize = tjBufSizeYUV2(h, yuvAlign, w, subsamp);
else dstSize = tjBufSize(h, w, subsamp);
if ((dstBuf = (unsigned char *)tjAlloc(dstSize)) == NULL)
THROW("Memory allocation failure");
@@ -671,8 +692,8 @@ static void bufSizeTest(void)
}
if (doYUV) {
- TRY_TJ(tjEncodeYUV3(handle, srcBuf, h, 0, w, TJPF_BGRX, dstBuf, pad,
- subsamp, 0));
+ TRY_TJ(tjEncodeYUV3(handle, srcBuf, h, 0, w, TJPF_BGRX, dstBuf,
+ yuvAlign, subsamp, 0));
} else {
TRY_TJ(tjCompress2(handle, srcBuf, h, 0, w, TJPF_BGRX, &dstBuf,
&dstSize, subsamp, 100,
@@ -918,7 +939,7 @@ static int bmpTest(void)
static void initTJUnitTest(int yuv, int noyuvpad, int autoalloc)
{
doYUV = yuv ? 1 : 0;
- pad = noyuvpad ? 1 : 4;
+ yuvAlign = noyuvpad ? 1 : 4;
alloc = autoalloc ? 1 : 0;
exitStatus = 0;
@@ -1138,7 +1159,7 @@ int main(int argc, char *argv[])
if (argc > 1) {
for (i = 1; i < argc; i++) {
if (!strcasecmp(argv[i], "-yuv")) doYUV = 1;
- else if (!strcasecmp(argv[i], "-noyuvpad")) pad = 1;
+ else if (!strcasecmp(argv[i], "-noyuvpad")) yuvAlign = 1;
else if (!strcasecmp(argv[i], "-alloc")) alloc = 1;
else if (!strcasecmp(argv[i], "-bmp")) return bmpTest();
else usage(argv[0]);
diff --git a/transupp.c b/transupp.c
index a3d878cc..78dc91b4 100644
--- a/transupp.c
+++ b/transupp.c
@@ -143,7 +143,7 @@ requant_comp(j_decompress_ptr cinfo, jpeg_component_info *compptr,
for (k = 0; k < DCTSIZE2; k++) {
temp = qtblptr->quantval[k];
qval = qtblptr1->quantval[k];
- if (temp != qval) {
+ if (temp != qval && qval != 0) {
temp *= ptr[k];
/* The following quantization code is copied from jcdctmgr.c */
#ifdef FAST_DIVIDE
diff --git a/turbojpeg-jni.c b/turbojpeg-jni.c
index 0cf5f702..446cbd2a 100644
--- a/turbojpeg-jni.c
+++ b/turbojpeg-jni.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C)2011-2022 D. R. Commander. All Rights Reserved.
+ * Copyright (C)2011-2023 D. R. Commander. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -26,6 +26,7 @@
* POSSIBILITY OF SUCH DAMAGE.
*/
+#include <limits.h>
#include "turbojpeg.h"
#include "jinclude.h"
#include <jni.h>
@@ -132,24 +133,28 @@ bailout:
JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSize
(JNIEnv *env, jclass cls, jint width, jint height, jint jpegSubsamp)
{
- jint retval = (jint)tjBufSize(width, height, jpegSubsamp);
+ unsigned long retval = tjBufSize(width, height, jpegSubsamp);
- if (retval == -1) THROW_ARG(tjGetErrorStr());
+ if (retval == (unsigned long)-1) THROW_ARG(tjGetErrorStr());
+ if (retval > (unsigned long)INT_MAX)
+ THROW_ARG("Image is too large");
bailout:
- return retval;
+ return (jint)retval;
}
/* TurboJPEG 1.4.x: TJ::bufSizeYUV() */
JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_bufSizeYUV__IIII
- (JNIEnv *env, jclass cls, jint width, jint pad, jint height, jint subsamp)
+ (JNIEnv *env, jclass cls, jint width, jint align, jint height, jint subsamp)
{
- jint retval = (jint)tjBufSizeYUV2(width, pad, height, subsamp);
+ unsigned long retval = tjBufSizeYUV2(width, align, height, subsamp);
- if (retval == -1) THROW_ARG(tjGetErrorStr());
+ if (retval == (unsigned long)-1) THROW_ARG(tjGetErrorStr());
+ if (retval > (unsigned long)INT_MAX)
+ THROW_ARG("Image is too large");
bailout:
- return retval;
+ return (jint)retval;
}
/* TurboJPEG 1.2.x: TJ::bufSizeYUV() */
@@ -166,13 +171,15 @@ JNIEXPORT jint JNICALL Java_org_libjpegturbo_turbojpeg_TJ_planeSizeYUV__IIIII
(JNIEnv *env, jclass cls, jint componentID, jint width, jint stride,
jint height, jint subsamp)
{
- jint retval = (jint)tjPlaneSizeYUV(componentID, width, stride, height,
- subsamp);
+ unsigned long retval = tjPlaneSizeYUV(componentID, width, stride, height,
+ subsamp);
- if (retval == -1) THROW_ARG(tjGetErrorStr());
+ if (retval == (unsigned long)-1) THROW_ARG(tjGetErrorStr());
+ if (retval > (unsigned long)INT_MAX)
+ THROW_ARG("Image is too large");
bailout:
- return retval;
+ return (jint)retval;
}
/* TurboJPEG 1.4.x: TJ::planeWidth() */
diff --git a/turbojpeg-mapfile b/turbojpeg-mapfile
index 5477fed2..07a429be 100644
--- a/turbojpeg-mapfile
+++ b/turbojpeg-mapfile
@@ -1,14 +1,14 @@
TURBOJPEG_1.0
{
global:
- tjInitCompress;
- tjCompress;
TJBUFSIZE;
- tjInitDecompress;
- tjDecompressHeader;
+ tjCompress;
tjDecompress;
+ tjDecompressHeader;
tjDestroy;
tjGetErrorStr;
+ tjInitCompress;
+ tjInitDecompress;
local:
*;
};
diff --git a/turbojpeg-mapfile.jni b/turbojpeg-mapfile.jni
index 44327912..4ae25aad 100644
--- a/turbojpeg-mapfile.jni
+++ b/turbojpeg-mapfile.jni
@@ -1,14 +1,14 @@
TURBOJPEG_1.0
{
global:
- tjInitCompress;
- tjCompress;
TJBUFSIZE;
- tjInitDecompress;
- tjDecompressHeader;
+ tjCompress;
tjDecompress;
+ tjDecompressHeader;
tjDestroy;
tjGetErrorStr;
+ tjInitCompress;
+ tjInitDecompress;
local:
*;
};
diff --git a/turbojpeg.c b/turbojpeg.c
index a1544f24..b5498dc8 100644
--- a/turbojpeg.c
+++ b/turbojpeg.c
@@ -1,5 +1,5 @@
/*
- * Copyright (C)2009-2022 D. R. Commander. All Rights Reserved.
+ * Copyright (C)2009-2023 D. R. Commander. All Rights Reserved.
* Copyright (C)2021 Alex Richardson. All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
@@ -31,6 +31,7 @@
libjpeg-turbo */
#include <ctype.h>
+#include <limits.h>
#include <jinclude.h>
#define JPEG_INTERNALS
#include <jpeglib.h>
@@ -42,7 +43,6 @@
#include "transupp.h"
#include "./jpegcomp.h"
#include "./cdjpeg.h"
-#include "jconfigint.h"
extern void jpeg_mem_dest_tj(j_compress_ptr, unsigned char **, unsigned long *,
boolean);
@@ -98,7 +98,7 @@ static void my_emit_message(j_common_ptr cinfo, int msg_level)
}
-/* Global structures, macros, etc. */
+/********************** Global structures, macros, etc. **********************/
enum { COMPRESS = 1, DECOMPRESS = 2 };
@@ -324,12 +324,14 @@ static void setCompDefaults(struct jpeg_compress_struct *cinfo,
else
jpeg_set_colorspace(cinfo, JCS_YCbCr);
+#ifdef C_PROGRESSIVE_SUPPORTED
if (flags & TJFLAG_PROGRESSIVE)
jpeg_simple_progression(cinfo);
#ifndef NO_GETENV
else if (!GETENV_S(env, 7, "TJ_PROGRESSIVE") && !strcmp(env, "1"))
jpeg_simple_progression(cinfo);
#endif
+#endif
cinfo->comp_info[0].h_samp_factor = tjMCUWidth[subsamp] / 8;
cinfo->comp_info[1].h_samp_factor = 1;
@@ -355,7 +357,7 @@ static int getSubsamp(j_decompress_ptr dinfo)
if (dinfo->num_components == 1 && dinfo->jpeg_color_space == JCS_GRAYSCALE)
return TJSAMP_GRAY;
- for (i = 0; i < NUMSUBOPT; i++) {
+ for (i = 0; i < TJ_NUMSAMP; i++) {
if (dinfo->num_components == pixelsize[i] ||
((dinfo->jpeg_color_space == JCS_YCCK ||
dinfo->jpeg_color_space == JCS_CMYK) &&
@@ -424,8 +426,9 @@ static int getSubsamp(j_decompress_ptr dinfo)
}
-/* General API functions */
+/*************************** General API functions ***************************/
+/* TurboJPEG 2.0+ */
DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
{
tjinstance *this = (tjinstance *)handle;
@@ -438,12 +441,14 @@ DLLEXPORT char *tjGetErrorStr2(tjhandle handle)
}
+/* TurboJPEG 1.0+ */
DLLEXPORT char *tjGetErrorStr(void)
{
return errStr;
}
+/* TurboJPEG 2.0+ */
DLLEXPORT int tjGetErrorCode(tjhandle handle)
{
tjinstance *this = (tjinstance *)handle;
@@ -453,6 +458,7 @@ DLLEXPORT int tjGetErrorCode(tjhandle handle)
}
+/* TurboJPEG 1.0+ */
DLLEXPORT int tjDestroy(tjhandle handle)
{
GET_INSTANCE(handle);
@@ -470,19 +476,21 @@ DLLEXPORT int tjDestroy(tjhandle handle)
with turbojpeg.dll for compatibility reasons. However, these functions
can potentially be used for other purposes by different implementations. */
+/* TurboJPEG 1.2+ */
DLLEXPORT void tjFree(unsigned char *buf)
{
free(buf);
}
+/* TurboJPEG 1.2+ */
DLLEXPORT unsigned char *tjAlloc(int bytes)
{
return (unsigned char *)malloc(bytes);
}
-/* Compressor */
+/******************************** Compressor *********************************/
static tjhandle _tjInitCompress(tjinstance *this)
{
@@ -514,6 +522,7 @@ static tjhandle _tjInitCompress(tjinstance *this)
return (tjhandle)this;
}
+/* TurboJPEG 1.0+ */
DLLEXPORT tjhandle tjInitCompress(void)
{
tjinstance *this = NULL;
@@ -529,12 +538,13 @@ DLLEXPORT tjhandle tjInitCompress(void)
}
+/* TurboJPEG 1.2+ */
DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp)
{
unsigned long long retval = 0;
int mcuw, mcuh, chromasf;
- if (width < 1 || height < 1 || jpegSubsamp < 0 || jpegSubsamp >= NUMSUBOPT)
+ if (width < 1 || height < 1 || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP)
THROWG("tjBufSize(): Invalid argument");
/* This allows for rare corner cases in which a JPEG image can actually be
@@ -551,6 +561,7 @@ bailout:
return (unsigned long)retval;
}
+/* TurboJPEG 1.0+ */
DLLEXPORT unsigned long TJBUFSIZE(int width, int height)
{
unsigned long long retval = 0;
@@ -570,19 +581,20 @@ bailout:
}
-DLLEXPORT unsigned long tjBufSizeYUV2(int width, int pad, int height,
+/* TurboJPEG 1.4+ */
+DLLEXPORT unsigned long tjBufSizeYUV2(int width, int align, int height,
int subsamp)
{
unsigned long long retval = 0;
int nc, i;
- if (subsamp < 0 || subsamp >= NUMSUBOPT)
+ if (align < 1 || !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
THROWG("tjBufSizeYUV2(): Invalid argument");
nc = (subsamp == TJSAMP_GRAY ? 1 : 3);
for (i = 0; i < nc; i++) {
int pw = tjPlaneWidth(i, width, subsamp);
- int stride = PAD(pw, pad);
+ int stride = PAD(pw, align);
int ph = tjPlaneHeight(i, height, subsamp);
if (pw < 0 || ph < 0) return -1;
@@ -595,20 +607,24 @@ bailout:
return (unsigned long)retval;
}
+/* TurboJPEG 1.2+ */
DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp)
{
return tjBufSizeYUV2(width, 4, height, subsamp);
}
+/* TurboJPEG 1.1+ */
DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int subsamp)
{
return tjBufSizeYUV(width, height, subsamp);
}
+/* TurboJPEG 1.4+ */
DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
{
- int pw, nc, retval = 0;
+ unsigned long long pw, retval = 0;
+ int nc;
if (width < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
THROWG("tjPlaneWidth(): Invalid argument");
@@ -616,20 +632,25 @@ DLLEXPORT int tjPlaneWidth(int componentID, int width, int subsamp)
if (componentID < 0 || componentID >= nc)
THROWG("tjPlaneWidth(): Invalid argument");
- pw = PAD(width, tjMCUWidth[subsamp] / 8);
+ pw = PAD((unsigned long long)width, tjMCUWidth[subsamp] / 8);
if (componentID == 0)
retval = pw;
else
retval = pw * 8 / tjMCUWidth[subsamp];
+ if (retval > (unsigned long long)INT_MAX)
+ THROWG("tjPlaneWidth(): Width is too large");
+
bailout:
- return retval;
+ return (int)retval;
}
+/* TurboJPEG 1.4+ */
DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
{
- int ph, nc, retval = 0;
+ unsigned long long ph, retval = 0;
+ int nc;
if (height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
THROWG("tjPlaneHeight(): Invalid argument");
@@ -637,24 +658,28 @@ DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp)
if (componentID < 0 || componentID >= nc)
THROWG("tjPlaneHeight(): Invalid argument");
- ph = PAD(height, tjMCUHeight[subsamp] / 8);
+ ph = PAD((unsigned long long)height, tjMCUHeight[subsamp] / 8);
if (componentID == 0)
retval = ph;
else
retval = ph * 8 / tjMCUHeight[subsamp];
+ if (retval > (unsigned long long)INT_MAX)
+ THROWG("tjPlaneHeight(): Height is too large");
+
bailout:
- return retval;
+ return (int)retval;
}
+/* TurboJPEG 1.4+ */
DLLEXPORT unsigned long tjPlaneSizeYUV(int componentID, int width, int stride,
int height, int subsamp)
{
unsigned long long retval = 0;
int pw, ph;
- if (width < 1 || height < 1 || subsamp < 0 || subsamp >= NUMSUBOPT)
+ if (width < 1 || height < 1 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
THROWG("tjPlaneSizeYUV(): Invalid argument");
pw = tjPlaneWidth(componentID, width, subsamp);
@@ -673,6 +698,7 @@ bailout:
}
+/* TurboJPEG 1.2+ */
DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
int width, int pitch, int height, int pixelFormat,
unsigned char **jpegBuf, unsigned long *jpegSize,
@@ -689,7 +715,7 @@ DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
pixelFormat < 0 || pixelFormat >= TJ_NUMPF || jpegBuf == NULL ||
- jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= NUMSUBOPT ||
+ jpegSize == NULL || jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP ||
jpegQual < 0 || jpegQual > 100)
THROW("tjCompress2(): Invalid argument");
@@ -741,6 +767,7 @@ bailout:
return retval;
}
+/* TurboJPEG 1.0+ */
DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
int pitch, int height, int pixelSize,
unsigned char *jpegBuf, unsigned long *jpegSize,
@@ -764,6 +791,7 @@ DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
}
+/* TurboJPEG 1.4+ */
DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
int width, int pitch, int height,
int pixelFormat, unsigned char **dstPlanes,
@@ -790,13 +818,13 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
if (srcBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
pixelFormat < 0 || pixelFormat >= TJ_NUMPF || !dstPlanes ||
- !dstPlanes[0] || subsamp < 0 || subsamp >= NUMSUBOPT)
+ !dstPlanes[0] || subsamp < 0 || subsamp >= TJ_NUMSAMP)
THROW("tjEncodeYUVPlanes(): Invalid argument");
if (subsamp != TJSAMP_GRAY && (!dstPlanes[1] || !dstPlanes[2]))
THROW("tjEncodeYUVPlanes(): Invalid argument");
if (pixelFormat == TJPF_CMYK)
- THROW("tjEncodeYUVPlanes(): Cannot generate YUV images from CMYK pixels");
+ THROW("tjEncodeYUVPlanes(): Cannot generate YUV images from packed-pixel CMYK images");
if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
@@ -922,9 +950,10 @@ bailout:
return retval;
}
+/* TurboJPEG 1.4+ */
DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
int width, int pitch, int height, int pixelFormat,
- unsigned char *dstBuf, int pad, int subsamp,
+ unsigned char *dstBuf, int align, int subsamp,
int flags)
{
unsigned char *dstPlanes[3];
@@ -934,14 +963,14 @@ DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
if (!this) THROWG("tjEncodeYUV3(): Invalid handle");
this->isInstanceError = FALSE;
- if (width <= 0 || height <= 0 || dstBuf == NULL || pad < 0 ||
- !IS_POW2(pad) || subsamp < 0 || subsamp >= NUMSUBOPT)
+ if (width <= 0 || height <= 0 || dstBuf == NULL || align < 1 ||
+ !IS_POW2(align) || subsamp < 0 || subsamp >= TJ_NUMSAMP)
THROW("tjEncodeYUV3(): Invalid argument");
pw0 = tjPlaneWidth(0, width, subsamp);
ph0 = tjPlaneHeight(0, height, subsamp);
dstPlanes[0] = dstBuf;
- strides[0] = PAD(pw0, pad);
+ strides[0] = PAD(pw0, align);
if (subsamp == TJSAMP_GRAY) {
strides[1] = strides[2] = 0;
dstPlanes[1] = dstPlanes[2] = NULL;
@@ -949,7 +978,7 @@ DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
int pw1 = tjPlaneWidth(1, width, subsamp);
int ph1 = tjPlaneHeight(1, height, subsamp);
- strides[1] = strides[2] = PAD(pw1, pad);
+ strides[1] = strides[2] = PAD(pw1, align);
dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
}
@@ -961,6 +990,7 @@ bailout:
return retval;
}
+/* TurboJPEG 1.2+ */
DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
int pitch, int height, int pixelFormat,
unsigned char *dstBuf, int subsamp, int flags)
@@ -969,6 +999,7 @@ DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
dstBuf, 4, subsamp, flags);
}
+/* TurboJPEG 1.1+ */
DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
int pitch, int height, int pixelSize,
unsigned char *dstBuf, int subsamp, int flags)
@@ -979,6 +1010,7 @@ DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
}
+/* TurboJPEG 1.4+ */
DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
const unsigned char **srcPlanes,
int width, const int *strides,
@@ -1005,7 +1037,7 @@ DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
THROW("tjCompressFromYUVPlanes(): Instance has not been initialized for compression");
if (!srcPlanes || !srcPlanes[0] || width <= 0 || height <= 0 ||
- subsamp < 0 || subsamp >= NUMSUBOPT || jpegBuf == NULL ||
+ subsamp < 0 || subsamp >= TJ_NUMSAMP || jpegBuf == NULL ||
jpegSize == NULL || jpegQual < 0 || jpegQual > 100)
THROW("tjCompressFromYUVPlanes(): Invalid argument");
if (subsamp != TJSAMP_GRAY && (!srcPlanes[1] || !srcPlanes[2]))
@@ -1117,8 +1149,9 @@ bailout:
return retval;
}
+/* TurboJPEG 1.4+ */
DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
- int width, int pad, int height, int subsamp,
+ int width, int align, int height, int subsamp,
unsigned char **jpegBuf,
unsigned long *jpegSize, int jpegQual,
int flags)
@@ -1130,14 +1163,14 @@ DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
if (!this) THROWG("tjCompressFromYUV(): Invalid handle");
this->isInstanceError = FALSE;
- if (srcBuf == NULL || width <= 0 || pad < 1 || height <= 0 || subsamp < 0 ||
- subsamp >= NUMSUBOPT)
+ if (srcBuf == NULL || width <= 0 || align < 1 || !IS_POW2(align) ||
+ height <= 0 || subsamp < 0 || subsamp >= TJ_NUMSAMP)
THROW("tjCompressFromYUV(): Invalid argument");
pw0 = tjPlaneWidth(0, width, subsamp);
ph0 = tjPlaneHeight(0, height, subsamp);
srcPlanes[0] = srcBuf;
- strides[0] = PAD(pw0, pad);
+ strides[0] = PAD(pw0, align);
if (subsamp == TJSAMP_GRAY) {
strides[1] = strides[2] = 0;
srcPlanes[1] = srcPlanes[2] = NULL;
@@ -1145,7 +1178,7 @@ DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
int pw1 = tjPlaneWidth(1, width, subsamp);
int ph1 = tjPlaneHeight(1, height, subsamp);
- strides[1] = strides[2] = PAD(pw1, pad);
+ strides[1] = strides[2] = PAD(pw1, align);
srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
}
@@ -1158,7 +1191,7 @@ bailout:
}
-/* Decompressor */
+/******************************* Decompressor ********************************/
static tjhandle _tjInitDecompress(tjinstance *this)
{
@@ -1188,6 +1221,7 @@ static tjhandle _tjInitDecompress(tjinstance *this)
return (tjhandle)this;
}
+/* TurboJPEG 1.0+ */
DLLEXPORT tjhandle tjInitDecompress(void)
{
tjinstance *this;
@@ -1203,6 +1237,7 @@ DLLEXPORT tjhandle tjInitDecompress(void)
}
+/* TurboJPEG 1.4+ */
DLLEXPORT int tjDecompressHeader3(tjhandle handle,
const unsigned char *jpegBuf,
unsigned long jpegSize, int *width,
@@ -1259,6 +1294,7 @@ bailout:
return retval;
}
+/* TurboJPEG 1.1+ */
DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
unsigned long jpegSize, int *width,
int *height, int *jpegSubsamp)
@@ -1269,6 +1305,7 @@ DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
jpegSubsamp, &jpegColorspace);
}
+/* TurboJPEG 1.0+ */
DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
unsigned long jpegSize, int *width,
int *height)
@@ -1280,19 +1317,21 @@ DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
}
-DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numscalingfactors)
+/* TurboJPEG 1.2+ */
+DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numScalingFactors)
{
- if (numscalingfactors == NULL) {
+ if (numScalingFactors == NULL) {
SNPRINTF(errStr, JMSG_LENGTH_MAX,
"tjGetScalingFactors(): Invalid argument");
return NULL;
}
- *numscalingfactors = NUMSF;
+ *numScalingFactors = NUMSF;
return (tjscalingfactor *)sf;
}
+/* TurboJPEG 1.2+ */
DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
unsigned long jpegSize, unsigned char *dstBuf,
int width, int pitch, int height, int pixelFormat,
@@ -1380,6 +1419,7 @@ bailout:
return retval;
}
+/* TurboJPEG 1.0+ */
DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
unsigned long jpegSize, unsigned char *dstBuf,
int width, int pitch, int height, int pixelSize,
@@ -1393,8 +1433,8 @@ DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
}
-static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
- int pixelFormat, int subsamp, int flags)
+static void setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
+ int pixelFormat, int subsamp, int flags)
{
int i;
@@ -1429,8 +1469,6 @@ static int setDecodeDefaults(struct jpeg_decompress_struct *dinfo,
if (dinfo->quant_tbl_ptrs[i] == NULL)
dinfo->quant_tbl_ptrs[i] = jpeg_alloc_quant_table((j_common_ptr)dinfo);
}
-
- return 0;
}
@@ -1443,6 +1481,7 @@ static void my_reset_marker_reader(j_decompress_ptr dinfo)
{
}
+/* TurboJPEG 1.4+ */
DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
const unsigned char **srcPlanes,
const int *strides, int subsamp,
@@ -1468,7 +1507,7 @@ DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
if ((this->init & DECOMPRESS) == 0)
THROW("tjDecodeYUVPlanes(): Instance has not been initialized for decompression");
- if (!srcPlanes || !srcPlanes[0] || subsamp < 0 || subsamp >= NUMSUBOPT ||
+ if (!srcPlanes || !srcPlanes[0] || subsamp < 0 || subsamp >= TJ_NUMSAMP ||
dstBuf == NULL || width <= 0 || pitch < 0 || height <= 0 ||
pixelFormat < 0 || pixelFormat >= TJ_NUMPF)
THROW("tjDecodeYUVPlanes(): Invalid argument");
@@ -1481,7 +1520,7 @@ DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
}
if (pixelFormat == TJPF_CMYK)
- THROW("tjDecodeYUVPlanes(): Cannot decode YUV images into CMYK pixels.");
+ THROW("tjDecodeYUVPlanes(): Cannot decode YUV images into packed-pixel CMYK images.");
if (pitch == 0) pitch = width * tjPixelSize[pixelFormat];
dinfo->image_width = width;
@@ -1496,9 +1535,7 @@ DLLEXPORT int tjDecodeYUVPlanes(tjhandle handle,
dinfo->progressive_mode = dinfo->inputctl->has_multiple_scans = FALSE;
dinfo->Ss = dinfo->Ah = dinfo->Al = 0;
dinfo->Se = DCTSIZE2 - 1;
- if (setDecodeDefaults(dinfo, pixelFormat, subsamp, flags) == -1) {
- retval = -1; goto bailout;
- }
+ setDecodeDefaults(dinfo, pixelFormat, subsamp, flags);
old_read_markers = dinfo->marker->read_markers;
dinfo->marker->read_markers = my_read_markers;
old_reset_marker_reader = dinfo->marker->reset_marker_reader;
@@ -1591,8 +1628,9 @@ bailout:
return retval;
}
+/* TurboJPEG 1.4+ */
DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
- int pad, int subsamp, unsigned char *dstBuf,
+ int align, int subsamp, unsigned char *dstBuf,
int width, int pitch, int height, int pixelFormat,
int flags)
{
@@ -1603,14 +1641,14 @@ DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
if (!this) THROWG("tjDecodeYUV(): Invalid handle");
this->isInstanceError = FALSE;
- if (srcBuf == NULL || pad < 0 || !IS_POW2(pad) || subsamp < 0 ||
- subsamp >= NUMSUBOPT || width <= 0 || height <= 0)
+ if (srcBuf == NULL || align < 1 || !IS_POW2(align) || subsamp < 0 ||
+ subsamp >= TJ_NUMSAMP || width <= 0 || height <= 0)
THROW("tjDecodeYUV(): Invalid argument");
pw0 = tjPlaneWidth(0, width, subsamp);
ph0 = tjPlaneHeight(0, height, subsamp);
srcPlanes[0] = srcBuf;
- strides[0] = PAD(pw0, pad);
+ strides[0] = PAD(pw0, align);
if (subsamp == TJSAMP_GRAY) {
strides[1] = strides[2] = 0;
srcPlanes[1] = srcPlanes[2] = NULL;
@@ -1618,7 +1656,7 @@ DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
int pw1 = tjPlaneWidth(1, width, subsamp);
int ph1 = tjPlaneHeight(1, height, subsamp);
- strides[1] = strides[2] = PAD(pw1, pad);
+ strides[1] = strides[2] = PAD(pw1, align);
srcPlanes[1] = srcPlanes[0] + strides[0] * ph0;
srcPlanes[2] = srcPlanes[1] + strides[1] * ph1;
}
@@ -1630,6 +1668,7 @@ bailout:
return retval;
}
+/* TurboJPEG 1.4+ */
DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
const unsigned char *jpegBuf,
unsigned long jpegSize,
@@ -1763,7 +1802,7 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
for (i = 0; i < dinfo->num_components; i++) {
jpeg_component_info *compptr = &dinfo->comp_info[i];
- if (jpegSubsamp == TJ_420) {
+ if (jpegSubsamp == TJSAMP_420) {
/* When 4:2:0 subsampling is used with IDCT scaling, libjpeg will try
to be clever and use the IDCT to perform upsampling on the U and V
planes. For instance, if the output image is to be scaled by 1/2
@@ -1810,9 +1849,10 @@ bailout:
return retval;
}
+/* TurboJPEG 1.4+ */
DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
unsigned long jpegSize, unsigned char *dstBuf,
- int width, int pad, int height, int flags)
+ int width, int align, int height, int flags)
{
unsigned char *dstPlanes[3];
int pw0, ph0, strides[3], retval = -1, jpegSubsamp = -1;
@@ -1822,7 +1862,7 @@ DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
this->jerr.stopOnWarning = (flags & TJFLAG_STOPONWARNING) ? TRUE : FALSE;
if (jpegBuf == NULL || jpegSize <= 0 || dstBuf == NULL || width < 0 ||
- pad < 1 || !IS_POW2(pad) || height < 0)
+ align < 1 || !IS_POW2(align) || height < 0)
THROW("tjDecompressToYUV2(): Invalid argument");
if (setjmp(this->jerr.setjmp_buffer)) {
@@ -1839,7 +1879,6 @@ DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
jpegwidth = dinfo->image_width; jpegheight = dinfo->image_height;
if (width == 0) width = jpegwidth;
if (height == 0) height = jpegheight;
-
for (i = 0; i < NUMSF; i++) {
scaledw = TJSCALED(jpegwidth, sf[i]);
scaledh = TJSCALED(jpegheight, sf[i]);
@@ -1849,10 +1888,12 @@ DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
if (i >= NUMSF)
THROW("tjDecompressToYUV2(): Could not scale down to desired image dimensions");
+ width = scaledw; height = scaledh;
+
pw0 = tjPlaneWidth(0, width, jpegSubsamp);
ph0 = tjPlaneHeight(0, height, jpegSubsamp);
dstPlanes[0] = dstBuf;
- strides[0] = PAD(pw0, pad);
+ strides[0] = PAD(pw0, align);
if (jpegSubsamp == TJSAMP_GRAY) {
strides[1] = strides[2] = 0;
dstPlanes[1] = dstPlanes[2] = NULL;
@@ -1860,7 +1901,7 @@ DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
int pw1 = tjPlaneWidth(1, width, jpegSubsamp);
int ph1 = tjPlaneHeight(1, height, jpegSubsamp);
- strides[1] = strides[2] = PAD(pw1, pad);
+ strides[1] = strides[2] = PAD(pw1, align);
dstPlanes[1] = dstPlanes[0] + strides[0] * ph0;
dstPlanes[2] = dstPlanes[1] + strides[1] * ph1;
}
@@ -1874,6 +1915,7 @@ bailout:
return retval;
}
+/* TurboJPEG 1.1+ */
DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
unsigned long jpegSize, unsigned char *dstBuf,
int flags)
@@ -1882,8 +1924,9 @@ DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
}
-/* Transformer */
+/******************************** Transformer ********************************/
+/* TurboJPEG 1.2+ */
DLLEXPORT tjhandle tjInitTransform(void)
{
tjinstance *this = NULL;
@@ -1903,6 +1946,7 @@ DLLEXPORT tjhandle tjInitTransform(void)
}
+/* TurboJPEG 1.2+ */
DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
unsigned long jpegSize, int n,
unsigned char **dstBufs, unsigned long *dstSizes,
@@ -2013,8 +2057,10 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
jpeg_mem_dest_tj(cinfo, &dstBufs[i], &dstSizes[i], alloc);
jpeg_copy_critical_parameters(dinfo, cinfo);
dstcoefs = jtransform_adjust_parameters(dinfo, cinfo, srccoefs, &xinfo[i]);
+#ifdef C_PROGRESSIVE_SUPPORTED
if (flags & TJFLAG_PROGRESSIVE || t[i].options & TJXOPT_PROGRESSIVE)
jpeg_simple_progression(cinfo);
+#endif
if (!(t[i].options & TJXOPT_NOOUTPUT)) {
jpeg_write_coefficients(cinfo, dstcoefs);
jcopy_markers_execute(dinfo, cinfo, t[i].options & TJXOPT_COPYNONE ?
@@ -2069,6 +2115,9 @@ bailout:
}
+/*************************** Packed-Pixel Image I/O **************************/
+
+/* TurboJPEG 2.0+ */
DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
int align, int *height, int *pixelFormat,
int flags)
@@ -2118,7 +2167,7 @@ DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
invert = (flags & TJFLAG_BOTTOMUP) == 0;
} else if (tempc == 'P') {
if ((src = jinit_read_ppm(cinfo)) == NULL)
- THROWG("tjLoadImage(): Could not initialize bitmap loader");
+ THROWG("tjLoadImage(): Could not initialize PPM loader");
invert = (flags & TJFLAG_BOTTOMUP) != 0;
} else
THROWG("tjLoadImage(): Unsupported file type");
@@ -2171,6 +2220,7 @@ bailout:
}
+/* TurboJPEG 2.0+ */
DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
int width, int pitch, int height, int pixelFormat,
int flags)
diff --git a/turbojpeg.h b/turbojpeg.h
index 02b54ca9..1f8756a6 100644
--- a/turbojpeg.h
+++ b/turbojpeg.h
@@ -1,6 +1,6 @@
/*
- * Copyright (C)2009-2015, 2017, 2020-2021 D. R. Commander.
- * All Rights Reserved.
+ * Copyright (C)2009-2015, 2017, 2020-2021, 2023 D. R. Commander.
+ * All Rights Reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
@@ -54,23 +54,24 @@
* Each plane is simply a 2D array of bytes, each byte representing the value
* of one of the components (Y, Cb, or Cr) at a particular location in the
* image. The width and height of each plane are determined by the image
- * width, height, and level of chrominance subsampling. The luminance plane
+ * width, height, and level of chrominance subsampling. The luminance plane
* width is the image width padded to the nearest multiple of the horizontal
- * subsampling factor (2 in the case of 4:2:0 and 4:2:2, 4 in the case of
- * 4:1:1, 1 in the case of 4:4:4 or grayscale.) Similarly, the luminance plane
- * height is the image height padded to the nearest multiple of the vertical
- * subsampling factor (2 in the case of 4:2:0 or 4:4:0, 1 in the case of 4:4:4
- * or grayscale.) This is irrespective of any additional padding that may be
- * specified as an argument to the various YUV functions. The chrominance
- * plane width is equal to the luminance plane width divided by the horizontal
- * subsampling factor, and the chrominance plane height is equal to the
- * luminance plane height divided by the vertical subsampling factor.
+ * subsampling factor (1 in the case of 4:4:4, grayscale, or 4:4:0; 2 in the
+ * case of 4:2:2 or 4:2:0; 4 in the case of 4:1:1.) Similarly, the luminance
+ * plane height is the image height padded to the nearest multiple of the
+ * vertical subsampling factor (1 in the case of 4:4:4, 4:2:2, grayscale, or
+ * 4:1:1; 2 in the case of 4:2:0 or 4:4:0.) This is irrespective of any
+ * additional padding that may be specified as an argument to the various YUV
+ * functions. The chrominance plane width is equal to the luminance plane
+ * width divided by the horizontal subsampling factor, and the chrominance
+ * plane height is equal to the luminance plane height divided by the vertical
+ * subsampling factor.
*
* For example, if the source image is 35 x 35 pixels and 4:2:2 subsampling is
* used, then the luminance plane would be 36 x 35 bytes, and each of the
- * chrominance planes would be 18 x 35 bytes. If you specify a line padding of
- * 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes, and
- * each of the chrominance planes would be 20 x 35 bytes.
+ * chrominance planes would be 18 x 35 bytes. If you specify a row alignment
+ * of 4 bytes on top of this, then the luminance plane would be 36 x 35 bytes,
+ * and each of the chrominance planes would be 20 x 35 bytes.
*
* @{
*/
@@ -86,8 +87,8 @@
* When pixels are converted from RGB to YCbCr (see #TJCS_YCbCr) or from CMYK
* to YCCK (see #TJCS_YCCK) as part of the JPEG compression process, some of
* the Cb and Cr (chrominance) components can be discarded or averaged together
- * to produce a smaller image with little perceptible loss of image clarity
- * (the human eye is more sensitive to small changes in brightness than to
+ * to produce a smaller image with little perceptible loss of image clarity.
+ * (The human eye is more sensitive to small changes in brightness than to
* small changes in color.) This is called "chrominance subsampling".
*/
enum TJSAMP {
@@ -245,8 +246,8 @@ enum TJPF {
* vice versa, but the mapping is typically not 1:1 or reversible, nor can it
* be defined with a simple formula. Thus, such a conversion is out of scope
* for a codec library. However, the TurboJPEG API allows for compressing
- * CMYK pixels into a YCCK JPEG image (see #TJCS_YCCK) and decompressing YCCK
- * JPEG images into CMYK pixels.
+ * packed-pixel CMYK images into YCCK JPEG images (see #TJCS_YCCK) and
+ * decompressing YCCK JPEG images into packed-pixel CMYK images.
*/
TJPF_CMYK,
/**
@@ -258,9 +259,10 @@ enum TJPF {
/**
* Red offset (in bytes) for a given pixel format. This specifies the number
* of bytes that the red component is offset from the start of the pixel. For
- * instance, if a pixel of format TJ_BGRX is stored in <tt>char pixel[]</tt>,
- * then the red component will be <tt>pixel[tjRedOffset[TJ_BGRX]]</tt>. This
- * will be -1 if the pixel format does not have a red component.
+ * instance, if a pixel of format TJPF_BGRX is stored in
+ * `unsigned char pixel[]`, then the red component will be
+ *`pixel[tjRedOffset[TJPF_BGRX]]`. This will be -1 if the pixel format does
+ * not have a red component.
*/
static const int tjRedOffset[TJ_NUMPF] = {
0, 2, 0, 2, 3, 1, -1, 0, 2, 3, 1, -1
@@ -268,31 +270,32 @@ static const int tjRedOffset[TJ_NUMPF] = {
/**
* Green offset (in bytes) for a given pixel format. This specifies the number
* of bytes that the green component is offset from the start of the pixel.
- * For instance, if a pixel of format TJ_BGRX is stored in
- * <tt>char pixel[]</tt>, then the green component will be
- * <tt>pixel[tjGreenOffset[TJ_BGRX]]</tt>. This will be -1 if the pixel format
- * does not have a green component.
+ * For instance, if a pixel of format TJPF_BGRX is stored in
+ * `unsigned char pixel[]`, then the green component will be
+ * `pixel[tjGreenOffset[TJPF_BGRX]]`. This will be -1 if the pixel format does
+ * not have a green component.
*/
static const int tjGreenOffset[TJ_NUMPF] = {
1, 1, 1, 1, 2, 2, -1, 1, 1, 2, 2, -1
};
/**
* Blue offset (in bytes) for a given pixel format. This specifies the number
- * of bytes that the Blue component is offset from the start of the pixel. For
- * instance, if a pixel of format TJ_BGRX is stored in <tt>char pixel[]</tt>,
- * then the blue component will be <tt>pixel[tjBlueOffset[TJ_BGRX]]</tt>. This
- * will be -1 if the pixel format does not have a blue component.
+ * of bytes that the blue component is offset from the start of the pixel. For
+ * instance, if a pixel of format TJPF_BGRX is stored in
+ * `unsigned char pixel[]`, then the blue component will be
+ * `pixel[tjBlueOffset[TJPF_BGRX]]`. This will be -1 if the pixel format does
+ * not have a blue component.
*/
static const int tjBlueOffset[TJ_NUMPF] = {
2, 0, 2, 0, 1, 3, -1, 2, 0, 1, 3, -1
};
/**
* Alpha offset (in bytes) for a given pixel format. This specifies the number
- * of bytes that the Alpha component is offset from the start of the pixel.
- * For instance, if a pixel of format TJ_BGRA is stored in
- * <tt>char pixel[]</tt>, then the alpha component will be
- * <tt>pixel[tjAlphaOffset[TJ_BGRA]]</tt>. This will be -1 if the pixel format
- * does not have an alpha component.
+ * of bytes that the alpha component is offset from the start of the pixel.
+ * For instance, if a pixel of format TJPF_BGRA is stored in
+ * `unsigned char pixel[]`, then the alpha component will be
+ * `pixel[tjAlphaOffset[TJPF_BGRA]]`. This will be -1 if the pixel format does
+ * not have an alpha component.
*/
static const int tjAlphaOffset[TJ_NUMPF] = {
-1, -1, -1, -1, -1, -1, -1, 3, 3, 0, 0, -1
@@ -318,8 +321,9 @@ enum TJCS {
* RGB colorspace. When compressing the JPEG image, the R, G, and B
* components in the source image are reordered into image planes, but no
* colorspace conversion or subsampling is performed. RGB JPEG images can be
- * decompressed to any of the extended RGB pixel formats or grayscale, but
- * they cannot be decompressed to YUV images.
+ * decompressed to packed-pixel images with any of the extended RGB or
+ * grayscale pixel formats, but they cannot be decompressed to planar YUV
+ * images.
*/
TJCS_RGB = 0,
/**
@@ -332,25 +336,27 @@ enum TJCS {
* original image. Originally, the analog equivalent of this transformation
* allowed the same signal to drive both black & white and color televisions,
* but JPEG images use YCbCr primarily because it allows the color data to be
- * optionally subsampled for the purposes of reducing bandwidth or disk
- * space. YCbCr is the most common JPEG colorspace, and YCbCr JPEG images
- * can be compressed from and decompressed to any of the extended RGB pixel
- * formats or grayscale, or they can be decompressed to YUV planar images.
+ * optionally subsampled for the purposes of reducing network or disk usage.
+ * YCbCr is the most common JPEG colorspace, and YCbCr JPEG images can be
+ * compressed from and decompressed to packed-pixel images with any of the
+ * extended RGB or grayscale pixel formats. YCbCr JPEG images can also be
+ * compressed from and decompressed to planar YUV images.
*/
TJCS_YCbCr,
/**
* Grayscale colorspace. The JPEG image retains only the luminance data (Y
* component), and any color data from the source image is discarded.
- * Grayscale JPEG images can be compressed from and decompressed to any of
- * the extended RGB pixel formats or grayscale, or they can be decompressed
- * to YUV planar images.
+ * Grayscale JPEG images can be compressed from and decompressed to
+ * packed-pixel images with any of the extended RGB or grayscale pixel
+ * formats, or they can be compressed from and decompressed to planar YUV
+ * images.
*/
TJCS_GRAY,
/**
* CMYK colorspace. When compressing the JPEG image, the C, M, Y, and K
* components in the source image are reordered into image planes, but no
* colorspace conversion or subsampling is performed. CMYK JPEG images can
- * only be decompressed to CMYK pixels.
+ * only be decompressed to packed-pixel images with the CMYK pixel format.
*/
TJCS_CMYK,
/**
@@ -360,56 +366,54 @@ enum TJCS {
* reversibly transformed into YCCK, and as with YCbCr, the chrominance
* components in the YCCK pixels can be subsampled without incurring major
* perceptual loss. YCCK JPEG images can only be compressed from and
- * decompressed to CMYK pixels.
+ * decompressed to packed-pixel images with the CMYK pixel format.
*/
TJCS_YCCK
};
/**
- * The uncompressed source/destination image is stored in bottom-up (Windows,
- * OpenGL) order, not top-down (X11) order.
+ * Rows in the packed-pixel source/destination image are stored in bottom-up
+ * (Windows, OpenGL) order rather than in top-down (X11) order.
*/
#define TJFLAG_BOTTOMUP 2
/**
* When decompressing an image that was compressed using chrominance
- * subsampling, use the fastest chrominance upsampling algorithm available in
- * the underlying codec. The default is to use smooth upsampling, which
- * creates a smooth transition between neighboring chrominance components in
- * order to reduce upsampling artifacts in the decompressed image.
+ * subsampling, use the fastest chrominance upsampling algorithm available.
+ * The default is to use smooth upsampling, which creates a smooth transition
+ * between neighboring chrominance components in order to reduce upsampling
+ * artifacts in the decompressed image.
*/
#define TJFLAG_FASTUPSAMPLE 256
/**
- * Disable buffer (re)allocation. If passed to one of the JPEG compression or
- * transform functions, this flag will cause those functions to generate an
- * error if the JPEG image buffer is invalid or too small rather than
- * attempting to allocate or reallocate that buffer. This reproduces the
- * behavior of earlier versions of TurboJPEG.
+ * Disable JPEG buffer (re)allocation. If passed to one of the JPEG
+ * compression or transform functions, this flag will cause those functions to
+ * generate an error if the JPEG destination buffer is invalid or too small,
+ * rather than attempt to allocate or reallocate that buffer.
*/
#define TJFLAG_NOREALLOC 1024
/**
- * Use the fastest DCT/IDCT algorithm available in the underlying codec. The
- * default if this flag is not specified is implementation-specific. For
- * example, the implementation of TurboJPEG for libjpeg[-turbo] uses the fast
- * algorithm by default when compressing, because this has been shown to have
- * only a very slight effect on accuracy, but it uses the accurate algorithm
- * when decompressing, because this has been shown to have a larger effect.
+ * Use the fastest DCT/IDCT algorithm available. The default if this flag is
+ * not specified is implementation-specific. For example, the implementation
+ * of the TurboJPEG API in libjpeg-turbo uses the fast algorithm by default
+ * when compressing, because this has been shown to have only a very slight
+ * effect on accuracy, but it uses the accurate algorithm when decompressing,
+ * because this has been shown to have a larger effect.
*/
#define TJFLAG_FASTDCT 2048
/**
- * Use the most accurate DCT/IDCT algorithm available in the underlying codec.
- * The default if this flag is not specified is implementation-specific. For
- * example, the implementation of TurboJPEG for libjpeg[-turbo] uses the fast
- * algorithm by default when compressing, because this has been shown to have
- * only a very slight effect on accuracy, but it uses the accurate algorithm
- * when decompressing, because this has been shown to have a larger effect.
+ * Use the most accurate DCT/IDCT algorithm available. The default if this
+ * flag is not specified is implementation-specific. For example, the
+ * implementation of the TurboJPEG API in libjpeg-turbo uses the fast algorithm
+ * by default when compressing, because this has been shown to have only a very
+ * slight effect on accuracy, but it uses the accurate algorithm when
+ * decompressing, because this has been shown to have a larger effect.
*/
#define TJFLAG_ACCURATEDCT 4096
/**
* Immediately discontinue the current compression/decompression/transform
- * operation if the underlying codec throws a warning (non-fatal error). The
- * default behavior is to allow the operation to complete unless a fatal error
- * is encountered.
+ * operation if a warning (non-fatal error) occurs. The default behavior is to
+ * allow the operation to complete unless a fatal error is encountered.
*/
#define TJFLAG_STOPONWARNING 8192
/**
@@ -441,8 +445,8 @@ enum TJCS {
*/
enum TJERR {
/**
- * The error was non-fatal and recoverable, but the image may still be
- * corrupt.
+ * The error was non-fatal and recoverable, but the destination image may
+ * still be corrupt.
*/
TJERR_WARNING = 0,
/**
@@ -509,9 +513,9 @@ enum TJXOP {
/**
* This option will cause #tjTransform() to return an error if the transform is
* not perfect. Lossless transforms operate on MCU blocks, whose size depends
- * on the level of chrominance subsampling used (see #tjMCUWidth
- * and #tjMCUHeight.) If the image's width or height is not evenly divisible
- * by the MCU block size, then there will be partial MCU blocks on the right
+ * on the level of chrominance subsampling used (see #tjMCUWidth and
+ * #tjMCUHeight.) If the image's width or height is not evenly divisible by
+ * the MCU block size, then there will be partial MCU blocks on the right
* and/or bottom edges. It is not possible to move these partial MCU blocks to
* the top or left of the image, so any transform that would require that is
* "imperfect." If this option is not specified, then any partial MCU blocks
@@ -530,29 +534,28 @@ enum TJXOP {
*/
#define TJXOPT_CROP 4
/**
- * This option will discard the color data in the input image and produce
- * a grayscale output image.
+ * This option will discard the color data in the source image and produce a
+ * grayscale destination image.
*/
#define TJXOPT_GRAY 8
/**
* This option will prevent #tjTransform() from outputting a JPEG image for
- * this particular transform (this can be used in conjunction with a custom
+ * this particular transform. (This can be used in conjunction with a custom
* filter to capture the transformed DCT coefficients without transcoding
* them.)
*/
#define TJXOPT_NOOUTPUT 16
/**
- * This option will enable progressive entropy coding in the output image
+ * 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 compression and decompression performance
- * considerably.
+ * default), but it will reduce decompression performance considerably.
*/
#define TJXOPT_PROGRESSIVE 32
/**
* This option will prevent #tjTransform() from copying any extra markers
- * (including EXIF and ICC profile data) from the source image to the output
- * image.
+ * (including EXIF and ICC profile data) from the source image to the
+ * destination image.
*/
#define TJXOPT_COPYNONE 64
@@ -586,12 +589,12 @@ typedef struct {
*/
int y;
/**
- * The width of the cropping region. Setting this to 0 is the equivalent of
+ * The width of the cropping region. Setting this to 0 is the equivalent of
* setting it to the width of the source JPEG image - x.
*/
int w;
/**
- * The height of the cropping region. Setting this to 0 is the equivalent of
+ * The height of the cropping region. Setting this to 0 is the equivalent of
* setting it to the height of the source JPEG image - y.
*/
int h;
@@ -610,7 +613,8 @@ typedef struct tjtransform {
*/
int op;
/**
- * The bitwise OR of one of more of the @ref TJXOPT_CROP "transform options"
+ * The bitwise OR of one of more of the @ref TJXOPT_COPYNONE
+ * "transform options"
*/
int options;
/**
@@ -619,10 +623,10 @@ typedef struct tjtransform {
*/
void *data;
/**
- * A callback function that can be used to modify the DCT coefficients
- * after they are losslessly transformed but before they are transcoded to a
- * new JPEG image. This allows for custom filters or other transformations
- * to be applied in the frequency domain.
+ * A callback function that can be used to modify the DCT coefficients after
+ * they are losslessly transformed but before they are transcoded to a new
+ * JPEG image. This allows for custom filters or other transformations to be
+ * applied in the frequency domain.
*
* @param coeffs pointer to an array of transformed DCT coefficients. (NOTE:
* this pointer is not guaranteed to be valid once the callback returns, so
@@ -630,21 +634,21 @@ typedef struct tjtransform {
* or library should make a copy of them within the body of the callback.)
*
* @param arrayRegion #tjregion structure containing the width and height of
- * the array pointed to by <tt>coeffs</tt> as well as its offset relative to
- * the component plane. TurboJPEG implementations may choose to split each
+ * the array pointed to by `coeffs` as well as its offset relative to the
+ * component plane. TurboJPEG implementations may choose to split each
* component plane into multiple DCT coefficient arrays and call the callback
* function once for each array.
*
* @param planeRegion #tjregion structure containing the width and height of
- * the component plane to which <tt>coeffs</tt> belongs
+ * the component plane to which `coeffs` belongs
*
- * @param componentID ID number of the component plane to which
- * <tt>coeffs</tt> belongs (Y, Cb, and Cr have, respectively, ID's of 0, 1,
- * and 2 in typical JPEG images.)
+ * @param componentID ID number of the component plane to which `coeffs`
+ * belongs. (Y, Cb, and Cr have, respectively, ID's of 0, 1, and 2 in
+ * typical JPEG images.)
*
- * @param transformID ID number of the transformed image to which
- * <tt>coeffs</tt> belongs. This is the same as the index of the transform
- * in the <tt>transforms</tt> array that was passed to #tjTransform().
+ * @param transformID ID number of the transformed image to which `coeffs`
+ * belongs. This is the same as the index of the transform in the
+ * `transforms` array that was passed to #tjTransform().
*
* @param transform a pointer to a #tjtransform structure that specifies the
* parameters and/or cropping region for this transform
@@ -663,14 +667,14 @@ typedef void *tjhandle;
/**
- * Pad the given width to the nearest 32-bit boundary
+ * Pad the given width to the nearest multiple of 4
*/
#define TJPAD(width) (((width) + 3) & (~3))
/**
- * Compute the scaled value of <tt>dimension</tt> using the given scaling
- * factor. This macro performs the integer equivalent of <tt>ceil(dimension *
- * scalingFactor)</tt>.
+ * Compute the scaled value of `dimension` using the given scaling factor.
+ * This macro performs the integer equivalent of `ceil(dimension *
+ * scalingFactor)`.
*/
#define TJSCALED(dimension, scalingFactor) \
(((dimension) * scalingFactor.num + scalingFactor.denom - 1) / \
@@ -685,27 +689,27 @@ extern "C" {
/**
* Create a TurboJPEG compressor instance.
*
- * @return a handle to the newly-created instance, or NULL if an error
- * occurred (see #tjGetErrorStr2().)
+ * @return a handle to the newly-created instance, or NULL if an error occurred
+ * (see #tjGetErrorStr2().)
*/
DLLEXPORT tjhandle tjInitCompress(void);
/**
- * Compress an RGB, grayscale, or CMYK image into a JPEG image.
+ * Compress a packed-pixel RGB, grayscale, or CMYK image into a JPEG image.
*
* @param handle a handle to a TurboJPEG compressor or transformer instance
*
- * @param srcBuf pointer to an image buffer containing RGB, grayscale, or
- * CMYK pixels to be compressed
+ * @param srcBuf pointer to a buffer containing a packed-pixel RGB, grayscale,
+ * or CMYK source image to be compressed
*
* @param width width (in pixels) of the source image
*
- * @param pitch bytes per line in the source image. Normally, this should be
- * <tt>width * #tjPixelSize[pixelFormat]</tt> if the image is unpadded, or
- * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line of the image
- * is padded to the nearest 32-bit boundary, as is the case for Windows
- * bitmaps. You can also be clever and use this parameter to skip lines, etc.
+ * @param pitch bytes per row in the source image. Normally this should be
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>, if the image is unpadded, or
+ * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each row of the image
+ * is padded to the nearest multiple of 4 bytes, as is the case for Windows
+ * bitmaps. You can also be clever and use this parameter to skip rows, etc.
* Setting this parameter to 0 is the equivalent of setting it to
* <tt>width * #tjPixelSize[pixelFormat]</tt>.
*
@@ -714,29 +718,28 @@ DLLEXPORT tjhandle tjInitCompress(void);
* @param pixelFormat pixel format of the source image (see @ref TJPF
* "Pixel formats".)
*
- * @param jpegBuf address of a pointer to an image buffer that will receive the
- * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer
- * to accommodate the size of the JPEG image. Thus, you can choose to:
+ * @param jpegBuf address of a pointer to a byte buffer that will receive the
+ * JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to
+ * accommodate the size of the JPEG image. Thus, you can choose to:
* -# pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and
* let TurboJPEG grow the buffer as needed,
- * -# set <tt>*jpegBuf</tt> to NULL to tell TurboJPEG to allocate the buffer
- * for you, or
+ * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
+ * or
* -# pre-allocate the buffer to a "worst case" size determined by calling
* #tjBufSize(). This should ensure that the buffer never has to be
- * re-allocated (setting #TJFLAG_NOREALLOC guarantees that it won't be.)
+ * re-allocated. (Setting #TJFLAG_NOREALLOC guarantees that it won't be.)
* .
- * If you choose option 1, <tt>*jpegSize</tt> should be set to the size of your
+ * If you choose option 1, then `*jpegSize` should be set to the size of your
* pre-allocated buffer. In any case, unless you have set #TJFLAG_NOREALLOC,
- * you should always check <tt>*jpegBuf</tt> upon return from this function, as
- * it may have changed.
+ * you should always check `*jpegBuf` upon return from this function, as it may
+ * have changed.
*
* @param jpegSize pointer to an unsigned long variable that holds the size of
- * the JPEG image buffer. If <tt>*jpegBuf</tt> points to a pre-allocated
- * buffer, then <tt>*jpegSize</tt> should be set to the size of the buffer.
- * Upon return, <tt>*jpegSize</tt> will contain the size of the JPEG image (in
- * bytes.) If <tt>*jpegBuf</tt> points to a JPEG image buffer that is being
- * reused from a previous call to one of the JPEG compression functions, then
- * <tt>*jpegSize</tt> is ignored.
+ * the JPEG buffer. If `*jpegBuf` points to a pre-allocated buffer, then
+ * `*jpegSize` should be set to the size of the buffer. Upon return,
+ * `*jpegSize` will contain the size of the JPEG image (in bytes.) If
+ * `*jpegBuf` points to a JPEG buffer that is being reused from a previous call
+ * to one of the JPEG compression functions, then `*jpegSize` is ignored.
*
* @param jpegSubsamp the level of chrominance subsampling to be used when
* generating the JPEG image (see @ref TJSAMP
@@ -750,7 +753,7 @@ DLLEXPORT tjhandle tjInitCompress(void);
*
* @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
* and #tjGetErrorCode().)
-*/
+ */
DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
int width, int pitch, int height, int pixelFormat,
unsigned char **jpegBuf, unsigned long *jpegSize,
@@ -758,55 +761,55 @@ DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
/**
- * Compress a YUV planar image into a JPEG image.
+ * Compress a unified planar YUV image into a JPEG image.
*
* @param handle a handle to a TurboJPEG compressor or transformer instance
*
- * @param srcBuf pointer to an image buffer containing a YUV planar image to be
- * compressed. The size of this buffer should match the value returned by
- * #tjBufSizeYUV2() for the given image width, height, padding, and level of
- * chrominance subsampling. The Y, U (Cb), and V (Cr) image planes should be
- * stored sequentially in the source buffer (refer to @ref YUVnotes
- * "YUV Image Format Notes".)
+ * @param srcBuf pointer to a buffer containing a unified planar YUV source
+ * image to be compressed. The size of this buffer should match the value
+ * returned by #tjBufSizeYUV2() for the given image width, height, row
+ * alignment, and level of chrominance subsampling. The Y, U (Cb), and V (Cr)
+ * image planes should be stored sequentially in the buffer. (Refer to
+ * @ref YUVnotes "YUV Image Format Notes".)
*
* @param width width (in pixels) of the source image. If the width is not an
* even multiple of the MCU block width (see #tjMCUWidth), then an intermediate
- * buffer copy will be performed within TurboJPEG.
+ * buffer copy will be performed.
*
- * @param pad the line padding used in the source image. For instance, if each
- * line in each plane of the YUV image is padded to the nearest multiple of 4
- * bytes, then <tt>pad</tt> should be set to 4.
+ * @param align row alignment (in bytes) of the source image (must be a power
+ * of 2.) Setting this parameter to n indicates that each row in each plane of
+ * the source image is padded to the nearest multiple of n bytes
+ * (1 = unpadded.)
*
* @param height height (in pixels) of the source image. If the height is not
* an even multiple of the MCU block height (see #tjMCUHeight), then an
- * intermediate buffer copy will be performed within TurboJPEG.
+ * intermediate buffer copy will be performed.
*
- * @param subsamp the level of chrominance subsampling used in the source
- * image (see @ref TJSAMP "Chrominance subsampling options".)
+ * @param subsamp the level of chrominance subsampling used in the source image
+ * (see @ref TJSAMP "Chrominance subsampling options".)
*
- * @param jpegBuf address of a pointer to an image buffer that will receive the
+ * @param jpegBuf address of a pointer to a byte buffer that will receive the
* JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to
* accommodate the size of the JPEG image. Thus, you can choose to:
* -# pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and
* let TurboJPEG grow the buffer as needed,
- * -# set <tt>*jpegBuf</tt> to NULL to tell TurboJPEG to allocate the buffer
- * for you, or
+ * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
+ * or
* -# pre-allocate the buffer to a "worst case" size determined by calling
* #tjBufSize(). This should ensure that the buffer never has to be
- * re-allocated (setting #TJFLAG_NOREALLOC guarantees that it won't be.)
+ * re-allocated. (Setting #TJFLAG_NOREALLOC guarantees that it won't be.)
* .
- * If you choose option 1, <tt>*jpegSize</tt> should be set to the size of your
+ * If you choose option 1, then `*jpegSize` should be set to the size of your
* pre-allocated buffer. In any case, unless you have set #TJFLAG_NOREALLOC,
- * you should always check <tt>*jpegBuf</tt> upon return from this function, as
- * it may have changed.
+ * you should always check `*jpegBuf` upon return from this function, as it may
+ * have changed.
*
* @param jpegSize pointer to an unsigned long variable that holds the size of
- * the JPEG image buffer. If <tt>*jpegBuf</tt> points to a pre-allocated
- * buffer, then <tt>*jpegSize</tt> should be set to the size of the buffer.
- * Upon return, <tt>*jpegSize</tt> will contain the size of the JPEG image (in
- * bytes.) If <tt>*jpegBuf</tt> points to a JPEG image buffer that is being
- * reused from a previous call to one of the JPEG compression functions, then
- * <tt>*jpegSize</tt> is ignored.
+ * the JPEG buffer. If `*jpegBuf` points to a pre-allocated buffer, then
+ * `*jpegSize` should be set to the size of the buffer. Upon return,
+ * `*jpegSize` will contain the size of the JPEG image (in bytes.) If
+ * `*jpegBuf` points to a JPEG buffer that is being reused from a previous call
+ * to one of the JPEG compression functions, then `*jpegSize` is ignored.
*
* @param jpegQual the image quality of the generated JPEG image (1 = worst,
* 100 = best)
@@ -816,9 +819,9 @@ DLLEXPORT int tjCompress2(tjhandle handle, const unsigned char *srcBuf,
*
* @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
* and #tjGetErrorCode().)
-*/
+ */
DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
- int width, int pad, int height, int subsamp,
+ int width, int align, int height, int subsamp,
unsigned char **jpegBuf,
unsigned long *jpegSize, int jpegQual,
int flags);
@@ -831,55 +834,54 @@ DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
*
* @param srcPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes
* (or just a Y plane, if compressing a grayscale image) that contain a YUV
- * image to be compressed. These planes can be contiguous or non-contiguous in
- * memory. The size of each plane should match the value returned by
- * #tjPlaneSizeYUV() for the given image width, height, strides, and level of
- * chrominance subsampling. Refer to @ref YUVnotes "YUV Image Format Notes"
- * for more details.
+ * source image to be compressed. These planes can be contiguous or
+ * non-contiguous in memory. The size of each plane should match the value
+ * returned by #tjPlaneSizeYUV() for the given image width, height, strides,
+ * and level of chrominance subsampling. Refer to @ref YUVnotes
+ * "YUV Image Format Notes" for more details.
*
* @param width width (in pixels) of the source image. If the width is not an
* even multiple of the MCU block width (see #tjMCUWidth), then an intermediate
- * buffer copy will be performed within TurboJPEG.
+ * buffer copy will be performed.
*
* @param strides an array of integers, each specifying the number of bytes per
- * line in the corresponding plane of the YUV source image. Setting the stride
+ * row in the corresponding plane of the YUV source image. Setting the stride
* for any plane to 0 is the same as setting it to the plane width (see
- * @ref YUVnotes "YUV Image Format Notes".) If <tt>strides</tt> is NULL, then
- * the strides for all planes will be set to their respective plane widths.
- * You can adjust the strides in order to specify an arbitrary amount of line
+ * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the
+ * strides for all planes will be set to their respective plane widths. You
+ * can adjust the strides in order to specify an arbitrary amount of row
* padding in each plane or to create a JPEG image from a subregion of a larger
- * YUV planar image.
+ * planar YUV image.
*
* @param height height (in pixels) of the source image. If the height is not
* an even multiple of the MCU block height (see #tjMCUHeight), then an
- * intermediate buffer copy will be performed within TurboJPEG.
+ * intermediate buffer copy will be performed.
*
- * @param subsamp the level of chrominance subsampling used in the source
- * image (see @ref TJSAMP "Chrominance subsampling options".)
+ * @param subsamp the level of chrominance subsampling used in the source image
+ * (see @ref TJSAMP "Chrominance subsampling options".)
*
- * @param jpegBuf address of a pointer to an image buffer that will receive the
+ * @param jpegBuf address of a pointer to a byte buffer that will receive the
* JPEG image. TurboJPEG has the ability to reallocate the JPEG buffer to
* accommodate the size of the JPEG image. Thus, you can choose to:
* -# pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and
* let TurboJPEG grow the buffer as needed,
- * -# set <tt>*jpegBuf</tt> to NULL to tell TurboJPEG to allocate the buffer
- * for you, or
+ * -# set `*jpegBuf` to NULL to tell TurboJPEG to allocate the buffer for you,
+ * or
* -# pre-allocate the buffer to a "worst case" size determined by calling
* #tjBufSize(). This should ensure that the buffer never has to be
- * re-allocated (setting #TJFLAG_NOREALLOC guarantees that it won't be.)
+ * re-allocated. (Setting #TJFLAG_NOREALLOC guarantees that it won't be.)
* .
- * If you choose option 1, <tt>*jpegSize</tt> should be set to the size of your
+ * If you choose option 1, then `*jpegSize` should be set to the size of your
* pre-allocated buffer. In any case, unless you have set #TJFLAG_NOREALLOC,
- * you should always check <tt>*jpegBuf</tt> upon return from this function, as
- * it may have changed.
+ * you should always check `*jpegBuf` upon return from this function, as it may
+ * have changed.
*
* @param jpegSize pointer to an unsigned long variable that holds the size of
- * the JPEG image buffer. If <tt>*jpegBuf</tt> points to a pre-allocated
- * buffer, then <tt>*jpegSize</tt> should be set to the size of the buffer.
- * Upon return, <tt>*jpegSize</tt> will contain the size of the JPEG image (in
- * bytes.) If <tt>*jpegBuf</tt> points to a JPEG image buffer that is being
- * reused from a previous call to one of the JPEG compression functions, then
- * <tt>*jpegSize</tt> is ignored.
+ * the JPEG buffer. If `*jpegBuf` points to a pre-allocated buffer, then
+ * `*jpegSize` should be set to the size of the buffer. Upon return,
+ * `*jpegSize` will contain the size of the JPEG image (in bytes.) If
+ * `*jpegBuf` points to a JPEG buffer that is being reused from a previous call
+ * to one of the JPEG compression functions, then `*jpegSize` is ignored.
*
* @param jpegQual the image quality of the generated JPEG image (1 = worst,
* 100 = best)
@@ -889,7 +891,7 @@ DLLEXPORT int tjCompressFromYUV(tjhandle handle, const unsigned char *srcBuf,
*
* @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
* and #tjGetErrorCode().)
-*/
+ */
DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
const unsigned char **srcPlanes,
int width, const int *strides,
@@ -903,11 +905,11 @@ DLLEXPORT int tjCompressFromYUVPlanes(tjhandle handle,
* The maximum size of the buffer (in bytes) required to hold a JPEG image with
* the given parameters. The number of bytes returned by this function is
* larger than the size of the uncompressed source image. The reason for this
- * is that the JPEG format uses 16-bit coefficients, and it is thus possible
- * for a very high-quality JPEG image with very high-frequency content to
- * expand rather than compress when converted to the JPEG format. Such images
- * represent a very rare corner case, but since there is no way to predict the
- * size of a JPEG image prior to compression, the corner case has to be
+ * is that the JPEG format uses 16-bit coefficients, so it is possible for a
+ * very high-quality source image with very high-frequency content to expand
+ * rather than compress when converted to the JPEG format. Such images
+ * represent very rare corner cases, but since there is no way to predict the
+ * size of a JPEG image prior to compression, the corner cases have to be
* handled.
*
* @param width width (in pixels) of the image
@@ -925,23 +927,24 @@ DLLEXPORT unsigned long tjBufSize(int width, int height, int jpegSubsamp);
/**
- * The size of the buffer (in bytes) required to hold a YUV planar image with
- * the given parameters.
+ * The size of the buffer (in bytes) required to hold a unified planar YUV
+ * image with the given parameters.
*
* @param width width (in pixels) of the image
*
- * @param pad the width of each line in each plane of the image is padded to
- * the nearest multiple of this number of bytes (must be a power of 2.)
+ * @param align row alignment (in bytes) of the image (must be a power of 2.)
+ * Setting this parameter to n specifies that each row in each plane of the
+ * image will be padded to the nearest multiple of n bytes (1 = unpadded.)
*
* @param height height (in pixels) of the image
*
* @param subsamp level of chrominance subsampling in the image (see
* @ref TJSAMP "Chrominance subsampling options".)
*
- * @return the size of the buffer (in bytes) required to hold the image, or
- * -1 if the arguments are out of bounds.
+ * @return the size of the buffer (in bytes) required to hold the image, or -1
+ * if the arguments are out of bounds.
*/
-DLLEXPORT unsigned long tjBufSizeYUV2(int width, int pad, int height,
+DLLEXPORT unsigned long tjBufSizeYUV2(int width, int align, int height,
int subsamp);
@@ -954,7 +957,7 @@ DLLEXPORT unsigned long tjBufSizeYUV2(int width, int pad, int height,
* @param width width (in pixels) of the YUV image. NOTE: this is the width of
* the whole image, not the plane width.
*
- * @param stride bytes per line in the image plane. Setting this to 0 is the
+ * @param stride bytes per row in the image plane. Setting this to 0 is the
* equivalent of setting it to the plane width.
*
* @param height height (in pixels) of the YUV image. NOTE: this is the height
@@ -1005,23 +1008,23 @@ DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp);
/**
- * Encode an RGB or grayscale image into a YUV planar image. This function
- * uses the accelerated color conversion routines in the underlying
- * codec but does not execute any of the other steps in the JPEG compression
- * process.
+ * Encode a packed-pixel RGB or grayscale image into a unified planar YUV
+ * image. This function performs color conversion (which is accelerated in the
+ * libjpeg-turbo implementation) but does not execute any of the other steps in
+ * the JPEG compression process.
*
* @param handle a handle to a TurboJPEG compressor or transformer instance
*
- * @param srcBuf pointer to an image buffer containing RGB or grayscale pixels
- * to be encoded
+ * @param srcBuf pointer to a buffer containing a packed-pixel RGB or grayscale
+ * source image to be encoded
*
* @param width width (in pixels) of the source image
*
- * @param pitch bytes per line in the source image. Normally, this should be
- * <tt>width * #tjPixelSize[pixelFormat]</tt> if the image is unpadded, or
- * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line of the image
- * is padded to the nearest 32-bit boundary, as is the case for Windows
- * bitmaps. You can also be clever and use this parameter to skip lines, etc.
+ * @param pitch bytes per row in the source image. Normally this should be
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>, if the image is unpadded, or
+ * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each row of the image
+ * is padded to the nearest multiple of 4 bytes, as is the case for Windows
+ * bitmaps. You can also be clever and use this parameter to skip rows, etc.
* Setting this parameter to 0 is the equivalent of setting it to
* <tt>width * #tjPixelSize[pixelFormat]</tt>.
*
@@ -1030,53 +1033,54 @@ DLLEXPORT int tjPlaneHeight(int componentID, int height, int subsamp);
* @param pixelFormat pixel format of the source image (see @ref TJPF
* "Pixel formats".)
*
- * @param dstBuf pointer to an image buffer that will receive the YUV image.
- * Use #tjBufSizeYUV2() to determine the appropriate size for this buffer based
- * on the image width, height, padding, and level of chrominance subsampling.
- * The Y, U (Cb), and V (Cr) image planes will be stored sequentially in the
- * buffer (refer to @ref YUVnotes "YUV Image Format Notes".)
+ * @param dstBuf pointer to a buffer that will receive the unified planar YUV
+ * image. Use #tjBufSizeYUV2() to determine the appropriate size for this
+ * buffer based on the image width, height, row alignment, and level of
+ * chrominance subsampling. The Y, U (Cb), and V (Cr) image planes will be
+ * stored sequentially in the buffer. (Refer to @ref YUVnotes
+ * "YUV Image Format Notes".)
*
- * @param pad the width of each line in each plane of the YUV image will be
- * padded to the nearest multiple of this number of bytes (must be a power of
- * 2.) To generate images suitable for X Video, <tt>pad</tt> should be set to
- * 4.
+ * @param align row alignment (in bytes) of the YUV image (must be a power of
+ * 2.) Setting this parameter to n will cause each row in each plane of the
+ * YUV image to be padded to the nearest multiple of n bytes (1 = unpadded.)
+ * To generate images suitable for X Video, `align` should be set to 4.
*
* @param subsamp the level of chrominance subsampling to be used when
* generating the YUV image (see @ref TJSAMP
* "Chrominance subsampling options".) To generate images suitable for X
- * Video, <tt>subsamp</tt> should be set to @ref TJSAMP_420. This produces an
- * image compatible with the I420 (AKA "YUV420P") format.
+ * Video, `subsamp` should be set to @ref TJSAMP_420. This produces an image
+ * compatible with the I420 (AKA "YUV420P") format.
*
* @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
* "flags"
*
* @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
* and #tjGetErrorCode().)
-*/
+ */
DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
int width, int pitch, int height, int pixelFormat,
- unsigned char *dstBuf, int pad, int subsamp,
+ unsigned char *dstBuf, int align, int subsamp,
int flags);
/**
- * Encode an RGB or grayscale image into separate Y, U (Cb), and V (Cr) image
- * planes. This function uses the accelerated color conversion routines in the
- * underlying codec but does not execute any of the other steps in the JPEG
- * compression process.
+ * Encode a packed-pixel RGB or grayscale image into separate Y, U (Cb), and
+ * V (Cr) image planes. This function performs color conversion (which is
+ * accelerated in the libjpeg-turbo implementation) but does not execute any of
+ * the other steps in the JPEG compression process.
*
* @param handle a handle to a TurboJPEG compressor or transformer instance
*
- * @param srcBuf pointer to an image buffer containing RGB or grayscale pixels
- * to be encoded
+ * @param srcBuf pointer to a buffer containing a packed-pixel RGB or grayscale
+ * source image to be encoded
*
* @param width width (in pixels) of the source image
*
- * @param pitch bytes per line in the source image. Normally, this should be
- * <tt>width * #tjPixelSize[pixelFormat]</tt> if the image is unpadded, or
- * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line of the image
- * is padded to the nearest 32-bit boundary, as is the case for Windows
- * bitmaps. You can also be clever and use this parameter to skip lines, etc.
+ * @param pitch bytes per row in the source image. Normally this should be
+ * <tt>width * #tjPixelSize[pixelFormat]</tt>, if the image is unpadded, or
+ * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each row of the image
+ * is padded to the nearest multiple of 4 bytes, as is the case for Windows
+ * bitmaps. You can also be clever and use this parameter to skip rows, etc.
* Setting this parameter to 0 is the equivalent of setting it to
* <tt>width * #tjPixelSize[pixelFormat]</tt>.
*
@@ -1093,26 +1097,26 @@ DLLEXPORT int tjEncodeYUV3(tjhandle handle, const unsigned char *srcBuf,
* Refer to @ref YUVnotes "YUV Image Format Notes" for more details.
*
* @param strides an array of integers, each specifying the number of bytes per
- * line in the corresponding plane of the output image. Setting the stride for
- * any plane to 0 is the same as setting it to the plane width (see
- * @ref YUVnotes "YUV Image Format Notes".) If <tt>strides</tt> is NULL, then
- * the strides for all planes will be set to their respective plane widths.
- * You can adjust the strides in order to add an arbitrary amount of line
- * padding to each plane or to encode an RGB or grayscale image into a
- * subregion of a larger YUV planar image.
+ * row in the corresponding plane of the YUV image. Setting the stride for any
+ * plane to 0 is the same as setting it to the plane width (see @ref YUVnotes
+ * "YUV Image Format Notes".) If `strides` is NULL, then the strides for all
+ * planes will be set to their respective plane widths. You can adjust the
+ * strides in order to add an arbitrary amount of row padding to each plane or
+ * to encode an RGB or grayscale image into a subregion of a larger planar YUV
+ * image.
*
* @param subsamp the level of chrominance subsampling to be used when
* generating the YUV image (see @ref TJSAMP
* "Chrominance subsampling options".) To generate images suitable for X
- * Video, <tt>subsamp</tt> should be set to @ref TJSAMP_420. This produces an
- * image compatible with the I420 (AKA "YUV420P") format.
+ * Video, `subsamp` should be set to @ref TJSAMP_420. This produces an image
+ * compatible with the I420 (AKA "YUV420P") format.
*
* @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
* "flags"
*
* @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
* and #tjGetErrorCode().)
-*/
+ */
DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
int width, int pitch, int height,
int pixelFormat, unsigned char **dstPlanes,
@@ -1122,9 +1126,9 @@ DLLEXPORT int tjEncodeYUVPlanes(tjhandle handle, const unsigned char *srcBuf,
/**
* Create a TurboJPEG decompressor instance.
*
- * @return a handle to the newly-created instance, or NULL if an error
- * occurred (see #tjGetErrorStr2().)
-*/
+ * @return a handle to the newly-created instance, or NULL if an error occurred
+ * (see #tjGetErrorStr2().)
+ */
DLLEXPORT tjhandle tjInitDecompress(void);
@@ -1134,7 +1138,7 @@ DLLEXPORT tjhandle tjInitDecompress(void);
*
* @param handle a handle to a TurboJPEG decompressor or transformer instance
*
- * @param jpegBuf pointer to a buffer containing a JPEG image or an
+ * @param jpegBuf pointer to a byte buffer containing a JPEG image or an
* "abbreviated table specification" (AKA "tables-only") datastream. Passing a
* tables-only datastream to this function primes the decompressor with
* quantization and Huffman tables that can be used when decompressing
@@ -1145,26 +1149,26 @@ DLLEXPORT tjhandle tjInitDecompress(void);
* @param jpegSize size of the JPEG image or tables-only datastream (in bytes)
*
* @param width pointer to an integer variable that will receive the width (in
- * pixels) of the JPEG image. If <tt>jpegBuf</tt> points to a tables-only
- * datastream, then <tt>width</tt> is ignored.
+ * pixels) of the JPEG image. If `jpegBuf` points to a tables-only datastream,
+ * then `width` is ignored.
*
* @param height pointer to an integer variable that will receive the height
- * (in pixels) of the JPEG image. If <tt>jpegBuf</tt> points to a tables-only
- * datastream, then <tt>height</tt> is ignored.
+ * (in pixels) of the JPEG image. If `jpegBuf` points to a tables-only
+ * datastream, then `height` is ignored.
*
* @param jpegSubsamp pointer to an integer variable that will receive the
* level of chrominance subsampling used when the JPEG image was compressed
- * (see @ref TJSAMP "Chrominance subsampling options".) If <tt>jpegBuf</tt>
- * points to a tables-only datastream, then <tt>jpegSubsamp</tt> is ignored.
+ * (see @ref TJSAMP "Chrominance subsampling options".) If `jpegBuf` points to
+ * a tables-only datastream, then `jpegSubsamp` is ignored.
*
* @param jpegColorspace pointer to an integer variable that will receive one
* of the JPEG colorspace constants, indicating the colorspace of the JPEG
- * image (see @ref TJCS "JPEG colorspaces".) If <tt>jpegBuf</tt>
- * points to a tables-only datastream, then <tt>jpegColorspace</tt> is ignored.
+ * image (see @ref TJCS "JPEG colorspaces".) If `jpegBuf` points to a
+ * tables-only datastream, then `jpegColorspace` is ignored.
*
* @return 0 if successful, or -1 if an error occurred (see #tjGetErrorStr2()
* and #tjGetErrorCode().)
-*/
+ */
DLLEXPORT int tjDecompressHeader3(tjhandle handle,
const unsigned char *jpegBuf,
unsigned long jpegSize, int *width,
@@ -1173,58 +1177,60 @@ DLLEXPORT int tjDecompressHeader3(tjhandle handle,
/**
- * Returns a list of fractional scaling factors that the JPEG decompressor in
- * this implementation of TurboJPEG supports.
+ * Returns a list of fractional scaling factors that the JPEG decompressor
+ * supports.
*
- * @param numscalingfactors pointer to an integer variable that will receive
+ * @param numScalingFactors pointer to an integer variable that will receive
* the number of elements in the list
*
* @return a pointer to a list of fractional scaling factors, or NULL if an
* error is encountered (see #tjGetErrorStr2().)
-*/
-DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numscalingfactors);
+ */
+DLLEXPORT tjscalingfactor *tjGetScalingFactors(int *numScalingFactors);
/**
- * Decompress a JPEG image to an RGB, grayscale, or CMYK image.
+ * Decompress a JPEG image into a packed-pixel RGB, grayscale, or CMYK image.
*
* @param handle a handle to a TurboJPEG decompressor or transformer instance
*
- * @param jpegBuf pointer to a buffer containing the JPEG image to decompress
+ * @param jpegBuf pointer to a byte buffer containing the JPEG image to
+ * decompress
*
* @param jpegSize size of the JPEG image (in bytes)
*
- * @param dstBuf pointer to an image buffer that will receive the decompressed
- * image. This buffer should normally be <tt>pitch * scaledHeight</tt> bytes
- * in size, where <tt>scaledHeight</tt> can be determined by calling
- * #TJSCALED() with the JPEG image height and one of the scaling factors
- * returned by #tjGetScalingFactors(). The <tt>dstBuf</tt> pointer may also be
- * used to decompress into a specific region of a larger buffer.
+ * @param dstBuf pointer to a buffer that will receive the packed-pixel
+ * decompressed image. This buffer should normally be `pitch * scaledHeight`
+ * bytes in size, where `scaledHeight` can be determined by calling #TJSCALED()
+ * with the JPEG image height and one of the scaling factors returned by
+ * #tjGetScalingFactors(). The `dstBuf` pointer may also be used to decompress
+ * into a specific region of a larger buffer.
*
* @param width desired width (in pixels) of the destination image. If this is
* different than the width of the JPEG image being decompressed, then
* TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired width. If <tt>width</tt> is
- * set to 0, then only the height will be considered when determining the
- * scaled image size.
- *
- * @param pitch bytes per line in the destination image. Normally, this is
- * <tt>scaledWidth * #tjPixelSize[pixelFormat]</tt> if the decompressed image
- * is unpadded, else <tt>#TJPAD(scaledWidth * #tjPixelSize[pixelFormat])</tt>
- * if each line of the decompressed image is padded to the nearest 32-bit
- * boundary, as is the case for Windows bitmaps. (NOTE: <tt>scaledWidth</tt>
- * can be determined by calling #TJSCALED() with the JPEG image width and one
- * of the scaling factors returned by #tjGetScalingFactors().) You can also be
- * clever and use the pitch parameter to skip lines, etc. Setting this
- * parameter to 0 is the equivalent of setting it to
+ * possible image that will fit within the desired width. If `width` is set to
+ * 0, then only the height will be considered when determining the scaled image
+ * size.
+ *
+ * @param pitch bytes per row in the destination image. Normally this should
+ * be set to <tt>scaledWidth * #tjPixelSize[pixelFormat]</tt>, if the
+ * destination image should be unpadded, or
+ * <tt>#TJPAD(scaledWidth * #tjPixelSize[pixelFormat])</tt> if each row of the
+ * destination image should be padded to the nearest multiple of 4 bytes, as is
+ * the case for Windows bitmaps. (NOTE: `scaledWidth` can be determined by
+ * calling #TJSCALED() with the JPEG image width and one of the scaling factors
+ * returned by #tjGetScalingFactors().) You can also be clever and use the
+ * pitch parameter to skip rows, etc. Setting this parameter to 0 is the
+ * equivalent of setting it to
* <tt>scaledWidth * #tjPixelSize[pixelFormat]</tt>.
*
* @param height desired height (in pixels) of the destination image. If this
* is different than the height of the JPEG image being decompressed, then
* TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired height. If <tt>height</tt>
- * is set to 0, then only the width will be considered when determining the
- * scaled image size.
+ * possible image that will fit within the desired height. If `height` is set
+ * to 0, then only the width will be considered when determining the scaled
+ * image size.
*
* @param pixelFormat pixel format of the destination image (see @ref
* TJPF "Pixel formats".)
@@ -1242,44 +1248,45 @@ DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
/**
- * Decompress a JPEG image to a YUV planar image. This function performs JPEG
- * decompression but leaves out the color conversion step, so a planar YUV
- * image is generated instead of an RGB image.
+ * Decompress a JPEG image into a unified planar YUV image. This function
+ * performs JPEG decompression but leaves out the color conversion step, so a
+ * planar YUV image is generated instead of a packed-pixel image.
*
* @param handle a handle to a TurboJPEG decompressor or transformer instance
*
- * @param jpegBuf pointer to a buffer containing the JPEG image to decompress
+ * @param jpegBuf pointer to a byte buffer containing the JPEG image to
+ * decompress
*
* @param jpegSize size of the JPEG image (in bytes)
*
- * @param dstBuf pointer to an image buffer that will receive the YUV image.
- * Use #tjBufSizeYUV2() to determine the appropriate size for this buffer based
- * on the image width, height, padding, and level of subsampling. The Y,
- * U (Cb), and V (Cr) image planes will be stored sequentially in the buffer
- * (refer to @ref YUVnotes "YUV Image Format Notes".)
+ * @param dstBuf pointer to a buffer that will receive the unified planar YUV
+ * decompressed image. Use #tjBufSizeYUV2() to determine the appropriate size
+ * for this buffer based on the scaled image width, scaled image height, row
+ * alignment, and level of chrominance subsampling. The Y, U (Cb), and V (Cr)
+ * image planes will be stored sequentially in the buffer. (Refer to
+ * @ref YUVnotes "YUV Image Format Notes".)
*
* @param width desired width (in pixels) of the YUV image. If this is
* different than the width of the JPEG image being decompressed, then
* TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired width. If <tt>width</tt> is
- * set to 0, then only the height will be considered when determining the
- * scaled image size. If the scaled width is not an even multiple of the MCU
- * block width (see #tjMCUWidth), then an intermediate buffer copy will be
- * performed within TurboJPEG.
+ * possible image that will fit within the desired width. If `width` is set to
+ * 0, then only the height will be considered when determining the scaled image
+ * size. If the scaled width is not an even multiple of the MCU block width
+ * (see #tjMCUWidth), then an intermediate buffer copy will be performed.
*
- * @param pad the width of each line in each plane of the YUV image will be
- * padded to the nearest multiple of this number of bytes (must be a power of
- * 2.) To generate images suitable for X Video, <tt>pad</tt> should be set to
- * 4.
+ * @param align row alignment (in bytes) of the YUV image (must be a power of
+ * 2.) Setting this parameter to n will cause each row in each plane of the
+ * YUV image to be padded to the nearest multiple of n bytes (1 = unpadded.)
+ * To generate images suitable for X Video, `align` should be set to 4.
*
* @param height desired height (in pixels) of the YUV image. If this is
* different than the height of the JPEG image being decompressed, then
* TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired height. If <tt>height</tt>
- * is set to 0, then only the width will be considered when determining the
- * scaled image size. If the scaled height is not an even multiple of the MCU
- * block height (see #tjMCUHeight), then an intermediate buffer copy will be
- * performed within TurboJPEG.
+ * possible image that will fit within the desired height. If `height` is set
+ * to 0, then only the width will be considered when determining the scaled
+ * image size. If the scaled height is not an even multiple of the MCU block
+ * height (see #tjMCUHeight), then an intermediate buffer copy will be
+ * performed.
*
* @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
* "flags"
@@ -1289,54 +1296,55 @@ DLLEXPORT int tjDecompress2(tjhandle handle, const unsigned char *jpegBuf,
*/
DLLEXPORT int tjDecompressToYUV2(tjhandle handle, const unsigned char *jpegBuf,
unsigned long jpegSize, unsigned char *dstBuf,
- int width, int pad, int height, int flags);
+ int width, int align, int height, int flags);
/**
* Decompress a JPEG image into separate Y, U (Cb), and V (Cr) image
* planes. This function performs JPEG decompression but leaves out the color
- * conversion step, so a planar YUV image is generated instead of an RGB image.
+ * conversion step, so a planar YUV image is generated instead of a
+ * packed-pixel image.
*
* @param handle a handle to a TurboJPEG decompressor or transformer instance
*
- * @param jpegBuf pointer to a buffer containing the JPEG image to decompress
+ * @param jpegBuf pointer to a byte buffer containing the JPEG image to
+ * decompress
*
* @param jpegSize size of the JPEG image (in bytes)
*
* @param dstPlanes an array of pointers to Y, U (Cb), and V (Cr) image planes
* (or just a Y plane, if decompressing a grayscale image) that will receive
- * the YUV image. These planes can be contiguous or non-contiguous in memory.
- * Use #tjPlaneSizeYUV() to determine the appropriate size for each plane based
- * on the scaled image width, scaled image height, strides, and level of
- * chrominance subsampling. Refer to @ref YUVnotes "YUV Image Format Notes"
- * for more details.
+ * the decompressed image. These planes can be contiguous or non-contiguous in
+ * memory. Use #tjPlaneSizeYUV() to determine the appropriate size for each
+ * plane based on the scaled image width, scaled image height, strides, and
+ * level of chrominance subsampling. Refer to @ref YUVnotes
+ * "YUV Image Format Notes" for more details.
*
* @param width desired width (in pixels) of the YUV image. If this is
* different than the width of the JPEG image being decompressed, then
* TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired width. If <tt>width</tt> is
- * set to 0, then only the height will be considered when determining the
- * scaled image size. If the scaled width is not an even multiple of the MCU
- * block width (see #tjMCUWidth), then an intermediate buffer copy will be
- * performed within TurboJPEG.
+ * possible image that will fit within the desired width. If `width` is set to
+ * 0, then only the height will be considered when determining the scaled image
+ * size. If the scaled width is not an even multiple of the MCU block width
+ * (see #tjMCUWidth), then an intermediate buffer copy will be performed.
*
* @param strides an array of integers, each specifying the number of bytes per
- * line in the corresponding plane of the output image. Setting the stride for
- * any plane to 0 is the same as setting it to the scaled plane width (see
- * @ref YUVnotes "YUV Image Format Notes".) If <tt>strides</tt> is NULL, then
- * the strides for all planes will be set to their respective scaled plane
- * widths. You can adjust the strides in order to add an arbitrary amount of
- * line padding to each plane or to decompress the JPEG image into a subregion
- * of a larger YUV planar image.
+ * row in the corresponding plane of the YUV image. Setting the stride for any
+ * plane to 0 is the same as setting it to the scaled plane width (see
+ * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the
+ * strides for all planes will be set to their respective scaled plane widths.
+ * You can adjust the strides in order to add an arbitrary amount of row
+ * padding to each plane or to decompress the JPEG image into a subregion of a
+ * larger planar YUV image.
*
* @param height desired height (in pixels) of the YUV image. If this is
* different than the height of the JPEG image being decompressed, then
* TurboJPEG will use scaling in the JPEG decompressor to generate the largest
- * possible image that will fit within the desired height. If <tt>height</tt>
- * is set to 0, then only the width will be considered when determining the
- * scaled image size. If the scaled height is not an even multiple of the MCU
- * block height (see #tjMCUHeight), then an intermediate buffer copy will be
- * performed within TurboJPEG.
+ * possible image that will fit within the desired height. If `height` is set
+ * to 0, then only the width will be considered when determining the scaled
+ * image size. If the scaled height is not an even multiple of the MCU block
+ * height (see #tjMCUHeight), then an intermediate buffer copy will be
+ * performed.
*
* @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
* "flags"
@@ -1352,40 +1360,42 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
/**
- * Decode a YUV planar image into an RGB or grayscale image. This function
- * uses the accelerated color conversion routines in the underlying
- * codec but does not execute any of the other steps in the JPEG decompression
- * process.
+ * Decode a unified planar YUV image into a packed-pixel RGB or grayscale
+ * image. This function performs color conversion (which is accelerated in the
+ * libjpeg-turbo implementation) but does not execute any of the other steps in
+ * the JPEG decompression process.
*
* @param handle a handle to a TurboJPEG decompressor or transformer instance
*
- * @param srcBuf pointer to an image buffer containing a YUV planar image to be
- * decoded. The size of this buffer should match the value returned by
- * #tjBufSizeYUV2() for the given image width, height, padding, and level of
- * chrominance subsampling. The Y, U (Cb), and V (Cr) image planes should be
- * stored sequentially in the source buffer (refer to @ref YUVnotes
- * "YUV Image Format Notes".)
+ * @param srcBuf pointer to a buffer containing a unified planar YUV source
+ * image to be decoded. The size of this buffer should match the value
+ * returned by #tjBufSizeYUV2() for the given image width, height, row
+ * alignment, and level of chrominance subsampling. The Y, U (Cb), and V (Cr)
+ * image planes should be stored sequentially in the source buffer. (Refer to
+ * @ref YUVnotes "YUV Image Format Notes".)
*
- * @param pad Use this parameter to specify that the width of each line in each
- * plane of the YUV source image is padded to the nearest multiple of this
- * number of bytes (must be a power of 2.)
+ * @param align row alignment (in bytes) of the YUV source image (must be a
+ * power of 2.) Setting this parameter to n indicates that each row in each
+ * plane of the YUV source image is padded to the nearest multiple of n bytes
+ * (1 = unpadded.)
*
* @param subsamp the level of chrominance subsampling used in the YUV source
* image (see @ref TJSAMP "Chrominance subsampling options".)
*
- * @param dstBuf pointer to an image buffer that will receive the decoded
- * image. This buffer should normally be <tt>pitch * height</tt> bytes in
- * size, but the <tt>dstBuf</tt> pointer can also be used to decode into a
- * specific region of a larger buffer.
+ * @param dstBuf pointer to a buffer that will receive the packed-pixel decoded
+ * image. This buffer should normally be `pitch * height` bytes in size, but
+ * the `dstBuf` pointer can also be used to decode into a specific region of a
+ * larger buffer.
*
* @param width width (in pixels) of the source and destination images
*
- * @param pitch bytes per line in the destination image. Normally, this should
- * be <tt>width * #tjPixelSize[pixelFormat]</tt> if the destination image is
- * unpadded, or <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line
- * of the destination image should be padded to the nearest 32-bit boundary, as
- * is the case for Windows bitmaps. You can also be clever and use the pitch
- * parameter to skip lines, etc. Setting this parameter to 0 is the equivalent
+ * @param pitch bytes per row in the destination image. Normally this should
+ * be set to <tt>width * #tjPixelSize[pixelFormat]</tt>, if the destination
+ * image should be unpadded, or
+ * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each row of the
+ * destination image should be padded to the nearest multiple of 4 bytes, as is
+ * the case for Windows bitmaps. You can also be clever and use the pitch
+ * parameter to skip rows, etc. Setting this parameter to 0 is the equivalent
* of setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>.
*
* @param height height (in pixels) of the source and destination images
@@ -1400,16 +1410,16 @@ DLLEXPORT int tjDecompressToYUVPlanes(tjhandle handle,
* and #tjGetErrorCode().)
*/
DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
- int pad, int subsamp, unsigned char *dstBuf,
+ int align, int subsamp, unsigned char *dstBuf,
int width, int pitch, int height, int pixelFormat,
int flags);
/**
- * Decode a set of Y, U (Cb), and V (Cr) image planes into an RGB or grayscale
- * image. This function uses the accelerated color conversion routines in the
- * underlying codec but does not execute any of the other steps in the JPEG
- * decompression process.
+ * Decode a set of Y, U (Cb), and V (Cr) image planes into a packed-pixel RGB
+ * or grayscale image. This function performs color conversion (which is
+ * accelerated in the libjpeg-turbo implementation) but does not execute any of
+ * the other steps in the JPEG decompression process.
*
* @param handle a handle to a TurboJPEG decompressor or transformer instance
*
@@ -1422,29 +1432,30 @@ DLLEXPORT int tjDecodeYUV(tjhandle handle, const unsigned char *srcBuf,
* details.
*
* @param strides an array of integers, each specifying the number of bytes per
- * line in the corresponding plane of the YUV source image. Setting the stride
+ * row in the corresponding plane of the YUV source image. Setting the stride
* for any plane to 0 is the same as setting it to the plane width (see
- * @ref YUVnotes "YUV Image Format Notes".) If <tt>strides</tt> is NULL, then
- * the strides for all planes will be set to their respective plane widths.
- * You can adjust the strides in order to specify an arbitrary amount of line
- * padding in each plane or to decode a subregion of a larger YUV planar image.
+ * @ref YUVnotes "YUV Image Format Notes".) If `strides` is NULL, then the
+ * strides for all planes will be set to their respective plane widths. You
+ * can adjust the strides in order to specify an arbitrary amount of row
+ * padding in each plane or to decode a subregion of a larger planar YUV image.
*
* @param subsamp the level of chrominance subsampling used in the YUV source
* image (see @ref TJSAMP "Chrominance subsampling options".)
*
- * @param dstBuf pointer to an image buffer that will receive the decoded
- * image. This buffer should normally be <tt>pitch * height</tt> bytes in
- * size, but the <tt>dstBuf</tt> pointer can also be used to decode into a
- * specific region of a larger buffer.
+ * @param dstBuf pointer to a buffer that will receive the packed-pixel decoded
+ * image. This buffer should normally be `pitch * height` bytes in size, but
+ * the `dstBuf` pointer can also be used to decode into a specific region of a
+ * larger buffer.
*
* @param width width (in pixels) of the source and destination images
*
- * @param pitch bytes per line in the destination image. Normally, this should
- * be <tt>width * #tjPixelSize[pixelFormat]</tt> if the destination image is
- * unpadded, or <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each line
- * of the destination image should be padded to the nearest 32-bit boundary, as
- * is the case for Windows bitmaps. You can also be clever and use the pitch
- * parameter to skip lines, etc. Setting this parameter to 0 is the equivalent
+ * @param pitch bytes per row in the destination image. Normally this should
+ * be set to <tt>width * #tjPixelSize[pixelFormat]</tt>, if the destination
+ * image should be unpadded, or
+ * <tt>#TJPAD(width * #tjPixelSize[pixelFormat])</tt> if each row of the
+ * destination image should be padded to the nearest multiple of 4 bytes, as is
+ * the case for Windows bitmaps. You can also be clever and use the pitch
+ * parameter to skip rows, etc. Setting this parameter to 0 is the equivalent
* of setting it to <tt>width * #tjPixelSize[pixelFormat]</tt>.
*
* @param height height (in pixels) of the source and destination images
@@ -1483,50 +1494,51 @@ DLLEXPORT tjhandle tjInitTransform(void);
* transform requires reading and performing Huffman decoding on all of the
* coefficients in the source image, regardless of the size of the destination
* image. Thus, this function provides a means of generating multiple
- * transformed images from the same source or applying multiple
- * transformations simultaneously, in order to eliminate the need to read the
- * source coefficients multiple times.
+ * transformed images from the same source or applying multiple transformations
+ * simultaneously, in order to eliminate the need to read the source
+ * coefficients multiple times.
*
* @param handle a handle to a TurboJPEG transformer instance
*
- * @param jpegBuf pointer to a buffer containing the JPEG source image to
+ * @param jpegBuf pointer to a byte buffer containing the JPEG source image to
* transform
*
* @param jpegSize size of the JPEG source image (in bytes)
*
* @param n the number of transformed JPEG images to generate
*
- * @param dstBufs pointer to an array of n image buffers. <tt>dstBufs[i]</tt>
- * will receive a JPEG image that has been transformed using the parameters in
- * <tt>transforms[i]</tt>. TurboJPEG has the ability to reallocate the JPEG
- * buffer to accommodate the size of the JPEG image. Thus, you can choose to:
- * -# pre-allocate the JPEG buffer with an arbitrary size using #tjAlloc() and
- * let TurboJPEG grow the buffer as needed,
- * -# set <tt>dstBufs[i]</tt> to NULL to tell TurboJPEG to allocate the buffer
- * for you, or
+ * @param dstBufs pointer to an array of n byte buffers. `dstBufs[i]` will
+ * receive a JPEG image that has been transformed using the parameters in
+ * `transforms[i]`. TurboJPEG has the ability to reallocate the JPEG
+ * destination buffer to accommodate the size of the transformed JPEG image.
+ * Thus, you can choose to:
+ * -# pre-allocate the JPEG destination buffer with an arbitrary size using
+ * #tjAlloc() and let TurboJPEG grow the buffer as needed,
+ * -# set `dstBufs[i]` to NULL to tell TurboJPEG to allocate the buffer for
+ * you, or
* -# pre-allocate the buffer to a "worst case" size determined by calling
* #tjBufSize() with the transformed or cropped width and height. Under normal
* circumstances, this should ensure that the buffer never has to be
- * re-allocated (setting #TJFLAG_NOREALLOC guarantees that it won't be.) Note,
- * however, that there are some rare cases (such as transforming images with a
- * large amount of embedded EXIF or ICC profile data) in which the output image
- * will be larger than the worst-case size, and #TJFLAG_NOREALLOC cannot be
- * used in those cases.
+ * re-allocated. (Setting #TJFLAG_NOREALLOC guarantees that it won't be.)
+ * Note, however, that there are some rare cases (such as transforming images
+ * with a large amount of embedded EXIF or ICC profile data) in which the
+ * transformed JPEG image will be larger than the worst-case size, and
+ * #TJFLAG_NOREALLOC cannot be used in those cases.
* .
- * If you choose option 1, <tt>dstSizes[i]</tt> should be set to the size of
- * your pre-allocated buffer. In any case, unless you have set
- * #TJFLAG_NOREALLOC, you should always check <tt>dstBufs[i]</tt> upon return
- * from this function, as it may have changed.
+ * If you choose option 1, then `dstSizes[i]` should be set to the size of your
+ * pre-allocated buffer. In any case, unless you have set #TJFLAG_NOREALLOC,
+ * you should always check `dstBufs[i]` upon return from this function, as it
+ * may have changed.
*
* @param dstSizes pointer to an array of n unsigned long variables that will
* receive the actual sizes (in bytes) of each transformed JPEG image. If
- * <tt>dstBufs[i]</tt> points to a pre-allocated buffer, then
- * <tt>dstSizes[i]</tt> should be set to the size of the buffer. Upon return,
- * <tt>dstSizes[i]</tt> will contain the size of the JPEG image (in bytes.)
+ * `dstBufs[i]` points to a pre-allocated buffer, then `dstSizes[i]` should be
+ * set to the size of the buffer. Upon return, `dstSizes[i]` will contain the
+ * size of the transformed JPEG image (in bytes.)
*
* @param transforms pointer to an array of n #tjtransform structures, each of
* which specifies the transform parameters and/or cropping region for the
- * corresponding transformed output image.
+ * corresponding transformed JPEG image.
*
* @param flags the bitwise OR of one or more of the @ref TJFLAG_ACCURATEDCT
* "flags"
@@ -1552,10 +1564,10 @@ DLLEXPORT int tjDestroy(tjhandle handle);
/**
- * Allocate an image buffer for use with TurboJPEG. You should always use
- * this function to allocate the JPEG destination buffer(s) for the compression
- * and transform functions unless you are disabling automatic buffer
- * (re)allocation (by setting #TJFLAG_NOREALLOC.)
+ * Allocate a byte buffer for use with TurboJPEG. You should always use this
+ * function to allocate the JPEG destination buffer(s) for the compression and
+ * transform functions unless you are disabling automatic buffer (re)allocation
+ * (by setting #TJFLAG_NOREALLOC.)
*
* @param bytes the number of bytes to allocate
*
@@ -1568,44 +1580,43 @@ DLLEXPORT unsigned char *tjAlloc(int bytes);
/**
- * Load an uncompressed image from disk into memory.
+ * Load a packed-pixel image from disk into memory.
*
- * @param filename name of a file containing an uncompressed image in Windows
+ * @param filename name of a file containing a packed-pixel image in Windows
* BMP or PBMPLUS (PPM/PGM) format
*
* @param width pointer to an integer variable that will receive the width (in
- * pixels) of the uncompressed image
+ * pixels) of the packed-pixel image
*
- * @param align row alignment of the image buffer to be returned (must be a
- * power of 2.) For instance, setting this parameter to 4 will cause all rows
- * in the image buffer to be padded to the nearest 32-bit boundary, and setting
- * this parameter to 1 will cause all rows in the image buffer to be unpadded.
+ * @param align row alignment of the packed-pixel buffer to be returned (must
+ * be a power of 2.) Setting this parameter to n will cause all rows in the
+ * buffer to be padded to the nearest multiple of n bytes (1 = unpadded.)
*
* @param height pointer to an integer variable that will receive the height
- * (in pixels) of the uncompressed image
+ * (in pixels) of the packed-pixel image
*
* @param pixelFormat pointer to an integer variable that specifies or will
- * receive the pixel format of the uncompressed image buffer. The behavior of
- * #tjLoadImage() will vary depending on the value of <tt>*pixelFormat</tt>
- * passed to the function:
- * - @ref TJPF_UNKNOWN : The uncompressed image buffer returned by the function
- * will use the most optimal pixel format for the file type, and
- * <tt>*pixelFormat</tt> will contain the ID of this pixel format upon
- * successful return from the function.
- * - @ref TJPF_GRAY : Only PGM files and 8-bit BMP files with a grayscale
- * colormap can be loaded.
+ * receive the pixel format of the packed-pixel buffer. The behavior of
+ * #tjLoadImage() will vary depending on the value of `*pixelFormat` passed to
+ * the function:
+ * - @ref TJPF_UNKNOWN : The packed-pixel buffer returned by this function will
+ * use the most optimal pixel format for the file type, and `*pixelFormat` will
+ * contain the ID of that pixel format upon successful return from this
+ * function.
+ * - @ref TJPF_GRAY : Only PGM files and 8-bit-per-pixel BMP files with a
+ * grayscale colormap can be loaded.
* - @ref TJPF_CMYK : The RGB or grayscale pixels stored in the file will be
* converted using a quick & dirty algorithm that is suitable only for testing
- * purposes (proper conversion between CMYK and other formats requires a color
- * management system.)
- * - Other @ref TJPF "pixel formats" : The uncompressed image buffer will use
- * the specified pixel format, and pixel format conversion will be performed if
+ * purposes. (Proper conversion between CMYK and other formats requires a
+ * color management system.)
+ * - Other @ref TJPF "pixel formats" : The packed-pixel buffer will use the
+ * specified pixel format, and pixel format conversion will be performed if
* necessary.
*
* @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP
* "flags".
*
- * @return a pointer to a newly-allocated buffer containing the uncompressed
+ * @return a pointer to a newly-allocated buffer containing the packed-pixel
* image, converted to the chosen pixel format and with the chosen row
* alignment, or NULL if an error occurred (see #tjGetErrorStr2().) This
* buffer should be freed using #tjFree().
@@ -1616,31 +1627,31 @@ DLLEXPORT unsigned char *tjLoadImage(const char *filename, int *width,
/**
- * Save an uncompressed image from memory to disk.
+ * Save a packed-pixel image from memory to disk.
*
- * @param filename name of a file to which to save the uncompressed image.
- * The image will be stored in Windows BMP or PBMPLUS (PPM/PGM) format,
- * depending on the file extension.
+ * @param filename name of a file to which to save the packed-pixel image. The
+ * image will be stored in Windows BMP or PBMPLUS (PPM/PGM) format, depending
+ * on the file extension.
*
- * @param buffer pointer to an image buffer containing RGB, grayscale, or
- * CMYK pixels to be saved
+ * @param buffer pointer to a buffer containing a packed-pixel RGB, grayscale,
+ * or CMYK image to be saved
*
- * @param width width (in pixels) of the uncompressed image
+ * @param width width (in pixels) of the packed-pixel image
*
- * @param pitch bytes per line in the image buffer. Setting this parameter to
- * 0 is the equivalent of setting it to
+ * @param pitch bytes per row in the packed-pixel image. Setting this
+ * parameter to 0 is the equivalent of setting it to
* <tt>width * #tjPixelSize[pixelFormat]</tt>.
*
- * @param height height (in pixels) of the uncompressed image
+ * @param height height (in pixels) of the packed-pixel image
*
- * @param pixelFormat pixel format of the image buffer (see @ref TJPF
+ * @param pixelFormat pixel format of the packed-pixel image (see @ref TJPF
* "Pixel formats".) If this parameter is set to @ref TJPF_GRAY, then the
- * image will be stored in PGM or 8-bit (indexed color) BMP format. Otherwise,
- * the image will be stored in PPM or 24-bit BMP format. If this parameter
- * is set to @ref TJPF_CMYK, then the CMYK pixels will be converted to RGB
- * using a quick & dirty algorithm that is suitable only for testing (proper
- * conversion between CMYK and other formats requires a color management
- * system.)
+ * image will be stored in PGM or 8-bit-per-pixel (indexed color) BMP format.
+ * Otherwise, the image will be stored in PPM or 24-bit-per-pixel BMP format.
+ * If this parameter is set to @ref TJPF_CMYK, then the CMYK pixels will be
+ * converted to RGB using a quick & dirty algorithm that is suitable only for
+ * testing purposes. (Proper conversion between CMYK and other formats
+ * requires a color management system.)
*
* @param flags the bitwise OR of one or more of the @ref TJFLAG_BOTTOMUP
* "flags".
@@ -1653,8 +1664,8 @@ DLLEXPORT int tjSaveImage(const char *filename, unsigned char *buffer,
/**
- * Free an image buffer previously allocated by TurboJPEG. You should always
- * use this function to free JPEG destination buffer(s) that were automatically
+ * Free a byte buffer previously allocated by TurboJPEG. You should always use
+ * this function to free JPEG destination buffer(s) that were automatically
* (re)allocated by the compression and transform functions or that were
* manually allocated using #tjAlloc().
*
@@ -1692,14 +1703,10 @@ DLLEXPORT char *tjGetErrorStr2(tjhandle handle);
DLLEXPORT int tjGetErrorCode(tjhandle handle);
-/* Deprecated functions and macros */
-#define TJFLAG_FORCEMMX 8
-#define TJFLAG_FORCESSE 16
-#define TJFLAG_FORCESSE2 32
-#define TJFLAG_FORCESSE3 128
+/* Backward compatibility functions and macros (nothing to see here) */
+/* TurboJPEG 1.0+ */
-/* Backward compatibility functions and macros (nothing to see here) */
#define NUMSUBOPT TJ_NUMSAMP
#define TJ_444 TJSAMP_444
#define TJ_422 TJSAMP_422
@@ -1715,46 +1722,55 @@ DLLEXPORT int tjGetErrorCode(tjhandle handle);
#define TJ_ALPHAFIRST 64
#define TJ_FORCESSE3 TJFLAG_FORCESSE3
#define TJ_FASTUPSAMPLE TJFLAG_FASTUPSAMPLE
-#define TJ_YUV 512
DLLEXPORT unsigned long TJBUFSIZE(int width, int height);
-DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int jpegSubsamp);
-
-DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp);
-
DLLEXPORT int tjCompress(tjhandle handle, unsigned char *srcBuf, int width,
int pitch, int height, int pixelSize,
unsigned char *dstBuf, unsigned long *compressedSize,
int jpegSubsamp, int jpegQual, int flags);
-DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
- int pitch, int height, int pixelSize,
- unsigned char *dstBuf, int subsamp, int flags);
-
-DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
- int pitch, int height, int pixelFormat,
- unsigned char *dstBuf, int subsamp, int flags);
+DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
+ unsigned long jpegSize, unsigned char *dstBuf,
+ int width, int pitch, int height, int pixelSize,
+ int flags);
DLLEXPORT int tjDecompressHeader(tjhandle handle, unsigned char *jpegBuf,
unsigned long jpegSize, int *width,
int *height);
+DLLEXPORT char *tjGetErrorStr(void);
+
+/* TurboJPEG 1.1+ */
+
+#define TJ_YUV 512
+
+DLLEXPORT unsigned long TJBUFSIZEYUV(int width, int height, int jpegSubsamp);
+
DLLEXPORT int tjDecompressHeader2(tjhandle handle, unsigned char *jpegBuf,
unsigned long jpegSize, int *width,
int *height, int *jpegSubsamp);
-DLLEXPORT int tjDecompress(tjhandle handle, unsigned char *jpegBuf,
- unsigned long jpegSize, unsigned char *dstBuf,
- int width, int pitch, int height, int pixelSize,
- int flags);
-
DLLEXPORT int tjDecompressToYUV(tjhandle handle, unsigned char *jpegBuf,
unsigned long jpegSize, unsigned char *dstBuf,
int flags);
-DLLEXPORT char *tjGetErrorStr(void);
+DLLEXPORT int tjEncodeYUV(tjhandle handle, unsigned char *srcBuf, int width,
+ int pitch, int height, int pixelSize,
+ unsigned char *dstBuf, int subsamp, int flags);
+/* TurboJPEG 1.2+ */
+
+#define TJFLAG_FORCEMMX 8
+#define TJFLAG_FORCESSE 16
+#define TJFLAG_FORCESSE2 32
+#define TJFLAG_FORCESSE3 128
+
+DLLEXPORT unsigned long tjBufSizeYUV(int width, int height, int subsamp);
+
+DLLEXPORT int tjEncodeYUV2(tjhandle handle, unsigned char *srcBuf, int width,
+ int pitch, int height, int pixelFormat,
+ unsigned char *dstBuf, int subsamp, int flags);
/**
* @}
diff --git a/wizard.txt b/wizard.txt
index c57fe38a..0e155f9e 100644
--- a/wizard.txt
+++ b/wizard.txt
@@ -149,7 +149,15 @@ the script represents a progressive or sequential file, by observing whether
Ss and Se values other than 0 and 63 appear. (The -progressive switch is
not needed to specify this; in fact, it is ignored when -scans appears.)
The scan script must meet the JPEG restrictions on progression sequences.
-(cjpeg checks that the spec's requirements are obeyed.)
+(cjpeg checks that the spec's requirements are obeyed.) More specifically:
+
+ * An AC scan cannot include coefficients from more than one component.
+
+ * An AC scan for a particular component must be preceded by a DC scan
+ that includes the same component.
+
+ * Only the first AC scan that includes a particular coefficient for a
+ particular component can include more than one bit from that coefficient.
Scan script files are free format, in that arbitrary whitespace can appear
between numbers and around punctuation. Also, comments can be included: a