Compare commits

...

32 Commits

Author SHA1 Message Date
Kornel
6c9f0897af MozJPEG 4.1.5 2023-10-12 17:52:31 +01:00
Kornel
0c6302e086 Merge remote-tracking branch 'libjpeg-turbo/2.1.x' into HEAD
* libjpeg-turbo/2.1.x:
  ChangeLog.md: List CVE ID fixed by ccaba5d7
  jpeglib.h: Document that JCS_RGB565 is decomp-only
  Fix block smoothing w/vert.-subsampled prog. JPEGs
2023-09-23 22:31:18 +01:00
DRC
4ae5d3dac5 ChangeLog.md: List CVE ID fixed by ccaba5d7
Closes #724
2023-09-14 17:23:13 -04:00
DRC
7722c54c63 jpeglib.h: Document that JCS_RGB565 is decomp-only
Closes #723
2023-09-11 12:47:39 -04:00
Kornel
61e03cc6b2 Fix #220 2023-09-04 15:58:41 +01:00
Kornel
3a691f41f9 Merge commit 'eadd243'
# By DRC
# Via DRC
* commit 'eadd243':
  Fix interblock smoothing with narrow prog. JPEGs
  jchuff.c/flush_bits(): Guard against free_bits < 0
  jchuff.c/flush_bits(): Guard against put_bits < 0
  Restore xform fuzzer behavior from before 19f9d8f0
  xform fuzz: Use src subsamp to calc dst buf size
  Doc: Mention that we are a JPEG ref implementation
  jchuff.c: Test for out-of-range coefficients
  turbojpeg.h: Make customFilter() proto match doc
  ChangeLog.md: Fix typo
  tjTransform(): Calc dst buf size from xformed dims
  Fix build warnings/errs w/ -DNO_GETENV/-DNO_PUTENV
  GitHub: Fix x32 build
  tjexample.c: Prevent integer overflow
  jpeg_crop_scanline: Fix calc w/sclg + 2x4,4x2 samp
  Decomp: Don't enable 2-pass color quant w/ RGB565
  TJBench: w/JPEG input imgs, set min tile= MCU size
  Bump version to 2.1.6 to prepare for new commits
  GitHub: Add pull request template
  Build: Clarify CMAKE_OSX_ARCHITECTURES error
  Build: Fail if included with add_subdirectory()

# Conflicts:
#	.github/workflows/build.yml
#	CMakeLists.txt
#	README.md
#	release/deb-control.in
2023-08-26 21:52:39 +01:00
Kornel
3bd754ee68 Merge tag '2.1.5.1'
# By DRC
# Via DRC
* tag '2.1.5.1':
  ChangeLog.md: Document d743a2c1
  OSS-Fuzz: Bail out immediately on decomp failure
  SIMD/x86: Initialize simd_support before every use
  Build: Define THREAD_LOCAL even if !WITH_TURBOJPEG

# Conflicts:
#	CMakeLists.txt
2023-08-26 21:49:51 +01:00
DRC
a9d87361c8 Fix block smoothing w/vert.-subsampled prog. JPEGs
The 5x5 interblock smoothing implementation, introduced in libjpeg-turbo
2.1, improperly extended the logic from the traditional 3x3 smoothing
implementation.  Both implementations point prev_block_row and
next_block_row to the current block row when processing, respectively,
the first and the last block row in the image:

  if (block_row > 0 || cinfo->output_iMCU_row > 0)
    prev_block_row =
      buffer[block_row - 1] + cinfo->master->first_MCU_col[ci];
  else
    prev_block_row = buffer_ptr;

  if (block_row < block_rows - 1 ||
      cinfo->output_iMCU_row < last_iMCU_row)
    next_block_row =
      buffer[block_row + 1] + cinfo->master->first_MCU_col[ci];
  else
    next_block_row = buffer_ptr;

6d91e950c8 naively extended that logic to
accommodate a 5x5 smoothing window:

  if (block_row > 1 || cinfo->output_iMCU_row > 1)
    prev_prev_block_row =
      buffer[block_row - 2] + cinfo->master->first_MCU_col[ci];
  else
    prev_prev_block_row = prev_block_row;

  if (block_row < block_rows - 2 ||
      cinfo->output_iMCU_row + 1 < last_iMCU_row)
    next_next_block_row =
      buffer[block_row + 2] + cinfo->master->first_MCU_col[ci];
  else
    next_next_block_row = next_block_row;

However, this new logic was only correct if block_rows == 1, so the
values of prev_prev_block_row and next_next_block_row were incorrect
when processing, respectively, the second and second to last iMCU rows
in a vertically-subsampled progressive JPEG image.

The intent was to:
- point prev_block_row to the current block row when processing the
  first block row in the image,
- point prev_prev_block_row to prev_block_row when processing the first
  two block rows in the image,
- point next_block_row to the current block row when processing the
  last block row in the image, and
- point next_next_block_row to next_block_row when processing the last
  two block rows in the image.

This commit modifies decompress_smooth_data() so that it computes the
current block row's position relative to the whole image and sets
the block row pointers based on that value.

This commit also restores a line of code that was accidentally deleted
by 6d91e950c8:

  access_rows += compptr->v_samp_factor; /* prior iMCU row too */

access_rows is merely a sanity check that tells the access_virt_barray()
method to generate an error if accessing the specified number of rows
would cause a buffer overrun.  Essentially, it is a belt-and-suspenders
measure to ensure that j*init_d_coef_controller() allocated enough rows
for the full-image virtual array.  Thus, excluding that line of code did
not cause an observable issue.

This commit also documents eadd2436ee in
the change log.

Fixes #721
2023-08-15 15:40:37 -04:00
DRC
eadd2436ee Fix interblock smoothing with narrow prog. JPEGs
Due to an oversight, the assignment of DC05, DC10, DC15, DC20, and DC25
(the right edge coefficients in the 5x5 interblock smoothing window) in
decompress_smooth_data() was incorrect for images exactly two MCU blocks
wide.  For such images, DC04, DC09, DC14, DC19, and DC24 were assigned
values based on the last MCU column, but DC05, DC10, DC15, DC20, and
DC25 were assigned values based on the first MCU column (because
block_num + 1 was never less than last_block_column.)  This commit
modifies jdcoefct.c so that, for images at least two MCU blocks wide,
DC05, DC10, DC15, DC20, and DC25 are assigned the same values as DC04,
DC09, DC14, DC19, and DC24 (respectively.)  DC05, DC10, DC15, DC20, and
DC25 are then immediately overwritten for images more than two MCU
blocks wide.

Since this issue was minor and not likely obvious to an end user, the
fix is undocumented.

Fixes #700
2023-08-03 16:07:54 -04:00
DRC
21f5688aa4 jchuff.c/flush_bits(): Guard against free_bits < 0
This fixes a buffer overrun, reported by OSS-Fuzz, that occurred when
attempting to transform a specially-crafted malformed arithmetic-coded
JPEG image into a baseline Huffman-coded JPEG destination image with
default Huffman tables.  This issue probably had a similar root cause to
the issue fixed in 31a301389b, but in this
case, the issue only occurred with the SIMD baseline Huffman encoder in
libjpeg-turbo 2.1.x and 2.0.x.  It was not reproducible in 3.0.x or when
using the C baseline Huffman encoder.  (NOTE: In order to reproduce the
issue with 2.1.x, it was necessary to revert
58cee6d90cd616c86fae142891b987c289ea055a.)
2023-07-25 17:40:35 -04:00
DRC
041c80a42e jchuff.c/flush_bits(): Guard against put_bits < 0
This fixes a UBSan negative shift warning, reported by OSS-Fuzz, that
occurred when attempting to transform a specially-crafted malformed
arithmetic-coded JPEG image into a baseline Huffman-coded JPEG
destination image with default Huffman tables.  This issue probably
had a similar root cause to the issue fixed in
31a301389b, but in this case, the issue
only occurred with the SIMD baseline Huffman encoder in libjpeg-turbo
2.1.x.  It was not reproducible in 2.0.x or 3.0.x or when using the
C baseline Huffman encoder.
2023-07-12 14:16:13 -04:00
DRC
58cee6d90c Restore xform fuzzer behavior from before 19f9d8f0
The intent was for the final transform operation to be the same as the
first transform operation but without TJXOPT_COPYNONE or
TJFLAG_NOREALLOC.  Unrolling the transform operations in
19f9d8f0fd accidentally changed that.
2023-07-06 10:29:27 -04:00
DRC
f48f73d4ec xform fuzz: Use src subsamp to calc dst buf size
Referring to
https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=60379
there are some specially-crafted malformed JPEG images that, when
transformed to grayscale, will exceed the worst-case transformed
grayscale JPEG image size.  This is similar in nature to the issue fixed
by 19f9d8f0fd, except that in this case,
the issue occurs regardless of the amount of metadata in the source
image.  Also, the tjTransform() function, the
Java_org_libjpegturbo_turbojpeg_TJTransformer_transform() JNI function,
and TJBench were behaving correctly in this case, because the TurboJPEG
API documentation specifies that the source image's subsampling type
should be used when computing the worst-case transformed JPEG image
size.  (However, only the Java API documentation specified that.  Oops.
The C API documentation now does as well.)  The documented usage
mitigates the issue, and only the transform fuzzer did not adhere to
that.  Thus, this was an issue with the fuzzer itself rather than an
issue with the library.
2023-07-06 09:10:30 -04:00
DRC
383286702c Doc: Mention that we are a JPEG ref implementation 2023-07-05 10:57:48 -04:00
DRC
31a301389b jchuff.c: Test for out-of-range coefficients
Restore two coefficient range checks from libjpeg to the C baseline
Huffman encoder.  This fixes an issue
(https://bugs.chromium.org/p/oss-fuzz/issues/detail?id=60253) whereby
the encoder could read from uninitialized memory when attempting to
transform a specially-crafted malformed arithmetic-coded JPEG source
image into a baseline Huffman-coded JPEG destination image with default
Huffman tables.  More specifically, the out-of-range coefficients caused
r to equal 256, which overflowed the actbl->ehufsi[] array.  Because the
overflow was contained within the huff_entropy_encoder structure, this
issue was not exploitable (nor was it observable at all on x86 or Arm
CPUs unless JSIMD_NOHUFFENC=1 or JSIMD_FORCENONE=1 was set in the
environment or unless libjpeg-turbo was built with WITH_SIMD=0.)

The fix is performance-neutral (+/- 1-2%) for x86-64 code and causes a
0-4% (avg. 1-2%, +/- 1-2%) compression regression for i386 code on Intel
CPUs when the C baseline Huffman encoder is used (JSIMD_NOHUFFENC=1).
The fix is performance-neutral (+/- 1-2%) on Intel CPUs when all of the
libjpeg-turbo SIMD extensions are disabled (JSIMD_FORCENONE=1).  The fix
causes a 0-2% (avg. <1%, +/- 1%) compression regression for PowerPC
code.
2023-07-01 08:20:38 -04:00
DRC
369b84a4ee turbojpeg.h: Make customFilter() proto match doc 2023-06-30 10:20:20 -04:00
DRC
53aafa949a ChangeLog.md: Fix typo 2023-06-29 17:45:21 -04:00
DRC
19f9d8f0fd tjTransform(): Calc dst buf size from xformed dims
When used with TJFLAG_NOREALLOC and with TJXOP_TRANSPOSE,
TJXOP_TRANSVERSE, TJXOP_ROT90, or TJXOP_ROT270, tjTransform()
incorrectly based the destination buffer size for a transform on the
source image dimensions rather than the transformed image dimensions.
This was apparently a long-standing bug that had existed in the
tjTransform() function since its inception.  As initially implemented in
the evolving libjpeg-turbo v1.2 code base, tjTransform() required
dstSizes[i] to be set regardless of whether TJFLAG_NOREALLOC was set.
ff78e37595, which was introduced later in
the evolving libjpeg-turbo v1.2 code base, removed that requirement and
planted the seed for the bug.  However, the bug was not activated until
9b49f0e4c7 was introduced still later in
the evolving libjpeg-turbo v1.2 code base, adding a subsampling type
argument to the (new at the time) tjBufSize() function and thus making
the width and height arguments no longer commutative.

The bug opened up the possibility that a JPEG source image could cause
tjTransform() to overflow the destination buffer for a transform if all
of the following were true:
- The JPEG source image used 4:2:2, 4:4:0, or 4:1:1 subsampling.  (These
  are the only supported subsampling types for which the width and
  height arguments to tjBufSize() are not commutative.)
- The width and height of the JPEG source image were such that
  tjBufSize(height, width, subsamplingType) returned a smaller value
  than tjBufSize(width, height, subsamplingType).
- The JPEG source image contained enough metadata that the size of the
  transformed image was larger than
  tjBufSize(height, width, subsamplingType).
- TJFLAG_NOREALLOC was set.
- TJXOP_TRANSPOSE, TJXOP_TRANSVERSE, TJXOP_ROT90, or TJXOP_ROT270 was
  used.
- TJXOPT_COPYNONE was not set.
- TJXOPT_CROP was not set.
- The calling program allocated
  tjBufSize(height, width, subsamplingType) bytes for the
  destination buffer, as the API documentation instructs.

The API documentation cautions that JPEG source images containing a
large amount of extraneous metadata (EXIF, IPTC, ICC, etc.) cannot
reliably be transformed if TJFLAG_NOREALLOC is set and TJXOPT_COPYNONE
is not set.  Irrespective of the bug, there are still cases in which a
JPEG source image with a large amount of metadata can, when transformed,
exceed the worst-case transformed JPEG image size.  For instance, if you
try to losslessly crop a JPEG image with 3 kB of EXIF data to 16x16
pixels, then you are guaranteed to exceed the worst-case 16x16 JPEG
image size unless you discard the EXIF data.

Even without the bug, tjTransform() will still fail with "Buffer passed
to JPEG library is too small" when attempting to transform JPEG source
images that meet the aforementioned criteria.  The bug is that the
function segfaults rather than failing gracefully, but the chances of
that occurring in a real-world application are very slim.  Any
real-world application developers who attempted to transform arbitrary
JPEG source images with TJFLAG_NOREALLOC set would very quickly realize
that they cannot reliably do that without also setting TJXOPT_COPYNONE.
Thus, I posit that the actual risk posed by this bug is low.
Applications such as web browsers that are the most exposed to security
risks from arbitrary JPEG source images do not use the TurboJPEG
lossless transform feature.  (None of those applications even use the
TurboJPEG API, to the best of my knowledge, and the public libjpeg API
has no equivalent transform function.)  Our only command-line interface
to the tjTransform() function, TJBench, was not exposed to the bug
because it had a compatible bug whereby it allocated the JPEG
destination buffer to the same size that tjTransform() erroneously
expected.  The TurboJPEG Java API was also not exposed to the bug
because of a similar compatible bug in the
Java_org_libjpegturbo_turbojpeg_TJTransformer_transform() JNI function.
(This commit fixes both compatible bugs.)

In short, best practices for tjTransform() are to use TJFLAG_NOREALLOC
only with JPEG source images that are known to be free of metadata (such
as images generated by tjCompress*()) or to use TJXOPT_COPYNONE along
with TJFLAG_NOREALLOC.  Still, however, the function shouldn't segfault
as long as the calling program allocates the suggested amount of space
for the JPEG destination buffer.

Usability notes:
tjTransform() could hypothetically require dstSizes[i] to be set
regardless of whether TJFLAG_NOREALLOC is set, but there are usability
pitfalls either way.  The main pitfall I sought to avoid with
ff78e37595 was a calling program failing
to set dstSizes[i] at all, thus leaving its value undefined.  It could
be argued that requiring dstSizes[i] to be set in all cases is more
consistent, but it could also be argued that not requiring it to be set
when TJFLAG_NOREALLOC is set is more user-proof.  tjTransform() could
also hypothetically set TJXOPT_COPYNONE automatically when
TJFLAG_NOREALLOC is set, but that could lead to user confusion.
2023-06-28 11:37:53 -04:00
DRC
fcfd2ada75 Fix build warnings/errs w/ -DNO_GETENV/-DNO_PUTENV
- strtest.c: Fix unused variable warnings if both -DNO_GETENV and
  -DNO_PUTENV are specified or if only -DNO_GETENV is specified.

- jinclude.h: Fix build error if only -DNO_GETENV is specified.

Fixes #697
2023-06-16 11:55:01 -04:00
DRC
58cbda3e37 GitHub: Fix x32 build
1f55ae7b0f accidentally overrode the value
of CMAKE_C_FLAGS, thus eliminating the -mx32 flag that was necessary to
enable x32.
2023-06-16 11:54:34 -04:00
DRC
be678e5a1b tjexample.c: Prevent integer overflow
Because width, height, and tjPixelSize[] are signed integers, signed
integer overflow will occur if width * height *
tjPixelSize[pixelFormat] > INT_MAX or jpegSize > INT_MAX, which would
cause an incorrect value to be passed to tjAlloc().  This commit
modifies tjexample.c in the following ways:

- Use malloc() rather than tjAlloc() to allocate the uncompressed image
  buffer.  (tjAlloc() is only necessary for JPEG buffers that will
  potentially be reallocated by the TurboJPEG API library.)

- Implicitly promote width, height, and tjPixelSize[pixelFormat] to
  size_t before multiplying them.

- If size_t is 32-bit, throw an error if width * height *
  tjPixelSize[pixelFormat] would overflow the data type.

- Throw an error if jpegSize would overflow a signed integer (which
  could only happen on a 64-bit machine.)

Since tjexample is not installed or packaged, the worst case for this
issue was that a downstream application might interpret tjexample.c
literally and introduce a similar overflow issue into its own code.
However, it's worth noting that such issues could also be introduced
when using malloc().
2023-06-02 11:02:11 -04:00
DRC
2e1b8a462f jpeg_crop_scanline: Fix calc w/sclg + 2x4,4x2 samp
When computing the downsampled width for a particular component,
jpeg_crop_scanline() needs to take into account the fact that the
libjpeg code uses a combination of IDCT scaling and upsampling to
implement 4x2 and 2x4 upsampling with certain decompression scaling
factors.  Failing to account for that led to incomplete upsampling of
4x2- or 2x4-subsampled components, which caused the color converter to
read from uninitialized memory.  With 12-bit data precision, this caused
a buffer overrun or underrun and subsequent segfault if the
uninitialized memory contained a value that was outside of the valid
sample range (because the color converter uses the value as an array
index.)

Fixes #669
2023-04-06 22:05:10 -05:00
DRC
42ce199c9c Decomp: Don't enable 2-pass color quant w/ RGB565
The 2-pass color quantization algorithm assumes 3-sample pixels.  RGB565
is the only 3-component colorspace that doesn't have 3-sample pixels, so
we need to treat it as a special case when determining whether to enable
2-pass color quantization.  Otherwise, attempting to initialize 2-pass
color quantization with an RGB565 output buffer could cause
prescan_quantize() to read from uninitialized memory and subsequently
underflow/overflow the histogram array.

djpeg is supposed to fail gracefully if both -rgb565 and -colors are
specified, because none of its destination managers (image writers)
support color quantization with RGB565.  However, prescan_quantize() was
called before that could occur.  It is possible but very unlikely that
these issues could have been reproduced in applications other than
djpeg.  The issues involve the use of two features (12-bit precision and
RGB565) that are incompatible, and they also involve the use of two
rarely-used legacy features (RGB565 and color quantization) that don't
make much sense when combined.

Fixes #668
Fixes #671
Fixes #680
2023-04-04 20:45:16 -05:00
DRC
bc087d6aa9 TJBench: w/JPEG input imgs, set min tile= MCU size
When -tile is used with a JPEG input image, TJBench generates the tiles
using lossless cropping, which will fail if the cropping region doesn't
align with an MCU boundary.  Furthermore, there is no reason to avoid
8x8 tiles when decompressing 4:4:4 or grayscale JPEG images.
2023-03-13 17:50:38 -05:00
DRC
7313fe5aea Bump version to 2.1.6 to prepare for new commits 2023-03-13 17:49:43 -05:00
DRC
9c432a4d40 GitHub: Add pull request template 2023-02-23 12:03:27 -06:00
DRC
c8a20e0c2f Build: Clarify CMAKE_OSX_ARCHITECTURES error
It's not that the build system doesn't support multiple values in
CMAKE_OSX_ARCHITECTURES.  It's that libjpeg-turbo, because of its SIMD
extensions, *cannot* support multiple values in CMAKE_OSX_ARCHITECTURES.
2023-02-23 12:03:06 -06:00
DRC
33eaf17e5b Build: Fail if included with add_subdirectory()
Even though BUILDING.md and CONTRIBUTING.md explicitly state that the
libjpeg-turbo build system does not and will not support being
integrated into downstream build systems using add_subdirectory() (see
0565548191), people continue to file bug
reports, feature requests, and pull requests regarding that (see #265,
 #637, and #653 in addition to the issues listed in
05655481917a2d2761cf2fe19b76f639b7f159ef.)  Responding to those
issues wastes our project's limited resources.  Hopefully people will
get the hint if the build system explicitly tells them that it can't be
included using add_subdirectory(), which will prompt them to read the
comments in CMakeLists.txt explaining why.  To anyone stumbling upon
this commit message, please refer to the discussions under the issues
listed above, as well as the issues listed in
0565548191.  Our project's position on
this has been stated, explained, and defended numerous times.
2023-02-10 10:49:30 -06:00
DRC
8ecba3647e ChangeLog.md: Document d743a2c1
+ bump version to 2.1.5.1
2023-02-08 09:29:21 -06:00
DRC
6316d4d752 OSS-Fuzz: Bail out immediately on decomp failure
Don't keep trying to decompress the same image if tj3Decompress*() has
already thrown an error.  Otherwise, if the image has an excessive
number of scans, then each iteration of the loop will try to decompress
up to the scan limit, which may cause the overall test to time out even
if one iteration doesn't time out.
2023-02-07 13:34:34 -06:00
DRC
d743a2c12e SIMD/x86: Initialize simd_support before every use
As long as a libjpeg instance is only used by one thread at a time, a
program is technically within its rights to call jpeg_start_*compress()
in one thread and jpeg_(read|write)_*(), with the same libjpeg instance,
in a second thread.  However, because the various jsimd_can*() functions
are called within the body of jpeg_start_*compress() and simd_support is
now thread-local (due to f579cc11b3), that
led to a situation in which simd_support was initialized in the first
thread but not the second.  The uninitialized value of simd_support is
0xFFFFFFFF, which the second thread interpreted to mean that it could
use any instruction set, and when it attempted to use AVX2 instructions
on a CPU that didn't support them, an illegal instruction error
occurred.

This issue was known to affect libvips.

This commit modifies the i386 and x86-64 SIMD dispatchers so that the
various jsimd_*() functions always call init_simd(), if simd_support is
uninitialized, prior to dispatching based on the value of simd_support.
Note that the other SIMD dispatchers don't need this, because only the
x86 SIMD extensions currently support multiple instruction sets.

This patch has been verified to be performance-neutral to within
+/- 0.4% with 32-bit and 64-bit code running on a 2.8 GHz Intel Xeon
W3530 and a 3.6 GHz Intel Xeon W2123.

Fixes #649
2023-02-02 10:46:57 -06:00
DRC
a93f6a7a63 Build: Define THREAD_LOCAL even if !WITH_TURBOJPEG
The SIMD dispatchers use thread-local storage now as well, because of
f579cc11b3.
2023-02-01 11:58:30 -06:00
32 changed files with 416 additions and 122 deletions

1
.gitattributes vendored
View File

@@ -3,3 +3,4 @@
/ci export-ignore /ci export-ignore
/.gitattributes export-ignore /.gitattributes export-ignore
*.ppm binary *.ppm binary
/ChangeLog.md conflict-marker-size=8

8
.github/pull_request_template.md vendored Normal file
View File

@@ -0,0 +1,8 @@
**Complete description of the bug fix or feature that this pull request implements**
**Checklist before submitting the pull request, to maximize the chances that the pull request will be accepted**
- [ ] Read CONTRIBUTING.md, a link to which appears under "Helpful resources" below. That document discusses general guidelines for contributing to libjpeg-turbo, as well as the types of contributions that will not be accepted or are unlikely to be accepted.
- [ ] Search the existing issues and pull requests (both open and closed) to ensure that a similar request has not already been submitted and rejected.
- [ ] Discuss the proposed bug fix or feature in a GitHub issue, through direct e-mail with the project maintainer, or on the libjpeg-turbo-devel mailing list.

View File

@@ -10,7 +10,7 @@ if(CMAKE_EXECUTABLE_SUFFIX)
endif() endif()
project(mozjpeg C) project(mozjpeg C)
set(VERSION 4.1.3) set(VERSION 4.1.5)
set(COPYRIGHT_YEAR "1991-2023") set(COPYRIGHT_YEAR "1991-2023")
string(REPLACE "." ";" VERSION_TRIPLET ${VERSION}) string(REPLACE "." ";" VERSION_TRIPLET ${VERSION})
list(GET VERSION_TRIPLET 0 VERSION_MAJOR) list(GET VERSION_TRIPLET 0 VERSION_MAJOR)
@@ -31,6 +31,34 @@ pad_number(VERSION_MINOR 3)
pad_number(VERSION_REVISION 3) pad_number(VERSION_REVISION 3)
set(LIBJPEG_TURBO_VERSION_NUMBER ${VERSION_MAJOR}${VERSION_MINOR}${VERSION_REVISION}) set(LIBJPEG_TURBO_VERSION_NUMBER ${VERSION_MAJOR}${VERSION_MINOR}${VERSION_REVISION})
# The libjpeg-turbo build system has never supported and will never support
# being integrated into another build system using add_subdirectory(), because
# doing so would require that we (minimally):
#
# 1. avoid using certain CMake variables, such as CMAKE_SOURCE_DIR,
# CMAKE_BINARY_DIR, and CMAKE_PROJECT_NAME;
# 2. avoid using implicit include directories and relative paths;
# 3. optionally provide a way to skip the installation of libjpeg-turbo
# components when the 'install' target is built;
# 4. optionally provide a way to postfix target names, to avoid namespace
# conflicts;
# 5. restructure the top-level CMakeLists.txt so that it properly sets the
# PROJECT_VERSION variable; and
# 6. design automated regression tests to ensure that new commits don't break
# any of the above.
#
# Even if we did all of that, issues would still arise, because it is
# impossible for an upstream build system to anticipate the widely varying
# needs of every downstream build system. That's why the CMake
# ExternalProject_Add() function exists. Downstream projects that wish to
# integrate libjpeg-turbo as a subdirectory should either use
# ExternalProject_Add() or make downstream modifications to the libjpeg-turbo
# build system to suit their specific needs. Please do not file bug reports,
# feature requests, or pull requests regarding this.
if(NOT CMAKE_SOURCE_DIR STREQUAL CMAKE_CURRENT_SOURCE_DIR)
message(FATAL_ERROR "The libjpeg-turbo build system cannot be integrated into another build system using add_subdirectory(). Use ExternalProject_Add() instead.")
endif()
# CMake 3.14 and later sets CMAKE_MACOSX_BUNDLE to TRUE by default when # CMake 3.14 and later sets CMAKE_MACOSX_BUNDLE to TRUE by default when
# CMAKE_SYSTEM_NAME is iOS, tvOS, or watchOS, which breaks the libjpeg-turbo # CMAKE_SYSTEM_NAME is iOS, tvOS, or watchOS, which breaks the libjpeg-turbo
# build. (Specifically, when CMAKE_MACOSX_BUNDLE is TRUE, executables for # build. (Specifically, when CMAKE_MACOSX_BUNDLE is TRUE, executables for
@@ -70,7 +98,7 @@ string(TOLOWER ${CMAKE_SYSTEM_PROCESSOR} CMAKE_SYSTEM_PROCESSOR_LC)
set(COUNT 1) set(COUNT 1)
foreach(ARCH ${CMAKE_OSX_ARCHITECTURES}) foreach(ARCH ${CMAKE_OSX_ARCHITECTURES})
if(COUNT GREATER 1) if(COUNT GREATER 1)
message(FATAL_ERROR "The libjpeg-turbo build system does not support multiple values in CMAKE_OSX_ARCHITECTURES.") message(FATAL_ERROR "libjpeg-turbo contains assembly code, so it cannot be built with multiple values in CMAKE_OSX_ARCHITECTURES.")
endif() endif()
math(EXPR COUNT "${COUNT}+1") math(EXPR COUNT "${COUNT}+1")
endforeach() endforeach()
@@ -496,19 +524,17 @@ if(NOT INLINE_WORKS)
endif() endif()
message(STATUS "INLINE = ${INLINE} (FORCE_INLINE = ${FORCE_INLINE})") message(STATUS "INLINE = ${INLINE} (FORCE_INLINE = ${FORCE_INLINE})")
if(WITH_TURBOJPEG) if(MSVC)
if(MSVC) set(THREAD_LOCAL "__declspec(thread)")
set(THREAD_LOCAL "__declspec(thread)") else()
else() set(THREAD_LOCAL "__thread")
set(THREAD_LOCAL "__thread") endif()
endif() check_c_source_compiles("${THREAD_LOCAL} int i; int main(void) { i = 0; return i; }" HAVE_THREAD_LOCAL)
check_c_source_compiles("${THREAD_LOCAL} int i; int main(void) { i = 0; return i; }" HAVE_THREAD_LOCAL) if(HAVE_THREAD_LOCAL)
if(HAVE_THREAD_LOCAL) message(STATUS "THREAD_LOCAL = ${THREAD_LOCAL}")
message(STATUS "THREAD_LOCAL = ${THREAD_LOCAL}") else()
else() message(WARNING "Thread-local storage is not available. The TurboJPEG API library's global error handler will not be thread-safe.")
message(WARNING "Thread-local storage is not available. The TurboJPEG API library's global error handler will not be thread-safe.") unset(THREAD_LOCAL)
unset(THREAD_LOCAL)
endif()
endif() endif()
if(UNIX AND NOT APPLE) if(UNIX AND NOT APPLE)

View File

@@ -1,3 +1,70 @@
2.1.6
=====
### Significant changes relative to 2.1.5.1:
1. Fixed an oversight in 1.4 beta1[8] that caused various segfaults and buffer
overruns when attempting to decompress various specially-crafted malformed
12-bit-per-component JPEG images using a 12-bit-per-component build of djpeg
(`-DWITH_12BIT=1`) with both color quantization and RGB565 color conversion
enabled.
2. Fixed an issue whereby `jpeg_crop_scanline()` sometimes miscalculated the
downsampled width for components with 4x2 or 2x4 subsampling factors if
decompression scaling was enabled. This caused the components to be upsampled
incompletely, which caused the color converter to read from uninitialized
memory. With 12-bit data precision, this caused a buffer overrun or underrun
and subsequent segfault if the sample value read from uninitialized memory was
outside of the valid sample range.
3. Fixed a long-standing issue whereby the `tjTransform()` function, when used
with the `TJXOP_TRANSPOSE`, `TJXOP_TRANSVERSE`, `TJXOP_ROT90`, or
`TJXOP_ROT270` transform operation and without automatic JPEG destination
buffer (re)allocation or lossless cropping, computed the worst-case transformed
JPEG image size based on the source image dimensions rather than the
transformed image dimensions. If a calling program allocated the JPEG
destination buffer based on the transformed image dimensions, as the API
documentation instructs, and attempted to transform a specially-crafted 4:2:2,
4:4:0, or 4:1:1 JPEG source image containing a large amount of metadata, the
issue caused `tjTransform()` to overflow the JPEG destination buffer rather
than fail gracefully. The issue could be worked around by setting
`TJXOPT_COPYNONE`. Note that, irrespective of this issue, `tjTransform()`
cannot reliably transform JPEG source images that contain a large amount of
metadata unless automatic JPEG destination buffer (re)allocation is used or
`TJXOPT_COPYNONE` is set.
4. Fixed an issue that caused the C Huffman encoder (which is not used by
default on x86 and Arm CPUs) to read from uninitialized memory when attempting
to transform a specially-crafted malformed arithmetic-coded JPEG source image
into a baseline Huffman-coded JPEG destination image.
5. Fixed two minor issues in the interblock smoothing algorithm that caused
mathematical (but not necessarily perceptible) edge block errors when
decompressing progressive JPEG images exactly two MCU blocks in width or that
use vertical chrominance subsampling.
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 2.1.5
===== =====
@@ -178,9 +245,9 @@ transform a specially-crafted malformed JPEG image.
### 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 1. Fixed a regression (CVE-2021-29390) introduced by 2.1 beta1[6(b)] whereby
decompress certain progressive JPEG images with one or more component planes of attempting to decompress certain progressive JPEG images with one or more
width 8 or less caused a buffer overrun. component planes of width 8 or less caused a buffer overrun.
2. Fixed a regression introduced by 2.1 beta1[6(b)] whereby attempting to 2. Fixed a regression introduced by 2.1 beta1[6(b)] whereby attempting to
decompress a specially-crafted malformed progressive JPEG image caused the decompress a specially-crafted malformed progressive JPEG image caused the

View File

@@ -65,7 +65,7 @@ $(function() {
<div class="contents"> <div class="contents">
<div class="textblock">Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:</div><ul> <div class="textblock">Here is a list of all documented struct and union fields with links to the struct/union documentation for each field:</div><ul>
<li>customFilter <li>customFilter
: <a class="el" href="structtjtransform.html#afd7fc262df33f741e120ef4183202ef5">tjtransform</a> : <a class="el" href="structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2">tjtransform</a>
</li> </li>
<li>data <li>data
: <a class="el" href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">tjtransform</a> : <a class="el" href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">tjtransform</a>

View File

@@ -65,7 +65,7 @@ $(function() {
<div class="contents"> <div class="contents">
&#160;<ul> &#160;<ul>
<li>customFilter <li>customFilter
: <a class="el" href="structtjtransform.html#afd7fc262df33f741e120ef4183202ef5">tjtransform</a> : <a class="el" href="structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2">tjtransform</a>
</li> </li>
<li>data <li>data
: <a class="el" href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">tjtransform</a> : <a class="el" href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">tjtransform</a>

View File

@@ -2664,7 +2664,7 @@ If you choose option 1, then <code>*jpegSize</code> should be set to the size of
<tr><td class="paramname">dstBufs</td><td>pointer to an array of n byte buffers. <code>dstBufs[i]</code> will receive a JPEG image that has been transformed using the parameters in <code>transforms[i]</code>. TurboJPEG has the ability to reallocate the JPEG destination buffer to accommodate the size of the transformed JPEG image. Thus, you can choose to:<ol type="1"> <tr><td class="paramname">dstBufs</td><td>pointer to an array of n byte buffers. <code>dstBufs[i]</code> will receive a JPEG image that has been transformed using the parameters in <code>transforms[i]</code>. TurboJPEG has the ability to reallocate the JPEG destination buffer to accommodate the size of the transformed JPEG image. Thus, you can choose to:<ol type="1">
<li>pre-allocate the JPEG destination buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83" title="Allocate a byte buffer for use with TurboJPEG.">tjAlloc()</a> and let TurboJPEG grow the buffer as needed,</li> <li>pre-allocate the JPEG destination buffer with an arbitrary size using <a class="el" href="group___turbo_j_p_e_g.html#gaec627dd4c5f30b7a775a7aea3bec5d83" title="Allocate a byte buffer for use with TurboJPEG.">tjAlloc()</a> and let TurboJPEG grow the buffer as needed,</li>
<li>set <code>dstBufs[i]</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li> <li>set <code>dstBufs[i]</code> to NULL to tell TurboJPEG to allocate the buffer for you, or</li>
<li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga67ac12fee79073242cb216e07c9f1f90" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tjBufSize()</a> with the transformed or cropped width and height. Under normal circumstances, this should ensure that the buffer never has to be re-allocated. (Setting <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable JPEG buffer (re)allocation.">TJFLAG_NOREALLOC</a> 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 <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable JPEG buffer (re)allocation.">TJFLAG_NOREALLOC</a> cannot be used in those cases.</li> <li>pre-allocate the buffer to a "worst case" size determined by calling <a class="el" href="group___turbo_j_p_e_g.html#ga67ac12fee79073242cb216e07c9f1f90" title="The maximum size of the buffer (in bytes) required to hold a JPEG image with the given parameters.">tjBufSize()</a> with the transformed or cropped width and height and the level of subsampling used in the source image. Under normal circumstances, this should ensure that the buffer never has to be re-allocated. (Setting <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable JPEG buffer (re)allocation.">TJFLAG_NOREALLOC</a> 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 <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable JPEG buffer (re)allocation.">TJFLAG_NOREALLOC</a> cannot be used in those cases.</li>
</ol> </ol>
If you choose option 1, then <code>dstSizes[i]</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable JPEG buffer (re)allocation.">TJFLAG_NOREALLOC</a>, you should always check <code>dstBufs[i]</code> upon return from this function, as it may have changed.</td></tr> If you choose option 1, then <code>dstSizes[i]</code> should be set to the size of your pre-allocated buffer. In any case, unless you have set <a class="el" href="group___turbo_j_p_e_g.html#ga8808d403c68b62aaa58a4c1e58e98963" title="Disable JPEG buffer (re)allocation.">TJFLAG_NOREALLOC</a>, you should always check <code>dstBufs[i]</code> upon return from this function, as it may have changed.</td></tr>
<tr><td class="paramname">dstSizes</td><td>pointer to an array of n unsigned long variables that will receive the actual sizes (in bytes) of each transformed JPEG image. If <code>dstBufs[i]</code> points to a pre-allocated buffer, then <code>dstSizes[i]</code> should be set to the size of the buffer. Upon return, <code>dstSizes[i]</code> will contain the size of the transformed JPEG image (in bytes.)</td></tr> <tr><td class="paramname">dstSizes</td><td>pointer to an array of n unsigned long variables that will receive the actual sizes (in bytes) of each transformed JPEG image. If <code>dstBufs[i]</code> points to a pre-allocated buffer, then <code>dstSizes[i]</code> should be set to the size of the buffer. Upon return, <code>dstSizes[i]</code> will contain the size of the transformed JPEG image (in bytes.)</td></tr>

View File

@@ -1,4 +1,4 @@
var searchData= var searchData=
[ [
['customfilter_0',['customFilter',['../structtjtransform.html#afd7fc262df33f741e120ef4183202ef5',1,'tjtransform']]] ['customfilter_0',['customFilter',['../structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2',1,'tjtransform']]]
]; ];

View File

@@ -1,4 +1,4 @@
var searchData= var searchData=
[ [
['customfilter_142',['customFilter',['../structtjtransform.html#afd7fc262df33f741e120ef4183202ef5',1,'tjtransform']]] ['customfilter_142',['customFilter',['../structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2',1,'tjtransform']]]
]; ];

View File

@@ -89,21 +89,21 @@ Data Fields</h2></td></tr>
<tr class="memitem:a688fe8f1a8ecc12a538d9e561cf338e3"><td class="memItemLeft" align="right" valign="top">void *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">data</a></td></tr> <tr class="memitem:a688fe8f1a8ecc12a538d9e561cf338e3"><td class="memItemLeft" align="right" valign="top">void *&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">data</a></td></tr>
<tr class="memdesc:a688fe8f1a8ecc12a538d9e561cf338e3"><td class="mdescLeft">&#160;</td><td class="mdescRight">Arbitrary data that can be accessed within the body of the callback function. <a href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">More...</a><br /></td></tr> <tr class="memdesc:a688fe8f1a8ecc12a538d9e561cf338e3"><td class="mdescLeft">&#160;</td><td class="mdescRight">Arbitrary data that can be accessed within the body of the callback function. <a href="structtjtransform.html#a688fe8f1a8ecc12a538d9e561cf338e3">More...</a><br /></td></tr>
<tr class="separator:a688fe8f1a8ecc12a538d9e561cf338e3"><td class="memSeparator" colspan="2">&#160;</td></tr> <tr class="separator:a688fe8f1a8ecc12a538d9e561cf338e3"><td class="memSeparator" colspan="2">&#160;</td></tr>
<tr class="memitem:afd7fc262df33f741e120ef4183202ef5"><td class="memItemLeft" align="right" valign="top">int(*&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#afd7fc262df33f741e120ef4183202ef5">customFilter</a> )(short *coeffs, <a class="el" href="structtjregion.html">tjregion</a> arrayRegion, <a class="el" href="structtjregion.html">tjregion</a> planeRegion, int componentIndex, int transformIndex, struct <a class="el" href="structtjtransform.html">tjtransform</a> *transform)</td></tr> <tr class="memitem:a0dc7697d59a7abe48afc629e96cbc1d2"><td class="memItemLeft" align="right" valign="top">int(*&#160;</td><td class="memItemRight" valign="bottom"><a class="el" href="structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2">customFilter</a> )(short *coeffs, <a class="el" href="structtjregion.html">tjregion</a> arrayRegion, <a class="el" href="structtjregion.html">tjregion</a> planeRegion, int componentID, int transformID, struct <a class="el" href="structtjtransform.html">tjtransform</a> *transform)</td></tr>
<tr class="memdesc:afd7fc262df33f741e120ef4183202ef5"><td class="mdescLeft">&#160;</td><td class="mdescRight">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. <a href="structtjtransform.html#afd7fc262df33f741e120ef4183202ef5">More...</a><br /></td></tr> <tr class="memdesc:a0dc7697d59a7abe48afc629e96cbc1d2"><td class="mdescLeft">&#160;</td><td class="mdescRight">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. <a href="structtjtransform.html#a0dc7697d59a7abe48afc629e96cbc1d2">More...</a><br /></td></tr>
<tr class="separator:afd7fc262df33f741e120ef4183202ef5"><td class="memSeparator" colspan="2">&#160;</td></tr> <tr class="separator:a0dc7697d59a7abe48afc629e96cbc1d2"><td class="memSeparator" colspan="2">&#160;</td></tr>
</table> </table>
<a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2> <a name="details" id="details"></a><h2 class="groupheader">Detailed Description</h2>
<div class="textblock"><p>Lossless transform. </p> <div class="textblock"><p>Lossless transform. </p>
</div><h2 class="groupheader">Field Documentation</h2> </div><h2 class="groupheader">Field Documentation</h2>
<a id="afd7fc262df33f741e120ef4183202ef5"></a> <a id="a0dc7697d59a7abe48afc629e96cbc1d2"></a>
<h2 class="memtitle"><span class="permalink"><a href="#afd7fc262df33f741e120ef4183202ef5">&#9670;&nbsp;</a></span>customFilter</h2> <h2 class="memtitle"><span class="permalink"><a href="#a0dc7697d59a7abe48afc629e96cbc1d2">&#9670;&nbsp;</a></span>customFilter</h2>
<div class="memitem"> <div class="memitem">
<div class="memproto"> <div class="memproto">
<table class="memname"> <table class="memname">
<tr> <tr>
<td class="memname">int(* tjtransform::customFilter) (short *coeffs, <a class="el" href="structtjregion.html">tjregion</a> arrayRegion, <a class="el" href="structtjregion.html">tjregion</a> planeRegion, int componentIndex, int transformIndex, struct <a class="el" href="structtjtransform.html">tjtransform</a> *transform)</td> <td class="memname">int(* tjtransform::customFilter) (short *coeffs, <a class="el" href="structtjregion.html">tjregion</a> arrayRegion, <a class="el" href="structtjregion.html">tjregion</a> planeRegion, int componentID, int transformID, struct <a class="el" href="structtjtransform.html">tjtransform</a> *transform)</td>
</tr> </tr>
</table> </table>
</div><div class="memdoc"> </div><div class="memdoc">

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C)2021 D. R. Commander. All Rights Reserved. * Copyright (C)2021, 2023 D. R. Commander. All Rights Reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@@ -88,7 +88,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
when using MemorySanitizer. */ when using MemorySanitizer. */
for (i = 0; i < w * h * tjPixelSize[pf]; i++) for (i = 0; i < w * h * tjPixelSize[pf]; i++)
sum += dstBuf[i]; sum += dstBuf[i];
} } else
goto bailout;
free(dstBuf); free(dstBuf);
dstBuf = NULL; dstBuf = NULL;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C)2021 D. R. Commander. All Rights Reserved. * Copyright (C)2021, 2023 D. R. Commander. All Rights Reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@@ -90,7 +90,8 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
when using MemorySanitizer. */ when using MemorySanitizer. */
for (i = 0; i < w * h * tjPixelSize[pf]; i++) for (i = 0; i < w * h * tjPixelSize[pf]; i++)
sum += dstBuf[i]; sum += dstBuf[i];
} } else
goto bailout;
free(dstBuf); free(dstBuf);
dstBuf = NULL; dstBuf = NULL;

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C)2021 D. R. Commander. All Rights Reserved. * Copyright (C)2021, 2023 D. R. Commander. All Rights Reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@@ -32,16 +32,13 @@
#include <string.h> #include <string.h>
#define NUMXFORMS 3
extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size) extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
{ {
tjhandle handle = NULL; tjhandle handle = NULL;
unsigned char *dstBufs[NUMXFORMS] = { NULL, NULL, NULL }; unsigned char *dstBufs[1] = { NULL };
unsigned long dstSizes[NUMXFORMS] = { 0, 0, 0 }, maxBufSize; unsigned long dstSizes[1] = { 0 }, maxBufSize;
int width = 0, height = 0, jpegSubsamp, jpegColorspace, i, t; int width = 0, height = 0, jpegSubsamp, jpegColorspace, i;
tjtransform transforms[NUMXFORMS]; tjtransform transforms[1];
#if defined(__has_feature) && __has_feature(memory_sanitizer) #if defined(__has_feature) && __has_feature(memory_sanitizer)
char env[18] = "JSIMD_FORCENONE=1"; char env[18] = "JSIMD_FORCENONE=1";
@@ -67,8 +64,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
if (jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP) if (jpegSubsamp < 0 || jpegSubsamp >= TJ_NUMSAMP)
jpegSubsamp = TJSAMP_444; jpegSubsamp = TJSAMP_444;
for (t = 0; t < NUMXFORMS; t++) memset(&transforms[0], 0, sizeof(tjtransform));
memset(&transforms[t], 0, sizeof(tjtransform));
transforms[0].op = TJXOP_NONE; transforms[0].op = TJXOP_NONE;
transforms[0].options = TJXOPT_PROGRESSIVE | TJXOPT_COPYNONE; transforms[0].options = TJXOPT_PROGRESSIVE | TJXOPT_COPYNONE;
@@ -76,44 +72,76 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
if (!dstBufs[0]) if (!dstBufs[0])
goto bailout; goto bailout;
transforms[1].r.w = (width + 1) / 2;
transforms[1].r.h = (height + 1) / 2;
transforms[1].op = TJXOP_TRANSPOSE;
transforms[1].options = TJXOPT_GRAY | TJXOPT_CROP | TJXOPT_COPYNONE;
dstBufs[1] =
(unsigned char *)malloc(tjBufSize((width + 1) / 2, (height + 1) / 2,
TJSAMP_GRAY));
if (!dstBufs[1])
goto bailout;
transforms[2].op = TJXOP_ROT90;
transforms[2].options = TJXOPT_TRIM | TJXOPT_COPYNONE;
dstBufs[2] = (unsigned char *)malloc(tjBufSize(height, width, jpegSubsamp));
if (!dstBufs[2])
goto bailout;
maxBufSize = tjBufSize(width, height, jpegSubsamp); maxBufSize = tjBufSize(width, height, jpegSubsamp);
if (tjTransform(handle, data, size, NUMXFORMS, dstBufs, dstSizes, transforms, if (tjTransform(handle, data, size, 1, dstBufs, dstSizes, transforms,
TJFLAG_LIMITSCANS | TJFLAG_NOREALLOC) == 0) { TJFLAG_LIMITSCANS | TJFLAG_NOREALLOC) == 0) {
/* Touch all of the output pixels in order to catch uninitialized reads /* Touch all of the output pixels in order to catch uninitialized reads
when using MemorySanitizer. */ when using MemorySanitizer. */
for (t = 0; t < NUMXFORMS; t++) { int sum = 0;
int sum = 0;
for (i = 0; i < dstSizes[t]; i++) for (i = 0; i < dstSizes[0]; i++)
sum += dstBufs[t][i]; sum += dstBufs[0][i];
/* Prevent the code above from being optimized out. This test should /* Prevent the code above from being optimized out. This test should
never be true, but the compiler doesn't know that. */ never be true, but the compiler doesn't know that. */
if (sum > 255 * maxBufSize) if (sum > 255 * maxBufSize)
goto bailout; goto bailout;
}
} }
transforms[0].options &= ~TJXOPT_COPYNONE;
free(dstBufs[0]); free(dstBufs[0]);
dstBufs[0] = NULL; dstBufs[0] = NULL;
transforms[0].r.w = (height + 1) / 2;
transforms[0].r.h = (width + 1) / 2;
transforms[0].op = TJXOP_TRANSPOSE;
transforms[0].options = TJXOPT_GRAY | TJXOPT_CROP | TJXOPT_COPYNONE;
dstBufs[0] =
(unsigned char *)malloc(tjBufSize((height + 1) / 2, (width + 1) / 2,
jpegSubsamp));
if (!dstBufs[0])
goto bailout;
maxBufSize = tjBufSize((height + 1) / 2, (width + 1) / 2, jpegSubsamp);
if (tjTransform(handle, data, size, 1, dstBufs, dstSizes, transforms,
TJFLAG_LIMITSCANS | TJFLAG_NOREALLOC) == 0) {
int sum = 0;
for (i = 0; i < dstSizes[0]; i++)
sum += dstBufs[0][i];
if (sum > 255 * maxBufSize)
goto bailout;
}
free(dstBufs[0]);
dstBufs[0] = NULL;
transforms[0].op = TJXOP_ROT90;
transforms[0].options = TJXOPT_TRIM;
dstBufs[0] = (unsigned char *)malloc(tjBufSize(height, width, jpegSubsamp));
if (!dstBufs[0])
goto bailout;
maxBufSize = tjBufSize(height, width, jpegSubsamp);
if (tjTransform(handle, data, size, 1, dstBufs, dstSizes, transforms,
TJFLAG_LIMITSCANS | TJFLAG_NOREALLOC) == 0) {
int sum = 0;
for (i = 0; i < dstSizes[0]; i++)
sum += dstBufs[0][i];
if (sum > 255 * maxBufSize)
goto bailout;
}
free(dstBufs[0]);
dstBufs[0] = NULL;
transforms[0].op = TJXOP_NONE;
transforms[0].options = TJXOPT_PROGRESSIVE;
dstSizes[0] = 0; dstSizes[0] = 0;
if (tjTransform(handle, data, size, 1, dstBufs, dstSizes, transforms, if (tjTransform(handle, data, size, 1, dstBufs, dstSizes, transforms,
@@ -128,8 +156,7 @@ extern "C" int LLVMFuzzerTestOneInput(const uint8_t *data, size_t size)
} }
bailout: bailout:
for (t = 0; t < NUMXFORMS; t++) free(dstBufs[0]);
free(dstBufs[t]);
if (handle) tjDestroy(handle); if (handle) tjDestroy(handle);
return 0; return 0;
} }

View File

@@ -499,7 +499,7 @@ final class TJBench {
// Original image // Original image
int w = 0, h = 0, ntilesw = 1, ntilesh = 1, subsamp = -1, cs = -1; int w = 0, h = 0, ntilesw = 1, ntilesh = 1, subsamp = -1, cs = -1;
// Transformed image // Transformed image
int tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp; int minTile, tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp;
FileInputStream fis = new FileInputStream(fileName); FileInputStream fis = new FileInputStream(fileName);
if (fis.getChannel().size() > (long)Integer.MAX_VALUE) if (fis.getChannel().size() > (long)Integer.MAX_VALUE)
@@ -541,7 +541,8 @@ final class TJBench {
(flags & TJ.FLAG_BOTTOMUP) != 0 ? (flags & TJ.FLAG_BOTTOMUP) != 0 ?
"Bottom-up" : "Top-down"); "Bottom-up" : "Top-down");
for (int tilew = doTile ? 16 : w, tileh = doTile ? 16 : h; ; minTile = Math.max(TJ.getMCUWidth(subsamp), TJ.getMCUHeight(subsamp));
for (int tilew = doTile ? minTile : w, tileh = doTile ? minTile : h; ;
tilew *= 2, tileh *= 2) { tilew *= 2, tileh *= 2) {
if (tilew > w) if (tilew > w)
tilew = w; tilew = w;

View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1997, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright (C) 2009-2011, 2014-2016, 2018-2022, D. R. Commander. * Copyright (C) 2009-2011, 2014-2016, 2018-2023, D. R. Commander.
* Copyright (C) 2015, Matthieu Darbois. * Copyright (C) 2015, Matthieu Darbois.
* Copyright (C) 2018, Matthias Räncker. * Copyright (C) 2018, Matthias Räncker.
* Copyright (C) 2020, Arm Limited. * Copyright (C) 2020, Arm Limited.
@@ -500,6 +500,8 @@ flush_bits(working_state *state)
int localbuf = 0; int localbuf = 0;
if (state->simd) { if (state->simd) {
if (state->cur.free_bits < 0)
ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
#if defined(__aarch64__) && !defined(NEON_INTRINSICS) #if defined(__aarch64__) && !defined(NEON_INTRINSICS)
put_bits = state->cur.free_bits; put_bits = state->cur.free_bits;
#else #else
@@ -518,7 +520,7 @@ flush_bits(working_state *state)
temp = (JOCTET)(put_buffer >> put_bits); temp = (JOCTET)(put_buffer >> put_bits);
EMIT_BYTE(temp) EMIT_BYTE(temp)
} }
if (put_bits) { if (put_bits > 0) {
/* fill partial byte with ones */ /* fill partial byte with ones */
temp = (JOCTET)((put_buffer << (8 - put_bits)) | (0xFF >> put_bits)); temp = (JOCTET)((put_buffer << (8 - put_bits)) | (0xFF >> put_bits));
EMIT_BYTE(temp) EMIT_BYTE(temp)
@@ -588,6 +590,11 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
/* Find the number of bits needed for the magnitude of the coefficient */ /* Find the number of bits needed for the magnitude of the coefficient */
nbits = JPEG_NBITS(nbits); nbits = JPEG_NBITS(nbits);
/* Check for out-of-range coefficient values.
* Since we're encoding a difference, the range limit is twice as much.
*/
if (nbits > MAX_COEF_BITS + 1)
ERREXIT(state->cinfo, JERR_BAD_DCT_COEF);
/* Emit the Huffman-coded symbol for the number of bits. /* Emit the Huffman-coded symbol for the number of bits.
* Emit that number of bits of the value, if positive, * Emit that number of bits of the value, if positive,
@@ -613,6 +620,9 @@ encode_one_block(working_state *state, JCOEFPTR block, int last_dc_val,
temp += nbits; \ temp += nbits; \
nbits ^= temp; \ nbits ^= temp; \
nbits = JPEG_NBITS_NONZERO(nbits); \ nbits = JPEG_NBITS_NONZERO(nbits); \
/* Check for out-of-range coefficient values */ \
if (nbits > MAX_COEF_BITS) \
ERREXIT(state->cinfo, JERR_BAD_DCT_COEF); \
/* if run length > 15, must emit special run-length-16 codes (0xF0) */ \ /* if run length > 15, must emit special run-length-16 codes (0xF0) */ \
while (r >= 16 * 16) { \ while (r >= 16 * 16) { \
r -= 16 * 16; \ r -= 16 * 16; \

View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1994-1996, Thomas G. Lane. * Copyright (C) 1994-1996, Thomas G. Lane.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright (C) 2010, 2015-2020, 2022, D. R. Commander. * Copyright (C) 2010, 2015-2020, 2022-2023, D. R. Commander.
* Copyright (C) 2015, Google, Inc. * Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg * For conditions of distribution and use, see the accompanying README.ijg
* file. * file.
@@ -236,9 +236,11 @@ jpeg_crop_scanline(j_decompress_ptr cinfo, JDIMENSION *xoffset,
/* Set downsampled_width to the new output width. */ /* Set downsampled_width to the new output width. */
orig_downsampled_width = compptr->downsampled_width; orig_downsampled_width = compptr->downsampled_width;
compptr->downsampled_width = compptr->downsampled_width =
(JDIMENSION)jdiv_round_up((long)(cinfo->output_width * (JDIMENSION)jdiv_round_up((long)cinfo->output_width *
compptr->h_samp_factor), (long)(compptr->h_samp_factor *
(long)cinfo->max_h_samp_factor); compptr->_DCT_scaled_size),
(long)(cinfo->max_h_samp_factor *
cinfo->_min_DCT_scaled_size));
if (compptr->downsampled_width < 2 && orig_downsampled_width >= 2) if (compptr->downsampled_width < 2 && orig_downsampled_width >= 2)
reinit_upsampler = TRUE; reinit_upsampler = TRUE;

View File

@@ -5,7 +5,7 @@
* Copyright (C) 1994-1997, Thomas G. Lane. * Copyright (C) 1994-1997, Thomas G. Lane.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2010, 2015-2016, 2019-2020, 2022, D. R. Commander. * Copyright (C) 2010, 2015-2016, 2019-2020, 2022-2023, D. R. Commander.
* Copyright (C) 2015, 2020, Google, Inc. * Copyright (C) 2015, 2020, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg * For conditions of distribution and use, see the accompanying README.ijg
* file. * file.
@@ -430,7 +430,8 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
my_coef_ptr coef = (my_coef_ptr)cinfo->coef; my_coef_ptr coef = (my_coef_ptr)cinfo->coef;
JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1; JDIMENSION last_iMCU_row = cinfo->total_iMCU_rows - 1;
JDIMENSION block_num, last_block_column; JDIMENSION block_num, last_block_column;
int ci, block_row, block_rows, access_rows; int ci, block_row, block_rows, access_rows, image_block_row,
image_block_rows;
JBLOCKARRAY buffer; JBLOCKARRAY buffer;
JBLOCKROW buffer_ptr, prev_prev_block_row, prev_block_row; JBLOCKROW buffer_ptr, prev_prev_block_row, prev_block_row;
JBLOCKROW next_block_row, next_next_block_row; JBLOCKROW next_block_row, next_next_block_row;
@@ -496,6 +497,7 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
(JDIMENSION)access_rows, FALSE); (JDIMENSION)access_rows, FALSE);
buffer += 2 * compptr->v_samp_factor; /* point to current iMCU row */ buffer += 2 * compptr->v_samp_factor; /* point to current iMCU row */
} else if (cinfo->output_iMCU_row > 0) { } else if (cinfo->output_iMCU_row > 0) {
access_rows += compptr->v_samp_factor; /* prior iMCU row too */
buffer = (*cinfo->mem->access_virt_barray) buffer = (*cinfo->mem->access_virt_barray)
((j_common_ptr)cinfo, coef->whole_image[ci], ((j_common_ptr)cinfo, coef->whole_image[ci],
(cinfo->output_iMCU_row - 1) * compptr->v_samp_factor, (cinfo->output_iMCU_row - 1) * compptr->v_samp_factor,
@@ -538,29 +540,30 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
inverse_DCT = cinfo->idct->inverse_DCT[ci]; inverse_DCT = cinfo->idct->inverse_DCT[ci];
output_ptr = output_buf[ci]; output_ptr = output_buf[ci];
/* Loop over all DCT blocks to be processed. */ /* Loop over all DCT blocks to be processed. */
image_block_rows = block_rows * cinfo->total_iMCU_rows;
for (block_row = 0; block_row < block_rows; block_row++) { for (block_row = 0; block_row < block_rows; block_row++) {
image_block_row = cinfo->output_iMCU_row * block_rows + block_row;
buffer_ptr = buffer[block_row] + cinfo->master->first_MCU_col[ci]; buffer_ptr = buffer[block_row] + cinfo->master->first_MCU_col[ci];
if (block_row > 0 || cinfo->output_iMCU_row > 0) if (image_block_row > 0)
prev_block_row = prev_block_row =
buffer[block_row - 1] + cinfo->master->first_MCU_col[ci]; buffer[block_row - 1] + cinfo->master->first_MCU_col[ci];
else else
prev_block_row = buffer_ptr; prev_block_row = buffer_ptr;
if (block_row > 1 || cinfo->output_iMCU_row > 1) if (image_block_row > 1)
prev_prev_block_row = prev_prev_block_row =
buffer[block_row - 2] + cinfo->master->first_MCU_col[ci]; buffer[block_row - 2] + cinfo->master->first_MCU_col[ci];
else else
prev_prev_block_row = prev_block_row; prev_prev_block_row = prev_block_row;
if (block_row < block_rows - 1 || cinfo->output_iMCU_row < last_iMCU_row) if (image_block_row < image_block_rows - 1)
next_block_row = next_block_row =
buffer[block_row + 1] + cinfo->master->first_MCU_col[ci]; buffer[block_row + 1] + cinfo->master->first_MCU_col[ci];
else else
next_block_row = buffer_ptr; next_block_row = buffer_ptr;
if (block_row < block_rows - 2 || if (image_block_row < image_block_rows - 2)
cinfo->output_iMCU_row + 1 < last_iMCU_row)
next_next_block_row = next_next_block_row =
buffer[block_row + 2] + cinfo->master->first_MCU_col[ci]; buffer[block_row + 2] + cinfo->master->first_MCU_col[ci];
else else
@@ -583,11 +586,11 @@ decompress_smooth_data(j_decompress_ptr cinfo, JSAMPIMAGE output_buf)
/* Update DC values */ /* Update DC values */
if (block_num == cinfo->master->first_MCU_col[ci] && if (block_num == cinfo->master->first_MCU_col[ci] &&
block_num < last_block_column) { block_num < last_block_column) {
DC04 = (int)prev_prev_block_row[1][0]; DC04 = DC05 = (int)prev_prev_block_row[1][0];
DC09 = (int)prev_block_row[1][0]; DC09 = DC10 = (int)prev_block_row[1][0];
DC14 = (int)buffer_ptr[1][0]; DC14 = DC15 = (int)buffer_ptr[1][0];
DC19 = (int)next_block_row[1][0]; DC19 = DC20 = (int)next_block_row[1][0];
DC24 = (int)next_next_block_row[1][0]; DC24 = DC25 = (int)next_next_block_row[1][0];
} }
if (block_num + 1 < last_block_column) { if (block_num + 1 < last_block_column) {
DC05 = (int)prev_prev_block_row[2][0]; DC05 = (int)prev_prev_block_row[2][0];

View File

@@ -5,7 +5,7 @@
* Copyright (C) 1991-1997, Thomas G. Lane. * Copyright (C) 1991-1997, Thomas G. Lane.
* Modified 2002-2009 by Guido Vollbeding. * Modified 2002-2009 by Guido Vollbeding.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright (C) 2009-2011, 2016, 2019, 2022, D. R. Commander. * Copyright (C) 2009-2011, 2016, 2019, 2022-2023, D. R. Commander.
* Copyright (C) 2013, Linaro Limited. * Copyright (C) 2013, Linaro Limited.
* Copyright (C) 2015, Google, Inc. * Copyright (C) 2015, Google, Inc.
* For conditions of distribution and use, see the accompanying README.ijg * For conditions of distribution and use, see the accompanying README.ijg
@@ -480,7 +480,8 @@ master_selection(j_decompress_ptr cinfo)
if (cinfo->raw_data_out) if (cinfo->raw_data_out)
ERREXIT(cinfo, JERR_NOTIMPL); ERREXIT(cinfo, JERR_NOTIMPL);
/* 2-pass quantizer only works in 3-component color space. */ /* 2-pass quantizer only works in 3-component color space. */
if (cinfo->out_color_components != 3) { if (cinfo->out_color_components != 3 ||
cinfo->out_color_space == JCS_RGB565) {
cinfo->enable_1pass_quant = TRUE; cinfo->enable_1pass_quant = TRUE;
cinfo->enable_external_quant = FALSE; cinfo->enable_external_quant = FALSE;
cinfo->enable_2pass_quant = FALSE; cinfo->enable_2pass_quant = FALSE;

View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1994, Thomas G. Lane. * Copyright (C) 1991-1994, Thomas G. Lane.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright (C) 2022, D. R. Commander. * Copyright (C) 2022-2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg * For conditions of distribution and use, see the accompanying README.ijg
* file. * file.
* *
@@ -123,6 +123,8 @@ static INLINE int GETENV_S(char *buffer, size_t buffer_size, const char *name)
#else #else
#include <errno.h>
/* This provides a similar interface to the Microsoft _putenv_s() function, but /* This provides a similar interface to the Microsoft _putenv_s() function, but
* other than parameter validation, it has no advantages over setenv(). * other than parameter validation, it has no advantages over setenv().
*/ */

View File

@@ -5,7 +5,7 @@
* Copyright (C) 1991-1998, Thomas G. Lane. * Copyright (C) 1991-1998, Thomas G. Lane.
* Modified 2002-2009 by Guido Vollbeding. * Modified 2002-2009 by Guido Vollbeding.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright (C) 2009-2011, 2013-2014, 2016-2017, 2020, D. R. Commander. * Copyright (C) 2009-2011, 2013-2014, 2016-2017, 2020, 2023, D. R. Commander.
* Copyright (C) 2015, Google, Inc. * Copyright (C) 2015, Google, Inc.
* mozjpeg Modifications: * mozjpeg Modifications:
* Copyright (C) 2014, Mozilla Corporation. * Copyright (C) 2014, Mozilla Corporation.
@@ -240,7 +240,8 @@ typedef enum {
JCS_EXT_BGRA, /* blue/green/red/alpha */ JCS_EXT_BGRA, /* blue/green/red/alpha */
JCS_EXT_ABGR, /* alpha/blue/green/red */ JCS_EXT_ABGR, /* alpha/blue/green/red */
JCS_EXT_ARGB, /* alpha/red/green/blue */ JCS_EXT_ARGB, /* alpha/red/green/blue */
JCS_RGB565 /* 5-bit red/6-bit green/5-bit blue */ JCS_RGB565 /* 5-bit red/6-bit green/5-bit blue
[decompression only] */
} J_COLOR_SPACE; } J_COLOR_SPACE;
/* DCT/IDCT algorithm options. */ /* DCT/IDCT algorithm options. */

View File

@@ -4,7 +4,7 @@
* This file was part of the Independent JPEG Group's software: * This file was part of the Independent JPEG Group's software:
* Copyright (C) 1991-1996, Thomas G. Lane. * Copyright (C) 1991-1996, Thomas G. Lane.
* libjpeg-turbo Modifications: * libjpeg-turbo Modifications:
* Copyright (C) 2009, 2014-2015, 2020, D. R. Commander. * Copyright (C) 2009, 2014-2015, 2020, 2023, D. R. Commander.
* For conditions of distribution and use, see the accompanying README.ijg * For conditions of distribution and use, see the accompanying README.ijg
* file. * file.
* *
@@ -1230,7 +1230,8 @@ jinit_2pass_quantizer(j_decompress_ptr cinfo)
cquantize->error_limiter = NULL; cquantize->error_limiter = NULL;
/* Make sure jdmaster didn't give me a case I can't handle */ /* Make sure jdmaster didn't give me a case I can't handle */
if (cinfo->out_color_components != 3) if (cinfo->out_color_components != 3 ||
cinfo->out_color_space == JCS_RGB565)
ERREXIT(cinfo, JERR_NOTIMPL); ERREXIT(cinfo, JERR_NOTIMPL);
/* Allocate the histogram/inverse colormap storage */ /* Allocate the histogram/inverse colormap storage */

View File

@@ -193,7 +193,7 @@ read_scan_script (j_compress_ptr cinfo, char *filename)
int scanno, ncomps, termchar; int scanno, ncomps, termchar;
long val; long val;
jpeg_scan_info *scanptr; jpeg_scan_info *scanptr;
#define MAX_SCANS 100 /* quite arbitrary limit */ #define MAX_SCANS 64 /* must match scan_buffer size */
jpeg_scan_info scans[MAX_SCANS]; jpeg_scan_info scans[MAX_SCANS];
if ((fp = fopen(filename, "r")) == NULL) { if ((fp = fopen(filename, "r")) == NULL) {

View File

@@ -2,4 +2,4 @@ libjpeg-turbo is a JPEG image codec that uses SIMD instructions to accelerate ba
libjpeg-turbo implements both the traditional libjpeg API as well as the less powerful but more straightforward TurboJPEG API. libjpeg-turbo also features colorspace extensions that allow it to compress from/decompress to 32-bit and big-endian pixel buffers (RGBX, XBGR, etc.), as well as a full-featured Java interface. libjpeg-turbo implements both the traditional libjpeg API as well as the less powerful but more straightforward TurboJPEG API. libjpeg-turbo also features colorspace extensions that allow it to compress from/decompress to 32-bit and big-endian pixel buffers (RGBX, XBGR, etc.), as well as a full-featured Java interface.
libjpeg-turbo was originally based on libjpeg/SIMD, an MMX-accelerated derivative of libjpeg v6b developed by Miyasaka Masaru. The TigerVNC and VirtualGL projects made numerous enhancements to the codec in 2009, and in early 2010, libjpeg-turbo spun off into an independent project, with the goal of making high-speed JPEG compression/decompression technology available to a broader range of users and developers. libjpeg-turbo was originally based on libjpeg/SIMD, an MMX-accelerated derivative of libjpeg v6b developed by Miyasaka Masaru. The TigerVNC and VirtualGL projects made numerous enhancements to the codec in 2009, and in early 2010, libjpeg-turbo spun off into an independent project, with the goal of making high-speed JPEG compression/decompression technology available to a broader range of users and developers. libjpeg-turbo is an ISO/IEC and ITU-T reference implementation of the JPEG standard.

View File

@@ -77,7 +77,8 @@ derivative of libjpeg v6b developed by Miyasaka Masaru. The TigerVNC and
VirtualGL projects made numerous enhancements to the codec in 2009, and in VirtualGL projects made numerous enhancements to the codec in 2009, and in
early 2010, libjpeg-turbo spun off into an independent project, with the goal early 2010, libjpeg-turbo spun off into an independent project, with the goal
of making high-speed JPEG compression/decompression technology available to a of making high-speed JPEG compression/decompression technology available to a
broader range of users and developers. broader range of users and developers. libjpeg-turbo is an ISO/IEC and ITU-T
reference implementation of the JPEG standard.
#-->%prep #-->%prep
#-->%setup -q -n @CMAKE_PROJECT_NAME@-%{version} #-->%setup -q -n @CMAKE_PROJECT_NAME@-%{version}

View File

@@ -2,7 +2,7 @@
* jsimd_i386.c * jsimd_i386.c
* *
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022, D. R. Commander. * Copyright (C) 2009-2011, 2013-2014, 2016, 2018, 2022-2023, D. R. Commander.
* Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois. * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
* *
* Based on the x86 SIMD extension for IJG JPEG library, * Based on the x86 SIMD extension for IJG JPEG library,
@@ -158,6 +158,9 @@ jsimd_rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int); void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
void (*mmxfct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int); void (*mmxfct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
if (simd_support == ~0U)
init_simd();
switch (cinfo->in_color_space) { switch (cinfo->in_color_space) {
case JCS_EXT_RGB: case JCS_EXT_RGB:
avx2fct = jsimd_extrgb_ycc_convert_avx2; avx2fct = jsimd_extrgb_ycc_convert_avx2;
@@ -217,6 +220,9 @@ jsimd_rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int); void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
void (*mmxfct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int); void (*mmxfct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
if (simd_support == ~0U)
init_simd();
switch (cinfo->in_color_space) { switch (cinfo->in_color_space) {
case JCS_EXT_RGB: case JCS_EXT_RGB:
avx2fct = jsimd_extrgb_gray_convert_avx2; avx2fct = jsimd_extrgb_gray_convert_avx2;
@@ -276,6 +282,9 @@ jsimd_ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int); void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int); void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
if (simd_support == ~0U)
init_simd();
switch (cinfo->out_color_space) { switch (cinfo->out_color_space) {
case JCS_EXT_RGB: case JCS_EXT_RGB:
avx2fct = jsimd_ycc_extrgb_convert_avx2; avx2fct = jsimd_ycc_extrgb_convert_avx2;
@@ -379,6 +388,9 @@ GLOBAL(void)
jsimd_h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data) JSAMPARRAY input_data, JSAMPARRAY output_data)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v2_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor, jsimd_h2v2_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
compptr->v_samp_factor, compptr->v_samp_factor,
@@ -399,6 +411,9 @@ GLOBAL(void)
jsimd_h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data) JSAMPARRAY input_data, JSAMPARRAY output_data)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v1_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor, jsimd_h2v1_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
compptr->v_samp_factor, compptr->v_samp_factor,
@@ -461,6 +476,9 @@ GLOBAL(void)
jsimd_h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr) JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v2_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width, jsimd_h2v2_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
input_data, output_data_ptr); input_data, output_data_ptr);
@@ -476,6 +494,9 @@ GLOBAL(void)
jsimd_h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr) JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v1_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width, jsimd_h2v1_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
input_data, output_data_ptr); input_data, output_data_ptr);
@@ -537,6 +558,9 @@ GLOBAL(void)
jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr) JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v2_fancy_upsample_avx2(cinfo->max_v_samp_factor, jsimd_h2v2_fancy_upsample_avx2(cinfo->max_v_samp_factor,
compptr->downsampled_width, input_data, compptr->downsampled_width, input_data,
@@ -555,6 +579,9 @@ GLOBAL(void)
jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr) JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v1_fancy_upsample_avx2(cinfo->max_v_samp_factor, jsimd_h2v1_fancy_upsample_avx2(cinfo->max_v_samp_factor,
compptr->downsampled_width, input_data, compptr->downsampled_width, input_data,
@@ -623,6 +650,9 @@ jsimd_h2v2_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY); void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY); void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
if (simd_support == ~0U)
init_simd();
switch (cinfo->out_color_space) { switch (cinfo->out_color_space) {
case JCS_EXT_RGB: case JCS_EXT_RGB:
avx2fct = jsimd_h2v2_extrgb_merged_upsample_avx2; avx2fct = jsimd_h2v2_extrgb_merged_upsample_avx2;
@@ -681,6 +711,9 @@ jsimd_h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY); void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY); void (*mmxfct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
if (simd_support == ~0U)
init_simd();
switch (cinfo->out_color_space) { switch (cinfo->out_color_space) {
case JCS_EXT_RGB: case JCS_EXT_RGB:
avx2fct = jsimd_h2v1_extrgb_merged_upsample_avx2; avx2fct = jsimd_h2v1_extrgb_merged_upsample_avx2;
@@ -785,6 +818,9 @@ GLOBAL(void)
jsimd_convsamp(JSAMPARRAY sample_data, JDIMENSION start_col, jsimd_convsamp(JSAMPARRAY sample_data, JDIMENSION start_col,
DCTELEM *workspace) DCTELEM *workspace)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_convsamp_avx2(sample_data, start_col, workspace); jsimd_convsamp_avx2(sample_data, start_col, workspace);
else if (simd_support & JSIMD_SSE2) else if (simd_support & JSIMD_SSE2)
@@ -797,6 +833,9 @@ GLOBAL(void)
jsimd_convsamp_float(JSAMPARRAY sample_data, JDIMENSION start_col, jsimd_convsamp_float(JSAMPARRAY sample_data, JDIMENSION start_col,
FAST_FLOAT *workspace) FAST_FLOAT *workspace)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_SSE2) if (simd_support & JSIMD_SSE2)
jsimd_convsamp_float_sse2(sample_data, start_col, workspace); jsimd_convsamp_float_sse2(sample_data, start_col, workspace);
else if (simd_support & JSIMD_SSE) else if (simd_support & JSIMD_SSE)
@@ -867,6 +906,9 @@ jsimd_can_fdct_float(void)
GLOBAL(void) GLOBAL(void)
jsimd_fdct_islow(DCTELEM *data) jsimd_fdct_islow(DCTELEM *data)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_fdct_islow_avx2(data); jsimd_fdct_islow_avx2(data);
else if (simd_support & JSIMD_SSE2) else if (simd_support & JSIMD_SSE2)
@@ -878,6 +920,9 @@ jsimd_fdct_islow(DCTELEM *data)
GLOBAL(void) GLOBAL(void)
jsimd_fdct_ifast(DCTELEM *data) jsimd_fdct_ifast(DCTELEM *data)
{ {
if (simd_support == ~0U)
init_simd();
if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_fdct_islow_sse2)) if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_fdct_islow_sse2))
jsimd_fdct_ifast_sse2(data); jsimd_fdct_ifast_sse2(data);
else else
@@ -887,6 +932,9 @@ jsimd_fdct_ifast(DCTELEM *data)
GLOBAL(void) GLOBAL(void)
jsimd_fdct_float(FAST_FLOAT *data) jsimd_fdct_float(FAST_FLOAT *data)
{ {
if (simd_support == ~0U)
init_simd();
if ((simd_support & JSIMD_SSE) && IS_ALIGNED_SSE(jconst_fdct_float_sse)) if ((simd_support & JSIMD_SSE) && IS_ALIGNED_SSE(jconst_fdct_float_sse))
jsimd_fdct_float_sse(data); jsimd_fdct_float_sse(data);
else if (simd_support & JSIMD_3DNOW) else if (simd_support & JSIMD_3DNOW)
@@ -942,6 +990,9 @@ jsimd_can_quantize_float(void)
GLOBAL(void) GLOBAL(void)
jsimd_quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace) jsimd_quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_quantize_avx2(coef_block, divisors, workspace); jsimd_quantize_avx2(coef_block, divisors, workspace);
else if (simd_support & JSIMD_SSE2) else if (simd_support & JSIMD_SSE2)
@@ -954,6 +1005,9 @@ GLOBAL(void)
jsimd_quantize_float(JCOEFPTR coef_block, FAST_FLOAT *divisors, jsimd_quantize_float(JCOEFPTR coef_block, FAST_FLOAT *divisors,
FAST_FLOAT *workspace) FAST_FLOAT *workspace)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_SSE2) if (simd_support & JSIMD_SSE2)
jsimd_quantize_float_sse2(coef_block, divisors, workspace); jsimd_quantize_float_sse2(coef_block, divisors, workspace);
else if (simd_support & JSIMD_SSE) else if (simd_support & JSIMD_SSE)
@@ -1017,6 +1071,9 @@ jsimd_idct_2x2(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col) JDIMENSION output_col)
{ {
if (simd_support == ~0U)
init_simd();
if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_red_sse2)) if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_red_sse2))
jsimd_idct_2x2_sse2(compptr->dct_table, coef_block, output_buf, jsimd_idct_2x2_sse2(compptr->dct_table, coef_block, output_buf,
output_col); output_col);
@@ -1029,6 +1086,9 @@ jsimd_idct_4x4(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col) JDIMENSION output_col)
{ {
if (simd_support == ~0U)
init_simd();
if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_red_sse2)) if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_red_sse2))
jsimd_idct_4x4_sse2(compptr->dct_table, coef_block, output_buf, jsimd_idct_4x4_sse2(compptr->dct_table, coef_block, output_buf,
output_col); output_col);
@@ -1123,6 +1183,9 @@ jsimd_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col) JDIMENSION output_col)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_idct_islow_avx2(compptr->dct_table, coef_block, output_buf, jsimd_idct_islow_avx2(compptr->dct_table, coef_block, output_buf,
output_col); output_col);
@@ -1139,6 +1202,9 @@ jsimd_idct_ifast(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col) JDIMENSION output_col)
{ {
if (simd_support == ~0U)
init_simd();
if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_ifast_sse2)) if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_ifast_sse2))
jsimd_idct_ifast_sse2(compptr->dct_table, coef_block, output_buf, jsimd_idct_ifast_sse2(compptr->dct_table, coef_block, output_buf,
output_col); output_col);
@@ -1152,6 +1218,9 @@ jsimd_idct_float(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col) JDIMENSION output_col)
{ {
if (simd_support == ~0U)
init_simd();
if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_float_sse2)) if ((simd_support & JSIMD_SSE2) && IS_ALIGNED_SSE(jconst_idct_float_sse2))
jsimd_idct_float_sse2(compptr->dct_table, coef_block, output_buf, jsimd_idct_float_sse2(compptr->dct_table, coef_block, output_buf,
output_col); output_col);

View File

@@ -2,7 +2,7 @@
* jsimd_x86_64.c * jsimd_x86_64.c
* *
* Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB * Copyright 2009 Pierre Ossman <ossman@cendio.se> for Cendio AB
* Copyright (C) 2009-2011, 2014, 2016, 2018, 2022, D. R. Commander. * Copyright (C) 2009-2011, 2014, 2016, 2018, 2022-2023, D. R. Commander.
* Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois. * Copyright (C) 2015-2016, 2018, 2022, Matthieu Darbois.
* *
* Based on the x86 SIMD extension for IJG JPEG library, * Based on the x86 SIMD extension for IJG JPEG library,
@@ -145,6 +145,9 @@ jsimd_rgb_ycc_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
void (*avx2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int); void (*avx2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int); void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
if (simd_support == ~0U)
init_simd();
switch (cinfo->in_color_space) { switch (cinfo->in_color_space) {
case JCS_EXT_RGB: case JCS_EXT_RGB:
avx2fct = jsimd_extrgb_ycc_convert_avx2; avx2fct = jsimd_extrgb_ycc_convert_avx2;
@@ -194,6 +197,9 @@ jsimd_rgb_gray_convert(j_compress_ptr cinfo, JSAMPARRAY input_buf,
void (*avx2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int); void (*avx2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int); void (*sse2fct) (JDIMENSION, JSAMPARRAY, JSAMPIMAGE, JDIMENSION, int);
if (simd_support == ~0U)
init_simd();
switch (cinfo->in_color_space) { switch (cinfo->in_color_space) {
case JCS_EXT_RGB: case JCS_EXT_RGB:
avx2fct = jsimd_extrgb_gray_convert_avx2; avx2fct = jsimd_extrgb_gray_convert_avx2;
@@ -243,6 +249,9 @@ jsimd_ycc_rgb_convert(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int); void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int); void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY, int);
if (simd_support == ~0U)
init_simd();
switch (cinfo->out_color_space) { switch (cinfo->out_color_space) {
case JCS_EXT_RGB: case JCS_EXT_RGB:
avx2fct = jsimd_ycc_extrgb_convert_avx2; avx2fct = jsimd_ycc_extrgb_convert_avx2;
@@ -333,6 +342,9 @@ GLOBAL(void)
jsimd_h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v2_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data) JSAMPARRAY input_data, JSAMPARRAY output_data)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v2_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor, jsimd_h2v2_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
compptr->v_samp_factor, compptr->v_samp_factor,
@@ -349,6 +361,9 @@ GLOBAL(void)
jsimd_h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v1_downsample(j_compress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY output_data) JSAMPARRAY input_data, JSAMPARRAY output_data)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v1_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor, jsimd_h2v1_downsample_avx2(cinfo->image_width, cinfo->max_v_samp_factor,
compptr->v_samp_factor, compptr->v_samp_factor,
@@ -403,6 +418,9 @@ GLOBAL(void)
jsimd_h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v2_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr) JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v2_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width, jsimd_h2v2_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
input_data, output_data_ptr); input_data, output_data_ptr);
@@ -415,6 +433,9 @@ GLOBAL(void)
jsimd_h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v1_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr) JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v1_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width, jsimd_h2v1_upsample_avx2(cinfo->max_v_samp_factor, cinfo->output_width,
input_data, output_data_ptr); input_data, output_data_ptr);
@@ -469,6 +490,9 @@ GLOBAL(void)
jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v2_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr) JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v2_fancy_upsample_avx2(cinfo->max_v_samp_factor, jsimd_h2v2_fancy_upsample_avx2(cinfo->max_v_samp_factor,
compptr->downsampled_width, input_data, compptr->downsampled_width, input_data,
@@ -483,6 +507,9 @@ GLOBAL(void)
jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr, jsimd_h2v1_fancy_upsample(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr) JSAMPARRAY input_data, JSAMPARRAY *output_data_ptr)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_h2v1_fancy_upsample_avx2(cinfo->max_v_samp_factor, jsimd_h2v1_fancy_upsample_avx2(cinfo->max_v_samp_factor,
compptr->downsampled_width, input_data, compptr->downsampled_width, input_data,
@@ -542,6 +569,9 @@ jsimd_h2v2_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY); void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY); void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
if (simd_support == ~0U)
init_simd();
switch (cinfo->out_color_space) { switch (cinfo->out_color_space) {
case JCS_EXT_RGB: case JCS_EXT_RGB:
avx2fct = jsimd_h2v2_extrgb_merged_upsample_avx2; avx2fct = jsimd_h2v2_extrgb_merged_upsample_avx2;
@@ -590,6 +620,9 @@ jsimd_h2v1_merged_upsample(j_decompress_ptr cinfo, JSAMPIMAGE input_buf,
void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY); void (*avx2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY); void (*sse2fct) (JDIMENSION, JSAMPIMAGE, JDIMENSION, JSAMPARRAY);
if (simd_support == ~0U)
init_simd();
switch (cinfo->out_color_space) { switch (cinfo->out_color_space) {
case JCS_EXT_RGB: case JCS_EXT_RGB:
avx2fct = jsimd_h2v1_extrgb_merged_upsample_avx2; avx2fct = jsimd_h2v1_extrgb_merged_upsample_avx2;
@@ -679,6 +712,9 @@ GLOBAL(void)
jsimd_convsamp(JSAMPARRAY sample_data, JDIMENSION start_col, jsimd_convsamp(JSAMPARRAY sample_data, JDIMENSION start_col,
DCTELEM *workspace) DCTELEM *workspace)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_convsamp_avx2(sample_data, start_col, workspace); jsimd_convsamp_avx2(sample_data, start_col, workspace);
else else
@@ -748,6 +784,9 @@ jsimd_can_fdct_float(void)
GLOBAL(void) GLOBAL(void)
jsimd_fdct_islow(DCTELEM *data) jsimd_fdct_islow(DCTELEM *data)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_fdct_islow_avx2(data); jsimd_fdct_islow_avx2(data);
else else
@@ -809,6 +848,9 @@ jsimd_can_quantize_float(void)
GLOBAL(void) GLOBAL(void)
jsimd_quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace) jsimd_quantize(JCOEFPTR coef_block, DCTELEM *divisors, DCTELEM *workspace)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_quantize_avx2(coef_block, divisors, workspace); jsimd_quantize_avx2(coef_block, divisors, workspace);
else else
@@ -963,6 +1005,9 @@ jsimd_idct_islow(j_decompress_ptr cinfo, jpeg_component_info *compptr,
JCOEFPTR coef_block, JSAMPARRAY output_buf, JCOEFPTR coef_block, JSAMPARRAY output_buf,
JDIMENSION output_col) JDIMENSION output_col)
{ {
if (simd_support == ~0U)
init_simd();
if (simd_support & JSIMD_AVX2) if (simd_support & JSIMD_AVX2)
jsimd_idct_islow_avx2(compptr->dct_table, coef_block, output_buf, jsimd_idct_islow_avx2(compptr->dct_table, coef_block, output_buf,
output_col); output_col);

View File

@@ -1,5 +1,5 @@
/* /*
* Copyright (C)2022 D. R. Commander. All Rights Reserved. * Copyright (C)2022-2023 D. R. Commander. All Rights Reserved.
* *
* Redistribution and use in source and binary forms, with or without * Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met: * modification, are permitted provided that the following conditions are met:
@@ -55,8 +55,12 @@ void invalid_parameter_handler(const wchar_t *expression,
int main(int argc, char **argv) int main(int argc, char **argv)
{ {
#if !defined(NO_GETENV) || !defined(NO_PUTENV)
int err; int err;
#endif
#ifndef NO_GETENV
char env[3]; char env[3];
#endif
#ifdef _MSC_VER #ifdef _MSC_VER
_set_invalid_parameter_handler(invalid_parameter_handler); _set_invalid_parameter_handler(invalid_parameter_handler);

View File

@@ -534,8 +534,8 @@ static int decompTest(char *fileName)
int ps = tjPixelSize[pf], tile, row, col, i, iter, retval = 0, decompsrc = 0; int ps = tjPixelSize[pf], tile, row, col, i, iter, retval = 0, decompsrc = 0;
char *temp = NULL, tempStr[80], tempStr2[80]; char *temp = NULL, tempStr[80], tempStr2[80];
/* Original image */ /* Original image */
int w = 0, h = 0, tilew, tileh, ntilesw = 1, ntilesh = 1, subsamp = -1, int w = 0, h = 0, minTile, tilew, tileh, ntilesw = 1, ntilesh = 1,
cs = -1; subsamp = -1, cs = -1;
/* Transformed image */ /* Transformed image */
int tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp; int tw, th, ttilew, ttileh, tntilesw, tntilesh, tsubsamp;
@@ -580,7 +580,8 @@ static int decompTest(char *fileName)
formatName(subsamp, cs, tempStr), pixFormatStr[pf], formatName(subsamp, cs, tempStr), pixFormatStr[pf],
(flags & TJFLAG_BOTTOMUP) ? "Bottom-up" : "Top-down"); (flags & TJFLAG_BOTTOMUP) ? "Bottom-up" : "Top-down");
for (tilew = doTile ? 16 : w, tileh = doTile ? 16 : h; ; minTile = max(tjMCUWidth[subsamp], tjMCUHeight[subsamp]);
for (tilew = doTile ? minTile : w, tileh = doTile ? minTile : h; ;
tilew *= 2, tileh *= 2) { tilew *= 2, tileh *= 2) {
if (tilew > w) tilew = w; if (tilew > w) tilew = w;
if (tileh > h) tileh = h; if (tileh > h) tileh = h;
@@ -599,10 +600,16 @@ static int decompTest(char *fileName)
if ((flags & TJFLAG_NOREALLOC) != 0 && if ((flags & TJFLAG_NOREALLOC) != 0 &&
(doTile || xformOp != TJXOP_NONE || xformOpt != 0 || customFilter)) (doTile || xformOp != TJXOP_NONE || xformOpt != 0 || customFilter))
for (i = 0; i < ntilesw * ntilesh; i++) { for (i = 0; i < ntilesw * ntilesh; i++) {
if (tjBufSize(tilew, tileh, subsamp) > (unsigned long)INT_MAX) unsigned long jpegBufSize;
if (xformOp == TJXOP_TRANSPOSE || xformOp == TJXOP_TRANSVERSE ||
xformOp == TJXOP_ROT90 || xformOp == TJXOP_ROT270)
jpegBufSize = tjBufSize(tileh, tilew, subsamp);
else
jpegBufSize = tjBufSize(tilew, tileh, subsamp);
if (jpegBufSize > (unsigned long)INT_MAX)
THROW("getting buffer size", "Image is too large"); THROW("getting buffer size", "Image is too large");
if ((jpegBuf[i] = (unsigned char *) if ((jpegBuf[i] = (unsigned char *)tjAlloc(jpegBufSize)) == NULL)
tjAlloc(tjBufSize(tilew, tileh, subsamp))) == NULL)
THROW_UNIX("allocating JPEG tiles"); THROW_UNIX("allocating JPEG tiles");
} }

View File

@@ -36,6 +36,7 @@
#define _CRT_SECURE_NO_DEPRECATE #define _CRT_SECURE_NO_DEPRECATE
#endif #endif
#include <limits.h>
#include <stdio.h> #include <stdio.h>
#include <stdlib.h> #include <stdlib.h>
#include <string.h> #include <string.h>
@@ -274,6 +275,8 @@ int main(int argc, char **argv)
if (size == 0) if (size == 0)
THROW("determining input file size", "Input file contains no data"); THROW("determining input file size", "Input file contains no data");
jpegSize = (unsigned long)size; jpegSize = (unsigned long)size;
if (jpegSize > (unsigned long)INT_MAX)
THROW("allocating JPEG buffer", "Input file is too large");
if ((jpegBuf = (unsigned char *)tjAlloc(jpegSize)) == NULL) if ((jpegBuf = (unsigned char *)tjAlloc(jpegSize)) == NULL)
THROW_UNIX("allocating JPEG buffer"); THROW_UNIX("allocating JPEG buffer");
if (fread(jpegBuf, jpegSize, 1, jpegFile) < 1) if (fread(jpegBuf, jpegSize, 1, jpegFile) < 1)
@@ -331,8 +334,12 @@ int main(int argc, char **argv)
outSubsamp = inSubsamp; outSubsamp = inSubsamp;
pixelFormat = TJPF_BGRX; pixelFormat = TJPF_BGRX;
if ((imgBuf = (unsigned char *)tjAlloc(width * height * if ((unsigned long long)width * height * tjPixelSize[pixelFormat] >
tjPixelSize[pixelFormat])) == NULL) (unsigned long long)((size_t)-1))
THROW("allocating uncompressed image buffer", "Image is too large");
if ((imgBuf =
(unsigned char *)malloc(sizeof(unsigned char) * width * height *
tjPixelSize[pixelFormat])) == NULL)
THROW_UNIX("allocating uncompressed image buffer"); THROW_UNIX("allocating uncompressed image buffer");
if (tjDecompress2(tjInstance, jpegBuf, jpegSize, imgBuf, width, 0, height, if (tjDecompress2(tjInstance, jpegBuf, jpegSize, imgBuf, width, 0, height,

View File

@@ -1203,6 +1203,10 @@ JNIEXPORT jintArray JNICALL Java_org_libjpegturbo_turbojpeg_TJTransformer_transf
for (i = 0; i < n; i++) { for (i = 0; i < n; i++) {
int w = jpegWidth, h = jpegHeight; int w = jpegWidth, h = jpegHeight;
if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
w = jpegHeight; h = jpegWidth;
}
if (t[i].r.w != 0) w = t[i].r.w; if (t[i].r.w != 0) w = t[i].r.w;
if (t[i].r.h != 0) h = t[i].r.h; if (t[i].r.h != 0) h = t[i].r.h;
BAILIF0(jdstBufs[i] = (*env)->GetObjectArrayElement(env, dstobjs, i)); BAILIF0(jdstBufs[i] = (*env)->GetObjectArrayElement(env, dstobjs, i));

View File

@@ -2065,6 +2065,10 @@ DLLEXPORT int tjTransform(tjhandle handle, const unsigned char *jpegBuf,
if (!xinfo[i].crop) { if (!xinfo[i].crop) {
w = dinfo->image_width; h = dinfo->image_height; w = dinfo->image_width; h = dinfo->image_height;
if (t[i].op == TJXOP_TRANSPOSE || t[i].op == TJXOP_TRANSVERSE ||
t[i].op == TJXOP_ROT90 || t[i].op == TJXOP_ROT270) {
w = dinfo->image_height; h = dinfo->image_width;
}
} else { } else {
w = xinfo[i].crop_width; h = xinfo[i].crop_height; w = xinfo[i].crop_width; h = xinfo[i].crop_height;
} }

View File

@@ -656,8 +656,8 @@ typedef struct tjtransform {
* @return 0 if the callback was successful, or -1 if an error occurred. * @return 0 if the callback was successful, or -1 if an error occurred.
*/ */
int (*customFilter) (short *coeffs, tjregion arrayRegion, int (*customFilter) (short *coeffs, tjregion arrayRegion,
tjregion planeRegion, int componentIndex, tjregion planeRegion, int componentID, int transformID,
int transformIndex, struct tjtransform *transform); struct tjtransform *transform);
} tjtransform; } tjtransform;
/** /**
@@ -1517,13 +1517,14 @@ DLLEXPORT tjhandle tjInitTransform(void);
* -# set `dstBufs[i]` to NULL to tell TurboJPEG to allocate the buffer for * -# set `dstBufs[i]` to NULL to tell TurboJPEG to allocate the buffer for
* you, or * you, or
* -# pre-allocate the buffer to a "worst case" size determined by calling * -# pre-allocate the buffer to a "worst case" size determined by calling
* #tjBufSize() with the transformed or cropped width and height. Under normal * #tjBufSize() with the transformed or cropped width and height and the level
* circumstances, this should ensure that the buffer never has to be * of subsampling used in the source image. Under normal circumstances, this
* re-allocated. (Setting #TJFLAG_NOREALLOC guarantees that it won't be.) * should ensure that the buffer never has to be re-allocated. (Setting
* Note, however, that there are some rare cases (such as transforming images * #TJFLAG_NOREALLOC guarantees that it won't be.) Note, however, that there
* with a large amount of embedded EXIF or ICC profile data) in which the * are some rare cases (such as transforming images with a large amount of
* transformed JPEG image will be larger than the worst-case size, and * embedded EXIF or ICC profile data) in which the transformed JPEG image will
* #TJFLAG_NOREALLOC cannot be used in those cases. * be larger than the worst-case size, and #TJFLAG_NOREALLOC cannot be used in
* those cases.
* . * .
* If you choose option 1, then `dstSizes[i]` should be set to the size of your * 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, * pre-allocated buffer. In any case, unless you have set #TJFLAG_NOREALLOC,